JSR269 annotation processing getElementsAnnotatedWith() return all the annotated elements each loop and cannot distinguish it belongs to which type

為{幸葍}努か 提交于 2021-02-11 14:58:23

问题


Recently, I have been intersted with the JSR-269 annotation processing and I want to write a lib to eliminate some boilerplate code with it, such as json processing. I really generate the code, then, however, I encounter a fatal problem and spent a lot of time but could not slove it.

The problem is, the RoundEnvironment.getElementsAnnotatedWith() method alway return all the elements annotated with the annotation, I cannot tistinguish which one comes from a specific class. Maybe the problem isn' t clear. I show you the code below.

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

the fisrt 2 are the annotation, JsonObject indicates that the annotated type is an JsonObject and JsonField indicates that the annotated field is an json field.

the latter 2 are the sample POJO class that I want to gennerate json-parse code.

in the Processor class, the AbstractProcessor.process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) method, when I call roundEnv.roundEnv.getElementsAnnotatedWith(JsonField.class) each type(Name, User) in a loop, the return result is all the json field, in the sample above, the result is ["last", "first", "age", "name", "sex"]. In this situatin, I cannot distinguish which field belongs to which POJO.

May be the words cannot explain what I mean. Here is what I do in the process method.

// 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...
}

Feel free to ask me anything I didn' t mention or not clear. Any suggestion is appreciated, Thanks in advance!


回答1:


You can build a collection of your json object elements by calling the getElementsAnnotatedWith(JsonField.class) method and filering the result based on the annotation of the enclosing element.

Here is a complete example (using runtime annotation processing for simplicity):

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

Output:

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

I'd also recommend to rather consider using a third-party library for mapping Java objects to JSON. For example, the Jackson processor



来源:https://stackoverflow.com/questions/27210759/jsr269-annotation-processing-getelementsannotatedwith-return-all-the-annotated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!