Spring Boot could not autowire and run - spring

I am unable to run the attached Spring Boot sampler application. It has an AMQP starter, requiring RabbitMQ. Fundamentally, it is a simple application that just sends a message to a RabbitMQ Exchange with a queue bound to it. I get the following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.messaging.MessageDeliveryManager com.company.exec.Application.messageDeliveryManager; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.company.messaging.MessageDeliveryManager] 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)}
Application.java
package com.company.exec;
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
MessageDeliveryManager messageDeliveryManager;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public void run(String... args) throws Exception {
messageDeliveryManager.sendMessage(String message);
}
}
MessageDeliveryManager.java
package com.company.messaging;
public interface MessageDeliveryManager {
void sendMessage(String message);
}
MessageDeliveryImpl.java
package com.company.messaging;
public class MessageDeliveryManagerImpl implements MessageDeliveryManager {
#Value("${app.exchangeName}")
String exchangeName;
#Value("${app.queueName}")
String queueName;
#Autowired
RabbitTemplate rabbitTemplate;
#Bean
Queue queue() {
return new Queue(queueName, false);
}
#Bean
DirectExchange exchange() {
return new DirectExchange(exchangeName);
}
#Bean
Binding binding(Queue queue, DirectExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(queueName);
}
public void sendMessage(String message) {
rabbitTemplate.send(queueName, message);
}
}
I would really appreciate if someone can review and provide a suggestion on what I am doing wrong.

Since you have a package tree like this:
com.company.exec
com.company.messaging
and just use a default #SpringBootApplication, it just doesn't see your MessageDeliveryManager and its implementation. That's because #ComponentScan (the meta-annotation on the #SpringBootApplication) does a scan only for the current package and its subpackages.
To make it worked you should add this:
#SpringBootApplication
#ComponentScan("com.company")
Or just move your Application to the root package - com.company.

Related

Replacing a Spring bean that have Autowired dependency during testing

I am trying to get Spring to replace a class that has autowired dependencies with another (test class) that do not have these autowire dependencies, but I always end up with a NoSuchBeanDefinitionException like this:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.experiments.beanreplacement.client.Connection' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I have created a simplifed example to show my problem.
I have two classes in my client package (Connection.java and TcpClient.java) and two in my application package (MessageSender.java and Scheduler.java)
package com.experiments.beanreplacement.client;
#Component
public class Connection {
public void send(String msg) { System.out.println("Connection send: " + msg); }
...
The TcpClient.java autowires the Connection class:
#Component
public class TcpClient {
#Autowired
Connection connection;
public void send(String msg) {
System.out.println("TcpClient send");
connection.send(START_OF_MESSAGE + msg + END_OF_MESSAGE);
}
}
The MessageSender class use the TcpClient to send messages:
package com.experiments.beanreplacement.application;
#Component
public class MessageSender {
#Autowired
TcpClient client;
public void sendAMessage() {
client.send("Hello world!");
client.send("Bye bye...");
}
}
I have set up a test to run this using JUnit:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/applicationContext.xml"})
public class MessageSenderTest {
#Autowired
MessageSender messageSender;
#Test
public void testMessageSender() {
messageSender.sendAMessage();
}
}
TcpClientMock class:
package client;
#Primary
public class TcpClientMock extends com.experiments.beanreplacement.client.TcpClient{
#Override
public void send(String msg) {
System.out.println("Mock client send: " + msg);
}
...
applicationContext.xml
<bean class="client.TcpClientMock" name="client" >
</bean>
<context:component-scan base-package="com.experiments.beanreplacement.application">
</context:component-scan>
...
In the applicationContext.xml file, I replace the TcpClient which is autowired in the MessageSender class with another (TcpClientMock).
I have adjusted the component-scan to only look at the path of the MessageSender and TcpClientMock, hoping to avoid having to deal with the autowire dependencies of the original TcpClient and underlying Connection.
However, I still get the "No qualifying bean of type 'com.experiments.beanreplacement.client.Connection' available: expected at least 1 bean which qualifies as autowire candidate." error even though the class using the autowire dependency is not part of the component-scan.
Is there a way to avoid this?
You should be able to Mock your TcpClient bean with #MockBean. In you test add:
#MockBean
TcpClient client;
in your test method you can specify the behavior of the send() method like so:
String msg = "anything";
doAnswer(i -> {
System.out.println("Mock client send: " + msg);
return null;
}
).when(client).send(msg);

Intellij Spring: NoSuchBeanDefinitionException: No bean named 'accountDAO' available

This is driving me nuts. I have the following files, it is a very simple setup.
public class MainApp {
public static void main(String[] args) {
//read the spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("Config.class");
//System.out.println("Bean names: " + Arrays.toString(context.getBeanNamesForType(AccountDAO.class)));
//get the bean from spring container
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
//call the business method
accountDAO.addAccount();
//close the spring context
context.close();
}
}
Config.java:
#Configuration
#ComponentScan("com.aop")
#EnableAspectJAutoProxy
public class Config {
}
LoggingAspectDemo.java:
#Aspect
#Component
public class LoggingAspectDemo {
//this is where we add all our related advices for the logging
//let's start with an #Before advice
#Before("execution(public void addAccount())")
public void beforeAddAccountAdvice() {
System.out.println("\n=======>>>> Executing #Before advice on method addAccount() <<<<========");
}
}
AccountDAO.java
#Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": Doing my Db work: Adding an account");
}
}
Everytime I run the MainApp.java, I get:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'accountDAO' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
All the files are under "com.aop" package so #ComponentScan should be scanning all the components. It looks simple enough but I can't get my hands around the problem, can anyone help me where I am going wrong?
You're invoking the constructor of AnnotationConfigApplicationContext with "Config.class" as String argument, but this constructor is actually for invoking with base packages i.e. the argument must be a package name.
Since you want to use it with the Configuration class, use the constructor which accepts Class instance instead i.e.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

Spring factory - NoUniqueBeanDefinitionException:

I am trying to implement factory pattern to get producer from a list of available ones. While doing it i am getting the below exception. Not able to figure out the issue with the code. Can you please let me know what i am missing.
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
Please find the code below
public interface Producer<T> {
public void start();
public List<T> produce() throws CEHServiceException;
public void stop();
}
#Component("A")
public class ProducerA extends Producer {
//Autowire Services & Properties
}
#Component("B")
public class ProducerB extends Producer {
//Autowire Services & Properties
}
#Configuration
public class AgentConfiguration {
#Bean
public ServiceLocatorFactoryBean createProducerFactoryBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(ProducerFactory.class);
return bean;
}
}
public interface ProducerFactory {
Producer getProducer(String producerName);
}
#Component
public class AdvancedAgentProcessor {
#Autowired
private ObjectFactory<AdvancedRunnerImpl> runnerFactory;
public void init(){
AdvancedRunnerImpl runner = runnerFactory.getObject();
runner.setProducerName("A");
runner.start();
}
}
#Component
#Scope("prototype")
public class AdvancedRunnerImpl implements Runner {
#Autowired private ProducerFactory producerFactory;
private Producer producer;
private String producerName;
public void start() {
producer = producerFactory.getProducer(this.producerName);
}
}
Full stack tracke
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.etl.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invokeServiceLocatorMethod(ServiceLocatorFactoryBean.java:377)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invoke(ServiceLocatorFactoryBean.java:363)
at com.sun.proxy.$Proxy34.getProducer(Unknown Source)
at com.test.runner.AdvancedRunnerImpl.start(AdvancedRunnerImpl.java:54)
at com.test.app.AdvancedAgentProcessor.init(AdvancedAgentProcessor.java:48)
at com.test.app.DataAgentApplication.main(DataAgentApplication.java:25)
Spring does not know which component to autowire. It seems that the problem is in the ProducerFactoryImplementation but we cannot see it.
There are three possible solutions:
Use Qualifiers so you can tell Spring which specific implementation you want.There is an example in StackOverflow
here
Use the Primary annotation (See more here3). That means that in case of ambiguity Spring will give priority to the #Primary annotated component
Autowire a list of beans. Something like:
#Autowired private List<Producer> myAvalilableProducers;
public Producer getByName(name){
for( Producer producer: myAvalilableProducers){
if(producer.getName().equals(name)){ return producer; }
}
throw new RuntimeException("No producer with name " + name " found");
}
This third option more useful when you do not know the specific instance at compile time or if you really want to inject a list of components.
You have two beans that extend Producer. Somewhere you are trying to autowire a Producer. Spring does not know which Producer to use.
This happens when the dynamic proxy is not able to pick the correct Bean. Please check whether this.producerName is null or empty.

With Spring boot and integration DSL, getting error ClassNotFoundException integration.history.TrackableComponent

Trying a very basic JMS receiver using Spring Boot, Integration and DSL. I have worked on XML based on Spring Integration, but am new to Spring Boot and DSL.
This is a code sample that I have so far
#SpringBootApplication
#IntegrationComponentScan
#EnableJms
public class JmsReceiver {
static String mailboxDestination = "RETRY.QUEUE";
#Configuration
#EnableJms
#IntegrationComponentScan
#EnableIntegration
public class MessageReceiver {
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(this.connectionFactory())
.destination(mailboxDestination))
.transform((String s) -> s.toUpperCase())
.get();
}
//for sneding message
#Bean
ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory acFac = new ActiveMQConnectionFactory();
acFac.setBrokerURL("tcp://crsvcdevlnx01:61616");
acFac.setUserName("admin");
acFac.setPassword("admin");
return new CachingConnectionFactory(acFac);
}
}
//Message send code
public static void main(String args[]) throws Throwable {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JmsReceiver.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
System.out.println("Sending a new mesage.");
MessageCreator messageCreator = new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("ping!");
}
};
jmsTemplate.send(mailboxDestination, messageCreator);
context.close();
}
}
And, I get this error when running with Gradle.
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFlow' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/integration/history/TrackableComponent
reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.
.
.
Caused by: java.lang.ClassNotFoundException: org.springframework.integration.history.TrackableComponent
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
My gradle dependencies:
compile "org.springframework.boot:spring-boot-starter-jersey",
"org.springframework.boot:spring-boot-starter-actuator",
"org.springframework.boot:spring-boot-configuration-processor",
"org.springframework.boot:spring-boot-starter-integration",
"org.springframework.integration:spring-integration-jms",
"org.springframework.integration:spring-integration-java-dsl:1.1.1.RELEASE",
"org.springframework.integration:spring-integration-flow:1.0.0.RELEASE",
"org.springframework.integration:spring-integration-core:4.2.2.RELEASE",
"org.springframework.integration:spring-integration-java-dsl:1.1.0.RELEASE",
"org.springframework.integration:spring-integration-flow:1.0.0.RELEASE",
"org.apache.activemq:activemq-spring:5.11.2",
UPDATE.. SOLVED: Thanks much. Changed two things:
Cleaned up gradle dependencies based on your advice. New ones looks like this:
compile "org.springframework.boot:spring-boot-starter-jersey",
"org.springframework.boot:spring-boot-starter-actuator",
"org.springframework.boot:spring-boot-configuration-processor",
"org.springframework.boot:spring-boot-starter-integration",
"org.springframework.integration:spring-integration-jms",
"org.springframework.integration:spring-integration-java-dsl:1.1.0.RELEASE",
"org.apache.activemq:activemq-spring:5.11.2"
Code was throwing constructor error about not being able to instantiate <init> in the inner class. Changed the Inner class to static. New Code:
#SpringBootApplication
#IntegrationComponentScan
#EnableJms
public class JmsReceiver {
static String lsamsErrorQueue = "Queue.LSAMS.retryMessage";
static String fatalErrorsQueue = "Queue.LSAMS.ManualCheck";
//receiver
#EnableJms
#EnableIntegration
#Configuration
public static class MessageReceiver {
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(this.connectionFactory())
.destination(lsamsErrorQueue))
//call LSAMS REST service with the payload received
.transform((String s) -> s.toUpperCase())
.handle(Jms.outboundGateway(this.connectionFactory())
.requestDestination(fatalErrorsQueue))
.get();
}
#Bean
ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory acFac = new ActiveMQConnectionFactory();
acFac.setBrokerURL("tcp://crsvcdevlnx01:61616");
acFac.setUserName("admin");
acFac.setPassword("admin");
return new CachingConnectionFactory(acFac);
}
}
//Message send code
public static void main(String args[]) throws Throwable {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JmsReceiver.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
System.out.println("Sending a new mesage.");
MessageCreator messageCreator = new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("ping!");
}
};
jmsTemplate.send(lsamsErrorQueue, messageCreator);
context.close();
}
}
Well, that fully looks like you have a version mess in your classpath.
First of all you shouldn't mix the same artifacts manually, like you have with spring-integration-java-dsl and spring-integration-flow. BTW, do you really need the last one?.. I mean is there some reason to keep spring-integration-flow? This project is about Modular Flows.
From other side you don't need to specify spring-integration-core if you are based on the Spring Boot (spring-boot-starter-integration in your case).
And yes: the TrackableComponent has been moved to the org.springframework.integration.support.management since Spring Integration 4.2 (https://jira.spring.io/browse/INT-3799).
From here it looks like you use the older Spring Integration version somehow:
- or Spring Boot 1.2.x
- or it is really side-effect of transitive dependency from spring-integration-flow...

Spring JavaConfig + JAX-WS Client

I need to create a webservice client to get sportsdata.
But I'm getting an exception when trying to #Autowired sportsdata.
Exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [de.openligadb.schema.SportsdataSoap] 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)}
JavaConfig:
#Configuration
#ComponentScan(basePackages = "com.example", excludeFilters = { #Filter(Configuration.class) })
public class MainConfig {
private #Value("${openligadb.wsdlDocumentUrl}") String wsdlDocumentUrl;
private #Value("${openligadb.endpointAddress}") String endpointAddress;
private #Value("${openligadb.namespaceUri}") String namespaceUri;
private #Value("${openligadb.serviceName}") String serviceName;
#Bean
public JaxWsPortProxyFactoryBean sportsdata() throws MalformedURLException {
JaxWsPortProxyFactoryBean ret = new JaxWsPortProxyFactoryBean();
ret.setWsdlDocumentUrl(new URL(wsdlDocumentUrl));
ret.setServiceInterface(SportsdataSoap.class);
ret.setEndpointAddress(endpointAddress);
ret.setNamespaceUri(namespaceUri);
ret.setServiceName(serviceName);
return ret;
}
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer ret = new PropertySourcesPlaceholderConfigurer();
ret.setLocation(new ClassPathResource("application.properties"));
return ret;
}
}
And yes: I know of #PropertySource but I need to create a bean for it to use it later in my Controller as well.
It's a FactoryBean interoperability problem with #Configuration. Take a look at this answer for details.
The short version is to add a bean explicitly to your configuration.
#Bean
public SportsdataSoap sportsdataSoap() throws ... {
return (SportsdataSoap) sportsdata().getObject();
}

Resources