views:

60

answers:

2

Given an generic interface like

interface DomainObjectDAO<T>
{
   T newInstance();
   add(T t);
   remove(T t);
   T findById(int id);
   // etc...    
}

I'd like to create a subinterface that specifies the type parameter:

  interface CustomerDAO extends DomainObjectDAO<Customer> 
  {
       // customer-specific queries - incidental.
  }

The implementation needs to know the actual template parameter type, but of course type erasure means isn't available at runtime. Is there some annotation that I could include to declare the interface type? Something like

  @GenericParameter(Customer.class)
  interface CustomerDAO extends DomainObjectDAO<Customer> 
  {
  }

The implementation could then fetch this annotation from the interface and use it as a substitute for runtime generic type access.

Some background:

This interface is implemented using JDK dynamic proxies as outlined here. The non-generic version of this interface has been working well, but it would be nicer to use generics and not have to create the methods in a subinterface just to specify the domain object type. Generics and proxies take care of most things, but the actual type is needed at runtime to implement the newInstance method, amongst others.

A: 

The implementation needs to know the actual template parameter type.

Surely, any implementation of CustomerDao implicitly knows that the type parameter is Customer. It is implementing DomainObjectDAO<Customer> not DomainObjectDAO<T>.

Problems are only going to arise if the CustomerDao class extends a generic abstract class, and that generic abstract class needs to know the actual type of T. But you can deal with that by passing the Class object for T (in this case Customer.class) to the superclass as a constructor argument.

Stephen C
I was going to write that in the question that I could pass the actual type as a constructor to the InvocationHandler, but I was wondering if there is an annotation to do the same job - the type belongs to the interface and not the implementation.
mdma
+1  A: 

It is possible to find the actual type argument of the Dao sub-interface (CustomerDAO), by invoking the following method:

import java.lang.reflect.ParameterizedType;

public static Class<?> getDomainClass(final Class<?> daoInterface) {
    ParameterizedType type = (ParameterizedType) daoInterface.getGenericInterfaces()[0];
    return (Class<?>) type.getActualTypeArguments()[0];
}

When you call it like

Class<?> domainClass = getDomainClass(daoInterface);

with daoInterface == CustomerDAO.class, then you will get domainClass == Customer.class.

In my implementation, a DaoFactory performs this call and uses the domainClass as a constructor argument for the DaoInvocationHandler.

Christian Semrau
Thanks! This is the solution. According to http://blog.springsource.com/2006/09/29/exploiting-generics-metadata/ not all generic information is erased - in particular, static information is maintained.
mdma