Autowiring tcp-outbound-channel-adapter using Id does not work - java

I am trying to autowire my tcp-inbound-channel-adapter bean defined as below. Later I will be starting this on certain conditions.
<int-ip:tcp-inbound-channel-adapter
id="inboundClient" channel="replies" connection-factory="client"
client-mode="true" auto-startup="false" retry-interval="10000" />
Autowiring as:
#Autowired
#Qualifier("inboundClient")
TcpReceivingChannelAdapter inboundClient;
My inboundClient is always null.
However when I do something as below, it works, without NPE, tc has object reference and starts the inbound adapter and receives data.
TcpReceivingChannelAdapter tc = (TcpReceivingChannelAdapter)
context.getBean("inboundClient");
Thread.sleep(5000);
tc.start();
Please let me know, if you have come across this or solved this.
EDIT:
I have my code posted here:
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
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
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<context:component-scan base-package="com.tcpclient" />
<context:annotation-config />
<!--Deserializer for incoming data on the socket -->
<bean
class="org.springframework.integration.ip.tcp.serializer.ByteArraySingleTerminatorSerializer"
id="serializeAndDeserializer">
<constructor-arg type="byte" value="0" />
</bean>
<!-- TCP Client configuration -->
<!-- Channels for communication -->
<int:channel id="tcp-client-input" />
<int:channel id="message" />
<int:channel id="message-serviceActivator" />
<int:gateway id="gateway" service-interface="com.tcpclient.ClientGateway"
default-request-channel="tcp-client-input" default-reply-channel="message" />
<int-ip:tcp-connection-factory id="clientFactory"
type="client" host="10.255.233.21" port="1234" single-use="false"
so-timeout="10000" deserializer="serializeAndDeserializer" serializer="serializeAndDeserializer" />
<int-ip:tcp-outbound-channel-adapter
id="outBoundClient" channel="tcp-client-input" connection-factory="clientFactory"
retry-interval="60000" auto-startup="false" />
<int-ip:tcp-inbound-channel-adapter
id="inBoundClient" channel="message" connection-factory="clientFactory"
client-mode="true" auto-startup="false" retry-interval="60000" />
<int:object-to-string-transformer
input-channel="message" output-channel="message-serviceActivator" />
<int:service-activator input-channel="message-serviceActivator"
method="onRtlsMessageArrival">
<bean class="com.tcpclient.HandleRtlsMessage" />
</int:service-activator></beans>
Config manager:
#component
public class RtlsConfigManager {
#Autowired
#Qualifier("inBoundClient")
TcpReceivingChannelAdapter inboundClient;
#Autowired
#Qualifier("outBoundClient")
TcpSendingMessageHandler outBoundClient;
public void initialize(Boolean canStart) {
try {
if (canStart) {
inboundClient.start();
outBoundClient.start();
}
} catch (Exception e) {
logger.error("Error occured while fetching data.");
}
}
}
Stack trace
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.integration.ip.tcp.TcpSendingMessageHandler] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=outBoundClient)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE]
If I take off below from existing code
#Autowired
#Qualifier("outBoundClient")
TcpSendingMessageHandler outBoundClient;
and
outBoundClient.start();
it starts my inBoundClient
Am I trying to autowire outBoundClient in a wrong way. Please let me know if you need more details.

You should inject these beans with type SmartLifeCycle not the TcpSendingMessageHandler type. The receiving adapter will work that way, though but since you want to use the lifecycle stuff it's better to narrow the type.
The sending handler actually has a bean name outBoundClient.handler but that's not what you want to start/stop, it is wrapped in a consumer (which implements SmartLifecyle and the type depends on the channel type; in this case, an EventDrivenConsumer).

Related

How to set port and connectionFactory during run time for Spring TCP integration

Basically, I am not aware of port before hand. I will make a REST request to a host to send the port number. I am getting the port number, but not able to move ahead as I am not able to set connection factory into inBoundClient with received port number. Please have a look at the code below, to understand the problem.
I have tcp connections defined as below:
<?xml version="1.0" encoding="UTF-8"?>
<context:component-scan base-package="com.tcpclient" />
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
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
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<context:annotation-config />
<!--Deserializer for incoming data on the socket -->
<bean
class="org.springframework.integration.ip.tcp.serializer.ByteArraySingleTerminatorSerializer"
id="serializeAndDeserializer">
<constructor-arg type="byte" value="0" />
</bean>
<!-- TCP Client configuration -->
<!-- Channels for communication -->
<int:channel id="tcp-client-input" />
<int:channel id="message" />
<int:channel id="message-serviceActivator" />
<int:gateway id="gateway" service-interface="com.tcpclient.ClientGateway"
default-request-channel="tcp-client-input" default-reply-channel="message" />
<int-ip:tcp-outbound-channel-adapter
id="outBoundClient" channel="tcp-client-input"
retry-interval="60000" auto-startup="false" />
<int-ip:tcp-inbound-channel-adapter
id="inBoundClient" channel="message"
client-mode="true" auto-startup="false" retry-interval="60000" />
<int:object-to-string-transformer
input-channel="message" output-channel="message-serviceActivator" />
<int:service-activator input-channel="message-serviceActivator"
method="onRtlsMessageArrival">
<bean class="com.tcpclient.HandleMessage" />
</int:service-activator>
</beans>
Config manager
In my class, I am trying below:
#component
public class ConfigManager {
#Autowired
#Qualifier("clientFactory")
TcpConnectionFactoryFactoryBean connFactory;
#Autowired
#Qualifier("inBoundClient")
SmartLifecycle inboundClient;
#Autowired
#Qualifier("outBoundClient")
SmartLifecycle outBoundClient;
public void initialize(Boolean canStart) {
try {
if (canStart) {
String portResponse = restTemplate.postForObject(SYSTEM_OPEN_SOCK_URI, openSockeEntity,
String.class);
int portNumber = parsePortFromJson(portResponse);
connFactory.setPort(portNumber);
TcpReceivingChannelAdapter receiver = (TcpReceivingChannelAdapter) inboundClient;
receiver.setConnectionFactory(connFactory);
receiver.start();
EventDrivenConsumer sender = (EventDrivenConsumer) outBoundClient;
sender.start();
}
} catch (Exception e) {
logger.error("Error occured while fetching data.");
}
}
}
But, at the line receiver.setConnectionFactory(connFactory);,
I have compiler error,
The method setConnectionFactory(AbstractConnectionFactory) in the type TcpReceivingChannelAdapter is not applicable for the arguments (TcpConnectionFactoryFactoryBean).
Is there anyway I could set port dynamically.
EDIT: As per Gary's suggestion,
#Autowired
#Qualifier("outboundClient.handler")
TcpSendingMessageHandler outBoundClient;`,
outBoundClient.setConnectionFactory(connFactory);
outBoundClient.setRetryInterval(60000);
outBoundClient.afterPropertiesSet();
outBoundClient.start();
But, I have this below error:
Dispatcher has no subscribers for channel 'application.tcp-client-input'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
when I try gateway.send("ACK"); one of my beans. but I have my outBoundClient having channel="tcp-client-input"
Since the port is set in a constructor, you can't change it after the bean is created.
You also can't change the port on a connection factory bean after is has already created its connection factory.
You need to create the connection factory yourself (new TcpNetClientConnectionFactory(...)) rather than have Spring create it - be sure to call afterPropertiesSet() after creating and configuring it and before you add it to the adapter.

Use Autowire to get sftpChannel configured in spring xml

I am using the following spring configuration to transfer a file from local folder to remote SFTP server.
<?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:int="http://www.springframework.org/schema/integration"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/sftp
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp-2.2.xsd">
<bean id="sftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="xxxxxxx" />
<property name="knownHosts" value = "C:\knownhosts"/>
<property name="user" value="wildfly" />
<property name="password" value="w!ldfly" />
<property name="port" value="22" />
</bean>
<int:channel id="sftpChannel" />
<sftp:outbound-channel-adapter id="triggerFtpOutBound" channel="sftpChannel"
session-factory="sftpSessionFactory" remote-directory="/home/wildfly">
</sftp:outbound-channel-adapter>
I am using the following code to send file.
#Autowired
private MessageChannel sftpChannel;
Function()
{
File f = new File("c:/test.txt");
Message<File> message = MessageBuilder.withPayload(f).build();
sftpChannel.send(message);
}
I am getting null pointer exception at sftpChannel.send(message). How can i autowire sftpChannel in my code?
The following code works. But, i want to Autowire sftpChannel.
ApplicationContext context = new ClassPathXmlApplicationContext("spring/config/spring-sftp.xml");
MessageChannel sftpChannel = context.getBean("sftpChannel", MessageChannel.class);
File f = new File("c:/test.txt");
Message<File> message = MessageBuilder.withPayload(f).build();
sftpChannel.send(message);
In order to use autowired you need to include
<context:annotation-config />
to your configuration file
<beans
//...
xmlns:context="http://www.springframework.org/schema/context"
//...
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
//...
<context:annotation-config />
//...
</beans>
Here, there is a full example
http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/
Autowiring works the same as any Spring application; the bean that gets the autowired channel must be declared as a bean in the context.
You can always debug Spring bean wiring by enabling DEBUG logging for org.springframework.
The framework puts out lots of information while wiring classes.
I'm not sure in your code, but that looks like you are going to use an #Autowired property from the constructor.
For this purpose you have to use the constructor injection.
Even if your Function is a valid Spring bean, it is a bad idea to send any message from the constructor.
Please, revise your design and read more books about Spring.

Spring Injection using #Autowired

I'm having a bad time trying to run my program using Spring #Autowired annotation.
Just to explain you what I'm trying to do, I have a main controller class, MainController, that always uses two other classes (SquadraController class and UserController class) to do some work.
Instead of instantiating these classes any time I need them, I decided to declare them as instance variables with the #Autowired annotation and call them any time I need them.
So I have my instance variables with #Autowired annotation and declared the beans in the context xml file, but I get the following error and I can't get out of it:
20/03/2015 15:10:00 - WARN - (AbstractApplicationContext.java:487) - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.fabrizio.fantavalcanneto.controller.UserController org.fabrizio.fantavalcanneto.controller.MainController.userController; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.fabrizio.fantavalcanneto.controller.UserController] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:663)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:629)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:677)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:548)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:489)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
This is my MainController class (the snippet that raises the error):
#Controller
public class MainController {
private static final Logger logger = LoggerFactory.getLogger(MainController.class);
#Autowired
private UserController userController;
#Autowired
private SquadraController squadraController;
This is the xml file where I declare my beans (I also tried to declare MainController bean without declaring the instance variables as properties):
<?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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="org.fabrizio.fantavalcanneto.controller" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="userController" class="org.fabrizio.fantavalcanneto.controller.UserController" >
</bean>
<bean id="mainController" class="org.fabrizio.fantavalcanneto.controller.MainController">
<property name="userController" value="userController"></property>
<property name="squadraController" value="squadraController"></property>
</bean>
<bean id="squadraController" class="org.fabrizio.fantavalcanneto.controller.SquadraController">
</bean>
</beans>
UserController and SquadraController have no instance variables.
If you are context component scanning you don't need to define the beans in the config file, something like this will work. All you need is #Controller annoation on the relevant classes :
<context:component-scan base-package="org.fabrizio.fantavalcanneto.controller" />
// for default converters etc add this aswell
<mvc:annotation-driven/>
Just check you have the correct base package/typos

Spring 4.1 #Qualifier doesnt'work

I have classes, xml configuration file and error stack trace like this. I have no idea why #Qualifier doesn't work. I see on errors that he don't even do anything.
DOG
public class SimpleDog implements Dog {
#Autowired
#Qualifier("small")
private Size size;
private String name;
public Size getSize() {
return size;
}
public void setSize(Size size) {
this.size = size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public void giveSound() {
System.out.println("dog size is : width : (" + size.getWidth() + ") , height : (" + size.getHeight() + ")");
System.out.println("dog's name : " + name);
}
}
TEST CLASS
public class Test2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-test2.xml");
SimpleDog dog = (SimpleDog) context.getBean("dog");
dog.giveSound();
}
}
spring.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="dog" class="com.tests.test2.SimpleDog">
<property name="name" value="Puppy" />
</bean>
<bean id="size1" class="com.tests.test2.Size">
<qualifier value="small"/>
<property name="height" value="2"/>
<property name="width" value="1"/>
</bean>
<bean id="size2" class="com.tests.test2.Size">
<qualifier value="large"/>
<property name="height" value="20"/>
<property name="width" value="10"/>
</bean>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
</beans>
Error Stack Trace
WARNING: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dog': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.tests.test2.Size com.tests.test2.SimpleDog.size; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
at pl.patrykgryta.test2.Test2.main(Test2.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.tests.test2.Size com.tests.test2.SimpleDog.size; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:555)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 18 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1016)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527)
... 20 more
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dog': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.tests.test2.Size com.tests.test2.SimpleDog.size; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
at pl.patrykgryta.test2.Test2.main(Test2.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.tests.test2.Size com.tests.test2.SimpleDog.size; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:555)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 18 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1016)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527)
... 20 more
Need help
Probably your ApplicationContext's BeanFactory is configured with default AutowireCandidateResolver (i.e. SimpleAutowireCandidateResolver) instead of QualifierAnnotationAutowireCandidateResolver.
In previous versions of Spring (before 4.0), QualifierAnnotationAutowireCandidateResolver was set during creation of most ApplicationContexts (compare AbstractRefreshableApplicationContext.customizeBeanFactory(DefaultListableBeanFactory) implementations).
Currently, QualifierAnnotationAutowireCandidateResolver for AppCtx is/can be applied by:
org.springframework.beans.factory.annotation.CustomAutowireConfigurer (see javadoc and implementation of postProcessBeanFactory(ConfigurableListableBeanFactory) method), e.g. add to your xml:
<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>org.springframework.beans.factory.annotation.Qualifier</value>
</set>
</property>
<context:annotation-config /> (see: AnnotationConfigBeanDefinitionParser.parse(Element,ParserContext) and related)
#Qualifier is used to reference a bean by its name or id. Since it can't find an xml entry that has a name or id of 'small' it tries to match by type, of which it found two instances of Size.
The following would work:
<bean id="small" class="com.tests.test2.Size">
<property name="height" value="2"/>
<property name="width" value="1"/>
</bean>
Though it appears you would like to treat instances of Size as pre-configured beans. If that were the case you could declare instances of Dog in your xml file and refer to Size beans ... something like this:
<bean id="rex" class="com.tests.test2.SimpleDog">
<property name="name" value="Puppy" />
<property name="size" ref="size1"/>
</bean>
#Qualifier(name="..") annotation and give the name of the bean that we want Spring to inject
and name of your beans are size1 and size2 .
so try
#Qualifier("size1")
#Qualifier("small") means you look for a bean named "small" (bean id="small" ...) #Autowired means you look for a bean with a type that matchs.
It makes sense to use this two configurations together in some cases. It means: look for a bean named like that, and if you don't find, then look for a bean with the correct type. This can be powerful, very.
From the Spring documentation, you can declare who is "small" with an xml qualifier, as you did. But in their example there is NO id="..." I don't know if it makes sense to define both qualifier and id. So I suppose (I don't test) you can repair your example by removing the parts id="sizeX"
As says your stacktrace
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.tests.test2.Size] is defined: expected single matching bean but found 2: size1,size2
Spring can't match a single bean to inject because he find 2 beans that could using, for this reason will thrown this exception.
Exception thrown when a BeanFactory is asked for a bean instance for
which multiple matching candidates have been found when only one
matching bean was expected.
Reference of Exception
Anyway you're using this thing in the wrong way, because there isn't any bean with id="small"
You must change #Qualifier("small") to #Qualifier("size1") or #Qualifier("size2").
In Spring 4.x you should work with the following XML schema in order for this to work for you:
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.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
and you should add the following tag:
<context:component-scan base-package="com.tests.test2" />
So the following XML should solve your problem (it solved mine :) ):
<?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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.tests.test2" />
<bean id="dog" class="com.tests.test2.SimpleDog">
<property name="name" value="Puppy" />
</bean>
<bean id="size1" class="com.tests.test2.Size">
<qualifier value="small"/>
<property name="height" value="2"/>
<property name="width" value="1"/>
</bean>
<bean id="size2" class="com.tests.test2.Size">
<qualifier value="large"/>
<property name="height" value="20"/>
<property name="width" value="10"/>
</bean>
</beans>
See more here.
We have struts 1.x used with Spring 3.x in our project. In the process of upgrading from spring 3->4, our qualifier annotation in the struts action does not work any more. After digging in and compare the Spring 3 and 4, finally found the reason.
reason1: QualifierAnnotationAutowireCandidateResolver is not the default resolver in spring 4
In Spring 3, after we create our beanfacotry in the application context, Spring will explicitly call :
beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
In spring 4, it is not called any more in the AbstractRefreshableApplicationContext’s
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory)
So for the parent(root) context, it should still work as is if you have the in the config xml. However for the child context the default resolver will become ‘SimpleAutowireCandidateResolver’
reason2: The child resolver is passed to parent when trying to determine ‘isAutowireCandidate()’ in Spring 4’s DefaultListableBeanFactory
The isAutowireCandidate() will delegate the responsibility to parent beanFactory if it cannot make decision.
In Spring 3, the delegation does not pass the resolver to the parent so that parent context uses its own resolver to call the isAutowireCandidate(). However in Spring 4, it changes. The resolver is passed as a parameter to the parent who uses it to call the isAutowireCandidate(). So even the parent has a ContextAnnotationAutowireCandidateResolver which extends QualifierAnnotationAutowireCandidateResolver as its resolver, it still does not help.
The #a5phyx solution should work if it is added to the child's application context xml.
Try using this bean definition in your beans.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:annotation-config/>
<!-- define your beans here-->
</beans>

Spring MVC MongoDB integration

I would like to create Spring MVC sample with mongoDB by this tutorial http://spring.io/guides/gs/accessing-data-mongodb/. I try #Autowired for CustomerRepository repository into my #Controller class, but I receive org.springframework.beans.factory.BeanCreationException for repository class member with exception message "....No matching bean of type [com.mvc.venko.CustomerRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency..."
My #Controller class and CustomerRepository are in same package.
I can't get the problem causing this exception.
PS: using springFramework 3.1.1.RELEASE, spring-data-mongodb 1.4.2.RELEASE
EDIT:
Complete conf.xml structure for resolving problem. Please switch to Spring 3.2.5
<?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:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<mongo:repositories base-package="com.mvc.venko" />
<mongo:mongo host="127.0.0.1" port="27017" />
<mongo:db-factory dbname="yourdb" write-concern="NONE" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
</beans>
I think you don't configure a bean of CustomerRepository type.
You can do this with this line in your spring-config.xml:
<mongo:repositories base-package="/path to your repository package/" />
more docs here

Categories

Resources