<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><title>DevBlog - kolejny blog o programowaniu</title><link>http://blog.miracki.net/</link><description>Wpisy z dziennika internetowego Jogger, wspomaganego przez Jabbera</description><lastBuildDate>Thu, 11 Mar 2010 01:11:56 +0100</lastBuildDate><generator>JoggerPL</generator><item><title>Wrażenia po Java Developer' Days 2009</title><link>http://blog.miracki.net/2009/10/20/wrazenia-po-java-developer-days-2009/</link><description>Parę dni temu w Krakowie dobiegła końca kolejna edycja konferencji skupionej wokół Javy. Moje pierwsze wrażenie po JDD 09 jest takie, że mogłoby być nieco lepiej. Zarówno poprzednia edycja JDD, jak i tegoroczne konferencje javowe, czyli GeeCON oraz Javarsovia, poprzeczkę postawiły wysoko, nawet bardzo. Wydaje mi się więc, że tegoroczna edycja wypadła nieco słabiej, choć oczekiwania były naprawdę spore.
Wykłady miały miejsce na Uniwersytecie Ekonomicznym i wydaje mi się, że nie była to miejscówka marzeń. Parę wykładów było prowadzonych w dwóch ścieżkach, a druga sala nadawała się bardzo średnio na konferencję, była za mała i mimo trzech (ale zbyt małych) ekranów, sporo osób nie mogło śledzić slajdów i kodowania na żywo. Zresztą główne miejsce, czyli przerobiona sala gimnastyczna, też nie zachwycała, podobnie zresztą jak cały catering. Nie to jednak jest esencją konferencji (czyż nie? ;), więc może zostawmy już średnio smaczny obiad, braki w ciasteczkach czy kiepsko pomyślane identyfikatory (najlepsze blipowe tagi dla nich to #usability oraz #fail).
Zaczęło się, co nieco dziwne, od wykładu sponsora i jak na taki charakter wykładu, to było całkiem nieźle. Dwójka prelegentów (T. Baeyens i J. Barrezz) Rad Hata pokazywała możliwości jBPM. Sesja na kolana nie rzuciła, chociaż samo soft wydał się całkiem sensowny, większość pokazu to były nagrane filmiki, więc wszystko działało bez zarzutu.
Dopiero następnym wykładem był &quot;keynote&quot; Marka Richardsa na temat &quot;messagingu&quot; (JMS i te sprawy). Oczywiście merytorycznie bez zarzutu, chociaż prelegent skupił się na podstawach. Była chwila kodowania na żywo, ogólnie wykład niezły, chociaż już po drugim użyciu wstawka o &quot;polish vodka&quot; wydawała się wystarczająco mało śmieszna, a prelegent dopiero się rozkręcał w temacie ;). Było fajnie, ale przecież to keynote, więc inaczej być raczej nie mogło. Zdarzyło mi się jednak uczestniczyć w paru lepszych wykładach.
Dalej był wykład kolejnego sponsora, czyli firmy e-Point na temat sytuacji (nie aż tak) wyjątkowych. Zwykle wykłady prelegentów z tej firmy skupiają się na dość częstych problemach czy zagadnieniach, jakie spotykamy programując w szeroko rozumianym JEE. Bywa różnie, ale tym razem akurat było całkiem konkretnie, a paru wymienionych na wykładzie rzeczy programiści nie nauczą w szkole, chociaż koniecznie powinni. Oczywiście część przedstawionych idei była też dyskusyjna. Sporo miejsca poświęconego zostało &quot;checked exceptions&quot;, w skrócie temu, że są złe. Nie jest to oczywiście odosobniona opinia; o tym, że &quot;checked exceptions&quot; muszą odejść, pisał ostatnio też Miško Hevery. I tak naprawdę trudno się tu z czymkolwiek nie zgodzić, osobiście dla mnie na topie bezsensu są UnsupportedEncodingException oraz wyjątki w czasie próby stworzenia nowego dokumentu DOM, no ale to żale na osobny wpis. Dobrym wzorcem (nawet bardzo) jest pokazywanie użytkownikowi wraz ze stroną błędu losowego kodu powiązanego z owym błędem (np. w Stripes takie zachowanie bardzo łatwo jest osiągnąć), w ten sposób kiedy dostajemy od użytkownika informację o problemie, potrafimy łatwo powiązać z nim konkretny wyjątek. Ogólnie wykład niezły, takie &quot;must know&quot; dobrego programisty.
Następnie wybrałem wykład Waldka Kota o bardzo skomplikowanym temacie. Generalnie uważam, że był to chyba najlepszy wykład JDD 09, tylko gdyby zatytułować go &quot;współbieżność w JEE może być sexy&quot;, zrobiłby większą furorę ;). Pokazanych zostało parę pomysłów na współbieżność, kiedy działamy w środowisku JEE. Prezentacja Work Manager API na WebLogicu pokazała, że z wątkami można żyć, i to całkiem bezboleśnie. No i Waldek jest zawsze dowodem na to, że Polak jednak może poprowadzić ciekawą prezentację techniczną, i to bez czerstwych żartów.
Wojtek Szeliga opowiedział o &quot;code review&quot;. Pokazał parę narzędzi, aczkolwiek prezentacja była bardzo zorientowana na produkty firm JetBrains i Atlassian. Nie twierdzę, że to źle, bo zasługują one na swoją bardzo dobrą opinię, chociaż na IntelliJ z Eclipse jeszcze nie migruję. Były też slajdy o dobrych praktykach przy przeglądach kodu, parę recept jak w ogóle zacząć, no i slajd o &quot;code review&quot; vs &quot;pair programming&quot; też się znalazł (swoją drogą w temacie polecam podcasty AgileTuning). Było całkiem zwinnie, czyli ogólnie w porządku.
Dalej każdy miał na pewno dylemat, który wykład zagranicznej gwiazdy JDD 09 wybrać. Jako że parę testów w Groovym już napisałem, postanowiłem znowu posłuchać Marka Richardsa, który opowiedział o paru anty-wzorcach. Oczywiście było sympatycznie, chociaż do większości sytuacji pasuje cytat &quot;Z czego się śmiejecie? Z siebie samych się śmiejecie!&quot;. Przedstawione złe praktyki można by odnieść nie tylko do Javy, ba, nie tylko do samego programowania. Konkretnie pokazane zostały m.in. zasada gwoździa (mając tylko młotek wszędzie widzi się gwoździe) i kult cargo (jakoś działa, ale nie wiem co, jak i gdzie).
Przedostatni wykład dla mnie to Domain Driven Design + Seam, o których opowiadał nieco chyba spięty Sławek Sobótka. Od strony merytorycznej było za to całkiem dobrze, zarówno jeśli chodzi o zainteresowanie DDD, jak i samym JBoss Seamem. Plus za przedstawienie konkretów, gdyż o ile o DDD się słyszy całkiem sporo, to do informacji o tym, jak to zagadnienie ugryźć w praktyce, wcale tak łatwo dotrzeć nie można.
Na deser został wykład Scotta Davisa o REST. Trzeba jedno przyznać amerykańskim prelegentom - potrafią robić show. I Scott je zrobił. Co do samej treści - było trochę przykładów, kodowanie na żywo w Groovym, porównanie złożoności SOAP z prostotą REST. Ogólnie prelegent pozostawił po sobie bardzo pozytywne wrażenie.
Napisałem na początku, że mogłoby być lepiej. Nie chcę jednak napisać, że konferencja się nie udała, bo to nie byłaby prawda. Było dobrze, miejscami bardzo dobrze i nieobecni mają czego żałować, bo jeśli nawet nie było mega hitów wśród wykładów i zupa była za słona ;), to zawsze zostaje tzw. społeczny aspekt konferencji. Miło było znowu zobaczyć (nie aż takich) starych znajomych, rozsianych obecnie po najróżniejszych firmach, nie tylko tych z Krakowa.</description><pubDate>Tue, 20 Oct 2009 18:22:59 +0200</pubDate><guid>http://blog.miracki.net/2009/10/20/wrazenia-po-java-developer-days-2009/</guid><category>Java</category><category>Konferencje</category><category>Techblog</category></item><item><title>Odkrywanie wiedzy z danych</title><link>http://blog.miracki.net/2009/10/06/odkrywanie-wiedzy-z-danych/</link><description>Taki tytuł może świadczyć tylko o tym, że na tapetę wchodzi data mining. Ludzie od marketingu wolą pewnie ogólniejsze określenie &quot;business intelligence&quot;, no ale chodzi mniej więcej o to samo, czyli o użycie paru fajnych algorytmów, aby przekopać tony danych i wyciągnąć jakieś nietrywialne wnioski.
Prawdę mówiąc, jeśli chodzi o Javę, to jakichkolwiek doświadczeń z BI nie mam żadnych poza researchem, który zrobiłem ostatnio z czystej ciekawości. Muszę natomiast stwierdzić, że Microsoft podszedł do sprawy całkiem profesjonalnie i w MS SQL Serverze od paru już wersji jest sporo przydatnych rzeczy do zabawy w drążenie danych, polecam zresztą stronę SqlServerDataMining.com. Firma Oracle też się chwali swoim pakietem o wiele mówiącej nazwie Oracle Data Mining. Nie jesteśmy jednak skazani tylko i wyłącznie na dostawców baz danych, chociaż wydaje się, że jak na Javę możliwości wyboru są dość ograniczone.
Warto zacząć od tego, że mamy dwa JSR poświęcone API dla data miningu, są to JSR-73 (Data Mining API) oraz JSR-247 (Data Mining 2.0). Pierwszy zgrzyt to informacja, że prace nad wersją 2.0 APi zostały wstrzymane. Drugim zgrzytem jest to, że raczej nie istnieje implementacja nawet pierwszej wersji standardu, której źródła można obejrzeć i z której można za darmo skorzystać. Liderem obu specyfikacji jest Mark Hornick, pracujący dla Oracle i, co za niespodzianka, w produktach tejże firmy należy szukać jakiejkolwiek implementacji opisywanego właśnie standardu. Można przejrzeć nawet przykłady użycia.
Ok, w takim razie co robić, jak żyć. Zasadniczo do wyboru mamy narzędzie Weka (sponsorowane przez Pentaho) oraz Rapid Miner (kiedyś znane jako YALE). Obydwa rozwiązania możemy używać &quot;standalone&quot;, ale możemy je też wykorzystać w naszym kodzie. Postaram się przedstawić tutaj najprostszy przypadek użycia, czyli klasyfikację na klasycznym zbiorze danych (ang. &quot;data set&quot;) Iris, opisującym parametry irysów (to takie kwiatki, gdyby ktoś pytał). Zbiór ten zawiera długości i szerokości dwóch różnych rodzajów płatków (ang. &quot;petal&quot; oraz &quot;sepal&quot;) irysa, w sumie opisuje 150 roślinek z trzech różnych gatunków. Chodzi oczywiście o rozpoznanie gatunku na podstawie zadanych parametrów.
Kwiatek z własnego ogródka, jakby nie patrzeć - irys.

        // załadowanie zbioru danych
        DataSource source = new DataSource(&quot;/tmp/iris.arff&quot;);
        Instances data = source.getDataSet();
        data.setClassIndex(data.numAttributes() - 1);

        // wybór algorytmu
        Classifier classifier = new NaiveBayes();
        classifier.buildClassifier(data);

        // uczenie modelu
        Evaluation evaluation = new Evaluation(data);
        evaluation.evaluateModel(classifier, data);

        // classifier.classifyInstance(inst) aby użyć modelu
        String summary = evaluation.toSummaryString();
        out.println(summary);

Powyższy kawałek kodu przedstawia pracę z Weką. Oczywiście tak na dobrą sprawę powinniśmy podzielić posiadane dane na dwa zbiory, jeden do uczenia, drugi do testowania, no ale powiedzmy, że dla celów prostej prezentacji tak też jest OK. Więcej informacji na temat używania Weka w kodzie można znaleźć na wiki projektu. Rozszerzenie *.arff to własny format danych Weki, ale równie dobrze można podpiąć jakikolwiek inny. Nieskalibrowany w żaden sposób algorytm miał 96% skuteczności w rozpoznawaniu gatunków w zbiorze, na którym się uczył.

        // inicjalizacja
        RapidMiner.init();
        
        // załadowanie zbioru danych
        Operator xrffSource = OperatorService.createOperator(XrffExampleSource.class);
        xrffSource.setParameter(XrffExampleSource.PARAMETER_DATA_FILE, &quot;/temp/iris.xrff&quot;);

        // przetwarzanie danych
        IOContainer container = xrffSource.apply(new IOContainer()); 
        ExampleSet exampleSet = container.get(ExampleSet.class); 
     
        // uczenie modelu
        Learner learner = OperatorService.createOperator(NaiveBayes.class); 
        Model model = learner.learn(exampleSet);

        // informacje o modelu
        out.println(model.toResultString());

        // stosujemy wytrenowany model na znanych już danych
        Operator modelApplier = OperatorService.createOperator(ModelApplier.class); 
        container = modelApplier.apply(container.append(model));

        // wyświetlamy dane
        ExampleSet resultSet = container.get(ExampleSet.class);
        int i = 0;
        Iterator examples = resultSet.iterator();
        while (examples.hasNext()) {
            out.print( ++i + &quot;: &quot;);
            Example reader = examples.next();
            Attributes attributes = reader.getAttributes();
            out.println(&quot;predicted: &quot; + reader.getValueAsString(attributes.getPredictedLabel()));
        }

Co w takim razie można powiedzieć o Rapid Miner? Jak widać, jest o wiele bardziej skomplikowany. Właściwie to trudno użyć go jako biblioteki, wpierw i tak musimy go zainicjalizować, co skutkuje potężną dawką logów. Może on korzystać z algorytmów Weki. Samo jego API bardzo mi się nie podoba, tworzenie obiektów poprzez refleksję spowodowane jest tutaj &quot;wstrzykiwaniem&quot; kontekstu do każdego nowo tworzonego obiektu. Tak samo &quot;brzydka&quot; jest metoda setParameter zamiast standardowych setterów, a to przecież jeszcze chyba nadal Java. Wedle dokumentacji w bardziej skomplikowanych przypadkach warto używać klasy Process, aczkolwiek sama dokumentacja nie wygląda na zbyt aktualną, najprostsze przykłady się nie kompilują. Abstrahując od brzydoty API, narzędzia bardzo przyjemnie używa się poprzez klikalne GUI. Warto także obejrzeć filmiki (oczywiście oparte na jakiejś o wiele starszej wersji).
Proste drzewko decyzyjne w Rapid Minerze.
Podsumowując, jest czym się bawić, aczkolwiek wypada też mieć nieco żyłki odkrywcy ;). W każdym razie zachęcam, bo data mining to całkiem fajny temat do eksploracji, zwłaszcza jeśli chodzi o samo działanie algorytmów.</description><pubDate>Tue, 06 Oct 2009 20:39:14 +0200</pubDate><guid>http://blog.miracki.net/2009/10/06/odkrywanie-wiedzy-z-danych/</guid><category>Data mining</category><category>Java</category><category>Techblog</category></item><item><title>ClassLoadery</title><link>http://blog.miracki.net/2009/10/04/classloadery/</link><description>ClassLoader to obiekt, który jest odpowiedzialny za ładowanie klas. Tak twierdzi javadoc w opisie do abstrakcyjnej klasy ClassLoader i z pewnością ma rację. W pisaniu prostych programów jakakolwiek wiedza na temat ładowania klas nie jest nam specjalnie potrzebna, nie ma jednak co ukrywać, że Java nie została stworzona do prostych programów, ale do szeroko rozumianego &quot;enterpri(s|c)e&quot;. A tam tego typu wiedza jest nie tylko przydatna, ale wręcz konieczna.
Zróbmy więc małą powtórkę z tego, jak ładowanie klas działa i dlaczego, jeśli w ogóle, jest fajne. Otóż powodem powstania koncepcji classloaderów w Javie były aplety, które w swoim czasie miały podbić świat. Wyszło jak wyszło, ale classloadery zostały. Liczba mnoga jest jak najbardziej uzasadniona, gdyż do czynienia mamy co najmniej z trzema, są to bootstrap, extension i system.
Typ &quot;bootrstrap&quot; ładuje klasy najważniejsze, systemowe, zazwyczaj te z rt.jar, czyli choćby java.lang.String. Wywołując getClassLoader() dla String.class dostaniemy null. Typ &quot;extension&quot; szuka klas w jre/lib/ext, a dopiero typ &quot;system&quot; ładuje klasy naszej aplikacji. Oczywiście w najprostszym przypadku, bo mamy przecież serwery aplikacyjne i OSGI, ale o tym następnym razem (i o samym OSGI, i o ładowaniu klas w takim wypadku).

public class ClassloaderFun {
    public static void main(String[] args) {
        // dostajemy null
        out.println(String.class.getClassLoader());
        // dostajemy sun.misc.Launcher$AppClassLoader@7d772e
        out.println(ClassloaderFun.class.getClassLoader());
        out.println(Thread.currentThread().getContextClassLoader());
    }
}

Idźmy dalej, bowiem ładowanie klas nierozłącznie powiązane jest z hierarchią. Każdy classloader (poza typem &quot;bootstrap&quot;) posiada jakiegoś przodka. Zazwyczaj zanim nasz classloader spróbuje załadować jakąś klasę, odpytuje najpierw właśnie owego przodka (wedle tzw. podejścia &quot;parent first&quot;). Każdy wątek posiada dostęp do kontekstowego classloadera, czyli tego, który aktualnie jest w użyciu. Zawsze możemy go podmienić za pomocą metody setContextClassLoader. Taka możliwość przydaje się choćby wtedy, kiedy chcemy, aby nowo tworzony wątek miał dostęp do klas ładowanych dynamicznie np. poprzez URLClassLoader. Warto jeszcze wspomnieć, że nie ma problemu z załadowaniem kilku różnych klas o tej samej nazwie zarówno samej klasy, jak i pakietu. Funkcję przestrzeni nazw pełnią tutaj właśnie classloadery.

        URL url = new URL(&quot;file:///tmp/plugin.jar&quot;);
        URLClassLoader pluginLoader = new URLClassLoader(new URL[] { url });
        Class clazz = pluginLoader.loadClass(&quot;net.miracki.classloader.plugin.PluginImpl&quot;);
        out.println(&quot;Loaded class: &quot; + clazz + &quot;, classloader &quot; + clazz.getClassLoader());
        ((Plugin) clazz.newInstance()).doSomething();

Z tematem ładowania klas powiązany jest wybór implementacji dla różnych API. Istnieje mechanizm SPI, czyli Service Provider Interface, który dzięki odpowiednim znacznikom w strukturze pliku *.jar pozwala poinformować maszynę wirtualną, że implementacją chociażby javax.xml.parsers.SAXParserFactory jest w przypadku Xercesa org.apache.xerces.jaxp.SAXParserFactoryImpl. Dokładnie odbywa się to dzięki umieszczeniu w katalogu /META-INF/services/ pliku o nazwie interfejsu, a którego treścią jest nazwa implementacji.
Z SPI można korzystać albo i nie, na przykład bardzo popularna fasada do logowania, czyli commons-logging używa tego mechanizmu, ale robi też o wiele więcej, co niesie ze sobą różne skutki. Otóż domyślna fabryka (do wyboru implementacji której używa się właśnie SPI) do tworzenia loggerów, czyli klasa org.apache.commons.logging.impl.LogFactoryImpl dynamicznie (tak, to słowo klucz, a kawałki kodu poniżej) szuka odpowiedniego loggera. W szczegóły wgłębiać się nie będę, zwłaszcza, że zrobił to już świetnie w swoim artykule o problemach związanych z ładowaniem klas w commons-logging Ceki Gülcü, twórca m.in. Log4j. Problemy te zaowocowały stworzeniem nowej fasady do logowania, czyli SLF4J oraz następcy Log4j, czyli Logbacka. Poniżej wycinki z kodu commons-logging:

private static final String[] classesToDiscover = {
    LOGGING_IMPL_LOG4J_LOGGER,
    &quot;org.apache.commons.logging.impl.Jdk14Logger&quot;,
    &quot;org.apache.commons.logging.impl.Jdk13LumberjackLogger&quot;,
    &quot;org.apache.commons.logging.impl.SimpleLog&quot;
};


for(int i=0; (i</description><pubDate>Sun, 04 Oct 2009 14:34:14 +0200</pubDate><guid>http://blog.miracki.net/2009/10/04/classloadery/</guid><category>Java</category><category>OSGI</category><category>Techblog</category></item><item><title>Bezpieczeństwo, nie tylko w świecie Javy</title><link>http://blog.miracki.net/2009/09/07/bezpieczenstwo-nie-tylko-w-swiecie-javy/</link><description>Myślę, że ostatnio ujawniony wyciek danych z serwisu Wykop.pl uświadomił niektórym, jak niebezpieczne może być używanie tego samego hasła w wielu miejscach, z bankiem i Allegro włącznie. Na temat samej administracji Wykopu wypowiadać się za bardzo nie chcę, wszakże ponoć nie kopie się leżącego. Jeśli jednak to prawda, że wyciek nastąpił już jakiś czas temu i w dodatku osoby zarządzające serwisem miały tego świadomość, brak informacji dla użytkowników o tym fakcie to raczej sprawa dla prokuratora i prawników.
Osobną kwestią jest używanie prawdziwych danych produkcyjnych na potrzeby nowej, testowej wersji serwisu. Osobiście nie widzę w tym nic złego (inni widzą). Projektując np. forum internetowe zamiast tysiąca postów z &quot;lorem ipsum&quot; lepiej mieć dostęp choćby do setki wpisów rzeczywistych użytkowników, inwencja niektórych osób może bowiem naprawdę zaskoczyć twórców oprogramowania ;). Oczywiście takie dane muszą zostać oczyszczone z &quot;wrażliwych&quot; informacji (a takimi są chociażby hasła). Całkiem możliwe też, że konieczne okaże się zamazanie danych osobowych, no ale to już też bardziej kwestia prawna. Swoją drogą myślę, że Wykop powinien spodziewać się w najbliższym czasie kontroli z GIODO.
Sprawą, która zwróciła moją uwagę, jest sposób trzymania hasła w systemie Wykopu. Niewiele trzeba, aby zorientować się, że hasła były kodowane za pomocą SHA1. Jest to zabezpieczenie zdecydowanie niewystarczające, chociaż dobrze, że przynajmniej ono zostało wdrożone. To, że istnieją systemy (i to jall... kie duże), które trzymają hasła w postaci jawnej, świadczy tylko o ich twórcach (jednak warto brać poprawkę na to, że w tym wypadku mamy sporo tzw. &quot;legacy code&quot;). To żadna filozofia użyć &quot;salta&quot; w nowo powstających systemach (a takim jest Wykop, to nie jest system bankowy z lat 60-tych, którego działania nie rozumie właściwie nikt). Generalnie dobrym pomysłem jest generowanie innego salta dla każdego hasła, wtedy po wyliczeniu sha1(salt + hasło) trudno będzie poznać, że dwóch użytkowników posiada identyczne hasła. Oczywiście baza zawsze może wyciec (nieprawdaż?), zatem doklejenie do hasła i generowanego salta jeszcze jakieś stałej zapisanej w &quot;propertiesach&quot; aplikacji powinno nas wystarczająco zabezpieczyć. Oczywiście żadne zabezpieczenia nie uchronią przed głupotą i brakiem wyobraźni, wszakże dla niektórych &quot;qwerty&quot; to silne hasło.
O ile braki w wiedzy na temat bezpieczeństwa wśród zwykłych użytkowników można wybaczyć (ale nie zaakceptować), o tyle wśród programistów brak takiej świadomości może prowadzić do sporych luk w bezpieczeństwie. Weźmy np. takie tagi JSP (JavaServer Pages) i EL (expression language). Domyślnie wszystkie teksty są &quot;escape'owane&quot;, czyli jeśli użytkownik nazywa się alert('xss'), to właśnie naszym oczom ukaże się taka nazwa, a nie javascriptowy alert. Pisanie własnych tagów powoduje jednak, że mamy do czynienia z tworzeniem HTML-a w kodzie Javy. Nie wolno wtedy zrobić czegoś takiego:

    @Override
    public void doTag() throws JspException, IOException {
        PageContext pageContext = (PageContext) getJspContext();
        JspWriter out = pageContext.getOut();
        out.println(&quot;&quot; + someMessage.getBody() + &quot;&quot;);
    }

Oprócz tego, że w ten sposób de facto przenosimy warstwę widoku do (zwykłych) klas Javy (a tego robić nie chcemy i nie powinniśmy, skryptlety są przecież passé), a nasz webmaster nie wie, co ma z takim tagiem zrobić, to dodatkowo prosimy się o XSS, nie mamy bowiem w takim wypadku żadnej walidacji. Lepiej zapisać tekst do wyświetlenia w kontekście JSP i wyświetlić go bezpiecznie za pomocą EL na samej stronie.
I jeszcze jeden przypadek, który nasunął mi się po lekturze sierpniowego SDJ i lekturze artykułu o Groovym. Tekst jest dobrze napisany (w przeciwieństwie do paru innych), tyle że mamy tam następujący kwiatek: &quot;GString (...) umożliwia dostęp do zmiennych z poziomu łańcuchów znaków (...) Może to mieć zastosowanie w wielu sytuacjach, np. (...) przy tworzeniu zapytań SQL&quot;. Takie podejście do pisania w SQL-u (aż by się chciało powiedzieć, że w stylu chłopców phpowców po gimnazjum) to prośba o kolejny atak, tym razem dla odmiany SQL Injection. Za nieużywanie sparametryzowanych zapytań powinno się w IT wprowadzić kary cielesne.
Trzeba też niestety uczciwie przyznać, że z wiedzą dotyczącą bezpieczeństwa (ogólnie pojętego) jest kiepsko, zwłaszcza w różnych startupach czy garażowych firmach (a i uczelnie dokładają tutaj swoją cegiełkę, a właściwie brak cegiełki). Głównym problemem dla firm  jest ROI, ale inwestycja w &quot;security&quot; jest bardziej ubezpieczeniem, zresztą nawet w podstawowym pakiecie bardzo tanim i efektywnym w przypadku zagrożenia. No bo co to za filozofia postawić firmowy VPN, wprowadzić salt do haseł w tworzonych systemach czy używać PreparedStatement. To przecież wydawałoby się podstawy podstaw.</description><pubDate>Mon, 07 Sep 2009 19:56:11 +0200</pubDate><guid>http://blog.miracki.net/2009/09/07/bezpieczenstwo-nie-tylko-w-swiecie-javy/</guid><category>Groovy</category><category>Java</category><category>Security</category><category>Techblog</category></item><item><title>O javowych blogach na spóźniony BlogDay 2009</title><link>http://blog.miracki.net/2009/09/02/o-javowych-blogach-na-spozniony-blogday-2009/</link><description>Swoje święta mają administratorzy, ma liczba PI, mają zatem też blogi. Jako że wpis ten i tak ukazuje się po deadline, który przypadał na 31 sierpnia, pozwolę sobie na modyfikację także i innych punktów regulaminu (więcej informacji na temat całej akcji można znaleźć na stronie BlogDay). Czyli będzie lista blogów, ale niekoniecznie pięciu, niekoniecznie nowo odkrytych i niekoniecznie niezwiązanych z poruszaną przeze mnie tematyką, a wręcz przeciwnie.

Swoją drogą z blogami ogólnie jest tak, że ludzie zbyt często piszą nie mając nic do przekazania. Wydaje mi się, że jednak z ludźmi zaangażowanymi w IT jest nieco inaczej - mają do przekazania całkiem sporo, lecz zbyt często kończy się to na paru wpisach, a potem blog pozostaje martwy. Z tego też powodu w Blog Day z czytnika RSS musiałem niestety wykasować sporo nieaktywnych blogów, zwłaszcza technicznych. A szkoda, bo zapowiadały się nieźle; niestety mało kto ma tyle zapału co Jacek Laskowski (który nota bene jest pośrednim twórcą i mojego bloga, ale to temat może na jakąś rocznicową notkę :).
Subiektywnie wybrane blogi javowe:
    Holistyczna inżynieria oprogramowania (http://art-of-software.blogspot.com) - chyba najlepszy według mnie w tym momencie polski blog javowy, stąd też zgłosiłem go do konkursu JDD 09 Java Guide. Autor nie opisuje kolejnych pięciuset frameworków webowych, ale kładzie nacisk na te aspekty pracy w świecie IT, których nie poznamy z dokumentacji ani też zapewne nie nauczymy się na studiach, niestety. Polecam, chociażby ze względu na humanistyczne zacięcie.
    Java and neighbourhood (http://nurkiewicz.blogspot.com) - od niedawna anglojęzyczny blog Tomka Nurkiewicza. Ciekawa dla mnie tematyka, przemyślane i interesujące notki, także jeżeli chodzi o ich formę (co często jest bolączką osób &quot;technicznych&quot;). Może trochę za rzadko pisze i nie ma archiwum, no ale nikt nie jest doskonały.
    Adam Bien's Weblog (http://www.adam-bien.com) - wpisy Adama w blogu są jak jego występy na konferencjach (w Polsce m.in. JDD i GeeCON) - oszczędne w formie (oraz krótkie), ale zazwyczaj z maksimum interesującej treści. Poza tym pisze często, bardzo często.

Wśród moich ulubionych blogów javowych (a nawet i czasem w czytniku) brak nazwisk takich jak Gosling czy chociażby Strachan, ciekawa treść bowiem często nie idzie w parze z zasługami danej osoby dla javowej społeczności. A Wy macie jakieś ulubione javowe zakątki w sieci, którymi chcielibyście się podzielić?</description><pubDate>Wed, 02 Sep 2009 17:00:52 +0200</pubDate><guid>http://blog.miracki.net/2009/09/02/o-javowych-blogach-na-spozniony-blogday-2009/</guid><category>Java</category></item><item><title>Dlaczego warto poznać Stripes Framework</title><link>http://blog.miracki.net/2009/08/24/dlaczego-warto-poznac-stripes-framework/</link><description>Frameworków webowych dla Javy jest mnóstwo, a wybór najlepszego to temat na wielodniowy &quot;flame&quot;. Wicket jest na topie, w GWT nie trzeba pisać HTML-a, JSF to standard, a Struts 2 to prawie że potomek legendarnych Strutsów. Istnieje jednak framework webowy, który może nie jest aż tak bardzo popularny jak wyżej wymienione, ale warto go poznać, bo w pełni na to zasługuje. Mowa oczywiście o tytułowym Stripes Framework.
Używałem już paru szkieletów webowych, ale przy ostatnim projekcie, w którym decydowałem o wyborze technologii, moje rozważania zakończyły się wyborem tandemu Spring + Stripes. Z perspektywy czasu widzę, że akurat w tym wypadku był to bardzo dobry traf, pomimo braku wcześniejszych doświadczeń ze Stripesami (chociaż parę mądrych osób wcześniej mi mówiło, że ten framework ma właściwie wszystko, czego się wymaga od javowego frameworka webowego - i mieli oni rację).
Nie będę tutaj opisywał, jak napisać &quot;Hello world&quot;, bo to już zrobili inni. Napiszę za to, dlaczego lubię Stripesy i dlaczego właśnie je warto użyć zamiast chociażby takiego Struts 2. Nieprzypadkowo wspominam tutaj o S2, gdyż w założeniach są to biblioteki bardzo podobne, oba frameworki są bowiem zdecydowanie akcyjne, nie komponentowe. Niektórym może się ta cecha podobać, innym mniej, ale ponoć &quot;de gustibus non est disputandum&quot;, zresztą nie chcemy tu wspomnianego flejma.
Jedną z miłych rzeczy, które spotkamy w Stripes Framework, jest wbudowany bardzo prosty mechanizm do powtórnego wykorzystywania layoutów. Dzięki trzem prostym tagom odpada nam konieczność używania zewnętrznych rozwiązań jak Tiles czy SiteMesh. O ile ten drugi jest przyjemny w użyciu, o tyle ilość xml-a koniecznego do wyprodukowania w Tilesach przy braku konwencji skutecznie do tej biblioteki zniechęca.
Kolejną sympatyczną niespodzianką jest tag do zrobienia kontrolki wyboru z javowych enumów. Standardowo w JSTL czegoś takiego nie znajdziemy, Struts 2 też nie oferuje w tym wypadku jakiegoś gotowego rozwiązania, a jest to chyba dość popularne użycie enumów w aplikacjach internetowych. W Stripesach możemy użyć taga , a o tym, w jaki sposób to zrobić, można doczytać w dokumentacji.
Na dokładkę zostają nam sprawy konfiguracji. Nie mamy ani kawałka xml-a poza standardowym web.xml, żadnych dodatkowych stripes.xml czy pluginów do obsługi adnotacji bądź włączenia konwencji, jeśli takowe w ogóle istnieją i nam zadziałają (tak, nieco piję tutaj do S2). Wszystko dostajemy od razu, a dzięki adnotacji @UrlBinding bardzo łatwo przyjdzie nam zrobić &quot;ładne&quot; URL-e. Być może są to szczegóły, ale z takich właśnie szczegółów składa się praca programisty. Zresztą pozytywnych niespodzianek jest w Stripes Framework o wiele więcej.
Ok, czy ten framework jest &quot;świętym Graalem&quot; wśród innych rozwiązań? Oczywiście nie, aczkolwiek trudno mi tutaj wytknąć jakiekolwiek jego niedoskonałości. Rzecz jasna nie każdemu mogą odpowiadać jsp (aczkolwiek można użyć Velocity czy FreeMaker) jako szablony, no ale to kwestia gustu. To, co mogłoby być nieco lepiej rozwiązane, to integracja ze Springiem, tzn. użycie go do tworzenia akcji tak, jak to robi Struts 2. Obecnie mamy adnotację @SpringBean (swoją drogą to już chyba jakaś konwencja nazewnicza, w Wickecie nazwa adnotacji do wstrzykiwania beanów Springa jest taka sama), natomiast nie mamy dostępu do np. @Value ze Springa 3. No ale to drobny szczegół (zresztą istnieją projekty, które pozwalają Springowi stać się zarządcą akcji stripesowych, tylko że mają one swoje wady), poza tym w wersji 1.6 (a kiedy piszę te słowa, najnowszą jest 1.5.1) możemy się i rozwiązania tej kwestii spodziewać. W każdym razie polecam przynajmniej spojrzeć przez chwilę na ten projekt, a nuż okaże się on dla Ciebie technologicznym strzałem nie w stopę, lecz w dziesiątkę.</description><pubDate>Mon, 24 Aug 2009 20:31:32 +0200</pubDate><guid>http://blog.miracki.net/2009/08/24/dlaczego-warto-poznac-stripes-framework/</guid><category>Java</category><category>Spring</category><category>Stripes</category><category>Techblog</category></item><item><title>Sposób na JPA i LazyInitializationException</title><link>http://blog.miracki.net/2009/08/17/sposob-na-jpa-i-lazyinitializationexception/</link><description>Temat lazy loadingu (leniwego ładowania?) przewijał się ostatnio na polskich blogach javowych. Pisał o nim Mateusz Zięba, o wydajności takiego rozwiązania wspominał też w świetnym wpisie Sławek Sobótka. Czy można coś jeszcze dodać? Myślę, że niewiele, ale spróbujmy skupić się na jednej rzeczy, a mianowicie na zamkniętej sesji JPA i sposobie, jak sobie w takim wypadku radzić gdy mamy jeszcze w naszych zależnościach Spring Framework oraz działamy w środowisku webowym.
Problem jest dość częsty (przykładowy &quot;stack trace&quot; poniżej) i jako taki ma też rozwiązanie, opisane zresztą w artykule Open Session in View na stronach naszego ulubionego ORM-a. W skrócie całe zamieszanie związane jest z tym, że nie zawsze w naszej warstwie logiki biznesowej operujemy na obiektach, które potem chcemy wyświetlić, a zatem ORM bardzo słusznie nie pobiera ich z bazy danych. Jednak gdy dochodzi do wyświetlenia listy w widoku, zamiast np. listy ulubionych kolorów użytkownika dostajemy błąd numer 500, a w logach straszy nas LazyInitializationException (oczywiście w przypadku H., bo specyfikacja JPA o takiej sytuacji w ogóle nie wspomina). Sesja jest już bowiem zamknięta i nie wiadomo, skąd te kolory wziąć, a całej bazy przecież nie pociągnęliśmy wcześniej, prawda? :). Z przyczyn oczywistych zmiana fetch na FetchType.EAGER raczej nie wchodzi w grę.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: net.miracki.Test.categories, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException (AbstractPersistentCollection.java:380)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected (AbstractPersistentCollection.java:372)
    at org.hibernate.collection.AbstractPersistentCollection.readSize (AbstractPersistentCollection.java:119)
    at org.hibernate.collection.PersistentSet.size (PersistentSet.java:162)
    ...

Problem jest, rozwiązanie dla Hibernate'a też. Niestety niewielki kłopot pojawia się, kiedy chcemy być standardowi i używamy Hibernate (albo czegokolwiek innego) poprzez właśnie JPA. Jak to zazwyczaj bywa, Spring Framework ma na takie zachowanie gotową i prostą receptę. W zasadzie wpis mógłby się kończyć na poniższym kawałku pliku web.xml:

    
        JpaFilter
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    
    
        JpaFilter
        /*
    

Dzięki temu filtrowi nie powinniśmy więcej spotkać wyjątku związanego z &quot;lazy loadingiem&quot;. Powyższy filtr istnieje zresztą też w wersji dla zwykłego Hibernate (jako klasa OpenSessionInViewFilter).
Abstrahując już od głównego tematu, ORM-y to narzędzia, które przed użyciem wypada przynajmniej choć trochę poznać, a do tego tutorial jak zrobić &quot;Hello World&quot; nie wystarczy. Brałem udział w projekcie, który z dobrodziejstw opisanych filtrów nie korzystał, przez co niektóre metody w warstwie logiki biznesowej posiadały argumenty typu boolean o nazwach attachCategories, attachCountries itp. Nie wiem, czy byłbym jednak w stanie wymienić wszystkie zasady dobrego kodowania, które w ten sposób zostały złamane ;). Ale jeśli chodzi o ORM-y, to prawie na samej górze mojej prywatnej listy idiotycznych rozwiązań jest adnotacja @Transient dla obiektów połączona z mapowaniem kluczy obcych do Longów z @Column, bo &quot;pociągniesz całą bazę, ORM-y to zło, ale niech już zostaną&quot;. Na całe szczęście takie podejście bardzo szybko minęło wraz z lekturą manuala...</description><pubDate>Mon, 17 Aug 2009 22:37:30 +0200</pubDate><guid>http://blog.miracki.net/2009/08/17/sposob-na-jpa-i-lazyinitializationexception/</guid><category>Hibernate</category><category>Java</category><category>JPA</category><category>Spring</category><category>Techblog</category></item><item><title>Płynne interfejsy</title><link>http://blog.miracki.net/2009/08/11/plynne-interfejsy/</link><description>Krótki urlop (który upłynął pod znakiem słońca, koloru różowego i Panthenolu w sprayu) szybko się skończył, wypada więc w tym gorącym czasie (chociaż bardziej ze względu na kupno Spring Source przez VMware aniżeli przez aktualną pogodę) powrócić do świata Javy. Na tapetę wędrują zatem płynne interfejsy.
Mam nadzieję, że za tytułowe tłumaczenie &quot;fluent interfaces&quot; nikt mnie na stosie palił nie będzie, chodzi wszakże o całkiem fajny styl programowania, który dodatkowo ostatnio jakby staje się coraz popularniejszy. Określenia &quot;fluent interface&quot; użył chyba po raz pierwszy sam Martin Fowler, a obecnie dorobiło się ono nawet swojego wpisu w Wikipedii. Rzecz nie jest w żadnym stopniu nowa ani rewolucyjna, w dodatku od razu widać powiązanie z &quot;method chaining&quot;. Na pewno każdy używał cout z C++, a zatem mniej lub bardziej świadomie korzystał też ze wspomnianej techniki, która teraz wraz ze spopularyzowaniem DSL-i przeżywa swoją drugą młodość, przynajmniej jeśli chodzi o świat Javy.
Odbiegając na chwilę lekko od tematu można czy nawet wypada wspomnieć o opisanych w Effective Java builderach (budowniczych). Przy klasie, która ma bardzo wiele atrybutów, bezpośrednie używanie konstruktorów z tymi parametrami nie jest najlepszym pomysłem. W pewnym momencie bowiem możemy stracić orientację, czy true na dwudziestej szóstej pozycji odnosi się do zablokowania użytkownika, czy do faktu posiadania uprawnień administracyjnych. Trzydzieści setterów jest natomiast obarczone ryzykiem, że gdzieś około piętnastej pozycji ktoś wywoła nam kod, który będzie potrzebował już w pełni stworzonego obiektu. Buildery takie są lekarstwem na wspomniane właśnie problemy, a wykorzystują one &quot;method chaining&quot;. Do ich generowania pod Eclipse istnieje odpowiednia wtyczka, całkiem zresztą znośna w użyciu, choć do ideału jej nieco brakuje.
Ok, co z tymi płynnymi interfejsami i czemu warto tracić na coś takiego w ogóle czas? Otóż jest tak, że większość czasu spędzamy czytając kod, więc powinno nam zależeć, aby ten kod był po prostu czytelny. A teraz weźmy na przykład standardowe API Javy do obsługi dat - czy poniższy kod (wzięty zresztą z opisu biblioteki Time and Money Erica Evansa) jest przejrzysty i łatwo zrozumiały na pierwszy rzut oka?

Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone(&quot;Universal&quot;);
calendar.set(Calendar.DATE, 5);
calendar.set(Calendar.MONTH, 3 - 1);
calendar.set(Calendar.YEAR, 2004);
Date march5_2004 = calendar.getTime();

Na całe szczęście w przypadku dat możemy użyć chociażby Joda Time, natomiast płynne interfejsy znalazły swój przyczółek w bibliotekach do mockowania, w tym w mojej ulubionej, czyli w Mockito (w poniższym przykładzie w parze z projektem Fest). Czy ktoś odważy się powiedzieć, że taki test nie jest naprawdę piękny? ;)

    @Test
    public void shouldGenerateValidLoginFromEmailForUser() {
        // given
        String name = &quot;test&quot;;
        User user = new User.Builder().mail(name + &quot;@example.com&quot;).build();
        given(userDAO.update(user)).willReturn(user);

        // when
        userLogicBean.generateLoginAndSave(user);

        // then
        assertThat(user.getLogin()).hasSize(User.Length.LOGIN).startsWith(name);
    }

Ale mocki i asercje to nie jedyne miejsce dla płynnych interfejsów. Wykorzystano je projektując chociażby Google Collections (warto popatrzeć na przykład na klasę MapMaker), a biblioteka Lambdaj pozwala pozbyć się niewiele mówiących pętli połączonych z mnóstwem ifów na rzecz tego typu konstrukcji:

List oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends);

Albo weźmy kolejny przykład - JPA. O ile JPA w pierwszej wersji było nieco wybrakowane, o tyle warto poczytać, co pisze o języku zapytań w JPA 2.0 Linda DeMichiel. Swoją drogą nawet Doctrine ORM w php było szybsze, jeśli chodzi o wykorzystanie &quot;method chainingu&quot; w zapytaniach.
Widać więc, że nawet świat Javy ewoluuje, starając się niwelować niedostatki samego języka bądź też niedoskonałego API. Oczywiście wszystkiego zrobić się nie da, problemem są metody zwracające void, nie można też wykryć w czasie wykonywania typu sparametryzowanej kolekcji. Są to jednak jedynie szczegóły, które można spróbować obejść (np. w Mockito dla metod zwracających void jest szereg metod do*, które zwykle pozwalają nam osiągnąć to, co chcemy).
</description><pubDate>Tue, 11 Aug 2009 21:05:24 +0200</pubDate><guid>http://blog.miracki.net/2009/08/11/plynne-interfejsy/</guid><category>Java</category><category>JPA</category><category>Mockito</category><category>Techblog</category></item><item><title>Eclipse w nowej odsłonie - Galileo</title><link>http://blog.miracki.net/2009/07/24/eclipse-w-nowej-odslonie-galileo/</link><description>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ł &quot;nieco&quot; 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.

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 &quot;Open Type&quot;, dostępne po naciśnięciu combo Shift+Ctrl+T. 

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.

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.</description><pubDate>Fri, 24 Jul 2009 21:37:14 +0200</pubDate><guid>http://blog.miracki.net/2009/07/24/eclipse-w-nowej-odslonie-galileo/</guid><category>Eclipse</category><category>Java</category><category>Techblog</category><category>java eclipse</category></item><item><title>Pliki *.properties w Spring Framework 3</title><link>http://blog.miracki.net/2009/07/23/pliki-properties-w-spring-framework-3/</link><description>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:




    
     
    
    


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(&quot;${admin.email}&quot;)
    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:




@Value(&quot;#{settings.adminEmail}&quot;)
private String adminEmail1;

@Value(&quot;#{settings.admin.email}&quot;)
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.</description><pubDate>Thu, 23 Jul 2009 22:11:40 +0200</pubDate><guid>http://blog.miracki.net/2009/07/23/pliki-properties-w-spring-framework-3/</guid><category>Java</category><category>Spring</category><category>Techblog</category><category>spring java</category></item><item><title>Słów parę o equals w Javie</title><link>http://blog.miracki.net/2009/07/19/slow-pare-o-equals-w-javie/</link><description>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 = &quot;test&quot;;
    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...
</description><pubDate>Sun, 19 Jul 2009 15:14:39 +0200</pubDate><guid>http://blog.miracki.net/2009/07/19/slow-pare-o-equals-w-javie/</guid><category>Java</category><category>Techblog</category></item><item><title>Hello world</title><link>http://blog.miracki.net/2009/07/18/hello-world/</link><description>Witam na moim Joggerze!
W zasadzie na powitaniu ta notka mogłaby się skończyć, ale jako że jest to debiut tego bloga w obecnej formie, wypada mi chyba napisać parę słów, czym chcę, aby ten blog się stał. Otóż mam nadzieję pisać o rzeczach (tylko) technicznych, związanych z programowaniem, czyli tym, czym się na co dzień zajmuję.
Na pewno sporo będzie o Javie, gdyż właśnie programując w niej spędzam większość swojego czasu, tworząc mniej lub bardziej ciekawe systemy, głównie internetowe.
Jeśli zaś chodzi o samego bloga, nieco czasu zajęło mi doprowadzenie go do takiego stanu, w jakim jest obecnie. Wszelkie uwagi są bardzo mile widziane. Wydaje mi się, że Jogger będzie bardzo dobrym miejscem na prowadzenie takiego bloga z powodu zorientowania na techniczne tematy i dużą techniczną społeczność.
Tzw. jednolinijkowce, zwykle inspirowane bieżąco rozwiązywanymi przeze mnie problemami można przejrzeć na moim blipie, gdzie równiez serdecznie zaprawszam.
Życzcie mi powodzenia i wytrwałości, pierwszy wpis to dopiero początek.
</description><pubDate>Sat, 18 Jul 2009 16:11:22 +0200</pubDate><guid>http://blog.miracki.net/2009/07/18/hello-world/</guid><category>Java</category><category>Off-topic</category></item></channel></rss>