diff --git a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java index 9b36faf67617a4..a1d4c2c81cb764 100644 --- a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java +++ b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java @@ -1,13 +1,18 @@ package io.quarkus.jaxb.deployment; +import java.io.File; import java.io.IOError; import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; import javax.inject.Inject; @@ -47,8 +52,11 @@ import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget.Kind; +import org.jboss.jandex.AnnotationValue; +import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.IndexView; +import org.jboss.jandex.Type; import com.sun.xml.bind.v2.model.annotation.Locatable; @@ -108,6 +116,7 @@ class JaxbProcessor { private static final DotName XML_SCHEMA = DotName.createSimple(XmlSchema.class.getName()); private static final DotName XML_JAVA_TYPE_ADAPTER = DotName.createSimple(XmlJavaTypeAdapter.class.getName()); private static final DotName XML_ANY_ELEMENT = DotName.createSimple(XmlAnyElement.class.getName()); + private static final DotName XML_SEE_ALSO = DotName.createSimple(XmlSeeAlso.class.getName()); private static final List JAXB_ROOT_ANNOTATIONS = Arrays.asList(XML_ROOT_ELEMENT, XML_TYPE, XML_REGISTRY); @@ -173,6 +182,18 @@ void processAnnotationsAndIndexFiles( proxyDefinitions.produce(new NativeImageProxyDefinitionBuildItem(className, Locatable.class.getName())); addReflectiveClass(reflectiveClass, true, false, className); }); + produceProxyIfExist(proxyDefinitions, "com.sun.xml.bind.marshaller.CharacterEscapeHandler"); + produceProxyIfExist(proxyDefinitions, "com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler"); + produceProxyIfExist(proxyDefinitions, "org.glassfish.jaxb.core.marshaller.CharacterEscapeHandler"); + produceProxyIfExist(proxyDefinitions, "com.sun.xml.txw2.output.CharacterEscapeHandler"); + produceProxyIfExist(proxyDefinitions, "org.glassfish.jaxb.characterEscapeHandler"); + produceProxyIfExist(proxyDefinitions, "org.glassfish.jaxb.marshaller.CharacterEscapeHandler"); + + proxyDefinitions.produce(new NativeImageProxyDefinitionBuildItem("com.sun.xml.txw2.TypedXmlWriter")); + Set proxiesCreated = new HashSet<>(); + DotName typedXmlWriterDN = DotName.createSimple("com.sun.xml.txw2.TypedXmlWriter"); + // getAllKnownDirectImplementors skip interface, so use own recursion + produceRecursiveProxies(index, typedXmlWriterDN, proxyDefinitions, proxiesCreated); for (JaxbFileRootBuildItem i : fileRoots) { try (Stream stream = iterateResources(i.getFileRoot())) { @@ -182,6 +203,50 @@ void processAnnotationsAndIndexFiles( } } + private void produceProxyIfExist(BuildProducer proxies, String interfaceName) { + try { + Class.forName(interfaceName); + proxies.produce(new NativeImageProxyDefinitionBuildItem(interfaceName)); + } catch (ClassNotFoundException e) { + //silent fail + } + } + + @BuildStep + void seeAlso(CombinedIndexBuildItem combinedIndexBuildItem, + BuildProducer reflectiveItems) { + IndexView index = combinedIndexBuildItem.getIndex(); + for (AnnotationInstance xmlSeeAlsoAnn : index.getAnnotations(XML_SEE_ALSO)) { + AnnotationValue value = xmlSeeAlsoAnn.value(); + Type[] types = value.asClassArray(); + for (Type t : types) { + reflectiveItems.produce(new ReflectiveClassBuildItem(false, false, t.name().toString())); + } + } + } + + void produceRecursiveProxies(IndexView index, + DotName interfaceDN, + BuildProducer proxies, Set proxiesCreated) { + index.getKnownDirectImplementors(interfaceDN).stream() + .filter(classinfo -> Modifier.isInterface(classinfo.flags())) + .map(ClassInfo::name) + .forEach((className) -> { + if (!proxiesCreated.contains(className.toString())) { + proxies.produce(new NativeImageProxyDefinitionBuildItem(className.toString())); + produceRecursiveProxies(index, className, proxies, proxiesCreated); + proxiesCreated.add(className.toString()); + } + }); + + } + + @BuildStep + void addDependencies(BuildProducer indexDependency) { + indexDependency.produce(new IndexDependencyBuildItem("org.glassfish.jaxb", "txw2")); + indexDependency.produce(new IndexDependencyBuildItem("org.glassfish.jaxb", "jaxb-runtime")); + } + @BuildStep void ignoreWarnings(BuildProducer ignoreWarningProducer) { for (DotName type : IGNORE_TYPES) { @@ -221,7 +286,8 @@ private void handleJaxbFile(Path p, BuildProducer BuildProducer reflectiveClass) { try { String path = p.toAbsolutePath().toString().substring(1); - String pkg = p.toAbsolutePath().getParent().toString().substring(1).replace("/", ".") + "."; + String pkg = p.toAbsolutePath().getParent().toString().substring(1) + .replace(File.separator, ".") + "."; resource.produce(new NativeImageResourceBuildItem(path));