Аннотации к созданию общего типа
Учитывая общий интерфейс, например
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
) в суперкласс в качестве аргумента конструктора.