This code will cause an exception to be thrown:
SimpMessagingTemplate template = ...;
template.convertAndSendToUser(dest, currentUserId, null); // payload param is null
There are many cases when you might want to send a WS message without a payload. E.g. "account activated" is received only by the same user who's account was just activated, so having a null/empty payload is completely reasonable since the client only cares that a message was sent to the /user/<my id>/activated
endpoint.
But passing payload
as null
causes the following exception:
Cannot invoke "Object.getClass()" because "payload" is null
at org.springframework.messaging.converter.AbstractMessageConverter.canConvertTo(AbstractMessageConverter.java:233) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:197) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.converter.CompositeMessageConverter.toMessage(CompositeMessageConverter.java:96) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.core.AbstractMessageSendingTemplate.doConvert(AbstractMessageSendingTemplate.java:181) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:150) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.simp.SimpMessagingTemplate.convertAndSendToUser(SimpMessagingTemplate.java:230) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.simp.SimpMessagingTemplate.convertAndSendToUser(SimpMessagingTemplate.java:218) ~[spring-messaging-5.3.6.jar:5.3.6]
at org.springframework.messaging.simp.SimpMessagingTemplate.convertAndSendToUser(SimpMessagingTemplate.java:204) ~[spring-messaging-5.3.6.jar:5.3.6]
at com.teslagov.clarakm.net.ws.WebsocketMessageSender.lambda$sendToUsers$0(WebsocketMessageSender.java:67) ~[net-ws-1.0.4.jar:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na]
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290) ~[na:na]
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:373) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:686) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:765) ~[na:na]
I can get around this by sending an arbitrary object as the payload (e.g. ""
), but this produces a "code smell".
Comment From: rstoyanchev
This comes from the MessageSendingOperations
contract, where payload
is not nullable, and all the down to the MessageConverter
and Message
contracts that require some kind of payload. It would be unclear what SimpMessagingTemplate
should do to fill in for a null
, and what type to use. Defining an EMPTY_PAYLOAD
constant and passing that explicitly I think is the most clear way to express the intent rather than leaving it null, which leaves more questions like what's in the message payload then?
Comment From: JoshMcCullough
I don't really follow why a null payload is unclear. The use case is a message where the destination alone is the enough to trigger some action, and there is no relevant payload to go along with the message. Sending an empty string just because the call-chain enforces the payload be non-null is less than ideal. E.g. what's the harm in sending a null/empty payload (and yes, I consider in this case that a null payload == an empty payload for all intents and purposes).