Spring Boot & RabbitMQ: message conversion content type - spring-boot

We are using Spring Boot 2.1.3.RELEASE and RabbitMQ. MessagePack is used for serialization.
We are using convertAndSend:
rabbitTemplate.convertAndSend("exchange", "routingKey", object);
And getting the following exception:
java.lang.UnsupportedOperationException: null
at org.msgpack.jackson.dataformat.MessagePackFactory.createGenerator(MessagePackFactory.java:102)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219)
at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.createMessage(AbstractJackson2MessageConverter.java:259)
at org.springframework.amqp.support.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:70)
at org.springframework.amqp.support.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:58)
at org.springframework.amqp.rabbit.core.RabbitTemplate.convertMessageIfNecessary(RabbitTemplate.java:1726)
at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1048)
at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1041)
This is the line where the exception is thrown:
return getRequiredMessageConverter().toMessage(object, new MessageProperties());
Is there a way to set the content type in MessageProperties to application/json? The default is application/octet-stream.

Related

Pass through SOAP proxy spring Unsupported media type multipart/related; type="application/xop+xml"; boundary

Hi I am trying to implement a pass through SOAP proxy via #RestController in spring. For this purpose I have mapped a rest controller in following way:
#RestController
class MyProxy {
#PostMapping(value = "/**")
public ResponseEntity<String> proxyPost(#RequestBody(required = false) String body, HttpServletRequest request) {}
}
The regular SOAP requests are going OK. The problem comes when a MTOM type of SOAP request is send via the proxy. Then spring failes with unrecognized content type. Here is the exception:
Caused by: org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is javax.servlet.ServletException: Unsupported Content-Type [multipart/related; type="application/xop+xml"; boundary="uuid:dacf4733-80b4-41bc-b2e1-db69b6beadf6"; start="<root.message#cxf.apache.org>"; start-info="text/xml"], expected [multipart/form-data]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.handleParseFailure(StandardMultipartHttpServletRequest.java:124)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:115)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:122)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1205)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
... 60 common frames omitted
Caused by: javax.servlet.ServletException: Unsupported Content-Type [multipart/related; type="application/xop+xml"; boundary="uuid:dacf4733-80b4-41bc-b2e1-db69b6beadf6"; start="<root.message#cxf.apache.org>"; start-info="text/xml"], expected [multipart/form-data]
at org.eclipse.jetty.server.Request.getParts(Request.java:2407)
at javax.servlet.http.HttpServletRequestWrapper.getParts(HttpServletRequestWrapper.java:317)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95)
... 66 common frames omitted
When receiving a multipart/* request Spring delegates this to the configured Multipart handler. This is enabled by default and for this case should be disabled.
spring.servlet.multipart.enabled=false
Adding the above to your properties should disable it and prevent the parsing, so you can handle it in your controller.

Spring Cloud Stream Kafka Binder KafkaTransactionManager results in a cycle in application context

I am setting up a basic Spring Cloud Stream producer with Kafka. The intent is to accept a HTTP POST, save the result of the post to a database with Spring Data JPA, and write the results to a Kafka topic using Spring Cloud Stream Kafka Binder. I am following the latest binder documentation on how to setup a KafkaTransactionManager, but this code results in an error on Application startup.
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| kafkaTransactionManager defined in com.example.tx.Application
↑ ↓
| org.springframework.boot.autoconfigure.kafka.KafkaAnnotationDrivenConfiguration
└─────┘
I have the following Bean defined in my Application class, which is the same as documentation.
#Bean
public KafkaTransactionManager kafkaTransactionManager(BinderFactory binders) {
ProducerFactory<byte[], byte[]> pf = ((KafkaMessageChannelBinder) binders.getBinder(null, MessageChannel.class)).getTransactionalProducerFactory();
KafkaTransactionManager tm = new KafkaTransactionManager<>(pf);
tm.setTransactionIdPrefix("tx-test");
return tm;
}
It seems that calling getBinder causes Spring to create the context again. How can I resolve this circular dependency?
Dependencies: Spring Boot parent 2.4.6; Spring Cloud BOM 2020.0.3
Something must have changed in one of the layers; here is a work around:
#Bean
SmartInitializingSingleton ktmProvider(BinderFactory binders, GenericApplicationContext context) {
return () -> {
context.registerBean("kafkaTransactionManager", KafkaTransactionManager.class,
((KafkaMessageChannelBinder) binders.getBinder(null, MessageChannel.class))
.getTransactionalProducerFactory());
context.getBean(KafkaTransactionManager.class).setTransactionIdPrefix("tx-test");
};
}
i.e. wait for the other beans to be created before registering and configuring the tm.

Spring data redis with kotlin breaks in version 2.3.2.RELEASE

After migrating Spring Boot from 2.3.0 to 2.3.2.RELEASE, my #RedisHash code is broken.
#RedisHash(value = "OtpCache", timeToLive = 5 * 60)
data class OtpCache(#Id val mobile: String,
val otp: String)
interface OtpCacheRepository : CrudRepository<OtpCache, String>
val optional = otpCacheRepository.findById("unknown")
println("optional = " + optional.isPresent)
When I try to find a instance of OtpCache with unknown identifier using findById, instead of getting a Optional.empty(), i see an exception
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method com.example.demo.OtpCache.<init>, parameter mobile
at com.example.demo.OtpCache.<init>(DemoApplication.kt) ~[main/:na]
at com.example.demo.OtpCache_Instantiator_humu2e.newInstance(Unknown Source) ~[main/:na]
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:238) ~[spring-data-commons-2.3.2.RELEASE.jar:2.3.2.RELEASE]
This code was working perfect in Spring Boot 2.3.0.RELEASE
I am using Kotlin data class for creating POJO in my codebase.
Here is link to sample repository
https://github.com/cancerian0684/bug-redishash-springboot

Can not registry a dynamic bean

I am migrating a Project which using JBOSS fuse to Spring Boot and I use this code for registry a dynamic DataSource:
PropertyPlaceholderDelegateRegistry reg = (PropertyPlaceholderDelegateRegistry) exchange.getContext().getRegistry();
CompositeRegistry cReg = (CompositeRegistry) reg.getRegistry();
SimpleRegistry simpleReg = new SimpleRegistry();
simpleReg.put(
Messaging.Names.SAM_DATABASE_CONNECTION_KEY.toString() + configuration.getCustomerNumber(),
dataSource);
cReg.addRegistry(simpleReg);
But when i migrated it to Spring boot, it does not work and has this Error:
There's uncaught exception has occured. Exception message:
org.apache.camel.spring.spi.ApplicationContextRegistry cannot be cast to org.apache.camel.impl.CompositeRegistry
Please help!!!

No converter found to convert to interface javax.jms.TextMessage

I am running a spring boot application that connects to activeMQ as a consumer from my Spring STS environment. I then run my camel blueprint from my JBoss Developer Studio app.
Here's the code from my listener:
#JmsListener(destination = '${tripRequest.updateStatus.destination}')
void handle(TextMessage message) {
When the message hits the consumer, I get the following exception:
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method could not be invoked with incoming message
Endpoint handler details:
Method [public void com.xxx.trip.request.messaging.status.TripRequestUpdateStatusListener.handle(javax.jms.TextMessage)]
Bean [com.xxx.trip.request.messaging.status.TripRequestUpdateStatusListener#1a99744a]
; nested exception is org.springframework.messaging.converter.MessageConversionException: No converter found to convert to interface javax.jms.TextMessage, message=GenericMessage [payload=byte[197], headers={CamelFileLastModified=1466448102155, CamelFileParent=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data, CamelFilePath=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data\one.json, CamelFileLength=22, jms_destination=queue://tripRequest.updateStatus.v1.0, jms_priority=4, CamelFileAbsolute=true, jms_timestamp=1466631945834, CamelFileName=one.json, jms_redelivered=false, jms_deliveryMode=2, CamelFileNameConsumed=one.json, breadcrumbId=ID-ThomasLaptop-55017-1466631942306-0-1, jms_replyTo=temp-queue://ID:ThomasLaptop-55022-1466631945608-1:1:1, CamelFileRelativePath=one.json, jms_correlationId=Camel-ID-ThomasLaptop-55017-1466631942306-0-3, id=3c38a185-44c7-4df2-fefb-1f3320e0262f, CamelFileAbsolutePath=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data\one.json, jms_expiration=1466631965834, jms_messageId=ID:ThomasLaptop-55022-1466631945608-1:1:2:1:1, CamelFileNameOnly=one.json, timestamp=1466631945924}]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:94) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:66) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:315) [spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:253) [spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1158) [spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1150) [spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1047) [spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_91]
Caused by: org.springframework.messaging.converter.MessageConversionException: No converter found to convert to interface javax.jms.TextMessage, message=GenericMessage [payload=byte[197], headers={CamelFileLastModified=1466448102155, CamelFileParent=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data, CamelFilePath=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data\one.json, CamelFileLength=22, jms_destination=queue://tripRequest.updateStatus.v1.0, jms_priority=4, CamelFileAbsolute=true, jms_timestamp=1466631945834, CamelFileName=one.json, jms_redelivered=false, jms_deliveryMode=2, CamelFileNameConsumed=one.json, breadcrumbId=ID-ThomasLaptop-55017-1466631942306-0-1, jms_replyTo=temp-queue://ID:ThomasLaptop-55022-1466631945608-1:1:1, CamelFileRelativePath=one.json, jms_correlationId=Camel-ID-ThomasLaptop-55017-1466631942306-0-3, id=3c38a185-44c7-4df2-fefb-1f3320e0262f, CamelFileAbsolutePath=C:\Users\Thom\git\brms-poc-esb\rule-cancel\data\one.json, jms_expiration=1466631965834, jms_messageId=ID:ThomasLaptop-55022-1466631945608-1:1:2:1:1, CamelFileNameOnly=one.json, timestamp=1466631945924}]
at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:118) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:98) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:138) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:107) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:90) ~[spring-jms-4.2.5.RELEASE.jar:4.2.5.RELEASE]
... 10 common frames omitted
I know for a fact that we have tested this with text messages sent from another application and this message works fine. I don't understand why it fails from my camel route. When I look at the message, it appears to be well-formed XML. Here it is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tripRequestUpdateStatus>
<id>1</id>
<status>Approved</status>
<updatedBy source="lgtc">1</updatedBy>
</tripRequestUpdateStatus>
Why does it need converted in the first place when I'm sending text? Why is conversion failing?
I guess you created a new question after you found out something, but forgot to mention this in this question: How to send text message instead of byte message
You send the messages as byte payload so the JMS consumer receives the message payload as a javax.jms.BytesMessage which Spring Integration is not able to convert to a javax.jms.TextMessage. So you can change your code to use a javax.jms.BytesMessage instead. Or have the sender send the JMS messages as Text based instead of Bytes.

Resources