quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.8k stars 2.68k forks source link

JAXB unmarshalling fails in native mode #36479

Closed turing85 closed 7 months ago

turing85 commented 1 year ago

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:

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

quarkus-bot[bot] commented 1 year ago

/cc @Karm (mandrel), @galderz (mandrel), @gsmet (jaxb), @zakkak (mandrel)

rysurd commented 1 year ago

Hello @turing85,

Can I try to tackle this issue if it's not already in someone's hands? Thanks!

turing85 commented 1 year ago

@ibourdier feel free. The ticket is unassigned. Although it might be worth consulting @gsmet first.

rysurd commented 1 year ago

Ok thanks! @gsmet can you give his inputs on this issue first please ?

maxandersen commented 1 year ago

@ibourdier I'm not aware of some working on this actively. please go ahead and dive into the reproducer and investigate.

rysurd commented 1 year ago

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.

rysurd commented 1 year ago

Hello again ! @maxandersen @turing85 @gsmet I am kind of stuck on this one actually ... :/ If possible I'd like a little bit of help. So far I found out that this particular error is thrown using native compilation :

2023-10-29 14:40:30,050 FINE  [jak.xml.bind] (executor-thread-1) Checking system property jakarta.xml.bind.JAXBContextFactory
2023-10-29 14:40:30,050 FINE  [jak.xml.bind] (executor-thread-1)   not found
2023-10-29 14:40:30,050 FINE  [jak.xml.bind] (executor-thread-1) Trying to create the platform default provider
2023-10-29 14:40:30,050 FINE  [jak.xml.bind] (executor-thread-1) Unable to find from OSGi: [jakarta.xml.bind.JAXBContextFactory]: java.lang.ClassNotFoundException: org.glassfish.hk2.osgiresourcelocator.ServiceLoader. This exception was synthesized during native image building from a call to java.lang.Class.forName(String) with constant arguments.

I tried to search around if there was a similar issue but got nothing good. I'm not even sure the issue is really coming from Quarkus, it may come from GraalVM instead. What is your point of view on this?

Btw when executing with non-native it seems to be fine :

2023-10-29 14:35:13,769 FINE  [jak.xml.bind] (executor-thread-1) Checking system property jakarta.xml.bind.JAXBContextFactory
2023-10-29 14:35:13,769 FINE  [jak.xml.bind] (executor-thread-1)   not found
2023-10-29 14:35:13,771 FINE  [jak.xml.bind] (executor-thread-1) ServiceProvider loading Facility used; returning object [org.glassfish.jaxb.runtime.v2.JAXBContextFactory]
2023-10-29 14:35:13,771 FINE  [jak.xml.bind] (executor-thread-1) Using jakarta.xml.bind-api on the class path.

Thanks a lot for helping :)

zakkak commented 1 year ago

@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 providing org.glassfish.hk2.osgiresourcelocator.ServiceLoader) is in the project's dependencies. You can do this with something like:

mvn dependency:tree | grep osgi-resource-locator

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.

rysurd commented 1 year ago

Thanks for the insights ... I'll try to check this week!

turing85 commented 1 year ago

The dependency is not present. I added the dependency explicitly to my demo project. This, however, does not change the behaviour.

turing85 commented 1 year ago

The (relevant) error is:

...
2023-10-31 00:34:54,666 FINE  [jak.xml.bind] (executor-thread-1) Checking system property jakarta.xml.bind.JAXBContextFactory
2023-10-31 00:34:54,666 FINE  [jak.xml.bind] (executor-thread-1)   not found
2023-10-31 00:34:54,666 FINE  [jak.xml.bind] (executor-thread-1) Trying to create the platform default provider
2023-10-31 00:34:54,666 FINE  [jak.xml.bind] (executor-thread-1) Unable to find from OSGi: [jakarta.xml.bind.JAXBContextFactory]: java.lang.reflect.InvocationTargetException
    at java.base@17.0.8/java.lang.reflect.Method.invoke(Method.java:568)
    at jakarta.xml.bind.ServiceLoaderUtil.lookupUsingOSGiServiceLoader(ServiceLoaderUtil.java:60)
    at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:373)
    at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:605)
    at io.quarkus.jaxb.runtime.JaxbContextProducer.createJAXBContext(JaxbContextProducer.java:80)
    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:61)
    at de.turing85.converter.FooConverter.unmarshalFromString(FooConverter.java:42)
    at de.turing85.converter.FooConverter.unmarshal(FooConverter.java:36)
    at java.base@17.0.8/java.lang.reflect.Method.invoke(Method.java:568)
    at org.apache.camel.support.ObjectHelper.invokeMethod(ObjectHelper.java:355)
    at org.apache.camel.impl.converter.StaticMethodTypeConverter.convertTo(StaticMethodTypeConverter.java:55)
    at org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvert(CoreTypeConverterRegistry.java:531)
    at org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvertTo(CoreTypeConverterRegistry.java:456)
    at org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvertTo(CoreTypeConverterRegistry.java:350)
    at org.apache.camel.impl.converter.CoreTypeConverterRegistry.mandatoryConvertTo(CoreTypeConverterRegistry.java:276)
    at org.apache.camel.support.MessageSupport.getMandatoryBody(MessageSupport.java:126)
    at org.apache.camel.support.processor.ConvertBodyProcessor.process(ConvertBodyProcessor.java:118)
    at org.apache.camel.support.processor.ConvertBodyProcessor.process(ConvertBodyProcessor.java:159)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:475)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.executeReactiveWork(DefaultReactiveExecutor.java:196)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:164)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:163)
    at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:383)
    at org.apache.camel.component.platform.http.vertx.VertxPlatformHttpConsumer.lambda$handleRequest$2(VertxPlatformHttpConsumer.java:198)
    at io.vertx.core.impl.ContextBase.lambda$null$0(ContextBase.java:137)
    at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
    at io.vertx.core.impl.ContextBase.lambda$executeBlocking$1(ContextBase.java:135)
    at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base@17.0.8/java.lang.Thread.run(Thread.java:833)
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807)
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210)
Caused by: java.lang.NullPointerException
    at org.glassfish.hk2.osgiresourcelocator.ServiceLoader.lookupProviderClasses(ServiceLoader.java:132)
    ... 53 more
...
turing85 commented 1 year ago

https://github.com/quarkusio/quarkus/blob/3149eced5c19184074005ee738bf8c0ab9c31dc6/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java#L296

Shouldn't this be JaxbContextFactory instead of JaxbContext?

turing85 commented 1 year ago

So I added

        providerItem
                .produce(new ServiceProviderBuildItem(JAXBContextFactory.class.getName(),
                        "org.glassfish.jaxb.runtime.v2.JAXBContextFactory"));

to the method above (I left the line I posted above)

Now, the application finds the JAXBContextFactory:

...
2023-10-31 02:51:02,978 FINE  [jak.xml.bind] (executor-thread-1) Checking system property jakarta.xml.bind.JAXBContextFactory
2023-10-31 02:51:02,979 FINE  [jak.xml.bind] (executor-thread-1)   not found
2023-10-31 02:51:02,979 FINE  [jak.xml.bind] (executor-thread-1) ServiceProvider loading Facility used; returning object [org.glassfish.jaxb.runtime.v2.JAXBContextFactory]

but alas, the application still fails with a slightly different stack trace:

...
Caused by: 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 org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:83)
    at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:421)
    at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:255)
    at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1115)
    at org.glassfish.jaxb.runtime.v2.ContextFactory.createContext(ContextFactory.java:144)
    at org.glassfish.jaxb.runtime.v2.JAXBContextFactory.createContext(JAXBContextFactory.java:44)
    at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:373)
    at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:605)
    at io.quarkus.jaxb.runtime.JaxbContextProducer.createJAXBContext(JaxbContextProducer.java:80)
    ... 49 more
...
turing85 commented 1 year ago

So I dug a bit deeper and found the message template for the error message. The template is:

PROPERTY_ORDER_CONTAINS_UNUSED_ENTRY = \
    Property {0} appears in @XmlType.propOrder, but no such property exists. Maybe you meant {1}?

Thus, it so not Property expression, but Property "expression". Now the question is where this comes from. And where executorService comes from. This pretty much looks like JAXB is very, very confused.

rysurd commented 1 year ago

In jaxb-runtime package, class ClassInfoImpl there is this method checkUnusedProperties() that throw our error :

/**
 * Report errors for unused propOrder entries.
 */
public void checkUnusedProperties() {
    for( int i=0; i<used.length; i++ )
        if(used[i]==null) {
            String unusedName = propOrder[i];
            String nearest = EditDistance.findNearest(unusedName, new AbstractList<>() {
                @Override
                public String get(int index) {
                    return properties.get(index).getName();
                }

                @Override
                public int size() {
                    return properties.size();
                }
            });
            boolean isOverriding = i <= (properties.size() - 1) && properties.get(i).hasAnnotation(OverrideAnnotationOf.class);
            if (!isOverriding) {
                builder.reportError(new IllegalAnnotationException(
                Messages.PROPERTY_ORDER_CONTAINS_UNUSED_ENTRY.format(unusedName,nearest),ClassInfoImpl.this));
            }
        }
}

I don't exactly know the working of that method but it look like it's searching for unused property names, and it found property "expression".

patient-developer commented 11 months ago

Hi,

I am facing a similar error, also testing with Graal VM using ghcr.io/graalvm/graalvm-community:17 as base image.

I receive the error with stacktrace (XXXXXXX for privacy's reason)

Error creating bean with name 'xmlConverter': Instantiation of supplied bean failed
2023-11-18T20:30:02.100322108Z  at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:317)
2023-11-18T20:30:02.100323590Z  at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:260)
2023-11-18T20:30:02.100324963Z  at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:200)
2023-11-18T20:30:02.100326436Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:947)
2023-11-18T20:30:02.100329221Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214)
2023-11-18T20:30:02.100330684Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1158)
2023-11-18T20:30:02.100332086Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
2023-11-18T20:30:02.100333629Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
2023-11-18T20:30:02.100335022Z  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
2023-11-18T20:30:02.100336535Z  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
2023-11-18T20:30:02.100338057Z  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
2023-11-18T20:30:02.100339580Z  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
2023-11-18T20:30:02.100342496Z  at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
2023-11-18T20:30:02.100344019Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
2023-11-18T20:30:02.100345542Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
2023-11-18T20:30:02.100347115Z  at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910)
2023-11-18T20:30:02.100348547Z  at org.springframework.beans.factory.support.RegisteredBean.resolveAutowiredArgument(RegisteredBean.java:229)
2023-11-18T20:30:02.100350100Z  at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:314)
2023-11-18T20:30:02.100351483Z  ... 56 common frames omitted
2023-11-18T20:30:02.100353016Z Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xmlConverter': Instantiation of supplied bean failed
2023-11-18T20:30:02.100354478Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1220)
2023-11-18T20:30:02.100356602Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1158)
2023-11-18T20:30:02.100358195Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
2023-11-18T20:30:02.100359768Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
2023-11-18T20:30:02.100364056Z  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
2023-11-18T20:30:02.100365629Z  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
2023-11-18T20:30:02.100367072Z  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
2023-11-18T20:30:02.100368595Z  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
2023-11-18T20:30:02.100370198Z  at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
2023-11-18T20:30:02.100371621Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
2023-11-18T20:30:02.100373504Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
2023-11-18T20:30:02.100374937Z  at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910)
2023-11-18T20:30:02.100376490Z  at org.springframework.beans.factory.support.RegisteredBean.resolveAutowiredArgument(RegisteredBean.java:229)
2023-11-18T20:30:02.100377902Z  at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:314)
2023-11-18T20:30:02.100379435Z  ... 73 common frames omitted
2023-11-18T20:30:02.100380728Z Caused by: org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException: 5 counts of IllegalAnnotationExceptions
2023-11-18T20:30:02.100382220Z  at org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:83)
2023-11-18T20:30:02.100383703Z  at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:421)
2023-11-18T20:30:02.100385056Z  at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:255)
2023-11-18T20:30:02.100386659Z  at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1115)
2023-11-18T20:30:02.100388081Z  at org.glassfish.jaxb.runtime.v2.ContextFactory.createContext(ContextFactory.java:144)
2023-11-18T20:30:02.100389534Z  at org.glassfish.jaxb.runtime.v2.JAXBContextFactory.createContext(JAXBContextFactory.java:44)
2023-11-18T20:30:02.100391007Z  at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:373)
2023-11-18T20:30:02.100392339Z  at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:605)
2023-11-18T20:30:02.100393712Z  at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:546)
2023-11-18T20:30:02.100395225Z  at XXXXXXX.XmlConverter.<init>(XmlConverter.java:32)
2023-11-18T20:30:02.100396668Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1252)
2023-11-18T20:30:02.100400084Z  at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949)
2023-11-18T20:30:02.100401547Z  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214)
2023-11-18T20:30:02.100403100Z  ... 86 common frames omitted

The constructor of my XmlConverter around line 32 looks like

@Component
public final class XmlConverter {

  // some constants

  private final JAXBContext requestContext;
  private final JAXBContext responseContext;

  public XmlConverter() throws JAXBException {
    this.requestContext = JAXBContext.newInstance(RequestType.class);      // <-- line 32
    this.responseContext = JAXBContext.newInstance(ResponseType.class);
  }

  // other code
}

This getTypeInfoSet method is

public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException {

    // check cache
    if(typeInfoSetCache!=null) {
        RuntimeTypeInfoSet r = typeInfoSetCache.get();
        if(r!=null)
            return r;
    }

    final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri);

    IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder();
    builder.setErrorHandler(errorHandler);

    for( Class c : classes ) {
        if(c==CompositeStructure.class)
            // CompositeStructure doesn't have TypeInfo, so skip it.
            // We'll add JaxBeanInfo for this later automatically
            continue;
        builder.getTypeInfo(new Ref<>(c));
    }

    this.hasSwaRef |= builder.hasSwaRef;
    RuntimeTypeInfoSet r = builder.link();

    errorHandler.check();  // <-- line 421
    assert r!=null : "if no error was reported, the link must be a success";

    typeInfoSetCache = new WeakReference<>(r);

    return r;
}

Any support is appreciated.

Thanks in advance and kind regards :)

gsmet commented 11 months ago

My wild guess is that the fields in https://github.com/apache/camel/blob/main/core/camel-core-model/src/main/java/org/apache/camel/model/ExpressionNode.java#L44 are not registered for reflection.

I would try the following patch:

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 17768f6d8e6..accd8006d4f 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
@@ -238,7 +238,7 @@ void processAnnotationsAndIndexFiles(
         JAXB_ANNOTATIONS.stream()
                 .map(Class::getName)
                 .forEach(className -> {
-                    addReflectiveClass(reflectiveClass, true, false, className);
+                    addReflectiveClass(reflectiveClass, true, true, className);
                 });

         // Register @XmlSeeAlso
rysurd commented 11 months ago

Nice findings @gsmet ... I'll try this asap and post here if this works but indeed that looks like it will ;)

gsmet commented 11 months ago

Ideally we would need a fix and a test (reproducing the issue outside of Camel, issue being with https://github.com/apache/camel/blob/main/core/camel-core-model/src/main/java/org/apache/camel/model/ThrottleDefinition.java#L40 ).

I also wonder if instead of registering all the fields for reflection, we should be more fine-grained and only release the ones referenced in XmlType#propOrder but I'm not completely sure how reflection works for hierarchy. Probably worth giving it a try.

@turing85 @rysurd if one of you is up to contribute a test and experiment with a fix, that would be awesome.

rysurd commented 11 months ago

I for sure can try to make the fix, and as for the test I can also give a shot. It'd be like a unit test or something more complex? If it's just to replicate the issue of a field not being registered for reflection I guess it'd be simple ... Otherwise let's just try :D

gsmet commented 11 months ago

The tests needs to be added to https://github.com/quarkusio/quarkus/tree/main/integration-tests/jaxb .

I would reproduce the fact that expression is in a parent as it's interesting, especially if someone wants to experiment with being more fine grained for propOrder.

rysurd commented 11 months ago

I tested and it seems like it doesn't solve our issue. I still got the @XmlType.propOrder expression doesn't exist error ... Even if I changed JaxbProcessor class with the change you suggested. But I noticed that the error message suggest "executorService" as next field... which is the first to appear after "correlationExpression".

And the field we want - expression - only appear in the extended class ExpressionNode. Could it be that adding XmlType fields for reflection is not enough because the field missing is not directly declared in the same class but rather in the extended one?

Edit : the @XmlTransient annotation in parent class ExpressionNode should allow ThrottleDefinition to get that missing field, but it's like this doesn't work at all in native mode.

rysurd commented 11 months ago

@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 :

[
  {
    "name" : "org.apache.camel.model.ExpressionNode",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true
  }
]

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

addReflectiveClass(reflectiveClass, true, true, "org.apache.camel.model.ExpressionNode");

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.

zakkak commented 11 months ago

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.

@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 extend io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem and io.quarkus.deployment.steps.NativeImageReflectConfigStep as well. Probably best done in a separate PR.

rysurd commented 11 months ago

Thanks @zakkak ! I'll try to do the change with ReflectiveHierarchyBuildItem then.

gsmet commented 11 months ago

@rysurd I'm not sure it's worth being more fine-grained for the specific fields. Just adding the parent would work. Using ReflectiveHierarchyBuildItem at the line @zakkak pointed out should be enough to fix the issue.

I would really appreciate if we could add a test to the -deployment module in passing so that it doesn't get broken again later.

rysurd commented 11 months ago

@gsmet so adding a test in the deployment module as well as adding an integration test for jaxb ?

rysurd commented 11 months ago

@gsmet @zakkak Hello ! I have made the changes using ReflectiveHierarchyBuildItem but I got an error stating that I needed to add all the Jaxb annotations into a Jandex index. I searched and added this into the jaxb deployment pom.xml :

<plugin>
    <groupId>io.smallrye</groupId>
    <artifactId>jandex-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>make-index</id>
            <goals>
                <goal>jandex</goal>
            </goals>
        </execution>
    </executions>
</plugin>

In the build logs I now see this :

[INFO] --- jandex:3.1.5:jandex (make-index) @ quarkus-jaxb-deployment ---
[INFO] Saving Jandex index: C:\quarkus\extensions\jaxb\deployment\target\classes\META-INF\jandex.idx

But at the end of the build I still got this issue :

Unable to properly register the hierarchy of the following classes for reflection as they are not in the Jandex index

But I noticed that the build is still successful and the reproducer still is successful too with native compilation. Am I doing something wrong there ? :( I followed these instructions : https://quarkus.io/guides/cdi-reference#how-to-generate-a-jandex-index

zakkak commented 11 months ago

@gsmet could you please help with that? I have no experience with Jandex indexing.

rysurd commented 11 months ago

No idea for this jandex issue @gsmet ? I am currently finishing writing an integration test for jaxb replicating the issue, I think I might open a PR after that but ideally I should know if the jandex messages are a showstopper or not 😄

turing85 commented 9 months ago

Hello @rysurd, @ppalaga, @gsmet! I can verify that the fix works for quarkus version 3.6.6. However, if I use a quarkus version > 3.6.6, the test starts failing again, with the same error message. I tested with versions 3.6.7, 3.6.9 and 3.7.1. So it seems that we have a regression. I have updated the reproducer to use quarkus 3.6.9.

Can we re-open the issue?

rysurd commented 9 months ago

Hello @turing85 ! The fix has unfortunately been reverted here https://github.com/quarkusio/quarkus/pull/38224 since 3.6.7, until further notice.

turing85 commented 9 months ago

Can we re-open the issue then? Or is there another issue to track the status?

Terrency commented 7 months ago

@turing85 Hi Turing, have u fixed this error with jaxb integrated with graalvm native? I am using jaxb2-maven-plugin@3.1.0 to generate Java classes from XML Schema, then constructing Java objects, and generating files through Marshaller. I encountered an issue where the program runs fine in a normal project, but when I use Spring Native to package and generate an exe, it encounters problems. It gives errors related to the generated Java objects, preventing further execution. The error is as follows:

Property expression appears in @XmlType.propOrder, but no such property exists. Maybe you meant null?
    this problem is related to the following location:
        at FmiModelDescription

is there any way to fix this or walkaround?

gsmet commented 7 months ago

This has been fixed in #38217 which is part of 3.9.

gsmet commented 7 months ago

@Terrency the problem is probably due to your classes/fields/methods not being marked for reflection. That is important for GraalVM to notice them and make sure they are not removed from the native executable.

That's one of the reason why we have Quarkus extensions.