wtorek, 24 lutego 2009

Pierwsze spotkanie Wrocław Java User Group


Tak tak moi mili, w końcu doczekaliśmy się wrocławskiego JUGa! Od czasu jak skończyłem zabawę ze studiami na Politechnice Wrocławskiej (i pałeczkę nad PWrJUG przejął kto inny), zastanawiałem się czy i kiedy ruszyć z wrocławskim JUGiem. No i tyle czasu mi to zastanawianie się zajęło, że temat w końcu ruszył ktoś inny, a mi pozostaje się już tylko przyłączyć. W głowie mam pełno pomysłów, jeśli chociaż połowe z nich uda się zrealizować, myślę, że będzie ciekawie.

Poniżej oficjalne zaproszenie ze strony Wrocław JUG:

Witam,
Mam ogromną przyjemność poinformować Was o powstaniu Wrocławskiej Grupy Użytkowników Technologii Java (tak, wreszcie ;-)

Już w najbliższy wtorek 24 lutego o godzinie 18:30 w sali 119 Instytutu Informatyki Uniwersytetu Wrocławskiego odbędzie się nasze pierwsze spotkanie. Wszystkich serdecznie zapraszamy.

Na początek Przemysław Pokrywka przybliży nam statycznie typizowaną wersję dobrze znanego wzorca builder. Wzorzec ten przeżywa teraz renesans popularności dzięki publikacjom Josha Blocha i oddźwięku w blogosferze. Nie radzi sobie jednak najlepiej z obsługą najbardziej skomplikowanych przypadków. Sprawdzenie poprawności parametrów tworzonego obiektu następuje późno - dopiero w czasie wykonania. Przemek przedstawi jego usprawnienie, dzięki któremu można zablokować możliwość tworzenia niepoprawnych obiektów już na etapie kompilacji. Pokaże, jak je wykorzystać na przykładzie zaczerpniętym z wrocławskiej rzeczywistości - czynności, która normalnie powinna być prosta, a została wspaniale skomplikowana - płatności za przedszkole :)

Przemek programuje w Javie od 9 lat, od 4 lat komercyjnie. Interesują go tematy z kręgu OOP, refaktoryzacji, wzorców projektowych, podejścia funkcyjnego, AOSD, SCM, Linux, open-source, agile, lean.

Z racji tego, że będzie to pierwsze spotkanie Wrocław JUG, po prelekcji Przemka zamierzamy omówić sprawy organizacyjne. Chcemy się przedstawić :-) , powiedzieć Wam jakie mamy plany i pomysły związane z Wrocław JUG. Wysłuchać Waszych opinii, pomysłów, dowiedzieć się jakie macie oczekiwania. Liczymy też na Waszą pomoc przy dalszym rozwijaniu całej inicjatywy.

Przewidywany czas spotkanie to około 2 godziny. Wstęp wolny!

Więcej informacji oraz aktualności związane z działalnością Wrocław JUG możecie znaleźć na www.wroclaw.jug.pl.

Serdecznie zapraszam (w moim i moich kolegów imieniu)
Paweł Zubkiewicz


Z mojej strony powiem tyle: przybywajcie licznie, im więcej nas, tym lepiej dla wszystkich :)

czwartek, 29 stycznia 2009

JBoss: jeden serwer, wiele domen

JBoss w standardowej konfiguracji przygotowany jest do pracy z jedną domeną. Oczywiście może obsługiwać więcej domen, ale wszystkie domeny dla danego serwera będą odwoływać się do tej samej instancji.
Przykładowo załóżmy, że kupiliśmy dwie domeny dla naszych dwóch niezależnych biznesów:

kwiaty-na-zamowienie.pl
antypatia.pl

Obie domeny wskazują na ten sam adres IP naszego serwera aplikacyjnego.

Napisaliśmy dwie niezależne aplikacje wykorzystując J2EE i spakowaliśmy je do war'ów lub ear'ów, w naszym przykładzie kwiaty.war oraz antypatia.war. Jeśli wdrożymy je na serwer aplikacyjny, bedziemy mieli do nich dostep z adresów:

http://kwiaty-na-zamowienie.pl/kwiaty
http://antypatia.pl/antypatia

Co jest nie tak z tym rozwiązaniem? Cóż, abstrachując narazie od faktu, że nikt nam nigdy nie wejdzie na naszą stronę (bo ludzie przezwyczajeni są do tego, iż w adresie wpisują tylko adres domeny (antypatia.pl, kwiaty-na-zamowienie.pl) i nie dopisują nic po slashu), musimy mieć jeszcze na uwadze, że takie adresy też będą działać:

http://kwiaty-na-zamowienie.pl/antypatia
http://antypatia.pl/kwiaty

a to już jest totalnie nie do zaakceptowania. O ile obie aplikacje są wdrożone na tym samym serwerze , o tyle chcielibyśmy http://kwiaty-na-zamowienie.pl przenosilo nas do aplikacji kwiaty.war, a http://antypatia.pl/ do aplikacji aplikacja.war.

Na szczęście serwer JBoss obsługuje wirtualne serwery w ramach różnych domen. Innymi słowy jesteśmy wstanie tak skonfigurować serwer aplikacyjny, aby obługiwał żądania w zależności od tego z jaką domeną będzie każdorazowo żadanie powiązane.
Konfirgurację tą przeprowadzamy w pliku server.xml (gdzie znaleźć ten plik pisałem w poście o zmianie defaultowego portu w JBossie). Cały trik polega na dodaniu tagów <Host> dla każdego wirtualnego serwera, który chcemy obsługiwać. Tak więc, aby obsłużyć dwie wspomniane już wcześniej domeny należy:

1. w pliku server.xml dodać:

<Server>

(...)
<Engine name="jboss.web" defaultHost="vhost1">
<Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm"
certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
/>
<Logger className="org.jboss.web.tomcat.Log4jLogger"
verbosityLevel="WARNING"
category="org.jboss.web.localhost.Engine"/>

<Host name="kwiaty" autoDeploy="true"
deployOnStartup="true" deployXML="true">
<Alias>kwiaty-na-zamowienie.pl
<Alias>www.kwiaty-na-zamowienie.pl
<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="vhost1" suffix=".log" pattern="common"
directory="${jboss.server.home.dir}/log"/>


<DefaultContext cookies="true" crossContext="true" override="true"/>
</Host>
<Host name="antypatia" autoDeploy="true"
deployOnStartup="true" deployXML="true">
<Alias>www.antypatia.pl
<Alias>antypatia.pl

<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="vhost2" suffix=".log" pattern="common"
directory="${jboss.server.home.dir}/log"/>

<DefaultContext cookies="true" crossContext="true" override="true"/>
</Host>
</Engine>
</Service>
</Server>
2. powiadomić każdą z aplikacji do jakiego serwera wirtualnego należą

W tym celu wystarczy w pliku jboss-web.xml dodać wpis (na przykładzie aplikacji antypatia.pl):
<jboss-web>
<virtual-host>antypatia.pl</virtual-host>
</jboss-web>

Na koniec aby nasza strona była widoczna z adres www.antypatia.pl a nie z www.antypatia.pl/antypatia, zmieniamy contextRoot na /.

Aby tego dokonać należy:

a) w przypadku aplikacji webowych będących poza plikiem .ear ponownie wyedytować plik i dodac wpis
<jboss-web>
<context-root>/</context-root>
<virtual-host>antypatia.pl</virtual-host>
</jboss-web>

b) w przypadku aplikacji pakowanych do pliku .ear

* wyedytować plik wdrożeniowy application.xml


<application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4"

(...)

<module>        
   <ejb>antypatia.jar    
</module>    
<module>        
   <web>            
     <web-uri>web-client.war</web-uri>            
     <context-root>/</context-root>        
   </web>    
</module>
</application>


Jesli naszego .eara budujemy przez Mavena, odpowiednik powyższego wpisu znajdziemy w POMie.


referencje:
http://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch07.html#ch9.virtualhost.ex
http://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch06.html
http://ranjankumar.com/2008/08/14/how-to-set-context-root-of-web-application-in-jboss/

środa, 28 stycznia 2009

News Buzz: 28 styczeń 2009

Kilka ciekawych artykułów znalezionych w sieci:

  • GIT: kompedium wiedzy - GIT to repozytorium kodu stworzone przez Linusa Torvaldsa (tak, ten gość od Linuxa), które zbiera ostatnimi czasy coraz większe rzesze zwolenników. Główne zalety to szybkość, rozproszona struktura oraz cudowne podejście do branch'y (jeśli kolejny dzień klniesz na svn, bo znów rzucił jakiś konflikt przy zwykłym margeu, zapoznaj sie z GITem - tu wszystko od poczatku do konca jest branchem i marge działają o niebo lepiej). W tym poście autor zebrał ogromną ilość linków do najróżniejszych zasobów w sieci odnoszących się do GITa. Gorąco polecam.
  • Optimize Your Team - ciekawy i relatywnie krótki post odnoszący się do metodyk zwinnych. Trendy, których w polskich firmach IT pewnie jeszcze długo nie zobaczymy
  • Maven 2 advanced - jak mówi sam autor, w sieci jest trylion tutoriali pokazujących podstawy Mavena, o wiele mniej artykułów odnośnie ciutke bardziej skomplikowanych przykładów niż przysłowiowe Hallo world. Pokaz slajdów ze spotkania włoskiego JUG Roma.
  • JEE6 - JPA 2.0 - aby być na czasie i wiedzieć w jakim kierunku zmierza enterprise Java, zachęcam do zapoznania się z tym krótkim wpisem
Miłego czytania :)

wtorek, 27 stycznia 2009

Unable to find valid certification path to requested target

Jeśli nawiązujecie połączenie z usługą sieciową (web service) poprzez https (czyli z użyciem SSL) natrafić możecie na dość znany wyjątek:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


Oznacza to tyle, że łączymy się z usługą przez SSL i nie znamy lub nie akceptujemy certyfikatu uwierzytelniającego tej usługi. Gdybyśmy łączyli się ze stroną www przez przeglądarkę, wyskoczyłoby nam znane okienko informujące nas, że połączenie nie może być nawiązane, gdyż (cytując Firefox'a) "certyfikat nie jest zaufany, ponieważ certyfikat wystawcy nie jest zaufany.". Wtedy najczęściej klikamy "Zaufaj witrynie" lub "Potwierdź wyjątek bezpieczeństwa" i już możemy oglądać naszą witrynę w bezpiecznym połączeniu SSL.

W przypadku programów napisanych w języku Java, nie mamy pewności, że zawsze po drugiej stronie aplikacji będzie siedział użytkownik, który kliknie "Potwierdź wyjątek bezpieczeństwa". Dlatego, aby aplikacja łączyła się zawsze poprawnie przez SSL, należy wcześniej ten "wyjątek" potwierdzić.
Najprostszym sposobem jest wygenerowanie tak zwanego keystore'a dla danego certyfikatu i potem użycie go w aplikacji. Robi się to w sposób następujący:

1. wygenerowanie pliku .cer

Jest to plik reprezentujący certyfikat. Często jest udostępniany przez firmę, z której serwerem łączymy się przez SSL. Jeśli jednak nie mamy do niego dostępu najprościej go zdobyć wchodząc na dany adres usługi (ten adres uslugi, z która później ma łączyć się nasza aplikacja) poprzez dowolną przeglądarkę. Potwierdzić certyfikat, następnie odnaleźć go w ustawieniach przeglądarki i na końcu wyeksportować do pliku .cer. Większość przeglądarek (na pewno Firefox i Opera) udostępniają taką funkcjonalność.

2. wygenerować keystore

Keystore możemy wygenerować wraz z narzędziem keytool, które dostępne mamy zawsze wraz z naszym JDK. Wywołujemy ten program w konsoli w sposób następujący:

keytool -import -trustcacerts -keystore cacerts -storepass twoje_haslo -noprompt -file cert.cer

gdzie: -file to wygenerowany w punkcie pierwszym plik .cer, -keystore to nazwa pliku keystore (może być dowolna), -storepass to hasło które będzie używane wraz z danym keystorem.

3. ustawienie propertiesów

Na końcu należy wygenerowany plik keystore (w naszym przypadku nazywa się cacerts) wrzucić do katalogu naszej aplikacji, a w samym kodzie ustawić dwa dodatkowe propertiesy:


System.setProperty("javax.net.ssl.trustStore", "cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "twoje_haslo");


Od tego momentu powinniśmy bez problemów łączyć się z dowolną bramką webservicową (czy też jakąkolwiek usługą w sieci) poprzez SSL.

Referencje:
http://wso2.org/forum/thread/3018
http://blogs.sun.com/andreas/entry/no_more_unable_to_find

czwartek, 22 stycznia 2009

Java Killers #10

Dziejszy Java Killer prosty i niezbyt wyrafinowany. Ależ jak wiele bólu może dostarczyć, gdy taki kod dostanie się na produkcje, wie tylko programista, który to przeżył...
No dobra, nie jest, aż tak tragicznie, ale mimo wszystko boli. Pytanie na dziś, co wypisze na konsoli działanie poniższego programu:


public static void main(String[] args) {

SortedSet names = new TreeSet();

names.add("Gąskalska Anna");
names.add("Enigmatyczna Jola");
names.add("Ambroży Tomasz");
names.add("Ędward Ącki");

System.out.println(names);

}



Odpowiedzi możliwych kilka, a prawdziwa jak zwykle tylko jedna:

A) [Gąskalska Anna]
B) [Ambroży Tomasz, Enigmatyczna Jola, Gąskalska Anna, Ędward Ącki]
C) [Ambroży Tomasz, Enigmatyczna Jola, Ędward Ącki, Gąskalska Anna ]
D) [Ambroży Tomasz, Ędward Ącki, Enigmatyczna Jola, Gąskalska Anna ]
E) java.util.SortedSet@122cdb6
F) błąd kompilacji



Otóż okazuje się, że prawidłowa odpowiedź to:
B) [Ambroży Tomasz, Enigmatyczna Jola, Gąskalska Anna, Ędward Ącki]

Jak to!? Przecież miała być lista posortowana alfbatecznie! Co jest grane? Cóż, program zachowuje się zgodnie ze specyfikacją, gdzie wyraźnie czytamy:

Method comparesTo (...) compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. (...) Method compareTo returns the difference of the two character values at position k in the two string -- that is, the value this.charAt(k)-anotherString.charAt(k).


A jak przyjrzymy się znakom Unicode, polskie krzaczki mają wartości o niebo większe od standardowych literek z alfabetu łacińskiego. I tak ę, ą, ć, ń, ż, ź, ś, ó oraz ł będzie zawsze stać za całą resztą abecadła.
Miejscie to prosze na uwadze, sortując swoje listy :)

środa, 21 stycznia 2009

Oracle Application Server (Apex) nie wstaje

Instalując Oracla na Ubuntu natknąłem się na ciekawą sytuację. Instancja bazy była uruchomiona, jednakże nie mogłem połączyć się z Application Serverem (a konkretnie z aplikacja apex, zarządzającą bazą danych). Ponieważ podobną sytuację spotkałem na dwóch różnych kompach, pomyślałęm, że podziele się wiedzą jak wyjść z takiego impasu.

Ponieważ żadnym Oraclowym ekspertem nie jestem, zrobiłem to co wydawało się intuicyjne:

1. sprawdziłem status

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe status
[sudo] password for pawel:

LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 03-NOV-2008 19:35:13

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
TNS-12541: TNS:no listener
TNS-12560: TNS:protocol adapter error
TNS-00511: No listener
Linux Error: 111: Connection refused
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=ingrid)(PORT=1521)))
TNS-12541: TNS:no listener
TNS-12560: TNS:protocol adapter error
TNS-00511: No listener
Linux Error: 111: Connection refused


2. Zrestartowałem

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe restart
Shutting down Oracle Database 10g Express Edition Instance.
Stopping Oracle Net Listener.

Starting Oracle Net Listener.
Starting Oracle Database 10g Express Edition Instance.

3. I zaczeło działać :)

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe status

LSNRCTL for Linux: Version 10.2.0.1.0 - Production

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.1.0 - Production
Uptime 0 days 0 hr. 0 min. 52 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Default Service XE
Listener Parameter File /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/admin/listener.ora
Listener Log File /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/log/listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=ingrid)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=8080))(Presentation=HTTP)(Session=RAW))
Services Summary...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
Service "XE" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
Service "XEXDB" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
Service "XE_XPT" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
The command completed successfully


Ot wielka filozofia... Ale działa i to chyba najważniejsze :)

wtorek, 20 stycznia 2009

SCJP passed, na horyzoncie SCBCD

Ten post przygotwany miałem już kilka miesięcy temu, ale gdzieś się zawieruszył w czeluściach archiwum. Cóż, lepiej późno niż wcale :)

Od dłuższego czasu jestem czytelnikiem bloga Racjonalny Developer. Z autorem bloga nie znam się za bardzo (wymieniliśmy kiedyś jedną czy dwie korespondencje), ale jednak mamy coś wspólnego. Po pierwsze w podobnym czasie pozakładaliśmy blogi, oboje mamy wpisy o trikach w javie (u mnie seria Java Killers u niego luźne wpisy), a teraz na dodatek zdaliśmy oboje SCJP w podobnym czasie i oboje przymierzamy się do SCBCD. Może to zbieg okoliczności, choć jak mówił Vandetta "nie ma zbiegów okoliczności, jest tylko ich złudzenie".
No ale pomyślałem sobie, że skoro racjonalny developer się chwali to ja też mogę. Zdałem SCJP 6.0. Hurra! Czy było trudno, hm... ciężko powiedzieć co znaczy trudno. Wydawało mi się, że będzie to bułka z masłem, a zdałem na 80%. Jeśli chcesz wiedzieć czy zdasz wystarczy przerobić 3 symulatory SCJP (których pełno w książkach i na sieci) i jeśli średnia wyniesie więcej jak 70% to spokojnie możesz się wybrać. Jeśli natomiast zależy ci na dogłebnym zdobyciu wiedzy, czyli nie idziesz po certyfikat tylko po to, żeby go mieć, ale też chcesz się czegoś po prostu w świecie nauczyć, polecam zdecydowanie książkę "SCJP, SCJD - Complete Java 2 Certification - Study Guide, 5Ed". Nie ma chyba bardziej kompletnego podręcznika do SCJP niż właśnie ta książka autorstwa Philip Heller oraz Simon Roberts (nota bene autorów wielu pytań egzaminacyjnych SCJP). Dodatkowo jako reviewu polecam "Sun Certified Programmer for Java 5 Study Guide" autorstwa Kathy Sierra. Książka jest prawie kompletna (kilku informacji w niej nie znalazłem), ale zawiera za to CD z mock egzaminami. Bardzio fajnie rozwiązane są te próbne egzaminy, gdyż jeśli nie znasz odpowiedzi na dane pytanie, program wskazuje Ci dokładne miejsce w książce, gdzie odpowiedź na to pytanie znajdziedz. Narzędzie bardzo przydatne przy powtórkach.

czwartek, 13 listopada 2008

Name clash: has the same erasure but does not override it

Pisząc aplikacje wykorzystujące generyki, możecie natrafić na przedziwny błąd. Wyobraźcie sobie interfejs IDao (z pojedyncza metoda updateStubs(List<T>) oraz klasę, która go implementuje AbstractDao. I nagle kompilator krzyczy:

Name clash: The method updateStubs(List) of type AbstractDao<T> has the same erasure as updateStubs(List) of type IDao but does not override it.


Zaraz zaraz, metoda z klasy ma taką samantykę i erasure jak nadrzędna metoda z interfejsu, ale jej nie nadpisuje? O co chodzi?
Spójrzmy na początek definicji interfejsu:


public interface IDao<T extends IStub> {


a następnie na początek defnicji klasy AbstractDao:


public abstract class AbstractDao<T extends IStub> implements IDao {


Co jest nie tak? Otóż wprawna osoba odrazu zauważy (a nieroztropny [czytaj ja] programista przegapi) fakt, iż przy IDao brakuje odwołania do typu generycznego! Poprawnie powyższa definicja powinna wyglądać następująco:


public abstract class AbstractDao<T extends IStub> implements IDao<T> {


Po tej małej zmianie wszystko powino być już w porządku, a kompilator nie krzyczy, że ma metode w podklasie, ale jej nie nadpisze.

poniedziałek, 10 listopada 2008

Java Killers #009

Jakiś czas temu odezwał się do mnie dobry znajomy Paweł Badeński, który uhahany rozpoczął rozmowę na gadu z tekstem "Patrz na to: ..." po czym wkleił kawałek kodu. Kod przerzuciłem na szybko do ulubionego IDE i już wtedy wiedziałem, że te kilka lini ma predyspozycje na kolejny odcinek killersów. Problem pozostawał jednak wciąż, gdyż za diabła nie wiedziałem, czemu kod zachowywał się właśnie tak a nie inaczej. Szybkie przestudiowania Java Language Specification nie dało odpowiedzi, google na szybko też nie były takie cwane, jak zwykle. Dopiero po dłuższej chwili grzebania udało mi się dotrzeć do buga na bugs.sun.com, gdzie po dogłebnej lekturze i ponownym otworzeniu Java Language Specification, wszystko stało się jasne. Jestem ciekaw czy i dla Was dziewiąta odsłona Java Killers będzie taką samą łamigłówką jak była dla mnie. A oto ona:

Mając poniższy kod, jakiego spodziewamy się outputu:


public class Foo
{
public int loo(List<String> a)
{
return 1;
}

public double loo(List<Integer> a)
{
return -1;
}

public static void main(String[] args)
{
List list = new ArrayList<Integer>();
System.out.println("output: " + new Foo().loo(list));
}

}
Odpowiedź poprawna tylko jedna, a kilka do wyboru:


A. Klasa nie skompiluje się, javac poinformuje nas, że "name clash: loo(java.util.List) and loo(java.util.List) have the same signature and erasure"
B. Klasa nie skompiluje się, javac poinformuje nas, że "reference to loo is ambiguous"
C. Skompiluje się, ale wyrzucony zostanie RuntimeException po uruchomieniu programu
D. Program skompiluje się i uruchomi się bez wyjątków i zostanie wypisane na ekranie 'output: -1'
E. Program skompiluje się i uruchomi się bez wyjątków i zostanie wypisane na ekranie 'output: 1'



I uwaga uwaga, poprawna odpowiedź to B!

Osoby, które przekonane były, że oby dwie metody loo miały taką samą sygnaturę i przez to kod się nie kompilował, nie martwcie się, nie byliście jedyni, którzy zaznaczyli odpowiedź A. Otóż okazuje się, że jednak sygnatury obu metod się różnią i występuje najprostszy w świecie method overloading. Później w czasie wywołania metody loo w ciele metody main, następuje konsternacja, gdyż kompilator widzi zmienną niegenneryczną List list i nie ma pojęcia do której metody loo ma się odwołać, stąd jego krzyk
"reference to loo is ambiguous".
Ok, ktoś się spyta, jak to metody loo mają taką samą sygnaturę? Patrząc na Java Language Specification punkt 8.4.9, widzimy, że:

* obie metody mają taką samą nazwę
* obie metody mają taką samą liczbę formalnych parametrów oraz parametrów typów prostych
* ALE typy tych parametrów się różnią, List<String> to co innego niż List<Integer>! Mimo, że przed samą kompilacją wszystkie generyki zostają zrzucone i nie są brane pod uwagę podczas kompilacji (pisałem o tym w poprzednich killersach) o tyle są uwzględniane podczas operacji zwanej "type erasure" - dlatego właśnie List<String> to co innego niż List<Integer>.

No i to tyle na dziś. Kto znał poprawną odpowiedź?

PS. Wspomniana strona do której dotarłem (i musiałem się nieźle nagooglać) znajduje się tutaj: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950

środa, 5 listopada 2008

Maven javaee-api-5

Jeśli dane jest Wam pisać aplikacje JEE5 z użyciem mavena, dość paradoksalnie możecie się spotkać z brakiem w dostępnych repozytoriach pliku javaee-api-5.jar (definiującego API standardu JEE5). Jeśli więc kiedykolwiek dostaniecie informacje od mavena, że nie może za żadne skarby znaleźć API JEE5, polecam zajrzeć tutaj:

https://maven-repository.dev.java.net/nonav/repository/javaee/jars/

W repozytorium java.net jar z API standardu leży sobie grzecznie, czekając, aż go ktoś ściągnie.