piątek, grudzień 28, 2007

API do kopiowania JavaBeans

Ostatnimi czasy często spotykam się z problemem konieczności stworzenia kopii JavaBean'a. O ile dla Javy napisano już tysiące API to jednak do tej prostej czynności wciąż nie ma rozwiązania idealnego.

Omówię teraz pokrótce o co mi chodzi. Przede wszystkim API takie powinno dostarczać następujące funkcjonalności:

  • kopiować wgłąb (tzw. deep copy) - kopiowanie referencji nie wchodzi w grę gdyż nie jest to wtedy tak naprawdę operacja kopiowania
  • nie kopiować n razy tej samej referencji - jeśli w oryginalnym obiekcie znajduje się wiele referencji do 1 obiektu, to w kopii też powinno być wiele referencji do skopiowanego obiektu
  • radzić sobie z cyklami - w przypadku wystąpienia cyklu nie powinien wyrzucać wyjątków
  • wykorzystywać dostarczony ClassLoader do wczytywania klas - tak aby można było dostarczyć zmodyfikowane klasy

Na www znalazłem kilka rozwiązań. Między innymi dobrze znane Commons Beanutils. Niestety ono nie spełnia ani jednego wymogu. Drugą biblioteką, która mi wpadła do rąk była Sojo. API jest w fazie rozwoju ale już teraz udostępnia wiele funkcjonalności. Obsługuje kopiowanie wgłąb i radzi sobie z cyklami. Nie kopiuje też uprzednio skopiowanej referencji. Niestety nie znalazłem sposobu na dostarczenie własnego ClassLoadera.

Ze względu na brak wymarzonej biblioteki zacząłem szukać alternatywnych rozwiązań. Pierwszą techniką, którą wykorzystałem była wbudowana serializacja. Niestety ta metoda nie pozwala na dostarczenie własnego ClassLoadera (wykorzystywany jest ClassLoader wywołujący metodę deserializacji) i wymaga by każda klasa implementowała interfejs Serializable.

Kolejnym rozwiązaniem, które przetestowałem było użycie koderów JavaBean<->XML dostarczanych wraz z JRE (klasy XMLEncoder, XMLDecoder). Technika ta jest zdecydowanie najwolniejsza, jednak na pierwszy rzut oka wydawało się, że posiada wszystkie cechy, które od takiego API wymagam. Niestety pomimo dostarczenia własnego ClassLoader'a nie jest on wykorzystywany do wczytania wszystkich niezbędnych klas.

Po kilku dniach próbowania różnych technologii stwierdziłem, że szybciej będzie jak sam zaimplementuję taką funkcjonalność. I w ten oto sposób w 2 dni napisałem proste API do kopiowania beanów ze wszystkimi funkcjonalnościami. API nosi roboczą nazwę BeanCopier i na razie dostępne jest do ściągnięcia na repozytorium Maven 2 pod adresem: http://eggframework.org/maven2.

Aby użyć API we własnym projekcie Maven 2 należy dodać do pom.xml:

<project>
    <dependencies>
        <dependency>
            <groupId>com.jacekolszak</groupId>
            <artifactId>beancopier</artifactId>
            <version>0.9</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>Egg Framework</id>
            <url>http://eggframework.org/maven2</url>
        </repository>
    </repositories>
</project>

Sposób użycia BeanCopier:

BeanCopier beanCopier = new BeanCopierImpl();
copy = beanCopier.copy(original, classLoader);

Niebawem wrzucę źródła na CVS. Póki co są one dostępne w jarze beancopier-0.9-sources.jar na repozytorium Maven 2.

UPDATE: Źródła są dostępne na repozytorium Bazaar po adresem: http://bazaar.launchpad.net/~jacekolszak/beancopier/trunk. Wystarczy wydać polecenie:
bzr branch http://bazaar.launchpad.net/~jacekolszak/beancopier/trunk
aby ściągnąć najnowsze źródła.

poniedziałek, grudzień 17, 2007

Fluent Interface w Egg Framework 2.0

Jedną z najciekawszych funkcjonalności wprowadzonych do Egg Framework 2.0 jest Fluent Interface - API, za pomocą którego można tworzyć czytelny kod aplikacji www w języku Java - wyglądający o dziwo bardzo podobnie do HTMLa.

Fluent Interface to pojęcie wprowadzone przez Martina Fowlera i Erica Evansa. Nazwali oni tym terminem pewien styl tworzenia interfejsów programowych. Więcej można przeczytać na blogu Martina Fowlera.

Oto przykład strony www stworzonej przy użyciu Fluent Interface zaimplementowanym w Egg Framework 2.0:

package org.eggframework2.view.examples.xhtml;

import static org.eggframework2.view.elements.xhtml.ext.FluentInterfaceMethods.*;

import org.eggframework2.view.elements.IElement;
import org.eggframework2.view.elements.xhtml.tags.Html;

public class FluentInterfaceUsageExample extends Html {

    public FluentInterfaceUsageExample() {
        IElement body = //
        body( //
                p("Hello World"), //
                a("Egg Framework Page", href("http://eggframework.org")), //
                form(action("/action.do"), method("post"), //
                        input(type("text"), name("Login")), br(), //
                        input(type("password"), name("Password")), br(), //
                        input(type("submit"), value("Please log me in"))//
                ),//
                table(//
                        tr(//
                                td("Cell 1"), td("Cell 2"), td("Cell 3")//
                        ),//
                        tr(//
                                td("Cell 1"), td("Cell 2"), td("Cell 3")//
                        )//
                ));

        add(body);
    }

    public static void main(String[] args) {
        System.out.println(new FluentInterfaceUsageExample());
    }
}

Jak widać kod Javy jest bardzo czytelny i podobny do wynikowego kodu HTML. Wszystko dzięki wykorzystaniu metod statycznych i statycznych importów. Dzięki zaimportowaniu wszystkich metod z klasy FluentInterfaceMethods możemy ich użyć w kodzie strony tak jakby były one jej częścią. Nie musimy więc poprzedzać nazwy metody nazwą klasy w jakiej jest ona zdefiniowana. To sprawia, że kod jest znacznie bardziej zwięzły.

Klasa FluentInterfaceMethods oprócz metod tworzących instancje elementów (znaczników) HTML posiada metody tworzące atrybuty np. type, name, id. Dzięki temu można w jednej linijce utworzyć element i ustawić jego atrybuty.

Jeśli często używasz układania kodu źródłowego (Pretty Print) to musisz być przygotowany na to, iż większość IDE ułoży kod takiej strony w jednej linijce (albowiem całą zawartość tworzysz poprzez zagnieżdżone wywołania metod). To na pewno nie przyczyni się do zwiększenia czytelności kodu, wręcz odwrotnie - znacznie ją pogorszy. Aby ustrzec się przed taką sytuacją należy użyć komentarzy ("//") w miejscach gdzie IDE ma złamać linię. Dzięki nim nawet po operacji układania kodu kod będzie ładnie się prezentował.

Fluent Interface w Egg Framework to sposób na zwiększenie czytelności tworzonego kodu. Jest to swojego rodzaju nakładka i wykorzystuje istniejące API. Po kilkunastu/kilkudziesięciu minutach pracy powinieneś się przyzwyczaić do tego "dziwnego stylu programowania". Od Ciebie zależy czy będziesz go wykorzystywał czy nie - w wielu wypadkach może okazać się lepszy, jednak mogą zdarzyć się sytuacje gdy utworzenie zawartości strony "w standardowy sposób" będzie prostsze i szybsze.

poniedziałek, sierpień 07, 2006

Przekleństwo frameworków Javowych

Egg Framework Dla Javy napisano już setki, jeśli nie tysiące szkieletów do pisania aplikacji webowych. Jeśli ktoś wnikliwie czyta newsy na theserverside to wie, że nowe frameworki powstają jak grzyby po deszczu.

Pytanie jednak brzmi... skoro każdy szkielet jest taki dobry, to czemu powstają nowe? Odpowiedź jest jedna - nie da się napisac szkieletu dla każdego. Ponadto wiele nowych frameworków bardziej utrudnia niż ułatwia życie programistów, starając się rozwiązać każdy problem. Świadczy może o tym na przykład fakt, iż wciąż najczęsciej używany jest Struts, pomimo swego sędziwego wieku.

Jakie więc powinny być cechy idealnego frameworka? W mojej opinii szkielet to narzędzie, które pozwoli programiście przede wszystkich na łatwiejsze i szybsze pisanie aplikacji. Dlatego też szkielet powinien być jak najprostszy, mieć przejrzyste API, zadbany i przemyślany kod źródłowy, aby programista mógł bez problemu go zrozumieć (często lepiej jest po prostu zobaczyć jako kod działa, aniżeli czytać często niekompletną dokumentację). Jeśli zaś mówimy o szybkości pisania aplikacji to developer powinien implementować ją w sposób niezwykle zwinny (ang. agile). Chodzi o to, żeby programista (na przykład na życzenie klienta) mógł bardzo szybko nanieść poprawki bez konieczności wprowadzania zmian w kilku miejscach, długim testowaniu aplikacji od strony GUI (na przykład w przypadku brak możliwości pisania testów jednostkowych dla komponentów GUI) czy wreszcie ciągłych restartów serwera. Jeszcze jedna kwestia - szkielet nie powinien w żaden sposób ograniczać programisty! Jeśli coś można w prosty sposób zrobić w HTMLu i JavaScriptcie, to i w tym szkielecie musi to być czynność prosta i przede wszystkim możliwa(!).

Oburzony brakiem "idealnego" frameworka, stworzyłem własny prototyp takiego szkieletu - zaprojektowany tak, aby mógłbyć podstawą większości aplikacji tworzonych w standardowym modelu klient-serwer (bez udziwnień AJAXowych, z wiszącymi połączeniami włącznie). Szkielet ten zawiera jedynie podstawową funkcjonalność (brakuje w nim chociażby walidatorów), jednak w mojej opinii jest ona w zupełności wystarczająca. Uznaję zasadę, że programista musi znać szkielet, którego używa w 100 procentach. Jeśli udostępniłbym programiście zaawansowane komponenty, to mógłby on w ogóle nie rozumieć zasady ich działania (co w końcu doprowadziłoby do poważnych przestojów w projekcie, związanyc z poprawianiem uprzednio napisanego kodu).

Ów prototyp okazał się na tyle ciekawy, że postanowiłem zacząć pisać projekt z prawdziwego zdarzenia. Projekt nosi nazwę Egg i jak sama nazwa wskazuje jest zalążkiem tworzonej przez Ciebie aplikacji. Używając go będziesz mógł stworzyć zarówno prostą, jak i szalenie skomplikowaną aplikację. Do niektórych jego cech należą: automatyczne reloadowanie klas bez restartów serwera, pełna obiektowość (możliwość tworzenia własnych komponentów w śmiesznie prosty sposób), DRY (zasada nie powtarzania kodu w różnych miejscach), CoC (konwencja zamiast konfiguracji) oraz możliwość łatwego testowania tworzenego GUI (na zasadach TDD). Wersja alpha projektu będzie dostępna w ciągu kilku dni na serwerach Google Code.

niedziela, maj 21, 2006

Google Web Toolkit

Szukając ostatnio javowych framework'ów do tworzenia aplikacji AJAXowych natrafiłem na Google Web Toolkit. Spotkałem już wiele narzędzi, jednak muszę przyznać, że jeszcze nigdy nie byłem tak podekscytowany :)

GWT to podobnie jak SWT czy SWING biblioteka do tworzenia interfejsów użytkownika. Jednak w tym przypadku tworzymy aplikacje webowe a nie desktopowe. Z pewnością niektórzy używali lub zapoznali się wcześniej z takimi frameworkami jak Echo - tu sprawa wygląda podobnie. Czemu więc jestem podekscytowany? Powodów jest kilka.

Pierwszy to ten, że Google ma za sobą stworzenie kilku świetnych aplikacji AJAXowych (Google Maps, GMAIL). Drugi fakt, że biblioteka jest na licencji Open Source (choć część kodu nie jest dostępna). Po trzecie framework umożliwia w łatwy sposób tworzenie kodu JavaScript w Javie (tak, kod Javy jest kompilowany do JavaScriptu!). Po czwarte umożliwia łatwe debugowanie (w trybie debugowania Java nie jest tłumaczona do JavaScriptu).

Podsumowując GWT wygląda bardzo okazale. Jest to nie tylko biblioteka ale też zbiór narzędzi, które znacznie mogą podnieść wydajność programisty. GWT może na zawsze zmienić życie programistów aplikacji webowych. Sprawi, że będą szybciej i lepiej tworzyć interaktywne interfejsy użytkownika. Wraz z powstaniem wersji stablinej i zaimplementowaniem obsługi Javy 5.0, GWT to ma szansę stać się najpopularniejszych frameworkiem aplikacji AJAX wszechczasów :D