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

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

问题描述

考虑以下代码:

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,

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

AnnotationTypeDeclaration:

AnnotationTypeDeclaration:

{InterfaceModifier} @ interface Identifier AnnotationTypeBody

根据

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.

关于原因,这导致

查看下一项,

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:

  • A primitive type
  • String
  • Class or an invocation of Class (§4.5)
  • An enum type
  • An annotation type
  • An array type whose component type is one of the preceding types (§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天全站免登陆