SimpMessagingTemplate no qualifying bean of type - spring

I'm trying to use the SimpMessagingTemplate class in my project to send some data via websocket.
The problem is that I always have an error, here is the complete error:
Error creating bean with name 'webSocketUserNotificationManagerImpl' defined in URL [...]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.messaging.simp.SimpMessagingTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
And here is the webSocketuserNotificationManagerImpl service:
#Service
public class WebSocketUserNotificationManagerImpl implements UserNotificationManager {
/**
* Template to use to send back a message to the user via Web-socket.
*/
private SimpMessagingTemplate template;
public WebSocketUserNotificationManagerImpl(SimpMessagingTemplate template) {
this.template = template;
}
private ObjectMapper jsonMapper = new ObjectMapper();
#Override
public void sendMessageToUser(String jobName, String eventType, Result result) {
....
}
public void sendDeleteMessageToUser(DeleteRequestsSocketMessage message, Principal principal) {
this.template.convertAndSendToUser(principal.getName().toLowerCase(),
"/status/delete", message);
}
}
I have this dependency in my pom:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
</dependency>
What is wrong, why the SimpMessagingTemplate bean doesn't exist ?

Okay so the bean SimpMessagingTemplate is not found in your application context .So make sure that the bean is getting created by spring automatically in the application context at startup and the annotations are provided as necessary for the creation like :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
}
Try using constructor injection like :
#Autowired
public WebSocketUserNotificationManagerImpl(SimpMessagingTemplate template) {
this.template = template;
}

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
has been deprecated.
You can add dependency –
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Then implement WebSocketMessageBrokerConfigurer

Related

Migrate an application to Spring boot 3.0 which uses camel-spring-boot-starter while waiting for Camel 4

I am migrating an application to Spring boot 3.0, but I have a problem with the injection of a ProducerTemplate in one of my services (annotation #Service se Spring Boot).
I was using the Spring Boot starter from Camel
Current Spring Boot version is : 2.7.5
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-rabbitmq-starter</artifactId>
<version>3.15.0</version>
</dependency>
My ProducerTemplate is injected into the constructor of my service that extends RouteBuilder
#Service
public class MyServiceImpl extends RouteBuilder implements MyService {
private final ProducerTemplate producerTemplate;
#Autowired
public MyServiceImpl(ProducerTemplate producerTemplate) {
this.producerTemplate = producerTemplate;
}
At startup, the application crashes with this message :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mycompany.ServiceImpl required a bean of type 'org.apache.camel.ProducerTemplate' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.apache.camel.ProducerTemplate' in your configuration.
It's not very clear to me how I should take it.
I guess I have to use the dependency
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>3.15.0</version>
</dependency>
instead of
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.15.0</version>
</dependency>
But I don't really know how I should instantiate the ProducerTemplate and the CamelContext ?
I tried without really believing something like this :
#Configuration
public class CamelConfig {
#Bean
public CamelContext getCamelContext() throws Exception {
CamelContext context = new DefaultCamelContext();
if (context.isStopped()) context.start();
return context;
}
#Bean
public ProducerTemplate getProducerTemplate() throws Exception
{
final ProducerTemplate template = getCamelContext().createProducerTemplate();
return template;
}
}
#Service
public class MyServiceImpl implements MyService {
private final ProducerTemplate producerTemplate;
private CamelContext context;
#Autowired
public MyServiceImpl(ProducerTemplate producerTemplate, CamelContext context) {
this.producerTemplate = producerTemplate;
this.context = context;
try {
this.context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:update-legacy")
.to("bean:updateJdbc");
The app failed with the following error message :
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: bean://updateJdbc due to: No bean could be found in the registry for: updateJdbc

Creating message queue in spring boot using apache camel

I'm very newbie to this messaging queue and just started learning some basic stuffs in this.
So for our spring boot application we followed an architecture like contoller talks to service & service talks to repository so here i have to create one controller that will accept a class DTO as a json and post these information to the message queue specified in the apache camel.
I'm following this link ! for my reference that works well but when i tried to implement it in my project , it saying me an error listed below.
Error
Exception encountered during context initialization - cancelling
refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'trackerQueueController': Unsatisfied
dependency expressed through field 'camelContext'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'org.apache.camel.CamelContext' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I have created an controller,routes & processor as below:
Controller
#RestController
#RequestMapping("/deviceinfo")
public class TrackerQueueController {
#Autowired
CamelContext camelContext;
#Autowired
private
ProducerTemplate producerTemplate;
#PostMapping()
public void startCamel(#RequestBody FieldUpdate fieldUpdate) {
producerTemplate.sendBody("activemq:topic:in", fieldUpdate);
}
}
Routes
#Component
public class TrackerQueueRoutes extends RouteBuilder {
#Override
public void configure() throws Exception {
from("activemq:topic:in")
.process(new TrackerProcessor() {
#Override
public void process(Exchange exchange) throws
Exception {
log.info("I'm in");
FieldUpdate body =
exchange.getIn().getBody(FieldUpdate.class);
log.info("Hello from camel processed message!
Received payload: {}" , body.getSerialNumber());
exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE,
HttpStatus.ACCEPTED);
}
});
}
}
Processor
public class TrackerProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
}
}
Can any one provide me some tutorial link that fulfil my need or any ideas.
As Claus Ibsen suggested in the comments, you have to add these dependencies to your POM file
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>[camel-version]</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
camel-spring-boot-starter automatically starts a CamelContext for you, discovers routes etc
spring-boot-starter-web keeps your application running by listening for web requests. Otherwise it would immediately shut down after startup because there is nothing to execute.
Since your Camel route class is correctly annotated (#Component) and subclassed (extends RouteBuilder), it should be auto-discovered by the Camel SpringBoot starter.
See the Camel-SpringBoot docs for all these topics and more.

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);

Autowiring not working in SpringBoot controller

Hi i was trying to work over an existing SpringBoot application. I created a service class and tried to autowire it in the existing controller, but when trying to build, its failing saying bean injection failed.
Cause: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'controller': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private
com.disooza.www.card.dispenser.service.FilaPartnerService
com.disooza.www.card.dispenser.controller.CardDispenserController.FilaPartnerService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.disooza.www.card.dispenser.service.FilaPartnerService] 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)
Following is my controller class:
#Controller
#RequestMapping(value = "/service")
public class CardController {
private static final Logger LOGGER = LoggerFactory.getLogger(CardController.class);
#Autowired
private CardDao dao;
#Autowired
private PaymentService paymentService;
#Autowired
private FilaPartnerService filaPartnerService;
FilaPartnerService is the newly created interface, and rest all autowires are working fine in this controller.
Interesting thing is when I try to place this service class in any other controller it is working fine. Any help over this issue will be appreciated, since I'm stuck with it.
This is my service interface:
#Service
public interface FilaPartnerService {
RetrievePaymentTokenResponse retrieveXXX(SupplierRequest request);
}
This is the implementation class:
#Component
public class FilaPartnerServiceImpl implements FilaPartnerService {
#Autowired
private RestTemplate restTemplate;
#Autowired
private RetrieveRequestBuilder retrieveRequestBuilder;
#Value("${filaPartner.url}")
private String filaServiceUrl;
#Override
public RetrievePaymentTokenResponse retrieveFilaPaymentToken(SupplierTokenRequest request) {
RetrievePaymentTokenResponse tokenResponse = null;
RetrievePaymentTokenRequest paymentServiceRequest = retrievePaymentTokenRequestBuilder.retrievePaymentTokenRequestBuilder(request);
try {
tokenResponse =
restTemplate.postForObject( FilaServiceUrl, paymentServiceRequest, RetrievePaymentTokenResponse.class);
} catch (RestClientException exp) {
//TO-DO return error code
}
return null;
}
}

How to create a Spring bean for apache logging Log class?

I'd like to create an autowired bean in a Dao class in order to do logging opperations. My way was hitherto static final statement like this:
private static final Log log = LogFactory.getLog(LoggedClass.class);
But now I'm trying to use IoC to turn classes decoupled.
If just add configuration in pom.xml and try to do sth like
#Autowired
Log log;
I receive an error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'funciDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.apache.commons.logging.Log br.com.bb.dirco.dao.impl.FunciDaoImpl.log; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'log' defined in class path resource [com/company/project/util/PersistenceConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.Class]: : No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
In order to get a logger, I had to provide a class to getLog method on LogFactory class and attribute it to Log instance. There's a way to do it using #Autowired Spring IoC? Thanks!
You can inject only those objects which are managed/created by Spring container. You have to register your bean (or factory method creating the bean) with container (with annotations like #Component/#Singleton/... or directly in xml)
In your case it's not very applicable since you have to have many different types (for every class) of logger objects provided by Spring and then when you inject they would have to be identified by different name/type for every class.
P.S. I don't see any problem using it the way you use it now
Where I work we have implemented support for #Autowired SLF4J Loggers using Springs BeanPostProcessor.
First you need to define an Logger placeholder bean in your application context. This bean is going to be injected by Spring into all bean with a #Autowired Logger field.
#Configuration
public class LoggerConfig {
#Bean
public Logger placeHolderLogger() {
return PlaceHolder.LOGGER;
}
#Bean
public AutowiredLoggerBeanPostProcessor loggerPostProcessor() {
return new AutowiredLoggerBeanPostProcessor();
}
}
Then you an AutowiredLoggerBeanPostProcessor which inspects all beans, indetify bean that contain Logger fields annotated with #Autowired (at this point should contain a reference to the Logger placeholder bean), create a new Logger for the partilcar bean an assigned it to the fields.
#Component
public class AutowiredLoggerBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
private void attachLogger(final Object bean) {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
if (Logger.class.isAssignableFrom(field.getType()) &&
(field.isAnnotationPresent(Autowired.class) ||
field.isAnnotationPresent(Inject.class))) {
ReflectionUtils.makeAccessible(field);
if (field.get(bean) == PlaceHolder.LOGGER) {
field.set(bean, LoggerFactory.getLogger(bean.getClass()));
}
}
}
});
}
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}

Resources