Unable to Autowire spring Component into camel Component - java

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 :/

Related

Constructor works fine with and without #Autowired

I have tennisCoach object created by Spring framework:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml") ;
Coach theCoach = context.getBean("tennisCoach", Coach.class);
Can't understand why I need #Autowired annotation in TennisCoach constructor in code below. It works fine with and without #Autowired annotation.
#Component
public class TennisCoach implements Coach {
private FortuneService fortuneService;
#Autowired
public TennisCoach(FortuneService theFortuneService) {
fortuneService = theFortuneService;
}
#Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
#Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
UPD
Content of 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"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.luv2code.springdemo"></context:component-scan>
</beans>
From #Autowired Javadoc:
If a class only declares a single constructor to begin with, it will always be used, even if not annotated.
Since Spring 4.3 you don’t need the #Autowired annotation as soon as you have the only constructor in your class.
Here #Autowired is used for constructor injection. TennisCoach has a dependency on FortuneService and it is injected through constructor. I'm not sure how you have configured beans in applicationContext.xml

No bean named is defined Exception

package com.mkyong.output;
IOutputGenerator.java
public interface IOutputGenerator
{
public void generateOutput();
}
package com.mkyong.output;
OutputHelper.java
#Component
public class OutputHelper {
#Autowired
IOutputGenerator outputGenerator;
public void generateOutput() {
outputGenerator.generateOutput();
}
/*//DI via setter method
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}*/
}
package com.mkyong.output.impl;
CsvOutputGenerator.java
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput() {
System.out.println("This is Csv Output Generator");
}
}
SpringBeans.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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.mkyong" />
</beans>
i am getting this exception Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'OutputHelper' is defined
even though i have marked OutputHelper as component.
I have changed
OutputHelper output = (OutputHelper) context.getBean("OutputHelper");
to
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
and it worked.
Hi i think you haven't added following in your Spring XML configuration
xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
<mvc:annotation-driven/>
you need to see top exception and read the whole line.
i guess there have a exception is nested exception just like #Autowired xxxxxx,meas autowired fail.
i have notice this:
#Autowired
IOutputGenerator outputGenerator;
and
#Component
public class CsvOutputGenerator implements IOutputGenerator
so, in the default, class name is used to #Autowired,you can rewrite to
#Autowired
IOutputGenerator csvOutputGenerator;
notice:
"csvOutputGenerator" first letter is lowercase
the easier option would be to enable annotations in beans already registered in the application context, means that you can just use #Autowired instead of getting manually all beans with context.getBean()
just add this line to your SpringBeans.xml
<context:annotation-config>
if you really want to understand what you are doing reading this could help.

java.lang.NullPointerException at object instantiation

My application uses struts and spring frameworks. I have a class FormA which has an autowired property in it. When I try to instantiate it while writing unit tests I get a Null Pointer Exception. Here is my code.
My ClassA:
public class FormA{
private String propertyOne;
#Autowired
private ServiceClass service;
public FormA(){
}
}
My unit test method:
#Test
public void testFormA(){
FormA classObj = new FormA();
}
#Autowired only works when object life cycle is managed by Spring.
You'll need to run your tests with #RunWith(SpringJUnit4ClassRunner.class), and instead of instantiating FormA manually, inject it in the test class as well, using #Autowired.
When you create an object by new, autowire\inject don't work...
as workaround you can try this:
create your template bean of NotesPanel
<bean id="notesPanel" class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
and create an istance in this way
applicationContext.getBean("notesPanel");
PROTOTYPE : This scopes a single bean definition to have any number of object instances.
anyway a unit test should be
Test class
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration(locations = { "classpath:META-INF/your-spring-context.xml" })
public class UserServiceTest extends AbstractJUnit4SpringContextTests {
#Autowired
private UserService userService;
#Test
public void testName() throws Exception {
List<UserEntity> userEntities = userService.getAllUsers();
Assert.assertNotNull(userEntities);
}
}
your-spring-context.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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="userService" class="java.package.UserServiceImpl"/>
</beans>

How do I use spring property sources within a child annotation context?

I'm trying to replicate something that works with XML config using annotated configuration classes. The problem I'm hitting is that property sources defined in the child context are not accessible.
The xml that works looks like
Parent context :
<?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="proxyChannelQueue" class="java.util.concurrent.ArrayBlockingQueue">
<constructor-arg value="10"/>
</bean>
</beans>
Child Context :
<?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:p="http://www.springframework.org/schema/p"
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">
<context:property-placeholder location="proxy-host.properties"/>
<bean class="org.eclipse.jetty.server.Server"
p:handler-ref="proxyHostHandler"
init-method="start">
<constructor-arg value="${proxyHostPort}"/>
</bean>
<bean id="proxyHostHandler" class="com.sjl.web.ProxyHostHandler"
p:proxyChannelQueue-ref="proxyChannelQueue"/>
</beans>
Start up code :
ClassPathXmlApplicationContext parentContext = new ClassPathXmlApplicationContext("test/parent-context.xml");
ClassPathXmlApplicationContext childContext = new ClassPathXmlApplicationContext(new String[] {"test/child-context.xml"}, parentContext);
My attempt at doing this using configuration classes looks like.
Parent Context :
#Configuration
public class ParentConfiguration {
#Bean(name = "proxyChannelQueue")
public BlockingQueue<ProxyChannel> getProxyChannelQueue() {
return new ArrayBlockingQueue<ProxyChannel>(10);
}
}
Child Context :
#Configuration
#PropertySource("classpath:proxy-host.properties")
public class ChildContext {
private static final Logger LOGGER = LoggerFactory.getLogger(ChildContext.class);
#Autowired
private Environment environment;
#Resource(name = "proxyChannelQueue")
private BlockingQueue<ProxyChannel> proxyChannelQueue;
public static void main(String[] args) {
new HierarchicalAnnotationConfigApplicationContext(ChildContext.class);
}
#Bean
public Server getJettyServer() throws Exception {
int proxyHostPort = environment.getProperty("proxyHostPort", Integer.class);
Server server = new Server(proxyHostPort);
server.setHandler(getHandler());
server.start();
return server;
}
#Bean
public Handler getHandler() {
ProxyHostHandler proxyHostHandler = new ProxyHostHandler();
proxyHostHandler.setProxyChannelQueue(proxyChannelQueue);
return proxyHostHandler;
}
}
Start up code :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class);
AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildContext.class);
childContext.refresh();
I'm getting a null pointer while trying to retrieve the proxyHostPort within the ChildContext getJettyServer method. Inspecting the environment variable shows that it contains only 2 property sources (systemProperties and systemEnvironment) and not the 3 I expect.
The same configuration works if I run them as a single combined context. E.g. :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class, ChildContext.class);
However I want the isolation that using parent contexts provide.
Cheers,
Peter

#Value annotation from Spring3 doesn't work in my program

I'm writing a java application with Spring 3.It's working well with xml,but not working at all in annotation.
here's my snippet:
#Service("oracleDB")
public class OracleDatabase implements IDatabase
{
#Value("oracle.jdbc.driver.OracleDriver")
private String driverName;
#Value("jdbc:oracle:thin:#")
private String url;
public String getDriverName()
{
return driverName;
}
}
My ApplicationContext.xml is like this:
<?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">
<context:annotation-config />
<context:component-scan
base-package="com.pdiwt.database"></context:component-scan>
</beans>
MyInvoker is like that:
public class MyInvoker{
public static void main(String args[]){
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
OracleDatabase oracelDB = beanFactory.getBean("oracleDB");
System.out.println(oracleDB.getDriverName());
}
}
guess what? The result is null. Is there anything wrong?
The problem here is using xmlbeanfactory, which is a common mistake. Try this instead, it will work perfectly:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
OracleDatabase oracleDB = (OracleDatabase)context.getBean("oracleDB");
...
I think the beanfactory is simply not powerful enough to handle the #Value annotations. More information can be found here.
If you're already using Spring, why would you get a connection this way instead of using Spring's DataSources? Seems odd at best; wrong-headed at worst.
I'd be giving that Repository a JdbcTemplate.

Categories