如何在Java中使用自定义类型注释

如何在Java中使用自定义类型注释,java,java-8,annotation-processing,type-annotation,Java,Java 8,Annotation Processing,Type Annotation,Java8具有名为Type annotations()的特性。我想将其用于简单的对象到对象映射器框架。我想这样定义注解@ExpectedType @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) public @interface ExpectedType { public Class<?> value(); } IObjectA是由

Java8具有名为Type annotations()的特性。我想将其用于简单的对象到对象映射器框架。我想这样定义注解@ExpectedType

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExpectedType {
    public Class<?> value();
}
IObjectA
是由类
ObjectA\u DTO
ObjectA\u Entity
实现的接口。我希望以这种方式使用的服务:

// it's correct
assert someService.doSomething(new ObjectA_DTO()).getClass() == ObjectA_DTO.class;
我想将SomeServiceImpl方法的调用更改为使用对象映射器。它可以通过使用或AOP生成代码来实现

问题是我编写了简单注释处理器,它根本不处理类型注释。simple annotations processor的源代码如下所示:

public class SomeServiceImpl() {
    public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) {
        return (ObjectA_Entity) obj; // it's correct
    }
}
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SimpleAnnotationsProcessor extends AbstractProcessor {

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Messager messager = processingEnv.getMessager();
        try {
            for (TypeElement e : annotations) {
                messager.printMessage(Diagnostic.Kind.NOTE, e.toString());
                for (Element elem : roundEnv.getElementsAnnotatedWith(e)) {
                    messager.printMessage(Diagnostic.Kind.NOTE, elem.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}
@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_DTO)
@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_Entity)
@SupportedAnnotationTypes(“*”)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
公共类SimpleNotationsProcessor扩展了AbstractProcessor{

公共布尔过程(Set我不确定我是否理解您试图实现的目标,但下面是一个示例,说明如何使用Java反射api访问注释:

package test;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;

public class TypeParameterTest {

    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExpectedType {
        public Class<?> value();
    }

    public static interface IObjectA {}

    public static class ObjectA_DTO implements IObjectA {}

    public static class ObjectA_Entity implements IObjectA {}

    public static class SomeServiceImpl {
        public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) {
            return (ObjectA_Entity) obj;
        }
    }

    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Method m = SomeServiceImpl.class.getMethod("doSomething", IObjectA.class);
        AnnotatedType returnType = m.getAnnotatedReturnType();
        Annotation returnTypeAnnotation = returnType.getAnnotation(ExpectedType.class);
        System.out.println(returnTypeAnnotation);

        AnnotatedType[] parameters = m.getAnnotatedParameterTypes();
        for (AnnotatedType p : parameters) {
            Annotation parameterAnnotation = p.getAnnotation(ExpectedType.class);
            System.out.println(parameterAnnotation);
        }
    }
}

不过请注意,并非所有可能的类型注释都可以通过反射api访问,但如果需要,您可以始终从字节码中读取它们(请参见我的答案)。

我认为您将在运行时使用注释与在“编译”时使用注释混为一谈时间取决于各种工具。
处理器
接口用于工具(编译器、javadoc生成器),而不是运行时代码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SearchDefinition {

    public String identifier() default "";

}

@SearchDefinition-可以在任何地方使用

我想我不清楚您试图实现的目标。为什么不让方法签名
ObjectA\u DTO doSomething(ObjectA\u Entity)
如果这是您希望它做的事情?方法签名不能是那样,因为我希望像这样使用服务实例
someService.doSomething(new ObjectA\u DTO())
。我希望实现对象映射器将
ObjectA\u DTO
映射到
ObjectA\u Entity
并且类型注释@ExpectedType定义目标类型。这就是签名必须是
IObjectA doSomething(IObjectA)的原因
。我顺便问了你一个问题……我做了一个关于产品线开发的学期项目,在这个项目中我们处理了注释。现在,我将给你留下这个重要的教程,它让我真正开始了这个主题(你可以跳过关于代码生成的第3部分)-稍后,我将重新检查这篇文章的进度。感谢您的链接,我指的是注释为
@Target(ElementType.TYPE\u参数)
@Target(ElementType.TYPE\u使用)
。它们没有传递到批注处理器的
进程
方法。我希望使用批注处理器进行此操作,因为它在运行时比反射更快,无论如何我接受您的答案。Checker framework可以从批注处理器(而不是从字节码)读取类型批注。你知道它是如何工作的吗?对不起,我还没有使用Checker框架。我不相信注释处理器会比使用反射更快(不过不确定)。但在遇到实际性能问题之前,我不会考虑任何优化。通常,反射速度足够快…您知道如何通过反射API访问与局部变量一起使用的类型的类型批注吗?类似于这样的
@NotNull String str=“”;
String str=(@Nullable String)null;
在方法体内部?我希望使用如下注释:
ObjectA\u DTO aDto=(@ExpectedType ObjectA\u DTO)someService.doSomething(…);
使用Java反射api无法访问变量声明或强制转换表达式上声明的类型批注。您可以通过使用外部库(如)读取方法的字节码来访问它们。我在本章末尾的hello world示例中使用了这种方法。以这种方式访问类型批注肯定是可行的一个静态代码分析和工具的选项,但我不推荐这样一种运行时访问类型注释的方法…我想生成代码,以获得更好的性能,就像MapStruct或Lombok所做的那样,而不是在运行时使用java反射。这个答案是完全错误的
@Target(ElementType.FIELD)
注释不能在任何地方使用。它只能与类字段一起使用。如果省略了
@Target
,它几乎可以在除类型转换(
(@SearchDefinition String)“abc”
)或泛型类型(
列表
)之外的任何地方使用。