Аннотации к созданию общего типа

Учитывая общий интерфейс, например

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

Я хотел бы создать субинтерфейс, который задает параметр типа:

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

Реализация должна знать фактический тип параметра шаблона, но, конечно, средства стирания стилей недоступны во время выполнения. Есть ли какая-то аннотация, которую я мог бы включить, чтобы объявить тип интерфейса? Что-то вроде

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

Затем реализация может извлечь эту аннотацию из интерфейса и использовать ее в качестве замены для доступа к родовому типу среды выполнения.

Некоторая предыстория:

Этот интерфейс реализован с использованием динамических прокси JDK, как описано здесь. Неоригинальная версия этого интерфейса работает хорошо, но было бы лучше использовать generics и не создавать методы в подинтерфейсе, чтобы указать тип объекта домена. Общие и прокси-серверы заботятся о большинстве вещей, но фактический тип необходим во время выполнения для реализации метода newInstance, среди прочих.

Ответ 1

Можно найти фактический аргумент типа под-интерфейса Dao (CustomerDAO), вызвав следующий метод:

import java.lang.reflect.ParameterizedType;

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

Когда вы называете это

Class<?> domainClass = getDomainClass(daoInterface);

с daoInterface == CustomerDAO.class, вы получите domainClass == Customer.class.

В моей реализации a DaoFactory выполняет этот вызов и использует domainClass как аргумент конструктора для DaoInvocationHandler.

Ответ 2

Реализация должна знать фактический тип параметра шаблона.

Несомненно, любая реализация CustomerDao неявно знает, что параметр типа Customer. Он реализует DomainObjectDAO<Customer> not DomainObjectDAO<T>.

Проблемы возникают только в том случае, если класс CustomerDao расширяет общий абстрактный класс и что общий абстрактный класс должен знать фактический тип T. Но вы можете справиться с этим, передав объект класса для T (в данном случае Customer.class) в суперкласс в качестве аргумента конструктора.