2014-11-30 3 views
0

최근에 JSR-269 주석 처리와 관련되어 있고 일부 상용구 코드를 제거하기 위해 lib를 작성하려고합니다. 그것은 json 처리와 같은 것입니다. 나는 정말로 코드를 생성하지만, 치명적인 문제를 겪고 많은 시간을 보냈지 만 그것을 슬쩍 할 수는 없었다.JSR269 주석 처리 getElementsAnnotatedWith()는 각 루프에 주석이 달린 모든 요소를 ​​반환하며 어떤 유형에 속하는지 구별 할 수 없습니다.

문제는 RoundEnvironment.getElementsAnnotatedWith() 메서드는 항상 주석이 달린 모든 요소를 ​​반환하기 때문에 특정 클래스에서 나온 요소를 명확하게 구분할 수 없습니다. 어쩌면 문제가 명확하지 않을 수도 있습니다. 아래 코드를 보여줍니다.

@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.TYPE) 
public @interface JsonObject { 
} 



@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.FIELD) 
public @interface JsonField { 
    String value() default ""; 
} 



@JsonObject 
public class Name { 
    @JsonField("last") public String last; 
    @JsonField("first") public String first; 
} 



@JsonObject 
public class User { 
    @JsonField("age") public int age; 
    @JsonField("name") public String name; 
    @JsonField("sex") public boolean sex; 
} 

fisrt 2

는 주석, 주석이 JsonObject 형이 된 JSONObject이고 JsonField는 주석 필드가 JSON 필드임을 나타 나타내고있다.

후자는 json-parse 코드를 생성하려는 샘플 POJO 클래스입니다. Processor 클래스

AbstractProcessor.process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)있어서, 상기 샘플의 결과는 [ "마지막"모든 JSON 필드이고 I는 루프 roundEnv.roundEnv.getElementsAnnotatedWith(JsonField.class) 각 유형 ( Name, User)를 호출 할 때, 반환 결과는, "first", "age", "name", "sex"). 이 상황에서 어떤 필드가 어떤 POJO에 속하는지 구분할 수 없습니다.

5 월 단어가 무슨 뜻인지 설명하지 못할 수도 있습니다. 다음은 process 메소드에서 수행하는 작업입니다.

// the set[Name, User] 
Set<? extends Element> jsonObjects = roundEnv.getElementsAnnotatedWith(JsonObject.class); 
for (Element jsonObject : jsonObjects) { 
    // the set[last, first, age, name, sex], **THIS IS THE PROBLEM** 
    Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(JsonField.class); 
    // other stuff... 
} 

아무 것도 묻지 않아도됩니다. 모든 제안은 감사드립니다, 미리 감사드립니다!

+0

둘러싼 클래스를 기반으로 지정된 컬렉션의 요소 형식을 구별하는 방법을 묻는 것이 정확히 이해 되었습니까? –

+0

@AlexeyGavrilov 네, 당신 말이 맞아요. 이제 각각의 생성 된 .java 파일에는''JsonField''로 주석이 달린 모든 fileds가 있습니다. 내 영어로 미안해. – longkai

+0

영어가 완벽합니다. 내 대답을 참조하십시오. –

답변

1

getElementsAnnotatedWith(JsonField.class) 메서드를 호출하고 포함 요소의 주석을 기반으로 결과를 필터링하여 json 객체 요소의 컬렉션을 빌드 할 수 있습니다. 여기

은 (단순에 대한 런타임 주석 처리를 사용하여) 완벽한 예입니다

@SupportedSourceVersion(SourceVersion.RELEASE_7) 
@SupportedAnnotationTypes("*") 
public class ElementFilterProcessor extends AbstractProcessor { 

    @Retention(RetentionPolicy.RUNTIME) 
    public static @interface JsonObject {} 

    @Retention(RetentionPolicy.RUNTIME) 
    public static @interface JsonField { String value(); } 

    @JsonObject 
    public class Name { 
     @JsonField("last") public String last; 
     @JsonField("first") public String first; 
    } 

    @JsonObject 
    public class User { 
     @JsonField("age") public int age; 
     @JsonField("name") public String name; 
     @JsonField("sex") public boolean sex; 
    } 

    public static void main(String[] args) { 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     final JavaCompiler.CompilationTask task = compiler.getTask(
       null, 
       null, 
       null, 
       null, 
       Collections.singleton(ElementFilterProcessor.class.getName()), 
       Collections.EMPTY_SET); 
     task.setProcessors(Collections.singleton(new ElementFilterProcessor())); 
     task.call(); 
    } 

    @Override 
    public boolean process(
      final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { 
     if (roundEnv.processingOver()) { 
      return true; 
     } 
     final Set<? extends Element> jsonFields = 
       roundEnv.getElementsAnnotatedWith(JsonField.class); 
     final Map<Element, List<Element>> jsonObjects = new HashMap<>(); 
     for (final Element element : jsonFields) { 
      final Element classElement = element.getEnclosingElement(); 
      if (classElement.getAnnotation(JsonObject.class) != null) { 
       List<Element> list = jsonObjects.get(classElement); 
       if (list == null) { 
        list = new ArrayList<>(); 
        jsonObjects.put(classElement, list); 
       } 
       list.add(element); 
      } 
     } 
     System.out.println(jsonObjects); 
     return false; 
    } 
} 

출력 :

{stackoverflow.annotation.ElementFilterProcessor.User=[age, name, sex], stackoverflow.annotation.ElementFilterProcessor.Name=[last, first]} 

나는 또한 오히려 매핑 타사 라이브러리를 사용하는 것을 고려하는 것이 좋습니다 것 Java 오브젝트를 JSON으로 변환합니다. 예 : the Jackson processor

+0

고마워요, 그것은 매력처럼 작동합니다. 나는 그 일을하는 공식적인 방법이있을 것이라고 생각했지만 아무 것도 없앴습니다. 이전에 본적이없는 코드 (jsr269 처리 API는 인터넷 검색시 거의 사용되지 않습니다). 여기 많이 배웠어, 고마워! 나는 전에 예전에 사용했던 잭슨을 사용했는데 아주 좋습니다! 이번에는 주된 목적은 jsr269에서 무언가를 배우는 것입니다. – longkai