Eclipse w nowej odsłonie - Galileo

Wpis dodany 24 lipca 2009 o godz. 21:37:14 w kategorii Eclipse, Java, Techblog.

Bodajże równo miesiąc temu światło dzienne ujrzała nowa wersja najpopularniejszego chyba w Polsce IDE (i to nie tylko w świecie Javy), czyli Eclipse, o numerku 3.5 i nośnej nazwie Galileo. Trochę nowości można zauważyć na pierwszy rzut oka, chociaż rewolucji nie ma.

Pierwszą nowością, która rzuca się od razu w oczy, jest nowy (znowu!) sposób instalacji pluginów. Chociaż faktycznie element ten był "nieco" niedopracowany w poprzednich wersjach, o tyle w wersji 3.4 naszego ulubionego IDE dało się z nim żyć i nie mogę znaleźć jakiegoś istotnego powodu, który uzasadniłby kolejny redesign tego elementu. Zwłaszcza, że w mojej opinii nowa wersja instalowania dodatków nie poprawia usability w jakiś szczególny sposób.

Instalowanie pluginów w Eclipse 3.5

Małą rzeczą, która jednak cieszy, jest zaznaczanie aktualnie wpisanych literek w nazwach typów, które mają szansę pasować do naszego wzorca. Mam na myśli oczywiście okienko "Open Type", dostępne po naciśnięciu combo Shift+Ctrl+T.

Okienko OpenType w Eclipse 3.5

No i to tyle jeśli chodzi o rzeczy, które rzuciły mi się w oczy po paru chwilach korzystania z nowej wersji Eclipse. W dokumentacji zobaczyłem jeszcze, że wprowadzono chociażby zaznaczanie obszaru tekstu za pomocą Alt+Shift+A. Rzeczywiście fajnie działa, chociaż nie jest to na pewno krytyczna funkcjonalność dla jakiegokolwiek IDE.

Wybór obszaru tekstu w Eclipse 3.5

Nowości jest oczywiście więcej, w tym dwie, które powinny być wprowadzone już dawno, dawno temu. Chodzi oczywiście o generowanie toString() (do tej pory używałem pluginu JUtils) oraz wybór Open Declaration/Implementation przy naciśnięciu Ctrl, nie od dziś bowiem wiadomo, że Java interfejsami stoi.

Coś jeszcze? Osobiście się cieszę, że wszystkie pluginy działają bezproblemowo (jest tego sporo i to chyba temat na oddzielną notkę) oraz że nareszcie przy zamknięciu IDE nie widzę okienka błędu, które nie wiem czemu towarzyszyło mi w Eclipse Ganymede. A na co jeszcze czekam? Odbyło się raczej bez zmian jeśli chodzi o ustawienia edytorów, więc aby zgodnie z konwencją przyjętą w projekcie używać spacji zamiast tabów, muszę przeklikać odpowiednie ustawienia w co najmniej pięciu miejscach (dwa dla Javy - edytor i formatter, do tego html, css i xml). Naprawdę nie można stworzyć globalnych ustawień dla kodu, które potem można ewentualnie modyfikować dla poszczególnych typów plików? No ale i tak fajnie widzieć postęp w pracach nad Eclipse, a ewolucja tego IDE idzie jak najbardziej we właściwym kierunku i za to należy się wielki szacun i podziękowania dla całego Eclipse Foundation.

Pliki *.properties w Spring Framework 3

Wpis dodany 23 lipca 2009 o godz. 22:11:40 w kategorii Java, Spring, Techblog.

Zdecydowana większość projektów, w których miałem okazję brać udział jako programista, opierała się na Spring Framework. Myślą przewodnią, która przyświecała twórcom tego cuda było przede wszystkim to, aby uprościć te rzeczy, co do których nie ma powodu, aby były skomplikowane. I jedną z takich rzeczy jest na pewno przechowywanie ustawień w plikach *.properties.

I znowu sytuacja z plikami *.properties nie jest w Javie tak prosta, jakby to się mogło na pierwszy rzut oka wydawać. Pomijając już kwestie samego wczytania takiego pliku (na przykład do klasy Properites) zwłaszcza w aplikacji webowej, dochodzi jeszcze kwestia kodowania, istotna z powodu częstego wykorzystywania w/w plików do tłumaczeń. Pomimo tego, że źródła możemy mieć w UTF-8, propertiesy zgodnie ze standardem zawsze kodowane są w ISO 8859-1. Chociaż może być to uciążliwe (ale nie z Eclipse razem z odpowiednim pluginem - polecam!), ma to sporo sensu i gwarantuje, że żaden nowy programista z błędnym kodowaniem projektu nie doda nam śmieci w postaci kwadracików i gwiazdek do repozytorium.

No ale powróćmy do samego Springa. Nie jest nowością wykorzystywanie ustawień z propertiesów w springowym xml-u i wstrzykiwanie ich do beanów. Można to zrobić mniej więcej tak:

<context:property-placeholder location="classpath:settings.properties" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" value="${db.url}" /> 
    <property name="username" value="${db.username}" />
    <property name="password" value="${db.password}" />
</bean>

Pewien kłopot zaczyna się, kiedy chcemy pozbyć się wszechobecnego xml-a (a chcemy, prawda?) i używać adnotacji. Do tej pory nie można było wykorzystać beana, który wczytywał propertiesy (jest to zresztą obiekt klasy PropertyPlaceholderConfigurer), aby w stworzonych przez nas ziarnach springowych do takich ustawień prosto się dostać. Sytuacja kończyła się zwykle tym, że powstawał jakiś ConfigurationService, który poza Springiem (bądź też wykorzystując niektóre jego niskopoziomowe mechanizmy) wczytywał dane z pliku (bądź plików) *.properties, a sam był wstrzykiwany wszędzie tam, gdzie potrzebny był dostęp do tychże ustawień.

Można spytać, czy nie da się tego zrobić prościej. Otóż w Spring Framework 3.0 jak najbardziej jest to możliwe dzięki adnotacji @Value. Wystarczy użyć następującej konstrukcji:

    @Value("${admin.email}")
    private String adminEmail;

Pewne zamieszanie może być związane z tym, że jednocześnie w nowej wersji Springa wprowadzono expression language, który również może być wykorzystywany w xml-u czy w adnotacjach. Kawałek kodu, który wkleiłem powyżej z dobrodziejstwa springowego EL nie korzysta, poniższy natomiast już jak najbardziej:

<util:properties id="settings" location="classpath:settings.properties"/>
@Value("#{settings.adminEmail}")
private String adminEmail1;

@Value("#{settings.admin.email}")
private String adminEmail12;

Różnica jest znaczna, chociaż teoretycznie występuje w jednym znaczku, tzn. w #. Jest to jednak zupełnie odmienna konstrukcja, której spore możliwości można dokładniej poznać przeglądając dokumentację. Warto jednak zauważyć, że jedynie zmienna adminEmail1 zostanie ustawiona, o ile w naszym pliku settings.properties znajdziemy wartość dla klucza adminEmail. Do zmiennej adminEmail2 byłaby wstrzyknięta wartość jedynie wtedy, jeśli admin byłoby obiektem z atrybutem email, a wiemy, że tak nie jest.

Jeśli zaś chodzi przykłady, gdzie Spring-EL się naprawdę przydaje, to kolejny raz odsyłam do wpisu o najnowszym Spring Security, warto zobaczyć jakie nowości udostępnia nam kolejna wersja tej biblioteki.

Słów parę o equals w Javie

Wpis dodany 19 lipca 2009 o godz. 15:14:39 w kategorii Java, Techblog.

Zastanawiałem się chwilę, o czym powinien być pierwszy prawdziwie techniczny wpis na tym blogu. Po głowie chodziło mi opisanie paru nowości, które wprowadza Spring Framework 3 bądź też dlaczego warto wybrać Stripes do budowy swojej aplikacji internetowej. Postanowiłem jednak zacząć od podstaw, czyli napisać parę słów o javowej metodzie equals, której implementacja nie jest aż tak trywialna, jak mogłoby się na pierwszy rzut oka wydawać.

Podobny temat został opisany już na pewno wiele razy, chociażby na fajnym blogu Antoniego Jakubiaka, jednak mam nadzieję dodać od siebie coś więcej.

Przede wszystkim trzeba pamiętać jakie warunki powinna nasza implementacja metody equals spełniać. Są one dokładnie opisane w dokumentacji klasy Object, w skrócie trzeba pamiętać o zwrotności, symetryczności, przechodniości, spójności i odpowiedniej obsłudze null. Jak łatwo złamać tę umowę możemy się przekonać analizując chociażby kod bardzo fajniej skądinąd biblioteki Spring Security, która dorobiła się ostatnio wersji 3.0.0.M1. W klasie GrantedAuthorityImpl możemy znaleźć:

    public boolean equals(Object obj) {
        if (obj instanceof String) {
            return obj.equals(this.role);
        }
        if (obj instanceof GrantedAuthority) {
            GrantedAuthority attr = (GrantedAuthority) obj;
            return this.role.equals(attr.getAuthority());
        }
        return false;
    }

Co jest nie tak z tym kodem? Otóż klasa GrantedAuthorityImpl zawiera jedynie nazwę roli, zatem jej autor chciał zapewne skrócić zapis, umożliwiając porównanie obiektu klasy GrantedAuthorityImpl bezpośrednio do Stringa, jednocześnie... łamiąc reguły, które metoda equals powinna spełniać. Przykład poniżej:

    private static final String ROLE = "test";
    private static final GrantedAuthorityImpl AUTHORITY = new GrantedAuthorityImpl(ROLE);

    public static void main(String[] args) {
        assert AUTHORITY.equals(ROLE);
        assert ROLE.equals(AUTHORITY);
    }

Łamanie reguły symetryczności to tylko jeden z wielu problemów, jakie można napotkać przy implementacji equals. W samym podstawowym API javowym znajdziemy klasy, które w głupi sposób łamią wspomniany kontrakt, jak robi to na przykład klasa URL. Używa ona bowiem do porównania adresów IP, a zatem wynik wywołania equals będzie zależny od środowiska, w którym uruchamiamy nasz program!

Te i wiele innych aspektów niby trywialnej do implementacji metody equals można przeanalizować razem z Joshuą Blochem w jego świetnej książce Effective Java. Według mnie jest to książka, którą każdy programista piszący w Javie powinien przeczytać, istnieje bowiem spore prawdopodobieństwo, że po takiej lekturze jakość tworzonego przez nas kodu znacząco się podniesie. W dodatku nie jest to publikacja, która szybko straci na aktualności, jak to jest w przypadku większości książek poświęconych różnym bibliotekom (a gdy doliczymy jeszcze czas ewentualnego tłumaczenia...).

Swoją drogą współczesne IDE (jak np. Eclipse) nieźle radzą sobie z automatycznym generowaniem equals (oraz hashCode, o której to metodzie też trzeba pamiętać). Zawsze dobrym pomysłem jest też napisanie testu. Według mnie bardzo ważne jest również, aby mieć świadomość tego, jakie skutki może nasz właśnie pisany kawałek kodu spowodować, zwłaszcza, kiedy nie przykładaliśmy większej wagi do jakości czy w ogóle istnienia testów w naszym projekcie. I wbrew pozorom u bardzo wielu programistów taka świadomość jest mocno ograniczona...