Thursday, February 18, 2010

Hibernate and dates

I've come back to a Hibernate problem that I had in my last role which revolves around how java.util.Dates are handled. The problem is this: you populate your POJO with java.util.Dates and persist it. Magically, these objects are turned into java.sql.Timestamps.

Sun warns you about this in a rather odd statement in the Java API.

"[I]t is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance."

Therefore:

aDate.equals(aTimestamp)


does not mean

aTimestamp.equals(aDate)


So, what? Gavin King says:

"Note that no self-respecting code should EVER call equals on a Timestamp."

But when you start putting objects into java.util.Collections, you no longer directly control if or when an equals method is called on your objects.

This lead me to post a bug report (and proposed fix) since what I saw in our project was that upon each transaction, either our POJO had all its Dates or non at all, alternating with each call. Clearly not good! The call was supposed to be idempotent.

Sadly, there has been no interest in my bug report. And although my fix works (albeit somewhat inefficiently), it would be nice to see Hibernate keep java.util.Dates as java.util.Dates.

Thursday, February 11, 2010

Continuing GWT/Spring integration

Ok, so the serialization of objects of my own classes wasn't perfect (the framework had problems with my own Exceptions). So, after some more tracing through the code, I found a hack to fix it.

The trouble is, this hack is becoming more obviously ugly (hey, I've only been playing with the GWT framework for a week). However, it does appear to work. So, for the sake of completeness, I'll put it here with the above caveat. Maybe I'll use Aspects to automatically populate my GWT server-side classes with Spring beans...

Here's the modified Spring controller class that delegates to the GWT server-side classes (taken from Richard Bondi's proposal):


public class GWTController
extends RemoteServiceServlet
implements Controller, ServletContextAware
{
// Instance fields
private MyRemoteServiceServlet remoteService;
private Class remoteServiceClass;
private ServletContext servletContext;
private Map servletToSerializationPolicy = new HashMap();


private GWTController() {
super();
}

// Public methods
/**
* Implements Spring Controller interface method.
*
* Call GWT's RemoteService doPost() method and return null.
*
* @param request current HTTP request
* @param response current HTTP response
* @return a ModelAndView to render, or null if handled directly
* @throws Exception in case of errors
*/
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
doPost(request, response);
return null; // response handled by GWT RPC over XmlHttpRequest
}

/**
* Process the RPC request encoded into the payload string and return a string
* that encodes either the method return or an exception thrown by it.
*/
public String processCall(String payload) throws SerializationException
{
try
{
SerializationPolicyProvider serializationPolicyProvider = new SerializationPolicyProvider() {

@Override
public SerializationPolicy getSerializationPolicy(
String moduleBaseURL,
String serializationPolicyStrongName) {
remoteService.setPerThreadRequest(perThreadRequest);
SerializationPolicy serializationPolicy = remoteService.getSerializationPolicy(moduleBaseURL, serializationPolicyStrongName);
servletToSerializationPolicy.put(remoteService, serializationPolicy);
return serializationPolicy;
}
};
RPCRequest rpcRequest =
RPC.decodeRequest(payload, this.remoteServiceClass, serializationPolicyProvider);

// delegate work to the spring injected service
return RPC.invokeAndEncodeResponse(this.remoteService,
rpcRequest.getMethod(),
rpcRequest.getParameters(),
servletToSerializationPolicy.get(remoteService));
}
catch (IncompatibleRemoteServiceException e)
{
return RPC.encodeResponseForFailure(null, e);
}
}


/**
* Setter for Spring injection of the GWT RemoteService object.
* @param RemoteService the GWT RemoteService implementation
* that will be delegated to by
* the {@code GWTController}.
*/
public void setRemoteService( MyRemoteServiceServlet remoteService )
{
this.remoteService = remoteService;
this.remoteServiceClass = this.remoteService.getClass();
}

@Override
public ServletContext getServletContext() {
return servletContext;
}

public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}

}


Hope this helps.

Tuesday, February 9, 2010

Google Web Kit, Spring and Serialization

I've just started playing with Google's Web Toolkit and I am impressed. Even a back-end programmer like me can write rich, AJAX front-ends!

However, integrating it with Spring is not trivial. There are many suggestions on how to do this. The simplest appeared to be Richard Bondi's suggestion that you can find here. It worked fine. Until, that is, I tried to send one of my own objects from client to server. I started seeing this:


Exception while dispatching incoming RPC call
com.google.gwt.user.client.rpc.SerializationException: Type 'xxx.xx.xxx.MyClass'
was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable'
and did not have a custom field serializer.
For security purposes, this type will not be serialized.



And, after stepping through the code (thank you, Google, for providing the source code by default with my Eclipse plug-in!) I saw that it was using the LegacySerializationPolicy that dates back to GWT 1.3, apparently.

That's no good! So, why wasn't Richard's excellent fix fully functional?

After a late night hacking session, I got a rough solution. I modified Richard's GWTController.processCall's try block such that it read:

SerializationPolicyProvider serializationPolicyProvider = new SerializationPolicyProvider() {
@Override
public SerializationPolicy getSerializationPolicy(
String moduleBaseURL,
String serializationPolicyStrongName) {
remoteService.setPerThreadRequest(perThreadRequest);
return remoteService.getSerializationPolicy(moduleBaseURL, serializationPolicyStrongName);
}
};
RPCRequest rpcRequest =
RPC.decodeRequest(payload, this.remoteServiceClass, serializationPolicyProvider);


Where your remoteService now has to inherit from this ugly class:

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

import org.springframework.web.context.ServletContextAware;

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

public class MyRemoteServiceServlet extends RemoteServiceServlet implements ServletContextAware {

private ServletContext servletContext;

public void setPerThreadRequest(ThreadLocal perThreadRequest) {
this.perThreadRequest = perThreadRequest;
}

@Override
public ServletContext getServletContext() {
return servletContext;
}

public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}

}


OK, it's not pretty but it works. And you had to extend RemoteServiceServlet anyway.

There may be a more elegant way but I've only just woke up so I will continue improving it and post any further thoughts later.