20 sierpnia 2008

Operatory . i [] w JSF 1.2 i egzamin JSF 1.1 - Basic na javaBLACKbelt

Podczas lektury książki o facelets (cf. Book review: Facelets) pojawiło się kilka przykładów konstrukcji Unified EL typu #{bean['value']}. Dla przypomnienia, Unified EL jest językiem wyrażeń wspólnym dla JSF 1.2 i JSP 2.1 (co za zbieg okoliczności z tymi numerami!). W zasadzie, to zgodnie z zapisami w specyfikacji JSF 1.2, rozdział 1.3.7 package javax.faces.el:

As of version 1.2 of this specification, all classes and interfaces in this package have been deprecated in favor of the Unified Expression Language (EL) from JSP 2.1.

Please see Chapter 5 "Expression Language and Managed Bean Facility".


Co oznacza ni mniej, ni więcej, że język wyrażeń JSF zmigrował (upodobnił się) do języka wyrażeń w JSP 2.1. Jako uzupełnienie dodam, że w rozdziale 5 Expression Language and Managed Bean Facility specyfikacji JSF 1.2 napisano:

JavaServer Faces relies on the Unified Expression Language (Unified EL, or just EL) provided by version 2.1 of the JavaServer Pages specification. The EL is described in a separate specification document delivered as part of the JSP 2.1 spec. Please consult that document for complete details about the EL.

Zaglądając do specyfikacji Expression Language Specification Version 2.1 (A component of the JavaServer Pages Specification Version 2.1), do rozdziału 1.6 Operators [] and . znalazłem to, czego nie mogłem zrozumieć podczas lektury książki Facelets:

The EL follows ECMAScript in unifying the treatment of the . and [] operators.

expr-a.identifier-b is equivalent to expr-a["identifier-b"];


I właśnie to było powodem mojego braku zrozumienia zapisów ${bean[items]} (tym razem wyrażenie JSP ze względu na użycie dolara '$' jako wyróżnika, kto - JSP vs JSF - i kiedy będzie interpretował wyrażenie) z książki. Sądziłem do tej pory, że wspomniana konstrukcja #{bean['value']} jest zarezerwowana wyłącznie dla atrybutów ziaren zarządzanych, których typem jest mapa (java.util.Map), czyli konstrukcja #{bean.localeMap.pl} jest równoznaczna z #{bean.localeMap['pl']}, gdzie bean dostarcza metody public Map getLocaleMap(). Teraz już wiem, że bean['value'] odpowiada bean.value, czyli (najczęściej) wykonaniu metody bean.getValue(). Należałoby wspomnieć, że realizacja rozwiązania wyrażenia pozostawia się w JSF obiektowi typu javax.el.ELResolver (więcej o nim w rozdziale 5.5.2 ELResolver specyfikacji JSF 1.2).

I zapewne nie pisałbym o tym, gdyby nie fakt, że znalazłem się dzisiaj na javaBLACKbelt i zachciało mi się egzaminu. Przeglądając listę egzaminów trafiłem na egzamin JSF 1.1 - Basic, który początkowo oblałem (już nie pamiętam kiedy i dlaczego, ale wprost nie mogłem uwierzyć, że wciąż jest na liście do poprawki). Dzisiaj był ten dzień, kiedy postanowiłem popróbować się z nim ponownie. I warto było! Bodajże 3. pytanie właśnie dotknęło wspomnianego tematu operatorów . i [] autorstwa Piotra Kowalskiego (!):
 #{bean.value}

is the same as

#{bean['value']}
I kiedy zobaczyłem je, od razu mnie olśniło! Odpowiedź jest...nie, nie odpowiem wprost i tak już wszystko wiadome, więc po co odkrywać Amerykę skoro dawno odkryta ;-) Teraz i Ty będziesz znał(a) odpowiedź! Może pora na podejście do JSF 1.1 - Basic? Pochwal się wynikiem i czy trafiłeś/-aś na wspomniane pytanie.

Poza tym jednym pytaniem od Piotra, dostałem jeszcze kolejne jego 4 pytania (dwa dotyczyły javax.faces.CONFIG_FILES) i muszę przyznać, że były na na prawdę wysokim poziomie. Gratulacje! Widać gość zna się na rzeczy. Na swoje jedno również trafiłem i może dlatego ostatecznie zakończyłem egzamin z wynikiem 22/ 24 = 91%. Pozostało 7 punktów do niebieskiego pasa (!), a przede mną darmowe Java SE Base API - Intermed, Java 5 New Language Features oraz XML Core - Basic.

Na koniec mojej przygody ze specyfikacją "Expression Language Specification Version 2.1" całkiem przypadkowo trafiłem na rozdział 1.17 Enums dotyczący typów wyliczeniowych (enum). Dowiedziałem się w nim o nieznanej mi wcześniej metodzie
 public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
Przykład użycia to (przykład ze specyfikacji) ${mySuit == 'Spade'}, który uruchomiłby Enum.valueOf(Suit.class, 'Spade'), który z kolei zwróciłby wartość Suit.Spade typu wyliczeniowego Suit. Nie wiem do tej pory, dlaczego zrobiła na mnie takie wrażenie, ale coś mi mówi, że kiedyś takiej metody poszukiwałem. Dodatkowo warto zapoznawać się z tego typu metodami, gdyż przyzwyczajają (= uczą obcować) z typami generycznymi (szablonowymi?), których mistrzami niewielu mogłoby się nazwać (dobrym materiałem szkoleniowym są z pewnością dwie pozycje - Java Generics FAQs - Frequently Asked Questions oraz Generics in the Java Programming Language, których całkowicie nie udało mi się jeszcze "skonsumować").

Pytanie konkursowe: W jaki sposób rozróżnia się wyrażenia JSF i JSP?