1

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!

Dherik
  • 17,757
  • 11
  • 115
  • 164

3 Answers3

1

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.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thank you for the attention! I will think in some wrapper object (like an `OptionalMyResponse`). – Dherik Jan 31 '18 at 17:16
0

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

elmehdi
  • 449
  • 2
  • 10
0

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.

Dherik
  • 17,757
  • 11
  • 115
  • 164