MessageDispatchingException: Dispatcher has no subscribers - spring-boot

Having a simple Spring Cloud Stream setup.
The interface
public interface MyKafkaBinding {
#Output(PUBLISHER)
MessageChannel publisher();
#Input("subscriber")
SubscribableChannel subscriber();
}
Binding
#EnableBinding(MyKafkaBinding.class)
Listener
#StreamListener(MyKafkaBinding.PUBLISHER)
public void listen(MyEvent message) {
// handle
}
App properties
spring.cloud.stream.bindings.publisher.destination=my-kafka-topic
spring.cloud.stream.bindings.publisher.producer.header-mode=headers
spring.cloud.stream.bindings.publisher.content-type=application/json
spring.cloud.stream.bindings.subscriber.destination=my-kafka-topic
spring.cloud.stream.bindings.subscriber.consumer.header-mode=headers
spring.cloud.stream.bindings.subscriber.content-type=application/json
It all works fine. Messages sent using the publisher are received.
Now I'm trying to send a message to this topic from another app, using KafkaTemplate:
kafkaTemplate.send(topic, message)
This time an error is thrown on the receiving side:
Caused by: org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'MyApp.subscriber'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=com.bax.so.MyEvent#6da11fec, headers={b3=[B#304c5b9f, kafka_offset=10, scst_nativeHeadersPresent=true, kafka_consumer=org.apache.kafka.clients.consumer.KafkaConsumer#742c6888, deliveryAttempt=3, kafka_timestampType=CREATE_TIME, kafka_receivedMessageKey=null, kafka_receivedPartitionId=0, kafka_receivedTopic=my-kafka-topic, kafka_receivedTimestamp=1578085559878, kafka_groupId=my-default-group-id}]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:453)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:401)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:187)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:166)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:109)
at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:205)
at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.sendMessageIfAny(KafkaMessageDrivenChannelAdapter.java:369)
at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.access$400(KafkaMessageDrivenChannelAdapter.java:74)
at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$IntegrationRecordMessageListener.onMessage(KafkaMessageDrivenChannelAdapter.java:431)
at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$IntegrationRecordMessageListener.onMessage(KafkaMessageDrivenChannelAdapter.java:402)
at org.springframework.kafka.listener.adapter.RetryingMessageListenerAdapter.lambda$onMessage$0(RetryingMessageListenerAdapter.java:120)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:211)
at org.springframework.kafka.listener.adapter.RetryingMessageListenerAdapter.onMessage(RetryingMessageListenerAdapter.java:114)
at org.springframework.kafka.listener.adapter.RetryingMessageListenerAdapter.onMessage(RetryingMessageListenerAdapter.java:40)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1592)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1575)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1534)
... 8 common frames omitted
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:138)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
... 27 common frames omitted
Spring version 5+.
Is this a valid scenario at all, sending messages using KafkaTemplate and expect them to be received by a cloud stream subscriber ?

Your #StreamListener is bound to the publisher channel instead of the subscriber channel.
Here is a working example:
#SpringBootApplication
#EnableBinding(MyKafkaBinding.class)
public class So59585815Application {
public static void main(String[] args) {
SpringApplication.run(So59585815Application.class, args);
}
#Autowired
private MessageChannel publisher;
#StreamListener("subscriber")
public void listen(String in) {
publisher.send(new GenericMessage<>(in.toUpperCase()));
}
#Bean
public ApplicationRunner runner(KafkaTemplate<byte[], byte[]> template) {
return args -> {
template.send("subscriber-topic", "foo".getBytes());
};
}
#KafkaListener(id = "listener", topics = "publisher-topic")
public void listen(byte[] in) {
System.out.println(new String(in));
}
}
interface MyKafkaBinding {
#Output("publisher")
MessageChannel publisher();
#Input("subscriber")
SubscribableChannel subscriber();
}
and
spring.cloud.stream.bindings.publisher.destination=publisher-topic
spring.cloud.stream.bindings.subscriber.destination=subscriber-topic
spring.cloud.stream.bindings.subscriber.group=myGroup
spring.kafka.consumer.auto-offset-reset=earliest

The reason for this problem in my project:
my project cannot connect to Kafka

Related

How to create custom error response in Spring Integration using java DSL

I have following simple proxy integration flow. The main task of which is to take request from the proxy send it to the actual endpoint, get the respond and send it back to the client.
#SpringBootApplication
#EnableIntegration
public class IntegrationApp {
#Value("${narko.pin}")
private String pinUrl;
public static void main(String[] args) {
SpringApplication.run(MinzdravApplication.class, args);
}
#Bean
public DirectChannel requestPinChannel() {
return new DirectChannel();
}
#Bean
public DirectChannel replyPinChannel() {
return new DirectChannel();
}
#Bean
public IntegrationFlow httpProxyFlowPin() throws Exception {
return IntegrationFlows
.from(Http.inboundGateway("/narko/api/patient/by-pinpp")
.requestChannel(requestPinChannel()).replyChannel(replyPinChannel())
.mappedRequestHeaders("activityid")
.errorChannel("httpProxyErrorFlow.input")
)
.wireTap(sf->sf.handle(new InwardMessageHandler()))
.enrichHeaders(h -> h.header("Content-Type", "application/json"))
.handle(Http.outboundGateway(pinUrl).charset("utf-8")
.expectedResponseType(String.class))
.channel(replyPinChannel())
.get();
}
#Bean
public IntegrationFlow httpProxyErrorFlow() {
return f -> f
.transform(Throwable::getCause)
.<HttpClientErrorException>handle((p, h) ->
new RuntimeException("custom exception"));
}
}
When the api at the outbound gateway is down. I have following error:
{
"timestamp": "2022-08-10T12:51:58.561+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/narko/api/patient/by-pinpp"
}
And I have following exceptions on logs:
java.lang.ClassCastException: class org.springframework.web.client.ResourceAccessException cannot be cast to class org.springframework.web.client.HttpClientErrorException (org.springframework.web.client.ResourceAccessException and org.springframework.web.client.HttpClientErrorException are in unnamed module of loader 'app')
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.integration.handler.LambdaMessageProcessor.processMessage(LambdaMessageProcessor.java:104) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:105) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:136) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:56) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:133) ~[spring-integration-core-5.5.10.jar:5.5.10]
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106) ~[spring-integration-core-5.5.10.jar:5.5.10]
How can I create custom exception response?
Any navigation or hint is appreciated.
First of all you don't need that .replyChannel(replyPinChannel() and .channel(replyPinChannel()). An inbound gateway sends a message with a replyChannel header, the last replying endpoint in the flow, not founding its outputChannel, will consult with that replyChannel.
Secondly, your solution about an error handler is OK, but you see yourself in the stacktrace that you just don't cast to the proper type: the ResourceAccessException is not an instance of HttpClientErrorException. Consider to expect a RestClientException instead which is a super for both ResourceAccessException and HttpClientErrorException.

Spring integration error:- org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel while connecting to MQ

I am trying to use Spring integration to connect to JMS client , but i am getting :-
[WARN ] 2018-08-22 10:57:20.378 [DispatchThread: [com.ibm.mq.jmqi.remote.impl.RemoteSession[connectionId=414D514353414D5030303144202020206CF77A5B9E4A5E21]]] SimpleMessageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'app-name:local:9010.inputChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage
and below is my spring integration configuration class
Any idea why i am getting this exception .
Many thanks in advance
The problem is exactly what the message says.
Dispatcher has no subscribers for channel 'app-name:local:9010.inputChannel'.
You have no subscriber on this bean
#Bean
public MessageChannel inputChannel() {
return new DirectChannel();
}
EDIT
#ServiceActivator(inputChannel = "inputChannel")
public void handle(String in) {
...
}
or
#Transformer(inputChannel = "inputChannel", outputChannel = "transformed")
public String handle(String in) {
retur in.toUpperCase();
}
#ServiceActivator(inputChannel = "transformed")
public void handle(String in) {
...
}

How to avoid the MessageDeliveryException?

I'm trying to send a simple message through tcp but I can't even manage that using spring integration... I'm really getting bored with that ...
So I tried using TcpOutboundGateway and TcpInboudGateway in client mode but I get a MessageDeliveryException.
Here is my code:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfiguration {
#Bean
public TcpNetClientConnectionFactory clientConnectionFactory() {
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory("localhost", 7015);
return factory;
}
#Bean
public DirectChannel outputChannel() {
return new DirectChannel();
}
#Bean
public MessageChannel replyChannel() {
return new DirectChannel();
}
// #Bean
// public TcpOutboundGateway tcpOutGateway(AbstractClientConnectionFactory clientConnectionFactory) {
// TcpOutboundGateway outGateway = new TcpOutboundGateway();
// outGateway.setConnectionFactory(clientConnectionFactory);
// outGateway.setOutputChannel(outputChannel());
// return outGateway;
// }
#Bean
public TcpInboundGateway tcpInboundGateway(AbstractClientConnectionFactory clientConnectionFactory) {
TcpInboundGateway inGateway = new TcpInboundGateway();
inGateway.setConnectionFactory(clientConnectionFactory);
inGateway.setClientMode(true);
inGateway.setRequestChannel(outputChannel());
inGateway.setReplyChannel(replyChannel());
return inGateway;
}
}
And the scheduled method to send the message :
#Component
public class SimulatorTask {
#Autowired
DirectChannel outputChannel;
#Scheduled( fixedDelay = 3000 )
public void sendMsg() {
outputChannel.send(new GenericMessage<>("Hello world!"));
}
}
The error I get :
2018-05-03 13:42:44.578 ERROR 11144 --- [ask-scheduler-7] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.outputChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=Hello world!, headers={id=ed173189-b102-6f85-5fe5-d901f4585140, timestamp=1525347764578}], failedMessage=GenericMessage [payload=Hello world!, headers={id=ed173189-b102-6f85-5fe5-d901f4585140, timestamp=1525347764578}]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:445)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:394)
at be.thingsplay.fmb920simulator.tcp.SimulatorTask.sendMsg(SimulatorTask.java:20)
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:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=Hello world!, headers={id=ed173189-b102-6f85-5fe5-d901f4585140, timestamp=1525347764578}]
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:138)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
... 16 more
I'm really getting bored with Spring...
So, what happens is that you are sending message successfully. The message does successfully get to the outputChannel which you chose to be a DirectChannel.
DirectChannel by definition requires a subscriber, which I don't see in your configuration (such as #Transformer or #ServiceActivator or any other type of MessageHandler), and exception is telling you exactly that.
So, if you just want to validate that the message is sent you may want to chose different implementation of channel. For example, you may choose QueueChannel which will buffer the messages until they are polled from it, or PublishSubscribeChannel which will drop messages if there are no subscribers.
Or, add a subscriber.
#ServiceActivator(inputChannel="outputChannel", outputChannel="replyChannel")
public Message echo(Message message) {
return message;
}

How to read pending messages from an ActiveMQ queue in Spring Boot

I like to read pending (not acknowledged) messages in a ActiveMQ queue using Spring boot. How to do that?
So far I can read a message the moment it is send to the queue:
#JmsListener(destination = "LOCAL.TEST",
containerFactory = "myJmsListenerContainerFactory")
public void receiveMessage(final Message jsonMessage) throws JMSException {
String messageData = null;
// jsonMessage.acknowledge(); // dont consume message (for testing)
LOGGER.info("=== Received message {}", jsonMessage);
}
using a standard configuration for the mq-connection:
#Bean
public ActiveMQConnectionFactory getActiveMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(BROKER_URL + ":" + BROKER_PORT);
return activeMQConnectionFactory;
}
and a standard ListenerContainerFactory:
#Bean
public DefaultJmsListenerContainerFactory myJmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(getActiveMQConnectionFactory());
factory.setConcurrency("1-1");
return factory;
}
But this just loggs a message if I manually send one using
#Autowired
private JmsTemplate jmsTemplate;
public void send(String destination, String message) {
LOGGER.info("sending message='{}' to destination='{}'", message, destination);
jmsTemplate.convertAndSend(destination, message);
}
with the standard template
#Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(getActiveMQConnectionFactory());
return template;
}
I cannot read messages sent earlier that are still in the Queue (since I didn't .acknowledge() them)...
JMS supports "browsing" messages which appears to be the functionality you want. You should therefore change your Spring application to use a QueueBrowser instead of actually consuming the messages.
Messages won't be resent if not acknowledged. They are not returned to the queue until the session is closed or the connection lost, for example by stopping (and restarting) the listener container created by the factory.
You can access the container using the JmsListenerEndpointRegistry bean (or stop/start the entire registry which will stop/start all of its containers).
To read all pending messages, you can do like this
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616?jms.redeliveryPolicy.maximumRedeliveries=1");
Connection connection = connectionFactory.createConnection("admin", "admin");
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("listenerQueue");
MessageConsumer consumer = session.createConsumer(destination);
QueueBrowser browser = session.createBrowser((Queue) destination);
Enumeration elems = browser.getEnumeration();
while (elems.hasMoreElements()) {
Message message = (Message) consumer.receive();
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Incoming Message: '" + textMessage.getText() + "'");
message.acknowledge();
}
}
connection.close();
Step by step implementation of Spring boot ActiveMQ. Lets write some code to make it more clear. This will help to read all pending messages in current session only.
Add these dependencies in pom.xml file.
<!-- Dependencies to setup JMS and active mq environment -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</dependency>
Add #EnableJms into your main controller where your main() method exists.
Create connection factory by adding these 2 methods in application controller only.
#Bean
public JmsListenerContainerFactory<?> myFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
logger.info("configuring jms connection factory....");
// anonymous class
factory.setErrorHandler(
new ErrorHandler() {
#Override
public void handleError(Throwable t) {
logger.error("An error has occurred in the transaction", t);
}
});
// lambda function
factory.setErrorHandler(t -> logger.info("An error has occurred in the transaction"));
configurer.configure(factory, connectionFactory);
return factory;
}
// Serialize message content to json using TextMessage
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
Mention credentials in in application.yml file as
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.broker-url=tcp://localhost:61616?jms.redeliveryPolicy.maximumRedeliveries=1
Autowire jmsTemplate in any spring bean class.
#Autowired
private JmsTemplate jmsTemplate;
Now it is time to send message to a queue.
jmsTemplate.convertAndSend("anyQueueName", "value1");
jmsTemplate.convertAndSend("anyQueueName", "value2");
...
Add a jmslistener. This method will be called automatically by JMS when any message will be pushed to queue.
#JmsListener(destination ="anyQueueName", containerFactory = "myFactory")
public void receiveMessage(String user) {
System.out.println("Received <" + user + ">");
}
Manually you can read the messages available in queue:-
import javax.jms.TextMessage;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;
public void readMessageFromQueue(){
jmsTemplate.browse("anyQueueName", new BrowserCallback<TextMessage>() {
#Override
public TextMessage doInJms(Session session, QueueBrowser browser) throws JMSException {
Enumeration<TextMessage> messages = browser.getEnumeration();
while (messages.hasMoreElements()) {
System.out.println("message found : -"+ messages.nextElement().getText());
}
}
});
}
Output :-
message found :- value1
message found :- value2
-Happy Coding

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...

Resources