Federico Mariani created CAMEL-24067:
----------------------------------------
Summary: 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
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)