Учитывая универсальный интерфейс как
interface DomainObjectDAO
{
T newInstance();
add(T t);
remove(T t);
T findById(int id);
// etc...
}
Я хотел бы создать подынтерфейс, который указывает параметр типа:
interface CustomerDAO extends DomainObjectDAO
{
// customer-specific queries - incidental.
}
Реализация должна знать фактический шаблонный тип параметра, но конечно ввести средства стирания, не доступно во времени выполнения. Есть ли некоторая аннотация, которую я мог включать для объявления интерфейсного типа? Что-то как
@GenericParameter(Customer.class)
interface CustomerDAO extends DomainObjectDAO
{
}
Реализация могла затем выбрать эту аннотацию от интерфейса и использовать его вместо универсального доступа типа во время выполнения.
Некоторый фон:
Этот интерфейс реализован с помощью JDK динамические прокси, как обрисовано в общих чертах здесь. Неуниверсальная версия этого интерфейса работала хорошо, но было бы более хорошо использовать дженерики и не иметь для создания методов в подынтерфейсе только для определения типа объекта области. Дженерики и прокси заботятся о большинстве вещей, но фактический тип необходим во времени выполнения для реализации newInstance
метод, среди других.
Можно найти фактический аргумент типа подинтерфейса 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
.
В моей реализации DaoFactory
выполняет этот вызов и использует domainClass
в качестве аргумента конструктора для DaoInvocationHandler
.
Реализация должна знать фактический тип параметра шаблона.
Конечно, любая реализация CustomerDao
неявно знает, что тип параметра - Customer
. Он реализует DomainObjectDAO
, а не DomainObjectDAO
.
Проблемы возникнут только в том случае, если класс CustomerDao
будет расширять общий абстрактный класс, и этому общему абстрактному классу понадобится знать фактический тип T
. Но с этим можно справиться, передав объект Class для T
(в данном случае Customer.class
) суперклассу в качестве аргумента конструктора.