First of all, I know there are very similar questions (Camel producerTemplate is not injected in spring MVC and Initializing camel from Spring annotation config) but they don't help in my case.
I have a bean which sends messages with ProducerTemplate:
public class SimpleProducer {
#Produce(uri = "activemq:queue:simple")
private ProducerTemplate activeMqProducer;
public void send(String message) {
activeMqProducer.sendBody(message);
}
}
When I use annotation driven configuration like below, it trhows NPE from the send method (activeMqProducer is not injected):
#Configuration
public class AnnotationConfigApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfigApp.class);
SimpleProducer simpleProducer = context.getBean(SimpleProducer.class);
simpleProducer.send("Hello World!");
}
#Autowired
private ApplicationContext ctx;
#Bean
public SimpleProducer simpleProducer() {
return new SimpleProducer();
}
#Bean
public CamelContext camelContext() throws Exception {
CamelContext camelContext = new SpringCamelContext(ctx);
camelContext.start();
return camelContext;
}
}
while using equivalent (at least I believe so) XML configuration, it sucessfully sends a message to ActiveMQ:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="simpleProducer" class="makasprzak.so.camel.producer.testing.SimpleProducer"/>
<spring:camelContext xmlns="http://camel.apache.org/schema/spring" id="simple.sender" />
</beans>
initialized like this:
public class XmlConfigApp {
public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext("context.xml");
SimpleProducer simpleProducer = context.getBean(SimpleProducer.class);
simpleProducer.send("Hello World!");
}
}
I've been playing with CamelContext implementation a bit, tried DefaultCamelContext or some SpringCamelContextFactory - no luck.
The problematic code is available in GitHub
<properties>
<camel.version>2.15.2</camel.version>
<activemq.version>5.10.0</activemq.version>
<java.version>1.8</java.version>
</properties>
What did I miss in the annotation configuration?
You should extend org.apache.camel.spring.javaconfig.CamelConfiguration in AnnotationConfigApp class
Related
I want to test a class that simple shutdown the application:
#Component
public class ShutdownManager {
#Autowired
private ApplicationContext applicationcontext;
public int shutdown(int returnCode) {
return SpringApplication.exit(applicationcontext, () -> returnCode);
}
}
The test case I created is this:
public class ShutdownManagerTest {
#Test
public void should_shutdown_gracefully() {
SpringApplication app = new SpringApplication(TestClass.class);
ConfigurableApplicationContext context = app.run();
ShutdownManager shutdownManager = (ShutdownManager)context.getBean("shutdownManager");
int result = shutdownManager.shutdown(10);
assertThat(result).isEqualTo(10);
}
#SpringBootApplication
#ImportResource("classpath:/core/shutdownmanagertest.xml")
private static class TestClass {
public TestClass() {
}
public static void main(String[] args) {
}
}
}
My shutdownmanagertest.xml contains only one bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shutdownManager" class="com.mycodebase.ShutdownManager" />
</beans>
However, when I run this, it complains that:
Field myOtherService in com.mycodebase.MyTask required a bean of type 'com.mycodebase.MyOtherService ' that could not be found.
The class MyTask is in the same package of the ShutdownManager which contains a field myOtherService which has an #Autowire annocation. But it is not defined in my test xml which contains just one bean.
Can someone help me understand why it tries to resolve a bean that is not in the context?
It's doing that because that's how #SpringBootApplication works.
#SpringBootApplication:
This is a convenience annotation that is equivalent to declaring #Configuration, #EnableAutoConfiguration and #ComponentScan.
#ComponentScan
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
So everything in the same or a subpackage of ShutdownManagerTest is being picked up.
I'm guessing something is wrong integrating my spring and camel contexts.
I'm unit testing a Camel Component, and I'm trying to inject a bean (MainframeEncoderProvider) generated by spring component-scan. I can see that the bean is being constructed (breakpointing an init block), and I can autowire it into ToFalinkProducerTest, but it's not getting into the camel Component. The component is instantiated via META-INF auto-discovery, if that's relevant (http://camel.apache.org/how-do-i-add-a-component.html)
Test class setup:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath*:spring-config/testContext.xml"})
public class ToFalinkProducerTest extends CamelTestSupport{
[some tests...]
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() {
//#formatter:off
from("direct:start")
.to("tofalink:x?encoderName=test")
.to("mock:result");
//#formatter:on
}
};
}
testContext:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
">
<!-- lightweight testcontext -->
<context:annotation-config/>
<context:component-scan base-package="net.mo"/>
<camel:camelContext>
<camel:contextScan/>
</camel:camelContext>
</beans>
component:
/**
* Represents the component that manages {#link ToFalinkEndpoint}.
*/
public class ToFalinkComponent extends DefaultComponent {
#Autowired
private MainframeEncoderProvider provider;
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
Endpoint endpoint = new ToFalinkEndpoint(uri, this);
setProperties(endpoint, parameters);
return endpoint;
}
protected MainframeEncoderProvider getProvider() {
return this.provider;
}
}
Managed to fix this, after a lot of faffing around. Replaced CamelTestSupport extension with CamelSpringTestSupport, and dropped #RunWith and #ContextConfiguration. Implemented createApplicationContext() with my xml spring context file, to retain the component scanning.
left the auto-discovery mechanic in place.
Now I just have to see whether it works at runtime :/
I am developing a standalone Spring 4 application, which uses javaFX. However, when I try to create a new ClassPathXmlApplicationContext, all autowired fields are null, leading to NPEs, even though I let Spring instantiate my classes.
This is my main class:
public class Main extends Application {
public static void main(String[] args) {
launch();
}
public void start(Stage stage) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
Gui gui = context.getBean(Gui.class);
stage.setScene(new Scene(gui, 400, 400));
stage.show();
}
}
This is my spring-config.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:annotation-config />
<context:component-scan base-package="org.my.package" />
</beans>
Gui class:
#Controller
#Scope("singleton")
public class Gui extends GridPane {
#Autowired
private NetManager netManager;
#Autowired
private MessengerComponent messenger;
public Gui() {
netManager.init("Username");
...
}
}
NetManager.class:
#Service
#Scope("singleton")
public class NetManager {
...
}
The NPE occurs before I even retrieve the first bean, during the creation of the application context. Any idea why?
The order of the injection is the following:
Constructor args
Fields
Setters/methods
Under the hood, Spring (or any DI framework) create your class by calling the constructor, and THEN inject the dependencies. So you can't use injected fields in your constructor: they will be injected after.
You should inject the needed dependencies in your constructor:
#Autowired
public Gui(NetManager netManager) {
this.netManager = netManager;
netManager.init("Username");
...
}
I have trouble with #Autowired annotation
autoWiredLocallyTest() passes
autoWireAtClassTest() failed
Here is my test cases:
/**
* Spring Autowired test.
*/
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
TestClazz t = new TestClazz();
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}
TestClazz is:
public class TestClazz {
#Autowired
#Qualifier("actions")
private ActionBeans tempowieBiny;
public boolean isAutowired(){
return(this.tempowieBiny!=null);
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="actions.xml" />
<import resource="datasources.xml" />
</beans>
actions.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id='actions' class="net.virtalab.jsonio.configuration.actions.ActionBeans" scope="singleton">
<qualifier value="actions" />
</bean>
</beans>
What was made wrong or not done, but required to do?
I using Spring 3.2.5-RELEASE.
You are instantiating TestClazz using the new operator (TestClazz t = new TestClazz();). You need to load it from your spring context if you want the #autowired beans to be properly initialised.
Try:
#Autowired
ApplicationContext testContext;
#Test
public void autoWireAtClassTest(){
// TestClazz t = new TestClazz();
TestClazz t = (TestClazz)testContext.getBean(TestClazz.class);
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
The problem here is that you're creating new TestClazz object every time. Autowire it instead:
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
// Added here
#Autowired
private TestClazz t;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
//TestClazz t = new TestClazz(); COMMENTED OUT
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}
I have been following the instructions here to implement a spring mvc handler interceptor using annotations and overriding DefaultAnnotationHandlerMapping.
However, my Interceptor is never called.
Can anyone see what I am doing wrong here?
I have implemented #Interceptors as in the blog post.
I've created one Interceptor:
#Component
public class InterceptorSpike extends HandlerInterceptorAdapter {
public InterceptorSpike() {
System.err.println("InterceptorSpike initialised");
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
throw new RuntimeException("Yay, intercepted!");
}
}
And a test controller:
#Controller
#Interceptors({InterceptorSpike.class})
public class TestController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public void doSomething() {
System.err.println("I'm doing something, have I been intercepted??");
}
}
A sample of my handler (mostly the same as the blog post)
#Component
public class HandlerInterceptorAnnotationAwareHandlerMapping extends DefaultAnnotationHandlerMapping {
public HandlerInterceptorAnnotationAwareHandlerMapping() {
System.err.println("HandlerInterceptorAnnotationAwareHandlerMapping initialised");
}
...
[EDIT - Ignore, left for completeness. I have reverted these steps to use autowiring again]
I originally autowired this using #Component, but moved it into the app context as I've been attempting different fixes.
I added the order, and I'm not using <mvc:annotation-driven/>. These were suggested by some posts whilst I was looking for solutions.
[/EDIT]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName">
<context:component-scan base-package="com.xxx"/>
<context:spring-configured/>
<!-- removed manual wiring -->
</beans>
And finally, here's my test :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/test-app-context.xml"})
public class ControllerInterceptorTest {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private TestController controller;
#Test
public void shouldInterceptMethod() {
Map<String, DefaultAnnotationHandlerMapping> mappings = applicationContext.getBeansOfType(DefaultAnnotationHandlerMapping.class);
for (String key : mappings.keySet()) {
DefaultAnnotationHandlerMapping mapping = mappings.get(key);
System.out.println(String.format("key [%s], order [%s], value = %s", key, mapping.getOrder(), mapping.getClass().getCanonicalName()));
}
controller.doSomething();
fail("should have thrown exception");
}
}
I get this output:
HandlerInterceptorAnnotationAwareHandlerMapping initialised
InterceptorSpike initialised
key [handlerInterceptorAnnotationAwareHandlerMapping], order [2147483647], value = com.xxx.interceptors.HandlerInterceptorAnnotationAwareHandlerMapping
I'm doing something, have I been intercepted??
java.lang.AssertionError: should have thrown exception
at org.junit.Assert.fail(Assert.java:91)
...
getHandlerExecutionChain on my new DefaultAnnotationHandlerMapping is never called.
Thank you for reading this far - I know there is a lot here!
Can anyone see what I've missed or done wrong?
Thanks!
The issue might be in this line:
private TestController controller = new TestController();
You need to get the "controller handle" from the context and not initialize yourself.