为什么不同的Java 7和Java 8之间isAnnotation present工作? [英] Why does isAnnotationPresent work differently between Java 7 and Java 8?
问题描述
我刚刚发现今天这个时候,我的单元测试有一个失败,因为升级从Java 7到Java 8单元测试调用它试图找到其中的一个子类,但有注释的方法的注释的方法不同的返回类型。
在Java 7中, isAnnotation present
似乎只能找到注解,如果他们在code真的声明。在Java 8, isAnnotation present
似乎包括儿童类被声明注释。
为了说明这一点,我创建了一个简单(??)测试类IAPTest(为IsAnnotation presentTest)。
进口java.lang.annotation.Retention;
进口java.lang.annotation.RetentionPolicy;
进口的java.lang.reflect.Method;公共类IAPTest {
@Retention(RetentionPolicy.RUNTIME)
公共静态@interface安诺{
}
公共静态接口I {
}
公共静态界面IE扩展I {
}
公共静态类A {
保护我的方法(){
返回null;
}
}
公共静态类B扩展A {
@Anno
IE保护法(){
返回null;
}
}
公共静态无效的主要(字串[] args){
针对(法方法:B.class.getDeclaredMethods()){
如果(method.getName()等于(方法)及&放大器; I.class.equals(method.getReturnType())){
的System.out.println(method.isAnnotation present(Anno.class));
}
}
}
}
在最新的Java 7(1.7.0_79在写作时),这种方法打印假。在最新的Java 8(1.8.0_66在写作时),这种方法打印真。我会直觉地期望它打印假。
这是为什么?这是否表明Java或错误在Java中是如何工作的预期变化?
修改:只是为了显示我用这个复制(与IAPTest.java目录等同于code以上块),精确的命令:
C:\\测试isannotation present>德尔的* .classC:\\测试isannotation present>设置JAVA_HOME = C:\\ NMA \\工具集\\ AJB1 \\ OracleJDK \\ jdk1.8.0_66C:\\测试isannotation present>设置PATH =%PATH%; C:\\ NMA \\工具集\\ AJB1 \\ OracleJDK \\ jdk1.8.0_66 \\ BINC:\\测试isannotation present> Java的版本
Java版本1.8.0_66
的Java(TM)SE运行时环境(建立1.8.0_66-B17)
Java的热点(TM)64位服务器VM(25.66建设-B17,混合模式)C:\\测试isannotation present>的javac IAPTest.javaC:\\测试isannotation present>的java IAPTest
真正C:\\测试isannotation present>
我相信这是关系到在的 Java的8兼容性指南
从此版本开始,参数和方法的注释被复制到
合成桥methods.This修复意味着,现在这样的程序:@Target(价值= {} ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)@interface ParamAnnotation {}
@Target(价值= {} ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)@interface MethodAnnotation {}
抽象类T< A,B> {
B M(A一){
返回null;
}
}
类CovariantReturnType扩展T<整数,整数GT; {
@MethodAnnotation
整数米(@ParamAnnotation整数I){
返回我;
} 公共类VisibilityChange扩展CovariantReturnType {}
}每个生成的电桥法将拥有的所有注释
方法将其重定向到。参数说明也将被复制。
这种变化的行为可能影响一些注解处理器或
一般来说任何应用程序使用该注释。
块引用>这是返回一个
第二个方法我
代替IE
是生成的,因为你有一个窄的合成方法在重写的方法返回类型比超类。请注意,这不是在声明的方法列表present如果你没有缩小返回类型。所以我觉得这是不是一个错误,而是一种蓄意的变化。I just discovered this today when one of my unit tests failed because of upgrading from Java 7 to Java 8. The unit test calls a method which tries to find an annotation on a method which is annotated on a child class but with a different return type.
In Java 7,
isAnnotationPresent
seems to only find annotations if they were really declared in code. In Java 8,isAnnotationPresent
seems to include annotations that were declared in child classes.To illustrate this I created a simple (??) test class IAPTest (for IsAnnotationPresentTest).
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; public class IAPTest { @Retention(RetentionPolicy.RUNTIME) public static @interface Anno { } public static interface I { } public static interface IE extends I { } public static class A { protected I method() { return null; } } public static class B extends A { @Anno protected IE method() { return null; } } public static void main(String[] args) { for (Method method : B.class.getDeclaredMethods()) { if (method.getName().equals("method") && I.class.equals(method.getReturnType())) { System.out.println(method.isAnnotationPresent(Anno.class)); } } } }
On the latest Java 7 (1.7.0_79 at time of writing), this method prints "false". On the latest Java 8 (1.8.0_66 at time of writing), this method prints "true". I would intuitively expect it to print "false".
Why is this? Does this indicate a bug in Java or an intended change in how Java works?
EDIT: Just to show the exact commands I used to replicate this (in a directory with IAPTest.java identical to the code block above):
C:\test-isannotationpresent>del *.class C:\test-isannotationpresent>set JAVA_HOME=C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66 C:\test-isannotationpresent>set PATH=%PATH%;C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66\bin C:\test-isannotationpresent>java -version java version "1.8.0_66" Java(TM) SE Runtime Environment (build 1.8.0_66-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode) C:\test-isannotationpresent>javac IAPTest.java C:\test-isannotationpresent>java IAPTest true C:\test-isannotationpresent>
解决方案I believe this is related to a change mentioned in the java 8 compatibility guide
As of this release, parameter and method annotations are copied to synthetic bridge methods.This fix implies that now for programs like:
@Target(value = {ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @interface ParamAnnotation {} @Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MethodAnnotation {} abstract class T<A,B> { B m(A a){ return null; } } class CovariantReturnType extends T<Integer, Integer> { @MethodAnnotation Integer m(@ParamAnnotation Integer i) { return i; } public class VisibilityChange extends CovariantReturnType {} }
Each generated bridge method will have all the annotations of the method it redirects to. Parameter annotations will also be copied. This change in the behavior may impact some annotations processor or in general any application that use the annotations.
The second method that returns an
I
instead of anIE
is a synthetic method generated because you have a narrower return type in the overridden method than in the super class. Note that it's not present in the list of declared methods if you don't have a narrowing return type. So I think this is not a bug, but a deliberate change.这篇关于为什么不同的Java 7和Java 8之间isAnnotation present工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!