我有一个很深的类层次结构,我想告诉JAXB绑定所有类。我有以下几种:
@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
有什么方法可以绑定所有这些类,而无需在每个超类中使用@XmlSeeAlso,并且不提及所有子类,因为我有很多子类。
如注释中所述,Java 不支持在运行时通过反射获取所有子类的请求功能。
但是应该可以在编译时检查项目中的所有类,并在jar文件中生成jaxb.index。
这种注释处理器的示例(不完整,因此不能直接工作,但为了演示这个想法(可以如下所示:
@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.index,其中包含它的所有子类。
即使您将项目拆分为多个 jar,并且根类位于一个 jar 中,子类位于另一个 jar 中,处理器仍然会被调用并生成每个 jar 的索引文件。然后,您只需将它们全部合并在一起,这可能只是一个与处理器一起交付的实用程序类。