• Home
  • RSS Feed
  • Log in

Accessing generic types at runtime in Java
Posted by Arjan Blokzijl mid-morning: February 7th, 2009

I was writing my n-th Dao implementation, this time using JPA.
I (and probably a whole lot of others) usually create a DAO per entity, parameterizing the entity type.
Specific DAO instances for entities implement the generic DAO using their entity type as type parameter. One generic DAO implementation exists, containing common operations like findById, persist, remove, etc. This generic DAO uses the class type specified by the implementing DAO classes (e.g. a Person) to manipulate or query the entity specified by this type. The (slightly) annoying problem for me has always been to instantiate that entity type in the generic DAO superclass. I've always done this by just creating a constructor in the generic DAO which takes a class argument containing the required Class of the entity. However, there's a better way, which I'll show in this post.

To start with an example, the generic DAO interface looks like this:

 
public interface GenericEntityDao<T> {
 
   T findById(Serializable id);
 
   List<T> findAll();
 
   ... more methods omitted
}
 

And its generic DAO implementation class looks something like this:

 
public abstract class GenericJpaDao<T> implements GenericDao<T> {
 
  private Class<T> entityBeanType;
 
  @PersistenceContext
  private EntityManager entityManager;
 
  public T findById(Serializable id) {
     return entityManager.find(getEntityBeanType(), id);
  }
 
  public List<T> findAll() {
      return entityManager.createQuery("from " + getEntityBeanType().getName() )
                          .getResultList();
  }
 
  protected Class<T> getEntityBeanType() {
      return entityBeanType;
  }
  ... more methods omitted
 
}
 

The question is, how do we obtain the parametized type of T for the entityBeanType field to use in our queries? Earlier, I used to just instantiate this type in the constructor, like so:

 
public GenericJpaDao(Class<T> entityBeanType) {
     this.entityBeanType = entityBeanType;
}
 
public JpaPersonDao extends GenericJpaEntityDao<Person> implements PersonDao {
   public PersonDao() {
      super(Person.class);
   }
}
 

But this is a bit silly, since we already know from the type parameter that the entity we're interested in has type Person.
However, there is an easier way out: we can use Java's ParameterizedType class to obtain information about the declared generic type. As stated in the javadoc:

/**
* ParameterizedType represents a parameterized type such as
* Collection<String>.
*
* A parameterized type is created the first time it is needed by a
* reflective method, as specified in this package. When a
* parameterized type p is created, the generic type declaration that
* p instantiates is resolved, and all type arguments of p are created
* recursively.


Thus, it seems that ParameterizedType contains the information that we want. How do we obtain an instance of it? The answer lies in Java's getGenericSuperclass method, defined on the Class object. This returns a Type representing the superclass of this Class. The Javadoc of the method states the following:

* If the superclass is a parameterized type, the Type
* object returned must accurately reflect the actual type
* parameters used in the source code. The parameterized type
* representing the superclass is created if it had not been
* created before.



The Type interface itself is just a marker interface, containing no methods. Depending on the case at hand, an Type extending the Type interface will be returned. In our case, we'll use the getGenericSuperclass method on a class extending our GenericJpaDao class. Thus, the superclass is JpaGenericDao, which is a parameterized type. In this case, the actual the Type object returned by getGenericSuperClass will be a ParameterizedType instance. This class contains a method getActualTypeArguments, which returns an array containing all generic type parameters used in the source code.

This is precisely what we desire, so in our GenericJpaDao class constructor, can get rid of the Class argument, and instead do the following:

 
  @SuppressWarnings("unchecked")
  public GenericJpaDao() {
    this.entityBeanType = ((Class<T>) ((ParameterizedType) getClass()
        .getGenericSuperclass()).getActualTypeArguments()[0]);
  }
 

We know there's precisely one type argument in our class, so we can take the first element of the array that is returned, which provides the Class of our entity. Thus we can get rid of all the annoying constructors with Class arguments, and handle determination of the entity type in just one place.

This may not provide the highest amount of code reduction you have ever experienced, but it's a neat trick in any case.

  • Share/Bookmark

Tags: generics, Java, JPA
Filed under JPA, Java | 10 Comments »



10 Responses to “Accessing generic types at runtime in Java”



    Maarten Winkels Says:
    Posted at: February 7, 2009 at 2:50 pm

    Hi Arjan,

    A neat trick indeed. I found it here, the first time I ever heard about it. The code itself though is just plain nasty, with all the explicit casting and using hardcoded array indexing. Also, it only works when you implement a generic interface or a generic superclass (I think?).

    Anyways, good to have it on the Xebia blog, so I know where to find that nasty line of code when I need it… ;)

    -Maarten



    Andrew Phillips Says:
    Posted at: March 5, 2009 at 12:33 pm

    A nice trick, indeed. But something to bear in mind here: this only works if

    • the type information is in a superclass and, thus,
    • the class that needs the type information inherits from the type-defining class.

    If you are class Foo<V> and you need access to the runtime type of V this unfortunately won’t work. Neither if you are FooUtils and get passed an instance of Foo.

    I’ll hopefully get round to writing a post about some of these issues soon…



    A general-purpose utility to retrieve Java generic type values | Xebia Blog Says:
    Posted at: March 12, 2009 at 2:28 pm

    [...] by Andrew Phillips in the early afternoon: March 12, 2009 In a recent post, Arjan Blokzijl discussed how Class.getGenericSuperclass can be used to access generic type [...]



    JPA implementation patterns: Data access objects | Xebia Blog Says:
    Posted at: March 29, 2009 at 5:52 pm

    [...] with the shared functionality and then subclass from that for each specific DAO. There are a lot of blogs out there about such a type-safe generic DAO pattern and you can even download some code from [...]



    Rob Says:
    Posted at: June 12, 2009 at 7:54 pm

    Thank you so much!! Saved me ours of javadoc reading :)

    I had the same feelings than you about redundancy by passing in the class. ParameterizedType is the solution!



    feng Says:
    Posted at: August 28, 2009 at 2:14 am

    Excellent article.

    I modified the code for the constructor as below so that it can handle multiple level inheritance.

    Class cls = getClass();
    while (!(cls.getSuperclass() == null ||
    cls.getSuperclass().equals(GenericJpaDao.class))) {
    cls = cls.getSuperclass();
    }

    if (cls.getSuperclass() == null)
    throw new RuntimeException(”Unexpected exception occurred.”);

    this.expressionType = ((Class) ((ParameterizedType) cls
    .getGenericSuperclass()).getActualTypeArguments()[0]);



    feng Says:
    Posted at: August 28, 2009 at 4:43 pm

    The code in my previous comment doesn’t display correctly due to the special characters “” for the markup language. I don’t know how to markup a code block. Can the mediator help me put the following code in the right format?

    Class cls = getClass();
    while (!(cls.getSuperclass() == null ||
    cls.getSuperclass().equals(AbstractExpression.class))) {
    cls = cls.getSuperclass();
    }

    if (cls.getSuperclass() == null)
    throw new RuntimeException("Unexpected exception occurred.");

    this.entityBeanType = ((Class) ((ParameterizedType) cls
    .getGenericSuperclass()).getActualTypeArguments()[0]);



    feng Says:
    Posted at: August 28, 2009 at 4:56 pm

    Sorry for submitting the same post multiple times. The following should display better. This will be my last try.

    Class<?> cls = getClass();
    while (!(cls.getSuperclass() == null ||
    cls.getSuperclass().equals(AbstractExpression.class))) {
    cls = cls.getSuperclass();
    }

    if (cls.getSuperclass() == null)
    throw new RuntimeException(”Unexpected exception occurred.”);

    this.entityBeanType = ((Class<T>) ((ParameterizedType) cls
    .getGenericSuperclass()).getActualTypeArguments()[0]);



    Luis Daniel Mesa Velásquez Says:
    Posted at: November 5, 2009 at 2:00 am

    Useful for when you have a subclass of a generic, in which case you don’t really need it, cuz you know the generic type and it saves you, perhaps, 2 lines of code per subclass…

    completely useless if you don’t have a subclass. I tried creating a “generic helper” to let me create a subclass and get around the block… It works, but i didn’t like not having an elegant solution either.



    Jelmer Says:
    Posted at: February 5, 2010 at 11:08 am

    Yes this is a useful trick. The exact same piece of code has been part of the caveat emptor sample applicatication for the Java Persistence with Hibernate for quite some time. As has been pointed out in the comments. This code doesn’t work in all cases.

    If you use spring3 you could use

    this.entityBeanType = GenericTypeResolver.resolveTypeArgument(getClass(), GenericDao.class)

    as a more elegant and robust solution



Leave a Reply

Click here to cancel reply.

Deployment automation for Java application running on Websphere, WebLogic and JBoss

Archives

  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009

Xebia Sites

  • Xebia Corporate
  • Xebia France
  • Xebia India

Categories

  • Java (282)
  • Agile (109)
  • General (50)
  • Testing (42)
  • Performance (42)
  • Hibernate (36)
  • Scrum (33)
  • Podcast (31)
  • Architecture (31)
  • Spring (28)
  • SOA (24)
  • Maven (22)
  • Project Management (22)
  • Middleware (23)
    • Deployment (14)
  • Flex (17)
  • JPA (17)
  • Eclipse (15)
  • Xebia Labs (15)
  • Quality Assurance (14)

Tag Cloud

    JavaOne fitnesse Ajax esb Scrum Xebia Testing Lean Agile Awareness Workshop SOA XML product owner Closures Semantic Web Maven Seam Groovy Hibernate Introduction to Agile Poppendieck Performance Scala qcon IntelliJ Spring Agile Architecture Java Grails Functional Programming