Disable automatic reply in Spring JMS - spring-boot

According to Spring reference documentation, method annotated with #JmsListener and have a non-void return type will have the result of the invocation encapsulated in a javax.jms.Message and sent either in the destination specified in the JMSReplyTo header of the original message or in the default destination configured on the listener.
If no destination is found then an InvalidDestinationException will be thrown.
Is there a way to disable this behavior of automatic reply ?
EDIT
I'm using an #AroundAdvice to log the result of the execution that's why i need to have a return type on my listener.

Returning null from the method if it has a return type, will disable reply processing.
You can detect the presence (or not) of a replyTo by adding a #Header parameter to the method.
Or, add a #SendTo with a destination to use if there's no header.
EDIT
Since you are using an advice to log the return value, you can simply return null from the advice, instead of the result of invocation.proceed().

Related

Nats.io, Golang: What's a `subj` parameter of a `js.PullSubscribe()` method for?

What's a subj parameter of a JetStream.PullSubscribe() method for?
I observe following behavior:
When a consumer is created without the FilterSubject configuration option, then no matter what I pass as subject to the js.PullSubscribe(), the subscription fetches all the consumer's messages.
When a consumer is created with a non-empty FilterSubject option, PullSubscribe returns with an error, if the subject differs from that filter.
Is this parameter of any use?

How return a Message (from Spring) to represent that the information was not found?

I'm working with messaging on Spring and I had a simple question.
When another services sends a message requesting an information that does not exists for the service that are able to answer, the first thing that I thoutght was pass a "null" do the payload:
MyResponse myResponse = service.find(id); //ops, the information with this id does not exists
Message<MyResponse> message = MessageBuilder
.withPayload(myResponse) // the information does not exists, so null
.copyHeadersIfAbsent(request.getHeaders())
.build();
But the method withPayload not accept null. So, what is the good practice or alternative to fill this message with a "empty" value to the original request receive the result and know that this information does not exists?
For now I'm passing a empty object (new MyResponse()) to the payload, but this could create a confusion for who consumes the message. I could create another class to represent this "not exists" state, but I'm trying to understand my options now.
Thanks!
The null payload doesn't bring too much information and isn't supported by many network protocols. More over there are many places in the framework which are based on the payload type, but if it is a null we might not have any information what and how to do with it. In some components the null return value is a signal to stop the flow and don't produce any messages downstream to reply.
The solution you may go is like constant object (MyNullResponse) to indicate that it is about a null.
You might also consider a way with an exception instead of an attempt to return null. Let's consider that you do some post-search processing and a bunch of filtering and conversion steps. In case of null your message will still travel all the flow down. But when we deal with an exception (like it is with the javax.persistence.EntityNotFoundException) we just bubble the problem to end-user immediately. And that's already the target service responsibility to represent that exception as a comprehensible message for end-user.
We have a JIRA ticket about null payload support. You can read there about more reasons and what other people think on the matter. My idea to allow something on the matter is like Optional.empty(). Then we can map it to null easily on the target end-user code.
You must clearly differentiate between The response itself ( in your case MyResponse object) and the existence or not of the information which something relative to you business logic, the message that you construct must be as generic as possible not hard coupled to your service layer, simple reason => the message is just a message you send to consumers , so if possible try to embed the existence or not of the information in your object MyResponse (Boolean Flag) , and construct it on the fly after invoking your service
instead of
MyResponse myResponse = service.find(id);
you can try this :
CustomResponse myResponse = service.find(id);
// use helper class to respect DRY principal if you need it somewhere
MyResponse messageReponse = ResponseBuilder.constructResponse(myReponse);
Message<MyResponse> message =// .. construct you message
In the example above ResponseBuilder take care of myResponse if it null, and fully create the response ( you could integrate all cases .. )
I would like to share with you guys my solution after read the #Artem answer.
I created an OptionalMessage class, very similar of Optional class from Java 8+. As I'm using application/json as content-type for messages.
I can use this OptionalMessage in different messages:
OptionalMessage optionalMessage = messaging.find(id);
if (optionalMessage.isPresent()) {
MyMessage myMessage = optionalMessage.getContent();
}
It has also the methods of() and empty(), used in the another side to populate the OptionalMessage.
The Json structure generated follow this example:
{
"content": { /*attributes */}
}
When we have no content (my "null" return), the Json look like this:
{
"content": null
}
I tried to use generics (OptionalMessage<MyMessage>), but I would need to change my Jackson setup (on IntegrationFlow DSL) to not receive the error java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyMessage when calling the getContent method.

Is it possible to proxy an interface with multiple methods going to different endpoints

I have an interface with methods foo() and bar() that I'd like to go to endpoints direct:foo and direct:bar. In the proxy configuration you are only allowed to enter one endpoint and I have not found any way to get the name of the method called in code to be able to route based on that name.
Am I missing some document somewhere?
Look at the info at http://camel.apache.org/message-endpoint.html related to 'toD'
I think you are using a Camel version > 2.15
Revert to old behaviour which does not bind parameters to body and then you will have accesso to BeanInvocation object that will tell you which method was called.
// Create Proxy
MyAuditService service = new ProxyBuilder(context)
.endpoint("direct:analyzeMethodCall") // dispatcher endpoint
.binding(false) // false: gives you BeanInvocation, true gives you parameter
.build(MyAuditService.class);
Then in your route from direct:analyzeMethodCall use a Processor to analyze the BeanInvocation object and call direct:foo or direct:bar. You must set the body explicitly.

How to specify content type produced by a handler in Spring Messaging?

I'm experimenting with Spring 4 WebSocket STOMP application. Is there a way to explicitly specify content type of the returned message produced by a handler? By default the handler below produces application/json and processed by corresponding message converter.
#Controller
public class ProductController {
#MessageMapping("/products/{id}")
public String getProduct(#DestinationVariable int id) {
return getProductById(id);
}
}
I'm looking for something like #RequestMapping(produces = "text/xml") in Spring MVC.
UPDATE (reply to Rossen's answer):
Ideally I would like to be able to return both formats depending on what the user asks for. But if I have to choose, I would say XML and almost never JSON (XML is just an example, we use binary format). I went the second way you suggested - configuring custom converters instead of the default ones.
I have implemented custom MessageConverter extending AbstractMessageConverter. In the constructor I've registered appropriate supported MimeType.
Then I've registered my custom converter by overriding WebSocketMessageBrokerConfigurer's configureMessageConverters, and return false from the method to not add default converters.
As soon as my controller returns the value I get NPE in SendToMethodReturnValueHandler's postProcessMessage. This happens because CompositeMessageConverter contains only a single converter - my custom one. But my converter fails AbstractMessageConverter's supportsMimeType check and AbstractMessageConverter's toMessage returns null. This null causes the exception in postProcessMessage.
As the workaround I can register additional default MimeType application/json for my custom converter. But it looks like too dirty to me.
There is nothing like the produces condition. The only way to do this right now is to inject SimpMessagingTemplate and then use the convertAndSend method variation that takes a MessagePostProcessor. It could be made simpler. What's your use case? Are you using JSON primarily and need to use XML in a few places? Or do you need to use XML primarily? If it is the latter you can simply configure the converters to use instead of the default ones.
I see that you can change the headers changing the Message converter.
For example:
SockJsClient sockJsClient = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
..
stompClient.setMessageConverter(new StringMessageConverter());
or
stompClient.setMessageConverter(new SimpleMessageConverter());
when you use StringMessageConverter then the Java client add an content-type header.
GenericMessage [payload=byte[33], headers={simpMessageType=MESSAGE, stompCommand=SEND, nativeHeaders={destination=[/app/chatchannel], content-type=[text/plain;charset=UTF-8], content-length=[33]}, simpSessionAttributes={ip=/127.0.0.1:59629}, simpHeartbeat=[J#147a2bf, contentType=text/plain;charset=UTF-8, lookupDestination=/chatchannel, simpSessionId=79431feb8b5f4a9497492ccc64f8965f, simpDestination=/app/chatchannel}]
But if you use SimpleMessageConverter, the content-type header is not add.
this is a clue about what you want to do?
Check this question, I put some code that could help you:
How configure the Spring Sockjs Java Client message converters

I use jersey + protobuf, How can I pass a meaningful error message back to client?

How can I pass a meaningful error message back to client? I can implement the ExceptionMapper to produce meaningful error message.
But how can I have writer to pass the message back to client?
I haven't used jersey personally, but my general approach here would be to simply include the result-state (including error message) in the returned message, i.e.
message GetCustomerResult {
optional string errorMessage = 1;
optional Customer customer = 2;
}
or similar, such that all your messages have a consistent way to report failure. If your error state is more than just a string, you could declare a message for that, and include it on all results, so you can just pass that to any shared error-handling code.
You can throw WebApplicationException which takes Response in a constructor and gets mapped by Jersey automatically to that response. You can put the meaningful message into the response body.

Resources