Thursday 26 July 2012

Trial with some Java generics

Introduction

It has been a while that I was able to post anything on this blog.  Due to various reasons, I didn't had any time to post an entry.
But things are slowly changing again, in the positive direction, and thus I found some time to create the following entry.  However, it is slightly off topic because it is not directly related to JSF or JEE but has to do with Java generics.

In the project, I needed the current date (system date) but in various 'formats', as a String, a java.util.Date and org.joda.time.LocalDate version. And I didn't want to use a method that returned the current date in the JodaTime version and call utility methods to convert it in the other formats if I needed them.  I went for the elegant solution like this.
 
String today = DateUtil.today();

Date todayAsDate = DateUtil.today();

Type erasure


I thought the solution was easy, I should have know that this kind of problem can't be solved, and created the following method
 
public static T today() {

   T result = null;

   // Logic goes here 

   return result; 

}

But the problem is that there is no way at runtime to determine what the return type should be. I started with reflection and used the method getGenericReturnType(). But other information than that the method should return Object and I defined something like T, wasn't available.
And then I realized that the kind of method I would like to write, isn't possible. Generics are used by the java compiler, but at runtime, there is no information about them available (there are some exceptions).  The processed is referred to as 'type erasure' and allowed backward binary compatible code.

So if we write code like this
        List myList = new ArrayList();
        myList.add("test");
        String value = myList.get(0);

The compiler converts it to this pre-5 compatible version
        List myList = new ArrayList();

        myList.add("test");

        String value = (String) myList.get(0);

And in the mean time, it is able to verify if we don't add anything else then a string to the collection.

Solution


I had to define a parameter which can be used to determine the return type like this
public static T today(Class returnType) {

   T result = null;

   // Logic goes here

   return result; 

}

This results in more code to type, but still quit elegant and type safe.
So something like
 
long time = DateUtil.today(Long.class);

won't compile.

On the other hand, using the class parameter leads to some ugly if statements which can be avoided by defining an Enum. But then we loose the type safety again and we need to introduce casting again.

Conclusion


In many situation, I love the possibilities that generics can offer.  And I don't know the impact of course, but having the extra generics information at runtime, maybe only when a compiler argument is specified, could be very handy in this situation.