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

NoClassDefFoundError in BuildCompatibleExtension #37337

Closed
vbaidak opened this issue Nov 27, 2023 · 10 comments · Fixed by #37397
Closed

NoClassDefFoundError in BuildCompatibleExtension #37337

vbaidak opened this issue Nov 27, 2023 · 10 comments · Fixed by #37397
Labels
area/arc Issue related to ARC (dependency injection) area/kotlin kind/bug Something isn't working
Milestone

Comments

@vbaidak
Copy link

vbaidak commented Nov 27, 2023

Describe the bug

Hi!

I'm trying to integrate the AxonFramework with Quarkus using the Jakarata's BuildCompatibleExtension, which is expected to be fully supported by Quarkus

Basically, I have these 2 classes:

// This class is registered via the SPI in META-INF/services
class AxonExtension : BuildCompatibleExtension {

	@Synthesis
	fun synthesis(syntheticComponents: SyntheticComponents) {
		syntheticComponents.addBean(Configuration::class.java)
			.type(Configuration::class.java)
			.scope(ApplicationScoped::class.java)
			.createWith(AxonConfigurationSyntheticBeanCreator::class.java)
	}

	open class AxonConfigurationSyntheticBeanCreator : SyntheticBeanCreator<Configuration> {
		override fun create(lookup: Instance<Any>, params: Parameters): Configuration =
			DefaultConfigurer.defaultConfiguration().buildConfiguration()
	}

}
@ApplicationScoped
class AxonConfigurer(private val configuration: Configuration) {

	@Startup
	fun startup() {
		configuration.start() // we're failing here
	}

	@Shutdown
	fun shutdown() {
		configuration.shutdown()
	}

}

When the application starts I get the following exception:

2023-11-27 20:36:42,551 ERROR [io.qua.run.Application] (Quarkus Main Thread) Failed to start application (with profile [dev]): java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:111)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
	at io.quarkus.runner.GeneratedMain.main(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:113)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NoClassDefFoundError: axonframework/AxonExtension$AxonConfigurationSyntheticBeanCreator
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_Bean.createSynthetic(Unknown Source)
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_Bean.doCreate(Unknown Source)
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_Bean.create(Unknown Source)
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_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:32)
	at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
	at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:34)
	at io.quarkus.arc.impl.ClientProxies.getApplicationScopedDelegate(ClientProxies.java:21)
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_ClientProxy.arc$delegate(Unknown Source)
	at org.axonframework.config.Configuration_c43ae979bb9b4bef9e5e8cd9524490415f9f2b13_Synthetic_ClientProxy.start(Unknown Source)
	at axonframework.AxonBootstrapper.startup(AxonBootstrapper.kt:19)
	at axonframework.AxonBootstrapper_ClientProxy.startup(Unknown Source)
	at axonframework.AxonBootstrapper_Observer_Synthetic_956ca697e4afd84927d0d5400c3426ddaf02372c.notify(Unknown Source)
	at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:346)
	at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:328)
	at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:82)
	at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:155)
	at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:106)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
	... 13 more
Caused by: java.lang.ClassNotFoundException: axonframework.AxonExtension$AxonConfigurationSyntheticBeanCreator
	at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:489)
	at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:466)
	... 36 more

Is this an expected behavior or am I doing something wrong?

Expected behavior

Bean successfully registered

Actual behavior

java.lang.NoClassDefFoundError exception is thrown

How to Reproduce?

  1. Check out the Project
  2. Execute ./gradlew quarkusDev

Output of uname -a or ver

No response

Output of java -version

java version "17.0.6" 2023-01-17 LTS Java(TM) SE Runtime Environment (build 17.0.6+9-LTS-190) Java HotSpot(TM) 64-Bit Server VM (build 17.0.6+9-LTS-190, mixed mode, sharing)

Quarkus version or git rev

3.5.2

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 8.4

Additional information

No response

@vbaidak vbaidak added the kind/bug Something isn't working label Nov 27, 2023
Copy link

quarkus-bot bot commented Nov 27, 2023

/cc @evanchooly (kotlin), @geoand (kotlin)

@geoand
Copy link
Contributor

geoand commented Nov 27, 2023

cc @Ladicek @mkouba

@Ladicek
Copy link
Contributor

Ladicek commented Nov 28, 2023

The code looks correct on the first sight. The stack trace shows that the synthetic bean has been registered, the Bean implementation has been generated, the CDI infrastructure behaves as expected, it's "just" that the class is not found at runtime. I'm not sure why off the top of my head; I'll play with the reproducer and report back.

@vbaidak
Copy link
Author

vbaidak commented Nov 28, 2023

@Ladicek , thanks!

I made 2 additional checks:

  • the issue reproduces only for ./gradlew quarkusDev launch. When building and running using the jar file java -jar quarkus-axon-issue/build/quarkus-app/quarkus-run.jar everything works
  • the issue is somehow connected with dependency. When I add a simple class inside the project and replace axon with it, this bean is successfully added to CDI even when launching with ./gradlew quarkusDev

I also tried setting up quarkus.class-loading.parent-first-artifacts=org.axonframework:axon-configuration, but this didn't help

@Ladicek
Copy link
Contributor

Ladicek commented Nov 28, 2023

OK, that's interesting to know. Maybe the Bean implementation should explicitly load the creator class from the TCCL, I think we're using a direct class reference right now, which may be wrong. I'll check.

@Ladicek
Copy link
Contributor

Ladicek commented Nov 29, 2023

OK, so the problem is:

  • since the target class for which the synthetic bean is created is a non-application class, the generated Bean implementation is also a non-application class and hence is loaded by the Base Runtime CL
  • however, the SyntheticBeanCreator implementation is an application class and hence is loaded by the Runtime CL (a child of the Base Runtime CL)

This means that the generated Bean class doesn't see the implementation of SyntheticBeanCreator.

This is only an issue in dev mode (or test mode), because in prod, class loading is mostly flat (see https://quarkus.io/guides/class-loading-reference).

As a workaround, the target library can be forced into the Runtime CL by setting

quarkus.class-loading.reloadable-artifacts=org.axonframework:axon-configuration

The most straightforward fix would be to turn all Bean classes for synthetic beans registered by build compatible extensions into application classes, but that has consequences (access to package-private methods might not work, hot reload performance might be affected). I think we should only do this for synthetic beans registered by extensions that are in the application. Most of the time, extensions should come from libraries (that is, all extension-related classes would also be non-application), in which case, we don't need (and want) to do anything. I'll try to figure out how to do that, it shouldn't be very hard. In the meantime, the workaround mentioned above should do the trick.

@Ladicek
Copy link
Contributor

Ladicek commented Nov 29, 2023

Should be fixed by #37397

@manovotn manovotn added the area/arc Issue related to ARC (dependency injection) label Nov 29, 2023
@vbaidak
Copy link
Author

vbaidak commented Nov 30, 2023

@Ladicek , I tried this setting too: quarkus.class-loading.reloadable-artifacts=org.axonframework:axon-configuration and it didn't help

So, I'll wait for the #37397

@Ladicek
Copy link
Contributor

Ladicek commented Nov 30, 2023

OK that is really weird. That setting definitely made things work when I tried locally. I confess I translated your reproducer from Kotlin/Gradle/YAML to Java/Maven/properties, to rule out a possible bug in some of these layers; let me try again.

@Ladicek
Copy link
Contributor

Ladicek commented Nov 30, 2023

That is funny, the documentation for quarkus.class-loading.reloadable-artifacts says:

WARNING: This config property can only be set in application.properties

And indeed, trying to set it in application.yml like this:

quarkus:
  class-loading:
    reloadable-artifacts: org.axonframework:axon-configuration

doesn't work. I don't know why, but renaming application.yml to application.properties and changing the content to

quarkus.class-loading.reloadable-artifacts=org.axonframework:axon-configuration

did help. Go figure 🤷

In any case, the PR should help.

@quarkus-bot quarkus-bot bot added this to the 3.7 - main milestone Nov 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) area/kotlin kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants