Wednesday, June 2, 2010

Fast and easy java bean mapping

Java Bean mapping is essential part of many applications. Mapping is often used to serialize Hibernate/JPA/JDO objects, to filter data, to save space/bandwidth when full object data is not needed.
When you are working on GWT application there are two common ways of mapping domain objects between front-end and back-end. One of them is to use same class on both client and server side and use some framework like Gilead to maintain session-related state of object.
Another way is to use data transfer objects on client side. Advantage of such approach are reduced bandwidth usage (you can transfer only data that you are really need in current operation and do not transfer unrelated to current operation data), increased security (you can expose only fields that are really needed to current operation), reduced memory footprint (no need to save session state data on server).
Popular bean mapping frameworks are including Dozer or Apache BeanUtils but all of these frameworks are intensively using reflections to perform mapping operations. Such approach is much slower than mapping performed "by hands", e.g. when you write code like this one:
EntityDto dto = new EntityDto();
dto.setId(entity.getId());
dto.setName(entity.getName());
...
I need solution that works as fast as "by hands" mapping but i am too lazy to write hundreds of lines of routine mapping code.
So i've started small project that generates mapping classes that are as fast as hand-written ones.
Project is located at Google Code: Bean Mapper and it is very easy to use.
To use it you should perform 3 easy steps:
  1. Define mapper interface and annotate methods that should be generated with @Mapper annotation:
    public interface EntityMapper {
       @Mapper
        List<DestinationEntity> map(List<SourceEntity> source);
    }
  2. Obtain implementation of mapper class through factory:
    EntityMapper mapper = (EntityMapper) MapperFactory.getInstance(EntityMapper.class);
    
  3. Use your mapper class:
    List<DestinationEntity> = mapper.map(someSource);
    

Methods that are being generated are as fast as hand-coded. For example if you have 2 classes like these:
public class ClassA {
    int fileld1;
    boolean field2;
    String field3;
    List<ClassA> children;
    //getters and setters
}
public class ClassA {
    String fileld1;
    String field2;
    String field3;
    List<ClassB> children;
    //getters and setters
}
the code being generated for mapping ClassA -> ClassB will look like this:
public ClassB map(ClassA param) {
    ClassB target = new ClassB();
    target.setField1(String.valueOf(param.getField1()));
    target.setField2(String.valueOf(param.getField2()));
    target.setField1(param.getField3());
    if (param.getChildren() != null) {
        target.setChildren(new ArrayList());
        for (ClassA child : param.getChildren()) {
            target.getChildren().add(map(child));
        }
    }
    return target;
}
Actually there will be little more code to properly handle null values, loop dependencies etc. but it will be code that is not using any Reflections overhead and it works several times faster than dynamic mapping frameworks. In some cases it works 100-200 times faster.

Project development is frozen for some time now but it looks stable and I am using it on some of my home projects without any problems.

Monday, May 3, 2010

Dynamic DAO generation

Almost any developer working on enterprise projects spend reasonable amount of time writing DAO classes and tests for them.
Most of this code is trivial, especially in case of ORM frameworks, and I think that it should be generated instead of hand-writing. Why should I waste my time writing routine code, writing tests for it and leaving space for errors despite of tests?
So I wrote very small framework (not actually framework, just a few classes) that generates DAO classes for Hibernate framework.
You just write interfaces for DAO, annotate them and framework do all the routine work for you.
Code being generated is usually as effective as hand-written one and [most] of bugs are already fixed.

Here how DAO interface looks:
public interface EntityDao extends DynamicDao<Entity, Long> {
        List<SomeEntity> getPaginatedFilteredByCriteriaOrderedByCriteria(
            @Pagination.Paginate Pagination pagination,
            @Restriction.Restrict Restriction restriction,
            @Ordering.Criteria Ordering ordering
    );
}

Here how it can be used:
EntityDao entityDao = (EntityDao) DaoFactory.getInstance(EntityDao.class, Entity.class, sessionFactory);
List<Entity> entities = entityDao.getPaginatedFilteredByCriteriaOrderedByCriteria(
    new Pagination(6, 7), 
    Restriction.or(
        Restriction.ilike("name", "vaLue 1"),
        Restriction.like("name", "value 2")),
    new Ordering("name", Ordering.Direction.DESC).Order("id"));

And this is example of actual code auto-generated for interface method above:
public List getPaginatedFilteredByCriteriaOrderedByCriteria(
   Pagination p0, Restriction p1, Ordering p2) {
    Session session = ThreadLocalSessionFactory.getSession();
    Criteria criteria = session.createCriteria(entityClass);
    Restriction restrictionValue = p1;
    Criterion criterion = getCriterion(restrictionValue);
    if (criterion != null) {
        criteria.add(criterion);
    }
    Ordering sortingCriteriaValue = p2;
    while (sortingCriteriaValue != null) {
        if (sortingCriteriaValue.getDirection() == Ordering.Direction.ASC) {
            criteria.addOrder(Order.asc(sortingCriteriaValue.getField()));
        } else if (sortingCriteriaValue.getDirection() == Ordering.Direction.DESC) {
            criteria.addOrder(Order.desc(sortingCriteriaValue.getField()));
        }
        sortingCriteriaValue = sortingCriteriaValue.getChild();
    }
    if (p0 != null) {
        criteria.setFirstResult(p0.getFirstResult());
        criteria.setMaxResults(p0.getMaxResults());
    }
    return criteria.list();
}

Generated DAO classes can be easily exposed as Spring beans.

More information, docs and examples on project's site on Google Code: http://code.google.com/p/dyndao/

The framework is not finished yet (code is not well documented, there are possibly bugs left etc.) and I have no time for it right now but I hope it will look as a real project in near future.
It looking stable and I know at least one project in production stage that is using it.
Anyone interested in project development are welcome.

Monday, April 19, 2010

Spring-managed GWT Remote Service: exposing Spring bean as GWT RPC

Update: there are easier and much easier ways of doing this.
I want to publish simple solution to expose Spring Bean as Google Web Toolkit Remote Service.
There are some solutions around but they are hard to configure, heavy-weight and often do not provide functionality required to use AOP-based annotations on service methods (like Spring Security @Secured) but I prefer minimal XML configuration (In this example there are only few lines of XML), annotation-driven configuration and functionality without any limitations.

So it is needed to create

a) Spring-managed servlet that will handle RPC calls
b) Remote Service common logic implementation
c) Simple GWT RPC Example

Spring servlet to handle RPC calls

package com.example.server.service;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Component("gwt-request-handler")
public class RemoteServiceHandler implements HttpRequestHandler, ApplicationContextAware {
    private ApplicationContext applicationContext;

    public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
        String requestPath = httpServletRequest.getServletPath();
        @SuppressWarnings({"unchecked"})
        Map<String, RemoteService> services = applicationContext.getBeansOfType(RemoteService.class);
        RemoteService service = null;
        for (String key : services.keySet()) {
            if (requestPath.endsWith(key)) {
                if (service != null) {
                    throw new IllegalStateException("More than one GWT RPC service bean matches request: " + requestPath);
                } else {
                    service = services.get(key);
                }
            }
        }
        if (service == null) {
            String availableServlets = "";
            for (String key : services.keySet()) {
                availableServlets += key + " -> " + services.get(key).getClass().getName() + "\n";
            }
            throw new IllegalStateException("Cannot find GWT RPC service bean for request: " + requestPath + "\nMake sure that service implementation extends RemoteServiceImpl instead of GWT RemoteServiceServlet\nList of available beans:\n" + availableServlets);
        }
        service.doPost(service, httpServletRequest, httpServletResponse);
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }
}

it should be configured as servlet in web.xml file:

<servlet>
        <servlet-name>gwt-request-handler</servlet-name>
        <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gwt-request-handler</servlet-name>
        <url-pattern>*.gwtrpc</url-pattern>
    </servlet-mapping>

Spring HttpRequestHandlerServlet will try to locate bean with name same as servlet name and use it to handle all requests matching specified url-pattern.

Remote Service common implementation


This class will take care of ServletContext because these beans are not actually servlets but GWT requires ServletContext to work.
Also it invokes remote methods in a way that allows AOP annotations to work.
Interface is needed to correct work with AOP based annotations, like @Transactional or @Secured

package com.example.server.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface RemoteService {
    void doPost(RemoteService service, HttpServletRequest request, HttpServletResponse response);

}

package com.example.server.service;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class RemoteServiceImpl extends RemoteServiceServlet implements RemoteService {
    private RemoteService service = null;

    public void doPost(RemoteService service, HttpServletRequest request, HttpServletResponse response) {
        this.service = service;
        doPost(request, response);
    }

    @Override
    public ServletContext getServletContext() {
        ServletContext context;
        try {
            context = super.getServletContext();
        } catch (Exception e) {
            context = getThreadLocalRequest().getSession().getServletContext();
        }
        return context;
    }

    @Override
    public String processCall(final String payload) throws SerializationException {
        final RPCRequest request = RPC.decodeRequest(payload, this.getClass(), this);
        try {
            Object result = request.getMethod().invoke(service, request.getParameters());
            return RPC.encodeResponseForSuccess(request.getMethod(), result, request.getSerializationPolicy());
        } catch (IllegalAccessException e) {
            return RPC.encodeResponseForFailure(request.getMethod(), e, request.getSerializationPolicy());
        } catch (InvocationTargetException e) {
            Throwable cause = e.getCause();
            return RPC.encodeResponseForFailure(request.getMethod(), cause, request.getSerializationPolicy());
        } catch (IncompatibleRemoteServiceException ex) {
            return RPC.encodeResponseForFailure(null, ex, request.getSerializationPolicy());
        } finally {
            service = null;
        }
    }
}

Simple Remote Service

Here is implementation of very simple remote service managed by Spring.
You can use any AOP annotation and/or other spring features like autowiring without any limitation.
package com.example.client.service;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.google.gwt.core.client.GWT;

@RemoteServiceRelativePath(TestService.URL)
public interface TestService extends RemoteService {
    public static final String URL = "services/TestService.gwtrpc";

    public String hello(String userName);

    public static class Instance {
        private static final TestServiceAsync instance = (TestServiceAsync) GWT.create(TestService.class);

        public static TestServiceAsync get() {
            return instance;
        }
    }
}

package com.example.server.service;

import com.example.client.service.TestService;
import org.springframework.stereotype.Component;

@Component(TestService.URL)
public class TestServiceImpl extends RemoteServiceImpl implements TestService {
    public String hello(String userName) {
        return "Hello " + userName;
    }
}

Spring context configuration


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
    <context:component-scan base-package="com.example.server.service"/>
</beans>

Wednesday, April 7, 2010

Unique constraint on App Engine Datastore

Another challenge I faced on GAE Datastore is inability to use unique constraints. Sometimes it is absolutely needed to have such constraints and this is my case.

Following solution is not universal but it will help in many cases. Idea is to create entity primary key based on field(s) that should be unique.

Consider following example:
public class Link implements Serializable {
    private Key key;
    private String parentId;
    private String childId;
    //getters and setters
}
It is needed to force that only one link exist for given pair (parent, child) and it can be done in the following way:
@PersistenceCapable
public class Link implements Serializable, StoreCallback {
    @Persistent
    @PrimaryKey
    private Key key;
    private String parentId;
    private String childId;
    //getters and setters
    @Override
    public void jdoPreStore() {
        key = KeyFactory.createKey(Link.class.getSimpleName(), parentId + "::" + childId);
    }
}
Of course any divider can be used instead of "::". Actually there are slightly more complex rules to ensure that generated string is uniquely identifies parentId and childId pair but it is unrelated to topic.

Tuesday, April 6, 2010

Google App Engine datastore case insensitive queries

I started working on small App Engine based project and very soon noticed that there is no possibility to execute case insensitive queries on App Engine Datastore. This was absolute must-have for my application so I performed some googling and came with simple yet effective solution I want to share.

The idea is to store lower-case versions of fields that are used in case-insensitive queries.
So I have class Person like this one (simplified):
@PersistenceCapable
public class Person implements Serializable {
 @PrimaryKey
 @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
 private Key key;
 private String firstName;
 private String lastName;
 //other fields
 //getters and setters
}
and I need to search persons by first/last name ignoring case.
Class should be extended to look like this one:
@PersistenceCapable
public class Person implements Serializable, javax.jdo.listener.StoreCallback {
 @PrimaryKey
 @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
 private Key key;
 private String firstName;
 private String lastName;
 private String firstNameLC;
 private String lastNameLC;
 @Override
 public void jdoPreStore() {
  firstNameLC = firstName == null ? null : firstName.toLowerCase();
  lastNameLC = lastName == null ? null : lastName.toLowerCase();
 } 
 //other fields
 //getters and setters
}
This forces firstNameLC and lastNameLC fields to be filled with lowercase versions of firstName and lastName fields on every update.
Note that you don't need getters and setters for lowercase version fields.
Query can be performed like this one:
{
    PersistenceManagerFactory factory = JDOHelper.getPersistenceManagerFactory("transactions-optional");
    PersistenceManager pm = factory.getPersistenceManager();
    List<person> persons = (List<person>) pm.newQuery("SELECT FROM Person WHERE firstNameLC == name PARAMETERS String name").execute("jOhN".toLowerCase());
}

That's all

UPD: found same solution on GOOGLE APP ENGINE JAVA PERSISTENCE blog. I have no idea why I missed it before.

First post

I am planning to use this blog to share my know-hows, how-tos and simple hints related to Java  programming.
At present my English level is far from perfect and one of the aims of this blog to improve it.
So any corrections/suggestions/etc are welcome.