Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JAXB unmarshalling fails in native mode #36479

Closed
turing85 opened this issue Oct 13, 2023 · 36 comments · Fixed by #37643
Closed

JAXB unmarshalling fails in native mode #36479

turing85 opened this issue Oct 13, 2023 · 36 comments · Fixed by #37643

Comments

@turing85
Copy link
Contributor

turing85 commented Oct 13, 2023

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.java nor Bar.java define propOrder. Defining them does not change the behaviour.
  • Notice that registering the classes Foo and Bar for reflectoin and serialization does not change the behaviour.
@quarkus-bot
Copy link

quarkus-bot bot commented Oct 13, 2023

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

@rysurd
Copy link
Contributor

rysurd commented Oct 15, 2023

Hello @turing85,

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

@turing85
Copy link
Contributor Author

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

@rysurd
Copy link
Contributor

rysurd commented Oct 15, 2023

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

@maxandersen
Copy link
Contributor

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

@rysurd
Copy link
Contributor

rysurd commented Oct 21, 2023

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
Copy link
Contributor

rysurd commented Oct 29, 2023

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
Copy link
Contributor

zakkak commented Oct 30, 2023

@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
Copy link
Contributor

rysurd commented Oct 30, 2023

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

@turing85
Copy link
Contributor Author

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

@turing85
Copy link
Contributor Author

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
Copy link
Contributor Author

turing85 commented Oct 31, 2023

.produce(new ServiceProviderBuildItem(JAXBContext.class.getName(),

Shouldn't this be JaxbContextFactory instead of JaxbContext?

@turing85
Copy link
Contributor Author

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
Copy link
Contributor Author

turing85 commented Oct 31, 2023

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
Copy link
Contributor

rysurd commented Nov 1, 2023

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
Copy link

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
Copy link
Member

gsmet commented Nov 21, 2023

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
Copy link
Contributor

rysurd commented Nov 21, 2023

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

@gsmet
Copy link
Member

gsmet commented Nov 21, 2023

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
Copy link
Contributor

rysurd commented Nov 21, 2023

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
Copy link
Member

gsmet commented Nov 21, 2023

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
Copy link
Contributor

rysurd commented Nov 21, 2023

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
Copy link
Contributor

rysurd commented Nov 26, 2023

@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
Copy link
Contributor

zakkak commented Nov 27, 2023

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

reflectiveClass.produce(ReflectiveClassBuildItem.builder(className).methods().fields().build());
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
Copy link
Contributor

rysurd commented Nov 27, 2023

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

@gsmet
Copy link
Member

gsmet commented Nov 27, 2023

@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
Copy link
Contributor

rysurd commented Nov 27, 2023

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

@rysurd
Copy link
Contributor

rysurd commented Nov 27, 2023

@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
Copy link
Contributor

zakkak commented Nov 30, 2023

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

@rysurd
Copy link
Contributor

rysurd commented Dec 5, 2023

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
Copy link
Contributor Author

turing85 commented Feb 2, 2024

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
Copy link
Contributor

rysurd commented Feb 2, 2024

Hello @turing85 ! The fix has unfortunately been reverted here #38224 since 3.6.7, until further notice.

@turing85
Copy link
Contributor Author

turing85 commented Feb 2, 2024

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

@gastaldi gastaldi reopened this Feb 5, 2024
@gastaldi gastaldi modified the milestone: 3.6.6 Feb 5, 2024
@Terrency
Copy link

@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
Copy link
Member

gsmet commented Mar 25, 2024

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

@gsmet gsmet closed this as completed Mar 25, 2024
@gsmet gsmet modified the milestones: 3.6.6, 3.9.0.CR1 Mar 25, 2024
@gsmet
Copy link
Member

gsmet commented Mar 25, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants