java - JAXB动态绑定(bind)子类

标签 java xml web-services jaxb annotation-processing

我有一个很深的类层次结构,我想告诉 JAXB 绑定(bind)所有类。我有以下内容:

@XmlSeeAlso(B.class)
Class A {}
@XmlSeeAlso(C.class)
Class B extends A{}
@XmlSeeAlso(D.class,E.class,...)
Class C extends B{}
Class D extends C{}; Class E extends C{} ... and so on 

有什么方法可以绑定(bind)所有这些类,而无需在每个父类(super class)中使用 @XmlSeeAlso ,并且无需提及所有子类,因为我有很多子类。

最佳答案

正如评论中提到的,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;
    }
}

一旦您在 jar 中添加了注释 JaxbRoot 和此处理器,并且理想情况下还有让 Java 在 jar 中自动找到此处理器的服务描述符,然后只需将该 jar 添加到您的类路径中,仅注释您的根类,您将生成 jaxb.in​​dex 及其所有子类。

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

关于java - JAXB动态绑定(bind)子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51892269/

相关文章:

php - 通用 REST 前端 - 它存在吗?

java - 关于 AbstractApplicationContext.getBeansOfType() 和 getBean() 的问题

java - 告诉 Hibernate 从脏检查中忽略属性

java - 完成游戏循环并转到另一个 Activity Android 2.1

java - cvc-elt.1.a : Cannot find the declaration of element "ear"

php - 如何实现 XSLT 分词功能?

Java:在大字典中搜索字符串的非常快速的方法

java - 线程中出现异常 "main"java.lang.OutOfMemoryError : Java heap space: Parsing dblp. xml

asp.net - 它应该是 WebAPI 还是 asmx

web-services - 如何知道 GlassFish 中哪个 Web 服务方法抛出了异常?