注释中的通用类型 [英] Generic types in annotations

查看:26
本文介绍了注释中的通用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class AnnotationTest {

    @GenericAnnotation<String>(foo = "Test")
    public class Bar1 {

    }

    @ObjectAnnotation(foo = "Test")
    public class Bar2 {

    }

    @WorkingAnnotation(foo = "Test")
    public class Bar3 {

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface GenericAnnotation<T> {

        public T foo();

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface ObjectAnnotation {

        public Object foo();

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface WorkingAnnotation {

        public String foo();

    }

}

Bar1 根本无法编译.一大堆错误.

Bar1 won't compile at all. Huge mess of errors.

Bar2 会编译得很好,但 ObjectAnnotation 注释不会.

Bar2 will compile fine, but the ObjectAnnotation annotation won't.

Bar3 可以很好地编译,但不允许泛型类型.

Bar3 will compile fine, but doesn't allow generic types.

如果 - 例如 - 我试图设置一个默认值,以防某个字段无法加载.此类可能是 IntegerStringBoolean[],实际上是任何可能的类型.这意味着处理每一种可能情况的注释都是一团糟.

If - for example - I am trying to set a default value in case a certain field can't be loaded. This class might be an Integer, String, Boolean[], really any of the possible types. This means a whole mess of annotations for handling every possibly case.

是否有正确的方法来处理注解中的泛型类型?如果没有,是否有明确的原因?

Is there a proper way to handle generic types in an annotation? If not, is there a clear reason why?

推荐答案

编译器的错误消息令人困惑,纯粹是因为它的布局不接受这样的语法.

The compiler's error messages are confusing purely because it is not laid out to accept such a syntax.

一个类似的问题已经发布这里.

A similar question was already posted here.

JLS,第 9.6 节 陈述了注释声明的一般语法如下:

The JLS, Section 9.6 states the general syntax of an annotation declaration as follows:

注解类型声明:

{InterfaceModifier} @ interface Identifier AnnotationTypeBody

令牌标识符,根据JLS,描述了类型的名称;无论是类、枚举、接口还是注解.

The token Identifier, in the terms of the JLS, describes the name of the type; be it class, enum, interface or annotation.

注解不能用泛型类型声明,因为这些由标记 类型参数,此处未包含.

An annotation can not be declared with generic types, as these are referred to by the token TypeParameters, which is not included here.

至于为什么,这导致

查看下一项,第 9.6.1 节,我们发现注释可以采用的类型限制:

Looking into the next item, Section 9.6.1, we spot the restriction of types an annotation can take:

注解类型中声明的方法的返回类型必须是以下之一,否则会出现编译时错误:

The return type of a method declared in an annotation type must be one of the following, or a compile-time error occurs:

  • 原始类型
  • 字符串
  • 类或类的调用(§4.5)
  • 枚举类型
  • 注释类型
  • 一个数组类型,其组件类型是上述类型之一 (§10.1).

(一些特殊情况将在下面进一步讨论,但与此问题无关)

(some special cases are addressed further below, but are irrelevant to this problem)

这些限制是导致您的第二个注释沮丧的原因.它根本不是为了容纳所有类型的对象而设计的.它甚至无法容纳原始类型的盒装类型!

These restrictions are what's causing the dejection of your second annotation. It is simply not designed to hold all types of Objects. It cannot even hold the boxed type of a primitive!

现在,回到案例 1:为什么通用注释在这个语法中是错误的?甚至在任何类型擦除发生之前,您的 GenericAnnotation 基本上可以是每种类型的 Object 的持有者.在其 foo 属性的定义中,它与您的 ObjectAnnotation 完全相同.

Now, back to Case 1 for a bit: Why are generic Annotations a wrong thing in this grammar? Even before any type erasure occurs, your GenericAnnotation can basically be a holder for every type of Object. It is, in the definition of its foo property, exactly the same as your ObjectAnnotation.

现在的问题是,为什么会有这种限制?通过限制注释可能包含的值,您可以获得两个优点:首先,所有值都是编译时常量.如果不大量使用反射,就无法从注解中获取依赖于运行时的值.

Now, the question is, why is that limitation in place? By limiting the values an annotation might contain, you get two advantages: First, all the values are to be compile-time constants. There is no way to get a runtime-dependent value either into or out of an annotation without heavy use of reflection.

这立即带来了第二个优势:甚至没有人愿意将不纯(有副作用)的代码放入注释中,这些代码可能会在应用程序生命周期的任何随机点加载.如果您可以引入任何类型的对象,那么它们的构造函数可能会在可能无法检测到的时间内产生任何类型的副作用,如果使用这种技术,则会增加调试的复杂性.

This immediately brings one to the second advantage: Nobody will even get the temptation to put impure (side-effecting) code inside annotations which may be loaded at any random point in the applications lifetime. If you could introduce any type of object, their constructors could do any kind of side-effect at a possibly undetectable time, increasing the complexity of debugging if this technique were used.

或者至少,这对我来说似乎是最合乎逻辑的,因为我找不到 Sun 或他们的继任者对此的官方说法.

Or at least, that's what seems the most logical to me, as there is no official word on this from either Sun or their successors that I could find.

遗憾的是,对此没有简单、富有表现力且容易的解决方法.由于您无法将进程放入 @Annotation-uses 中,因此您甚至无法使用 ObjectOutputStream 和 ByteArrayOutputStream 将对象序列化为字节数组.

There is, sadly, no simple, expressive and easy workaround to this. As you cannot place processes into @Annotation-uses, you can not even do something fancy as serializing the object into a byte array using ObjectOutputStream and ByteArrayOutputStream.

这篇关于注释中的通用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆