Jacek Olszak: Sugar free Java
Blog about everything which has something to do with Java, programming and web applications.
Monday, January 09, 2012
TryCatch: Nieblokujące serwery sterowane zdarzeniami
Wstęp
Równoległa obsługa żądań
Zyski
Zastosowanie
Problemy
Technologie
Thursday, December 15, 2011
TryCatch: Rozpoczęcie działalności TryCatch
Sunday, February 27, 2011
Use Java as a dynamically typed programming language
Java is a statically typed programming language. This means that at the time of compilation the types of variables used in the program are known. This feature is one of the most powerful (if not the most powerful) thing, which gives a programmer warnings about bad code written before he runs it. This allows also to build powerful development environments like Eclipse with content assists and refactoring support. Unfortunately there is no rose without a thorn. Because of static typing a program code is a much bigger (types need to be specified in declarations, casting is necessarily) and sometimes simple problem becomes too complex. If you don't believe in this statement - check the core of JavaServer Pages technology (I mean scriptlets, without JSP tags) and see how much unnecessarily code you need to write just to print some attribute's field on the screen.
There is a lot of frameworks written for Java. Most of these frameworks use interfaces or abstract classes as a building block. Let me give an example: in order to create a HTTP servlet you need to create a new class extending the abstract HttpServlet class. This is simple, but... hmm... Do you really need to write a dedicated class for every action? It will not be better if you have multiple actions grouped together? Because of static typing you can't just do this easily, which of course does not mean that this is not possible. The solution is the reflection API bundled into JRE. You can execute methods, access or update fields etc. of objects of any type.
As a simple example what you can do with reflections check the following code of controller written in Egg Framework (full stack web framework being developed by me):
package controllers; import static framework.GlobalHelpers.*; import framework.Response; public class SampleController { public void newProduct() { Product product = paramsAsBean(Product.class); // TODO save product in db } public Response removeProduct() { if (session("logged") == null) { // not allowed return renderText("Access denied"); } // TODO remove product from db return null; } }
The Egg Framework uses reflections extensively. There is no configuration (Convention over Configuration), no interfaces. Every class can be a controller, every class can be a form bean etc. (just plain old java objects - POJO). In this example Egg Framework uses request parameters sent to the server to decide which method (action) to invoke. Note that both methods have different signatures - not only the name, but the return type. But for Egg Framework it does not matter. If the action returns something not null then Egg Framework handles this, otherwise it runs normal processing. In this example I have used also static methods (check the import static statement on the top). Static imports are really great and can simplify your program dramatically.
So what the conclusion for this post? I think that there is still a lot to do in Java libraries, frameworks and APIs design. Egg Framework is one of many examples how to make Java programs looks prettier.
Friday, December 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.