[
https://issues.apache.org/jira/browse/CAMEL-24067?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Claus Ibsen updated CAMEL-24067:
--------------------------------
Fix Version/s: 4.22.0
> camel-spring - SpringInjector does not inject CamelContext into
> CamelContextAware beans created via factory method
> ------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-24067
> URL: https://issues.apache.org/jira/browse/CAMEL-24067
> Project: Camel
> Issue Type: Bug
> Components: camel-spring
> Affects Versions: 4.21.0
> Reporter: Federico Mariani
> Assignee: Claus Ibsen
> Priority: Major
> Fix For: 4.22.0
>
>
> Core {{DefaultInjector.newInstance(type, factoryClass, factoryMethod)}} calls
> {{CamelContextAware.trySetCamelContext(answer, camelContext)}} after invoking
> the factory method. {{SpringInjector}} (the injector used by every
> {{SpringCamelContext}}, i.e. all camel-spring / camel-spring-boot
> applications) has the same factory-method code but *without* the
> {{trySetCamelContext}} call.
> As a result, a {{CamelContextAware}} bean created through a factory method -
> e.g. the property-binding syntax {{#class:com.foo.MyBean#createMyBean}} on an
> endpoint/component option - gets the {{CamelContext}} injected on a plain
> {{CamelContext}} but *not* when running in Spring. Same route, different
> behavior depending on runtime.
> Two smaller defects in the same method could be fixed together:
> * when the factory method exists but is not {{public static}}, the method
> silently returns {{null}} instead of raising an error (same silent-null
> exists in core, but core at least documents the contract via the same code
> path)
> * the guard {{fm.getReturnType() != Void.class}} tests the boxed {{Void}}
> wrapper; a {{void}} factory method has return type {{void.class}}
> ({{Void.TYPE}}), so the check never excludes anything (this quirk is shared
> with {{DefaultInjector}} and could be fixed in both)
> Reproducer (verified on 4.22.0-SNAPSHOT: the {{DefaultCamelContext}} test
> passes, the {{SpringCamelContext}} test fails; dependencies: camel-core,
> camel-spring, junit-jupiter):
> {code:java}
> package org.apache.camel.spring.repro;
> import org.apache.camel.CamelContext;
> import org.apache.camel.CamelContextAware;
> import org.apache.camel.impl.DefaultCamelContext;
> import org.apache.camel.spring.SpringCamelContext;
> import org.junit.jupiter.api.Test;
> import
> org.springframework.context.annotation.AnnotationConfigApplicationContext;
> import static org.junit.jupiter.api.Assertions.assertNotNull;
> public class SpringInjectorFactoryMethodTest {
> @Test
> void factoryMethodBeanGetsCamelContextWithDefaultInjector() throws
> Exception {
> try (DefaultCamelContext camel = new DefaultCamelContext()) {
> camel.start();
> MyBean bean = camel.getInjector().newInstance(MyBean.class,
> "createMyBean");
> assertNotNull(bean);
> // passes: DefaultInjector calls
> CamelContextAware.trySetCamelContext
> assertNotNull(bean.getCamelContext());
> }
> }
> @Test
> void factoryMethodBeanGetsCamelContextWithSpringInjector() throws
> Exception {
> try (AnnotationConfigApplicationContext appCtx = new
> AnnotationConfigApplicationContext()) {
> appCtx.refresh();
> SpringCamelContext camel = new SpringCamelContext(appCtx);
> camel.start();
> try {
> MyBean bean = camel.getInjector().newInstance(MyBean.class,
> "createMyBean");
> assertNotNull(bean);
> // EXPECTED: same behavior as DefaultInjector
> // ACTUAL: fails, SpringInjector skips CamelContextAware
> injection
> assertNotNull(bean.getCamelContext());
> } finally {
> camel.stop();
> }
> }
> }
> public static class MyBean implements CamelContextAware {
> private CamelContext camelContext;
> public static MyBean createMyBean() {
> return new MyBean();
> }
> @Override
> public CamelContext getCamelContext() {
> return camelContext;
> }
> @Override
> public void setCamelContext(CamelContext camelContext) {
> this.camelContext = camelContext;
> }
> }
> }
> {code}
> Suggested fix: mirror {{DefaultInjector}} - after {{answer =
> type.cast(obj);}} add {{CamelContextAware.trySetCamelContext(answer,
> camelContext)}}. {{SpringInjector}} currently has no {{CamelContext}}
> reference, but it is always created from
> {{SpringCamelContext.createInjector()}}, which can pass {{this}} (or the
> {{ApplicationContext}} lookup can be used).
> _This issue was found during an AI-assisted code review of the camel-spring
> component. Reported by Claude Code on behalf of Federico Mariani. The
> reproducers were executed and verified against 4.22.0-SNAPSHOT (main) before
> filing._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)