2014-12-22 35 views
9

Java 8具有稱爲類型註釋(JSR 308)的功能。我想將它用於簡單的Object to Object映射器框架。我想定義註釋@ExpectedType這樣如何在Java中使用自定義類型註釋

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

,然後用它在我的代碼是這樣的:

public class SomeServiceImpl() { 
    public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) { 
     return (ObjectA_Entity) obj; // it's correct 
    } 
} 

IObjectA是類ObjectA_DTOObjectA_Entity實現的接口。我想用這種方式的服務:

// it's correct 
assert someService.doSomething(new ObjectA_DTO()).getClass() == ObjectA_DTO.class; 

我想改變調用SomeServiceImpl方法來使用Object映射器。它可以通過使用JSR 269或AOP生成的代碼來實現。

問題是我寫了簡單的註釋處理器,它根本不處理類型註釋。簡單的註釋處理器的來源是這樣的:

@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; 
    } 
} 

任何想法如何使用或如何SimpleAnnotationsProcessor訪問類型的註釋?可插入註釋處理API的使用對我來說不是必要的我認爲它比Java反射會有更好的性能。無論如何,我不知道如何通過Java Reflection訪問類型註釋。

+0

使用我猜我不清楚你想達到什麼目標。爲什麼不只是讓方法簽名'ObjectA_DTO doSomething(ObjectA_Entity)',如果這就是你期望的呢? –

+0

方法簽名不能這樣,因爲我想使用像這個'someService.doSomething(new ObjectA_DTO())'這樣的服務實例。我想實現對象映射器來映射'ObjectA_DTO'到'ObjectA_Entity',並且類型註釋@ExpectedType定義了目標類型。這是簽名必須是'IObjectA doSomething(IObjectA)'的原因。 –

+0

我剛剛發現你的問題......我在處理註釋的產品線開發中完成了一個學期的項目。現在,我將給你留下這個重要的教程,它真的讓我討論這個主題(你可以跳過關於代碼生成的第3部分) - https://deors.wordpress.com/2011/09/26/annotation-types/稍後,我會重新檢查這個帖子的進展情況。 – ThisClark

回答

2

我不知道我明白你想什麼來實現的,但這裏有一個例子,你如何與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); 
     } 
    } 
} 

輸出看起來是這樣的:

@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_DTO) 
@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_Entity) 

請注意,並非所有可能的類型註釋都可以通過反射api訪問,但如果需要,您可以隨時從字節代碼中讀取它們(請參閱我的回答here)。

+0

我想使用註釋處理器來做它,因爲它可能會在運行時更快,然後反射,無論如何,我接受你的答案。 Checker框架可以從註釋處理器(而不是字節碼)讀取類型註釋。你知道它怎麼樣? –

+0

對不起,我還沒有使用過Checker框架。我不認爲註釋處理器會比使用反射更快(不確定)。但在遇到實際性能問題之前,我不會考慮任何優化。通常反射速度足夠快... – Balder

+0

你知道如何通過反射API訪問用於本地變量的類型註釋嗎?像這樣的'@NotNull String str =「」;'或'String str =(@Nullable String)null;'方法體內?我想使用'@ ExpectedType'註釋,如下所示:'ObjectA_DTO aDto =(@ExpectedType ObjectA_DTO)someService.doSomething(...);' –

0

我認爲你在運行時混合使用註釋,而不是在各種工具的「編譯」時使用註釋。 Processor接口用於工具(編譯器,javadoc生成器),不在運行時代碼中。

+0

我想生成代碼以獲得更好的性能,例如MapStruct或Lombok,而不是在運行時使用java反射。 –

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

    public String identifier() default ""; 

} 

@SearchDefinition - 可以在任何地方

+1

這個答案是完全錯誤的@Target(ElementType.FIELD)'註釋不能在任何地方使用。它只能用於類字段。如果省略'@ Target',則除了類型轉換('(@SearchDefinition String)「abc」')或泛型類型('List <@SearchDefinition String>')外,它幾乎可以用於任何地方。 –