JAXB动态绑定子类

时间:2018-08-17 09:24:11

标签: java xml web-services jaxb annotation-processing

我有很深的类层次结构,我想告诉JAXB绑定所有类。我有以下几种:

webpack-dev-server --mode development  --hot

有什么方法可以绑定所有这些类,而无需在每个超类中使用@XmlSeeAlso,也不必提及所有子类,因为我有很多子类。

1 个答案:

答案 0 :(得分:0)

如评论中所述,Java不支持通过运行时在反射时获取所有子类的请求功能。

但是应该可以在编译时检查项目中的所有类,并在jar文件中生成jaxb.in​​dex。

这样的注释处理器的一个例子(不完整,因此不能直接工作,但是要证明这个想法)如下:

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class JaxbProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env) {
        super.init(env);

        // Java 8 compiler plugin API to hook on compilation of every single class.
        JavacTask.instance(env).addTaskListener(new TaskListener() {

            // Prepare the writer
            PrintWriter writer = new PrintWriter(env.getFiler().createResource(/* Details of output jaxb.index file */).openWriter());
            Set<TypeElement> jaxbParents = new HashSet<>();

            @Override public void started(TaskEvent taskEvent) {
                // Nothing needs to be done here.
            }

            @Override public void finished(TaskEvent taskEvent) {
                if(taskEvent.getKind() == ANALYZE) {

                    // This is where the compiler invokes our code.
                    // Side effect of this inspection is to collect all classes, that should be included in our jaxb.index
                    // into the jaxbParents set.
                    inspect(taskEvent.getTypeElement());

                    // Now simply write it to the file (output details to be provided).
                    // We should actually only write down difference from previous invocation. Let me fix it later.
                    jaxbParents.forEach(writer::println);
                }
            }

            private void inspect(TypeElement type) {

                // First inspect current class element
                testForJaxbParent(type);

                // Do not forget to inspect also inner classes.
            type.getEnclosedElements().stream().filter(TypeElement.class::isInstance).map(TypeElement.class::cast).forEach(this::testForJaxbParent);
            }

            /**
             * Test if the type should be added to JAXB index file.
             */
            private boolean testForJaxbParent(TypeElement type) {
                if(jaxbParents.contains(type)) {
                    // It's already in the set, so no need to bother with it.
                    return true;
                }
                if(type.getAnnotation(JaxbRoot.class) != null || testForJaxbParent((TypeElement) env.getTypeUtils().asElement(type.getSuperclass()))) {
                    // If our type is annotated with our special "extension" to JAXB - JaxbRoot, it means, that it is our
                    // root class, that needs to be added to the jaxb.index.
                    //
                    // If it is not annotated, then still test hierarchy of superclasses recursively, and if there is any
                    // superclass being the root, then add it including all children on the stack at the return from the
                    // recursion.
                    return jaxbParents.add(type);
                }
                return false;
            }
        });
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // No real annotation processing needed.
        return false;
    }
}

一旦在批注中包含注解JaxbRoot和该处理器,并且理想情况下,还可以通过服务描述符使Java自动在jar中找到该处理器,然后只需将jar添加到您的类路径中,仅注释您的root类,您将获得带有其所有子类的生成的jaxb.in​​dex。

即使将项目分成多个jar,将根类放在一个jar中,将子类放在另一个jar中,处理器仍会被调用并为每个jar生成索引文件。然后,您只需要将它们全部合并在一起,这可以是与处理器一起交付的一个实用程序类。