Java泛型类型绑定到带有特定注释的类上

时间:2019-11-02 09:45:55

标签: java generics annotations

在Java中,可以将泛型参数绑定到实现特定接口的类,因此可以进行以下操作

interface MyInterface {}

class MyClassA implements MyInterface {}

class MyBoundedClassA<T extends MyInterface>

现在,如果我想将参数绑定到使用特定注释进行注释的类的接口,该怎么办?

interface @MyAnnotation {}

@MyAnnotation
class MyClassB {}

class MyBoundedClassB<T extends MyAnnotation> // NOT possible

是否有可能在Java中实现这种行为?

----编辑

根据要求添加真实示例。轻松修改域以使示例更易于理解。

有一个众所周知的用于序列化对象的杰克逊库。该库不支持字符串以外的映射键的序列化,因此无法立即进行以下操作

class TimeRange {
  LocalDateTime startDate;
  LocalDateTime endDate;

}

class SportsmenActivities {
  private Map<String, <TimeRange, List<Activity>>  sportActivities;
}

在此示例中,外部地图的键为“ sportsmanCode” liek“ andy”,“ mike”,“ john”。内部地图包含给定运动员在给定期间内执行的活动。

所以让我们说安迪(Andy)正在慢跑一天,而不是参加比赛:

new SportsmanActivities().get("andy").put(TimeRange.of('2012-12-01,'2012-12-02'), List.with(new JoggingActivity)) // did some pseudo code here for readablity

现在,正如杰克逊所说的那样,它不会立即进行序列化,因此我编写了通用模块,可以对这种复杂的地图进行序列化。

要使用该功能,您需要做的就是这样注释“ key”类:

@KeySerializable
class TimeRange {
  @MyMapKey
  LocalDateTime startDate;
  @MyMapKey
  LocalDateTime endDate;

}

您可能会猜到,用@MyMapKey注释的字段将用于生成MapKey。

现在,我有一个jackson类的实现,该类可以动态地序列化所有通过@KeySerializable注释的“文本映射键”传递的内容。签名正在跟进

    class MyMapKeySerializer<T> extends JsonSerializer<T> {
      serialize (T keyToSerialize) { 
      // do magic 
      }

   }

这可行,但是我想将T限制为仅接受带有@KeySerializable注释的类,因为仅对于此类,这种方法才有意义。理想情况下,它将类似于:

   class MyMapKeySerializer<T annotatedWith @KeySerializable> extends JsonSerializer<T> {
      serialize (T keyToSerialize) { 
      // do magic 
      }

   } 

2 个答案:

答案 0 :(得分:3)

如果您的目标是断言仅接受带注释的类,那么您只有几个解决方法:

  1. 编写一个在编译时进行断言的注释处理器(请参阅@NonNull等如何工作)。这是一项有趣的工作,但对于许多经验丰富的Java开发人员来说,编译/类型系统是全新的,因此意义非凡。
  2. 使用某种形式的AOP(AspectJ,Spring AOP等)通过Decorator“建议”所有带注释的方法,该Decorator的职责是断言参数具有相同的注释。
  3. 在运行时使用parameter.getClass().isAnnotationPresent(MyAnnotation.class)明确检查

答案 1 :(得分:1)

诸如Checker Framework之类的工具会插入到编译器中,以类似于您请求的方式的方式限制泛型实例化。它被实现为注释处理器,并为正确使用提供了编译时保证。

For example,您可以编写class MyList<T extends @NonNull Object> {...}

通过Checker Framework,您可以build your own checker来实施您喜欢的关于@KeySerializable的任何规则。就您而言,规则可能是如此简单,以至于您只需要定义几个类型限定符并使用Subtyping Checker即可-至少在一开始。

请注意,要使Checker框架使用@KeySerializable注释,该注释必须是类型注释,而不是声明注释。