Allow use of @JsonView on @MessageMapping methods
Issue: SPR-12741
This commit is contained in:
parent
c36435c042
commit
876c9694c4
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
@ -38,13 +39,24 @@ import org.springframework.util.MimeType;
|
|||
* and MIME type.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class AbstractMessageConverter implements MessageConverter {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
/**
|
||||
* Name of the header that can be set to provide further information
|
||||
* ({@link MethodParameter} instance) about the origin of the payload (for
|
||||
* {@link #toMessage(Object, MessageHeaders)}) or about the target of the payload
|
||||
* ({@link #fromMessage(Message, Class)}).
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public static final String METHOD_PARAMETER_HINT_HEADER = "methodParameterHint";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final List<MimeType> supportedMimeTypes;
|
||||
|
||||
private ContentTypeResolver contentTypeResolver = new DefaultContentTypeResolver();
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.nio.charset.Charset;
|
|||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
|
@ -33,6 +34,7 @@ import com.fasterxml.jackson.databind.MapperFeature;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
|
@ -212,16 +214,27 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
|||
@Override
|
||||
public Object convertToInternal(Object payload, MessageHeaders headers) {
|
||||
try {
|
||||
Class<?> serializationView = getSerializationView(headers);
|
||||
if (byte[].class.equals(getSerializedPayloadClass())) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
JsonEncoding encoding = getJsonEncoding(getMimeType(headers));
|
||||
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(out, encoding);
|
||||
this.objectMapper.writeValue(generator, payload);
|
||||
if (serializationView != null) {
|
||||
this.objectMapper.writerWithView(serializationView).writeValue(generator, payload);
|
||||
}
|
||||
else {
|
||||
this.objectMapper.writeValue(generator, payload);
|
||||
}
|
||||
payload = out.toByteArray();
|
||||
}
|
||||
else {
|
||||
Writer writer = new StringWriter();
|
||||
this.objectMapper.writeValue(writer, payload);
|
||||
if (serializationView != null) {
|
||||
this.objectMapper.writerWithView(serializationView).writeValue(writer, payload);
|
||||
}
|
||||
else {
|
||||
this.objectMapper.writeValue(writer, payload);
|
||||
}
|
||||
payload = writer.toString();
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +244,24 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
|||
return payload;
|
||||
}
|
||||
|
||||
private Class<?> getSerializationView(MessageHeaders headers) {
|
||||
MethodParameter returnType = (headers == null ? null :
|
||||
(MethodParameter)headers.get(METHOD_PARAMETER_HINT_HEADER));
|
||||
if (returnType == null) {
|
||||
return null;
|
||||
}
|
||||
JsonView annotation = returnType.getMethodAnnotation(JsonView.class);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?>[] classes = annotation.value();
|
||||
if (classes.length != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"@JsonView only supported for handler methods with exactly 1 class argument: " + returnType);
|
||||
}
|
||||
return classes[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the JSON encoding to use for the given content type.
|
||||
* @param contentType the MIME type from the MessageHeaders, if any
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
|||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver;
|
||||
|
@ -51,6 +52,7 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
|||
* the message is sent to each destination.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
|
||||
|
@ -162,10 +164,10 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
|||
for (String destination : destinations) {
|
||||
destination = this.placeholderHelper.replacePlaceholders(destination, varResolver);
|
||||
if (broadcast) {
|
||||
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue);
|
||||
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(null, returnType));
|
||||
}
|
||||
else {
|
||||
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(sessionId));
|
||||
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(sessionId, returnType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +176,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
|||
String[] destinations = getTargetDestinations(sendTo, message, this.defaultDestinationPrefix);
|
||||
for (String destination : destinations) {
|
||||
destination = this.placeholderHelper.replacePlaceholders(destination, varResolver);
|
||||
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId));
|
||||
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, returnType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,12 +212,15 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
|||
new String[] {defaultPrefix + destination} : new String[] {defaultPrefix + "/" + destination});
|
||||
}
|
||||
|
||||
private MessageHeaders createHeaders(String sessionId) {
|
||||
private MessageHeaders createHeaders(String sessionId, MethodParameter returnType) {
|
||||
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
|
||||
if (getHeaderInitializer() != null) {
|
||||
getHeaderInitializer().initHeaders(headerAccessor);
|
||||
}
|
||||
headerAccessor.setSessionId(sessionId);
|
||||
if (sessionId != null) {
|
||||
headerAccessor.setSessionId(sessionId);
|
||||
}
|
||||
headerAccessor.setHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER, returnType);
|
||||
headerAccessor.setLeaveMutable(true);
|
||||
return headerAccessor.getMessageHeaders();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||
import org.springframework.messaging.core.MessageSendingOperations;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
|
||||
|
@ -44,6 +45,7 @@ import org.springframework.util.Assert;
|
|||
* input message. The message is then sent directly back to the connected client.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
|
||||
|
@ -109,16 +111,17 @@ public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturn
|
|||
logger.debug("Reply to @SubscribeMapping: " + returnValue);
|
||||
}
|
||||
|
||||
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, subscriptionId));
|
||||
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, subscriptionId, returnType));
|
||||
}
|
||||
|
||||
private MessageHeaders createHeaders(String sessionId, String subscriptionId) {
|
||||
private MessageHeaders createHeaders(String sessionId, String subscriptionId, MethodParameter returnType) {
|
||||
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
|
||||
if (getHeaderInitializer() != null) {
|
||||
getHeaderInitializer().initHeaders(headerAccessor);
|
||||
}
|
||||
headerAccessor.setSessionId(sessionId);
|
||||
headerAccessor.setSubscriptionId(subscriptionId);
|
||||
headerAccessor.setHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER, returnType);
|
||||
headerAccessor.setLeaveMutable(true);
|
||||
return headerAccessor.getMessageHeaders();
|
||||
}
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
package org.springframework.messaging.converter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
@ -174,6 +177,23 @@ public class MappingJackson2MessageConverterTests {
|
|||
assertEquals(contentType, message.getHeaders().get(MessageHeaders.CONTENT_TYPE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonView() throws Exception {
|
||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Method method = this.getClass().getDeclaredMethod("handle");
|
||||
MethodParameter returnType = new MethodParameter(method, -1);
|
||||
map.put(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER, returnType);
|
||||
MessageHeaders headers = new MessageHeaders(map);
|
||||
Message<?> message = converter.toMessage(handle(), headers);
|
||||
String actual = new String((byte[]) message.getPayload(), UTF_8);
|
||||
|
||||
assertThat(actual, containsString("\"withView1\":\"with\""));
|
||||
assertThat(actual, not(containsString("\"withView2\":\"with\"")));
|
||||
assertThat(actual, not(containsString("\"withoutView\":\"without\"")));
|
||||
}
|
||||
|
||||
|
||||
public static class MyBean {
|
||||
|
||||
|
@ -238,4 +258,51 @@ public class MappingJackson2MessageConverterTests {
|
|||
}
|
||||
}
|
||||
|
||||
public interface MyJacksonView1 {};
|
||||
public interface MyJacksonView2 {};
|
||||
|
||||
public static class JacksonViewBean {
|
||||
|
||||
@JsonView(MyJacksonView1.class)
|
||||
private String withView1;
|
||||
|
||||
@JsonView(MyJacksonView2.class)
|
||||
private String withView2;
|
||||
|
||||
private String withoutView;
|
||||
|
||||
public String getWithView1() {
|
||||
return withView1;
|
||||
}
|
||||
|
||||
public void setWithView1(String withView1) {
|
||||
this.withView1 = withView1;
|
||||
}
|
||||
|
||||
public String getWithView2() {
|
||||
return withView2;
|
||||
}
|
||||
|
||||
public void setWithView2(String withView2) {
|
||||
this.withView2 = withView2;
|
||||
}
|
||||
|
||||
public String getWithoutView() {
|
||||
return withoutView;
|
||||
}
|
||||
|
||||
public void setWithoutView(String withoutView) {
|
||||
this.withoutView = withoutView;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonView(MyJacksonView1.class)
|
||||
public JacksonViewBean handle() {
|
||||
JacksonViewBean bean = new JacksonViewBean();
|
||||
bean.setWithView1("with");
|
||||
bean.setWithView2("with");
|
||||
bean.setWithoutView("without");
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.messaging.simp.annotation.support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER;
|
||||
|
@ -23,6 +24,7 @@ import static org.springframework.messaging.support.MessageHeaderAccessor.*;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Principal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
@ -41,6 +43,8 @@ import org.springframework.core.MethodParameter;
|
|||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
|
@ -57,6 +61,7 @@ import org.springframework.util.MimeType;
|
|||
* Test fixture for {@link SendToMethodReturnValueHandlerTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class SendToMethodReturnValueHandlerTests {
|
||||
|
||||
|
@ -69,18 +74,21 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
|
||||
private SendToMethodReturnValueHandler handlerAnnotationNotRequired;
|
||||
|
||||
private SendToMethodReturnValueHandler jsonHandler;
|
||||
|
||||
@Mock private MessageChannel messageChannel;
|
||||
|
||||
@Captor ArgumentCaptor<Message<?>> messageCaptor;
|
||||
@Captor private ArgumentCaptor<Message<?>> messageCaptor;
|
||||
|
||||
private MethodParameter noAnnotationsReturnType;
|
||||
private MethodParameter sendToReturnType;
|
||||
private MethodParameter sendToDefaultDestReturnType;
|
||||
private MethodParameter sendToWithPlaceholdersType;
|
||||
private MethodParameter sendToWithPlaceholdersReturnType;
|
||||
private MethodParameter sendToUserReturnType;
|
||||
private MethodParameter sendToUserSingleSessionReturnType;
|
||||
private MethodParameter sendToUserDefaultDestReturnType;
|
||||
private MethodParameter sendToUserSingleSessionDefaultDestReturnType;
|
||||
private MethodParameter jsonViewReturnType;
|
||||
|
||||
|
||||
@Before
|
||||
|
@ -90,10 +98,13 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
|
||||
SimpMessagingTemplate messagingTemplate = new SimpMessagingTemplate(this.messageChannel);
|
||||
messagingTemplate.setMessageConverter(new StringMessageConverter());
|
||||
|
||||
this.handler = new SendToMethodReturnValueHandler(messagingTemplate, true);
|
||||
this.handlerAnnotationNotRequired = new SendToMethodReturnValueHandler(messagingTemplate, false);
|
||||
|
||||
SimpMessagingTemplate jsonMessagingTemplate = new SimpMessagingTemplate(this.messageChannel);
|
||||
jsonMessagingTemplate.setMessageConverter(new MappingJackson2MessageConverter());
|
||||
this.jsonHandler = new SendToMethodReturnValueHandler(jsonMessagingTemplate, true);
|
||||
|
||||
Method method = this.getClass().getDeclaredMethod("handleNoAnnotations");
|
||||
this.noAnnotationsReturnType = new MethodParameter(method, -1);
|
||||
|
||||
|
@ -104,7 +115,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
this.sendToReturnType = new MethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToWithPlaceholders");
|
||||
this.sendToWithPlaceholdersType = new MethodParameter(method, -1);
|
||||
this.sendToWithPlaceholdersReturnType = new MethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUser");
|
||||
this.sendToUserReturnType = new MethodParameter(method, -1);
|
||||
|
@ -117,6 +128,9 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToUserDefaultDestinationSingleSession");
|
||||
this.sendToUserSingleSessionDefaultDestReturnType = new MethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("handleAndSendToJsonView");
|
||||
this.jsonViewReturnType = new MethodParameter(method, -1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,6 +157,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals("/topic/dest", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.noAnnotationsReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -161,12 +176,14 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals("/dest1", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
|
||||
accessor = getCapturedAccessor(1);
|
||||
assertEquals(sessionId, accessor.getSessionId());
|
||||
assertEquals("/dest2", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -185,6 +202,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals("/topic/dest", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToDefaultDestReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -220,6 +238,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertTrue(accessor.isMutable());
|
||||
assertEquals("sess1", accessor.getSessionId());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.noAnnotationsReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -261,7 +280,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
accessor.setSubscriptionId("sub1");
|
||||
accessor.setHeader(DESTINATION_TEMPLATE_VARIABLES_HEADER, vars);
|
||||
Message<?> message = MessageBuilder.createMessage(PAYLOAD, accessor.getMessageHeaders());
|
||||
this.handler.handleReturnValue(PAYLOAD, this.sendToWithPlaceholdersType, message);
|
||||
this.handler.handleReturnValue(PAYLOAD, this.sendToWithPlaceholdersReturnType, message);
|
||||
|
||||
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
|
||||
|
||||
|
@ -287,12 +306,14 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertEquals("/user/" + user.getName() + "/dest1", accessor.getDestination());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToUserSingleSessionReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
|
||||
accessor = getCapturedAccessor(1);
|
||||
assertEquals(sessionId, accessor.getSessionId());
|
||||
assertEquals("/user/" + user.getName() + "/dest2", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToUserSingleSessionReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -364,6 +385,7 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals("/user/" + user.getName() + "/queue/dest", accessor.getDestination());
|
||||
assertEquals(MIME_TYPE, accessor.getContentType());
|
||||
assertNull("Subscription id should not be copied", accessor.getSubscriptionId());
|
||||
assertEquals(this.sendToUserSingleSessionDefaultDestReturnType, accessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -386,6 +408,22 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
assertEquals("sess1", accessor.getSessionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonView() throws Exception {
|
||||
|
||||
given(this.messageChannel.send(any(Message.class))).willReturn(true);
|
||||
|
||||
String sessionId = "sess1";
|
||||
Message<?> inputMessage = createInputMessage(sessionId, "sub1", "/app", "/dest", null);
|
||||
this.jsonHandler.handleReturnValue(handleAndSendToJsonView(), this.jsonViewReturnType, inputMessage);
|
||||
|
||||
verify(this.messageChannel).send(this.messageCaptor.capture());
|
||||
Message<?> message = this.messageCaptor.getValue();
|
||||
assertNotNull(message);
|
||||
|
||||
assertEquals("{\"withView1\":\"with\"}", new String((byte[])message.getPayload(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
|
||||
private Message<?> createInputMessage(String sessId, String subsId, String destinationPrefix,
|
||||
String destination, Principal principal) {
|
||||
|
@ -475,4 +513,54 @@ public class SendToMethodReturnValueHandlerTests {
|
|||
return PAYLOAD;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@SendTo({"/dest"})
|
||||
@JsonView(MyJacksonView1.class)
|
||||
public JacksonViewBean handleAndSendToJsonView() {
|
||||
JacksonViewBean payload = new JacksonViewBean();
|
||||
payload.setWithView1("with");
|
||||
payload.setWithView2("with");
|
||||
payload.setWithoutView("without");
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
private interface MyJacksonView1 {};
|
||||
private interface MyJacksonView2 {};
|
||||
|
||||
private static class JacksonViewBean {
|
||||
|
||||
@JsonView(MyJacksonView1.class)
|
||||
private String withView1;
|
||||
|
||||
@JsonView(MyJacksonView2.class)
|
||||
private String withView2;
|
||||
|
||||
private String withoutView;
|
||||
|
||||
public String getWithView1() {
|
||||
return withView1;
|
||||
}
|
||||
|
||||
public void setWithView1(String withView1) {
|
||||
this.withView1 = withView1;
|
||||
}
|
||||
|
||||
public String getWithView2() {
|
||||
return withView2;
|
||||
}
|
||||
|
||||
public void setWithView2(String withView2) {
|
||||
this.withView2 = withView2;
|
||||
}
|
||||
|
||||
public String getWithoutView() {
|
||||
return withoutView;
|
||||
}
|
||||
|
||||
public void setWithoutView(String withoutView) {
|
||||
this.withoutView = withoutView;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,8 +18,10 @@ package org.springframework.messaging.simp.annotation.support;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Principal;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
@ -32,6 +34,8 @@ import org.springframework.core.MethodParameter;
|
|||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.messaging.core.MessageSendingOperations;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
|
@ -50,6 +54,7 @@ import static org.mockito.BDDMockito.*;
|
|||
* Test fixture for {@link SubscriptionMethodReturnValueHandler}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class SubscriptionMethodReturnValueHandlerTests {
|
||||
|
||||
|
@ -60,9 +65,11 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
|
||||
private SubscriptionMethodReturnValueHandler handler;
|
||||
|
||||
private SubscriptionMethodReturnValueHandler jsonHandler;
|
||||
|
||||
@Mock private MessageChannel messageChannel;
|
||||
|
||||
@Captor ArgumentCaptor<Message<?>> messageCaptor;
|
||||
@Captor private ArgumentCaptor<Message<?>> messageCaptor;
|
||||
|
||||
private MethodParameter subscribeEventReturnType;
|
||||
|
||||
|
@ -70,6 +77,8 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
|
||||
private MethodParameter messageMappingReturnType;
|
||||
|
||||
private MethodParameter subscribeEventJsonViewReturnType;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
|
@ -78,9 +87,12 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
|
||||
SimpMessagingTemplate messagingTemplate = new SimpMessagingTemplate(this.messageChannel);
|
||||
messagingTemplate.setMessageConverter(new StringMessageConverter());
|
||||
|
||||
this.handler = new SubscriptionMethodReturnValueHandler(messagingTemplate);
|
||||
|
||||
SimpMessagingTemplate jsonMessagingTemplate = new SimpMessagingTemplate(this.messageChannel);
|
||||
jsonMessagingTemplate.setMessageConverter(new MappingJackson2MessageConverter());
|
||||
this.jsonHandler = new SubscriptionMethodReturnValueHandler(jsonMessagingTemplate);
|
||||
|
||||
Method method = this.getClass().getDeclaredMethod("getData");
|
||||
this.subscribeEventReturnType = new MethodParameter(method, -1);
|
||||
|
||||
|
@ -89,6 +101,9 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
|
||||
method = this.getClass().getDeclaredMethod("handle");
|
||||
this.messageMappingReturnType = new MethodParameter(method, -1);
|
||||
|
||||
method = this.getClass().getDeclaredMethod("getJsonView");
|
||||
this.subscribeEventJsonViewReturnType = new MethodParameter(method, -1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,6 +138,7 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
assertEquals(subscriptionId, headerAccessor.getSubscriptionId());
|
||||
assertEquals(destination, headerAccessor.getDestination());
|
||||
assertEquals(MIME_TYPE, headerAccessor.getContentType());
|
||||
assertEquals(this.subscribeEventReturnType, headerAccessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -149,6 +165,26 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
assertTrue(headerAccessor.isMutable());
|
||||
assertEquals(sessionId, headerAccessor.getSessionId());
|
||||
assertEquals(subscriptionId, headerAccessor.getSubscriptionId());
|
||||
assertEquals(this.subscribeEventReturnType, headerAccessor.getHeader(AbstractMessageConverter.METHOD_PARAMETER_HINT_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonView() throws Exception {
|
||||
|
||||
given(this.messageChannel.send(any(Message.class))).willReturn(true);
|
||||
|
||||
String sessionId = "sess1";
|
||||
String subscriptionId = "subs1";
|
||||
String destination = "/dest";
|
||||
Message<?> inputMessage = createInputMessage(sessionId, subscriptionId, destination, null);
|
||||
|
||||
this.jsonHandler.handleReturnValue(getJsonView(), this.subscribeEventJsonViewReturnType, inputMessage);
|
||||
|
||||
verify(this.messageChannel).send(this.messageCaptor.capture());
|
||||
Message<?> message = this.messageCaptor.getValue();
|
||||
assertNotNull(message);
|
||||
|
||||
assertEquals("{\"withView1\":\"with\"}", new String((byte[])message.getPayload(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,4 +213,54 @@ public class SubscriptionMethodReturnValueHandlerTests {
|
|||
public String handle() {
|
||||
return PAYLOAD;
|
||||
}
|
||||
|
||||
@SubscribeMapping("/jsonview") // not needed for the tests but here for completeness
|
||||
@JsonView(MyJacksonView1.class)
|
||||
public JacksonViewBean getJsonView() {
|
||||
JacksonViewBean payload = new JacksonViewBean();
|
||||
payload.setWithView1("with");
|
||||
payload.setWithView2("with");
|
||||
payload.setWithoutView("without");
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
private interface MyJacksonView1 {};
|
||||
private interface MyJacksonView2 {};
|
||||
|
||||
private static class JacksonViewBean {
|
||||
|
||||
@JsonView(MyJacksonView1.class)
|
||||
private String withView1;
|
||||
|
||||
@JsonView(MyJacksonView2.class)
|
||||
private String withView2;
|
||||
|
||||
private String withoutView;
|
||||
|
||||
public String getWithView1() {
|
||||
return withView1;
|
||||
}
|
||||
|
||||
public void setWithView1(String withView1) {
|
||||
this.withView1 = withView1;
|
||||
}
|
||||
|
||||
public String getWithView2() {
|
||||
return withView2;
|
||||
}
|
||||
|
||||
public void setWithView2(String withView2) {
|
||||
this.withView2 = withView2;
|
||||
}
|
||||
|
||||
public String getWithoutView() {
|
||||
return withoutView;
|
||||
}
|
||||
|
||||
public void setWithoutView(String withoutView) {
|
||||
this.withoutView = withoutView;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue