quarkus: JAXB unmarshalling fails in native mode
Describe the bug
When a class annotated with JAXB annotations is unmarshalled, the unmarshalling fails with
...
Caused by: java.lang.RuntimeException: org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Property expression appears in @XmlType.propOrder, but no such property exists. Maybe you meant executorService?
this problem is related to the following location:
at org.apache.camel.model.ThrottleDefinition
at io.quarkus.jaxb.runtime.JaxbContextProducer.createJAXBContext(JaxbContextProducer.java:82)
at io.quarkus.jaxb.runtime.JaxbContextProducer.jaxbContext(JaxbContextProducer.java:31)
at io.quarkus.jaxb.runtime.JaxbContextProducer_ProducerMethod_jaxbContext_6a6d20272304edd64c7bdfa35e3ed5d5971a3949_Bean.doCreate(Unknown Source)
at io.quarkus.jaxb.runtime.JaxbContextProducer_ProducerMethod_jaxbContext_6a6d20272304edd64c7bdfa35e3ed5d5971a3949_Bean.create(Unknown Source)
at io.quarkus.jaxb.runtime.JaxbContextProducer_ProducerMethod_jaxbContext_6a6d20272304edd64c7bdfa35e3ed5d5971a3949_Bean.create(Unknown Source)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:113)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:37)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:34)
at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:34)
at io.quarkus.jaxb.runtime.JaxbContextProducer_ProducerMethod_jaxbContext_6a6d20272304edd64c7bdfa35e3ed5d5971a3949_Bean.get(Unknown Source)
at io.quarkus.jaxb.runtime.JaxbContextProducer_ProducerMethod_jaxbContext_6a6d20272304edd64c7bdfa35e3ed5d5971a3949_Bean.get(Unknown Source)
at io.quarkus.arc.impl.Instances$3.get(Instances.java:132)
at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.impl.LazyInstanceHandle.instanceInternal(LazyInstanceHandle.java:32)
at io.quarkus.arc.impl.AbstractInstanceHandle.get(AbstractInstanceHandle.java:46)
at de.turing85.converter.FooConverter.getContext(FooConverter.java:51)
at de.turing85.converter.FooConverter.unmarshalFromString(FooConverter.java:39)
at de.turing85.converter.FooConverter.unmarshal(FooConverter.java:34)
at java.base@21/java.lang.reflect.Method.invoke(Method.java:580)
at org.apache.camel.support.ObjectHelper.invokeMethod(ObjectHelper.java:355)
... 28 more
...
Expected behavior
The object gets unmarshalled
Actual behavior
The above exception is thrown.
How to Reproduce?
Reproducer:
- Clone https://github.com/turing85/quarkus-camel-jaxb
git clone https://github.com/turing85/quarkus-camel-jaxb.git cd quarkus-camel-jaxb - Build the application, run the tests
./mvnw clean verify - Observe that the tests succeed
- Build the application natively, run the tests
./mvnw --define native clean verify - Observe that the tests fail with above exception
Output of uname -a or ver
Linux ecco 5.15.0-52-generic #58-Ubuntu SMP Thu Oct 13 08:03:55 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Output of java -version
openjdk version “17.0.8” 2023-07-18 OpenJDK Runtime Environment Temurin-17.0.8+7 (build 17.0.8+7) OpenJDK 64-Bit Server VM Temurin-17.0.8+7 (build 17.0.8+7, mixed mode, sharing)
GraalVM version (if different from Java)
mandrel-23.0.1.2-java17
Quarkus version or git rev
3.2.6.Final
Build tool (ie. output of mvnw --version or gradlew --version)
Apache Maven 3.9.3 (21122926829f1ead511c958d89bd2f672198ae9f) Maven home: /home/marco/.m2/wrapper/dists/apache-maven-3.9.3-bin/326f10f4/apache-maven-3.9.3 Java version: 17.0.8, vendor: Eclipse Adoptium, runtime: /opt/java/mandrel/23.0.1.2-java17 Default locale: en_US, platform encoding: UTF-8 OS name: “linux”, version: “5.15.0-52-generic”, arch: “amd64”, family: “unix”
Additional information
- Notice that neither
Foo.javanorBar.javadefinepropOrder. Defining them does not change the behaviour. - Notice that registering the classes
FooandBarfor reflectoin and serialization does not change the behaviour.
About this issue
- Original URL
- State: open
- Created 9 months ago
- Comments: 30 (14 by maintainers)
@rysurd I’m not sure it’s worth being more fine-grained for the specific fields. Just adding the parent would work. Using
ReflectiveHierarchyBuildItemat the line @zakkak pointed out should be enough to fix the issue.I would really appreciate if we could add a test to the
-deploymentmodule in passing so that it doesn’t get broken again later.@rysurd If I am getting this right, there is currently no logic in Quarkus for registering it automatically. In https://github.com/quarkusio/quarkus/blob/4a5006e3240c65688c19e48bb22a04c65272bdfa/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java#L207 Quarkus registers the annotated (with
XMlType) classes themselves for reflection, but doesn’t do this reflectively for their superclasses.I believe the right fix is to change the logic there to register the classes reflectively (using
io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem.Builder).Regarding @gsmet’s comment of only registering the fields mentioned in
propOrder, although it sounds the right thing to do I am afraid we currently lack the support for doing such fine grain registrations in Quarkus, so you would need to extendio.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItemandio.quarkus.deployment.steps.NativeImageReflectConfigStepas well. Probably best done in a separate PR.@gsmet I found something really interesting. I added -H:ReflectionConfigurationFiles=reflection-config.json flag to the reproducer’s application.properties in order to add this config :
And this time it worked. So explicitly marking ExpressionNode for reflection seems to solve our issue, meaning the problem is the fact that this class is not marked for reflection at all. Is there a way within quarkus to do this? Mark a class for reflection without the need to add a json config file?
Thanks a lot!
EDIT : Found it. I added
At line 275 in JaxbProcessor and it worked! I’ll do more tests and if good I’m adding an integration test and will open a PR. However I’m wondering if a better fix would be to go deeper and see why ExpressionNode wasn’t automatically marked for reflexion … Which is weird.
The tests needs to be added to https://github.com/quarkusio/quarkus/tree/main/integration-tests/jaxb .
I would reproduce the fact that
expressionis in a parent as it’s interesting, especially if someone wants to experiment with being more fine grained forpropOrder.So I dug a bit deeper and found the message template for the error message. The template is:
Thus, it so not
Property expression, butProperty "expression". Now the question is where this comes from. And whereexecutorServicecomes from. This pretty much looks like JAXB is very, very confused.@rysurd The exception you posted indicates that the said class cannot be found on the classpath.
Please check to see if
org.glassfish.hk2:osgi-resource-locator(the maven artefact providingorg.glassfish.hk2.osgiresourcelocator.ServiceLoader) is in the project’s dependencies. You can do this with something like:If the dependency is present check to see if it’s declared as optional, when compiling native images only compile dependencies are considered, so you might need to explicitly add the dependency as a compile dependency.
Sure will do, thanks! I was a bit struggling with setting up the local env to start the reproducer but now it’s all done and good.
@ibourdier I’m not aware of some working on this actively. please go ahead and dive into the reproducer and investigate.
@ibourdier feel free. The ticket is unassigned. Although it might be worth consulting @gsmet first.