如何基于特定注解的类定义泛型类型?
能否直接用@Audited注解作为泛型类型边界?
答案是不行,Java泛型的类型边界只能是类或接口,注解类型(Annotation)没法作为泛型声明里的extends约束条件。@Audited是注解,不属于类/接口范畴,所以你写的public interface AuditRecordService<E extends Audited>这种写法在语法上就通不过。
下面给你几个不用额外继承的替代方案:
方案1:用轻量标记接口
搞一个空的标记接口,让所有带@Audited的实体实现它,既避免了继承,又能在泛型里做编译时约束:
// 空标记接口,只用来做泛型约束 public interface Auditable {} // 实体类实现这个接口,不影响原有继承结构 @Entity @Audited class Record implements Auditable { private Long id; private String something; private String somethingElse; } // 泛型接口用标记接口做边界 public interface AuditRecordService<E extends Auditable> { // 比如定义获取修订记录的方法 List<Object[]> getEntityRevisions(E entity); }
这种方式比继承抽象类灵活多了,毕竟Java支持多实现,不会占实体类的单一继承名额。
方案2:运行时结合反射检查注解
要是不想加标记接口,也可以在服务类的方法里通过反射检查实体类有没有@Audited注解,在运行时做校验:
import org.hibernate.envers.Audited; public interface AuditRecordService<E> { // 传实体类的Class对象,方便反射检查 List<Object[]> getRevisions(Class<E> entityClass, Long entityId); // 默认方法做注解校验 default void validateAuditable(Class<E> entityClass) { if (!entityClass.isAnnotationPresent(Audited.class)) { throw new IllegalArgumentException("实体类 " + entityClass.getName() + " 没标@Audited注解,没法拿审计数据"); } } } // 实现类示例 class AuditRecordServiceImpl<E> implements AuditRecordService<E> { private final AuditReader auditReader; public AuditRecordServiceImpl(AuditReader auditReader) { this.auditReader = auditReader; } @Override public List<Object[]> getRevisions(Class<E> entityClass, Long entityId) { validateAuditable(entityClass); return auditReader.createQuery() .forRevisionsOfEntity(entityClass, false, true) .add(AuditEntity.id().eq(entityId)) .getResultList(); } }
这种方式没有编译时约束,但能在运行时快速拦住不符合要求的实体类,适合不想改实体类结构的场景。
方案3:自定义注解处理器(进阶玩法)
要是既想要编译时强约束又不想用标记接口,可以写个自定义注解处理器,在编译阶段检查所有带@Audited的类是否符合要求(比如必须实现某个接口),不符合就抛编译错误。不过这个实现成本高,适合大型项目统一规范用。
内容的提问来源于stack exchange,提问作者Staxx
相关产品推荐
相关产品推荐

