micronaut-core icon indicating copy to clipboard operation
micronaut-core copied to clipboard

NoSuchMethodError/KSP generated bean definition constructor missing parameters for class with AOP advice

Open jdpgrailsdev opened this issue 1 year ago • 2 comments

Expected Behavior

KSP should generate the correct constructor in the $Definition$Intercepted generated class when the inspected Kotlin class utilizes an AOP advice annotation on open methods in the class.

Actual Behaviour

At runtime, Micronaut fails to instantiate the class:

Message: 'void io.airbyte.cron.jobs.$WorkloadMonitor$Definition$Intercepted.<init>(io.airbyte.api.client.WorkloadApiClient, java.time.Duration, java.time.Duration, io.airbyte.metrics.lib.MetricClient, kotlin.jvm.functions.Function1, io.micronaut.context.BeanResolutionContext, io.micronaut.context.BeanContext, io.micronaut.context.Qualifier, java.util.List, io.micronaut.aop.InterceptorRegistry, int, kotlin.jvm.internal.DefaultConstructorMarker)'
Path Taken: new $WorkloadMonitor$Definition$Intercepted(WorkloadApiClient workloadApiClient,Duration nonSyncWorkloadTimeout,Duration syncWorkloadTimeout,MetricClient metricClient,Function1 timeProvider,BeanResolutionContext $beanResolutionContext,BeanContext $beanContext,Qualifier $qualifier,List $interceptors,InterceptorRegistry $interceptorRegistry)
	at io.micronaut.context.DefaultBeanContext.resolveByBeanFactory(DefaultBeanContext.java:2326) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2281) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2293) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.createRegistration(DefaultBeanContext.java:3095) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.SingletonScope.getOrCreate(SingletonScope.java:80) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.findOrCreateSingletonBeanRegistration(DefaultBeanContext.java:2997) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.resolveBeanRegistration(DefaultBeanContext.java:2958) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.resolveBeanRegistration(DefaultBeanContext.java:2732) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1731) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:837) ~[micronaut-inject-4.4.10.jar:4.4.10]
	at io.micronaut.scheduling.processor.ScheduledMethodProcessor.lambda$process$2(ScheduledMethodProcessor.java:123) ~[micronaut-context-4.4.10.jar:4.4.10]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[?:?]
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) ~[?:?]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[?:?]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[?:?]
	at java.base/java.lang.Thread.run(Thread.java:1583) [?:?]
Caused by: java.lang.NoSuchMethodError: 'void io.airbyte.cron.jobs.$WorkloadMonitor$Definition$Intercepted.<init>(io.airbyte.api.client.WorkloadApiClient, java.time.Duration, java.time.Duration, io.airbyte.metrics.lib.MetricClient, kotlin.jvm.functions.Function1, io.micronaut.context.BeanResolutionContext, io.micronaut.context.BeanContext, io.micronaut.context.Qualifier, java.util.List, io.micronaut.aop.InterceptorRegistry, int, kotlin.jvm.internal.DefaultConstructorMarker)'
	at io.airbyte.cron.jobs.$WorkloadMonitor$Definition$Intercepted$Definition.instantiate(Unknown Source) ~[io.airbyte-airbyte-cron-dev.jar:?]
	at io.micronaut.context.DefaultBeanContext.resolveByBeanFactory(DefaultBeanContext.java:2311) ~[micronaut-inject-4.4.10.jar:4.4.10]
	... 16 more

The actual class that is represented by the bean definition can be seen here. The advice annotation can be seen here. The interceptor bean for the advice can be seen here.

For what it's worth, commenting out all references to the @Instrument and @Tag annotations in the WorkloadMonitor class makes the issue go away, confirming that this is somehow related to the use of the AOP advice and KSP.

Steps To Reproduce

  1. Check out https://github.com/airbytehq/airbyte-platform/
  2. Build the project from the root of the repository (/.gradlew clean build)
  3. Edit the docker-compose.yaml file. Find the airbyte-cron: section and add the following environment variable to the environment block: WORKLOAD_MONITOR_ENABLED="true"
  4. From the root of the repository, launch the application: docker-compose -f docker-compose.yaml up
  5. Watch the output of the airbyte/cron image to see the failure to create the WorkloadMonitor bean.

Environment Information

No response

Example Application

https://github.com/airbytehq/airbyte-platform/

Version

4.4.3

jdpgrailsdev avatar Jun 07 '24 02:06 jdpgrailsdev

Looks like the default values aren’t implemented for the proxy

dstepanov avatar Jun 07 '24 05:06 dstepanov

Looks like the default values aren’t implemented for the proxy

@dstepanov Interesting. I did look at the byte code generated by the processor and the constructor is missing the last three parameters in the stack trace (InterceptorRegistry Int and DefaultConstructorMarker). That seems to align with possible what you are referring to.

jdpgrailsdev avatar Jun 07 '24 12:06 jdpgrailsdev

Tested again with the 4.5.1 release and it still produces the same NoSuchMethodError

jdpgrailsdev avatar Jul 29 '24 16:07 jdpgrailsdev

I had the same issue in one of our services, removing the default value from the constructor worked for me.

I did try your application a bit but didn't manage to see the NoSuchMethodError from the WorkloadMonitor as mentioned in the Steps to Reproduce. I wanted to see if by removing OffsetDateTime::now in the WorkloadMonitor constructor would be a workaround for you too

nilols avatar Aug 20 '24 05:08 nilols

@nilols Removing the default value from the constructor parameter appears to have worked. Thanks again for the help!

jdpgrailsdev avatar Aug 26 '24 18:08 jdpgrailsdev