INT-1000 polishing JsonInboundMessageMapper
This commit is contained in:
@@ -38,42 +38,41 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* {@link InboundMessageMapper} implementation that maps incoming JSON messages to a {@link Message} with the specified payload type.
|
||||
*
|
||||
* TODO - Need to figure out if we need to go as deep in mapping HeaderTypes...right now it wouldn't work if the header type was something like List<TestBean>
|
||||
* - cannot assume order as implemented; headers may not always precede the payload
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @since 2.0
|
||||
*/
|
||||
public class InboundJsonMessageMapper implements
|
||||
InboundMessageMapper<String> {
|
||||
public class JsonInboundMessageMapper implements InboundMessageMapper<String> {
|
||||
|
||||
private static final String MESSAGE_FORMAT_ERROR = "JSON message is invalid. Expected a message in the format of {\"headers\":{...},\"payload\":{...}} but was ";
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static Map<String, Class<?>> DEFAULT_HEADER_TYPES;
|
||||
|
||||
private Map<String, Class<?>> headerTypes = DEFAULT_HEADER_TYPES;
|
||||
|
||||
private boolean mapToPayload = false;
|
||||
|
||||
private JavaType payloadType;
|
||||
|
||||
static {
|
||||
DEFAULT_HEADER_TYPES = new HashMap<String, Class<?>>();
|
||||
DEFAULT_HEADER_TYPES.put(MessageHeaders.ID, UUID.class);
|
||||
DEFAULT_HEADER_TYPES.put(MessageHeaders.TIMESTAMP, Long.class);
|
||||
DEFAULT_HEADER_TYPES.put(MessageHeaders.EXPIRATION_DATE, Long.class);
|
||||
}
|
||||
|
||||
public InboundJsonMessageMapper(Class<?> payloadType) {
|
||||
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final JavaType payloadType;
|
||||
|
||||
private final Map<String, Class<?>> headerTypes = DEFAULT_HEADER_TYPES;
|
||||
|
||||
private volatile boolean mapToPayload = false;
|
||||
|
||||
|
||||
public JsonInboundMessageMapper(Class<?> payloadType) {
|
||||
this.payloadType = TypeFactory.type(payloadType);
|
||||
}
|
||||
|
||||
public InboundJsonMessageMapper(TypeReference<?> typeReference) {
|
||||
|
||||
public JsonInboundMessageMapper(TypeReference<?> typeReference) {
|
||||
this.payloadType = TypeFactory.type(typeReference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setHeaderTypes(Map<String, Class<?>> headerTypes) {
|
||||
this.headerTypes.putAll(headerTypes);
|
||||
}
|
||||
@@ -84,14 +83,16 @@ public class InboundJsonMessageMapper implements
|
||||
|
||||
public Message<?> toMessage(String jsonMessage) throws Exception {
|
||||
JsonParser parser = new JsonFactory().createJsonParser(jsonMessage);
|
||||
if (mapToPayload) {
|
||||
if (this.mapToPayload) {
|
||||
try {
|
||||
Object payload = objectMapper.readValue(parser, payloadType);
|
||||
return MessageBuilder.withPayload(payload).build();
|
||||
} catch (JsonMappingException ex) {
|
||||
}
|
||||
catch (JsonMappingException ex) {
|
||||
throw new IllegalArgumentException("Mapping of JSON message "+jsonMessage+" directly to payload of type "+payloadType.getRawClass().getName()+" failed.", ex);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
String error = MESSAGE_FORMAT_ERROR + jsonMessage;
|
||||
Assert.isTrue(parser.nextToken() == JsonToken.START_OBJECT, error);
|
||||
Assert.isTrue(parser.nextToken() == JsonToken.FIELD_NAME, error);
|
||||
@@ -101,10 +102,12 @@ public class InboundJsonMessageMapper implements
|
||||
while (parser.nextToken() != JsonToken.END_OBJECT) {
|
||||
String headerName = parser.getCurrentName();
|
||||
parser.nextToken();
|
||||
Class<?> headerType = headerTypes.containsKey(headerName) ? headerTypes.get(headerName) : Object.class;
|
||||
Class<?> headerType = this.headerTypes.containsKey(headerName) ?
|
||||
this.headerTypes.get(headerName) : Object.class;
|
||||
try {
|
||||
headers.put(headerName, objectMapper.readValue(parser, headerType));
|
||||
} catch (JsonMappingException ex) {
|
||||
headers.put(headerName, this.objectMapper.readValue(parser, headerType));
|
||||
}
|
||||
catch (JsonMappingException ex) {
|
||||
throw new IllegalArgumentException("Mapping header \""+headerName+"\" of JSON message "+jsonMessage+" to header type "+payloadType.getRawClass().getName()+" failed.", ex);
|
||||
}
|
||||
}
|
||||
@@ -112,11 +115,13 @@ public class InboundJsonMessageMapper implements
|
||||
Assert.isTrue(parser.getCurrentName().equals("payload"), error);
|
||||
parser.nextToken();
|
||||
try {
|
||||
Object payload = objectMapper.readValue(parser, payloadType);
|
||||
Object payload = this.objectMapper.readValue(parser, this.payloadType);
|
||||
return MessageBuilder.withPayload(payload).copyHeaders(headers).build();
|
||||
} catch (JsonMappingException ex) {
|
||||
}
|
||||
catch (JsonMappingException ex) {
|
||||
throw new IllegalArgumentException("Mapping payload of JSON message "+jsonMessage+" to payload type "+payloadType.getRawClass().getName()+" failed.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,21 +45,23 @@ import org.springframework.integration.support.MessageBuilder;
|
||||
* @author Mark Fisher
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class InboundJsonMessageMapperTests {
|
||||
public class JsonInboundMessageMapperTests {
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
|
||||
|
||||
@Factory
|
||||
public static Matcher<Message<?>> sameExceptImmutableHeaders(Message<?> operand) {
|
||||
return new MessageMatcher(operand);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToMessageWithHeadersAndStringPayload() throws Exception {
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":\"myPayloadStuff\"}";
|
||||
Message<String> expected = MessageBuilder.withPayload("myPayloadStuff").setHeader(MessageHeaders.TIMESTAMP, new Long(1)).setHeader(MessageHeaders.ID, id).build();
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertThat(result, sameExceptImmutableHeaders(expected));
|
||||
}
|
||||
@@ -68,7 +70,7 @@ public class InboundJsonMessageMapperTests {
|
||||
public void testToMessageWithStringPayload() throws Exception {
|
||||
String jsonMessage = "\"myPayloadStuff\"";
|
||||
String expected = "myPayloadStuff";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
mapper.setMapToPayload(true);
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertEquals(expected, result.getPayload());
|
||||
@@ -80,7 +82,7 @@ public class InboundJsonMessageMapperTests {
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":" + getBeanAsJson(bean) + "}";
|
||||
Message<TestBean> expected = MessageBuilder.withPayload(bean).setHeader(MessageHeaders.TIMESTAMP, new Long(1)).setHeader(MessageHeaders.ID, id).build();
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(TestBean.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(TestBean.class);
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertThat(result, sameExceptImmutableHeaders(expected));
|
||||
}
|
||||
@@ -89,7 +91,7 @@ public class InboundJsonMessageMapperTests {
|
||||
public void testToMessageWithBeanPayload() throws Exception {
|
||||
TestBean expected = new TestBean();
|
||||
String jsonMessage = getBeanAsJson(expected);
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(TestBean.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(TestBean.class);
|
||||
mapper.setMapToPayload(true);
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertEquals(expected, result.getPayload());
|
||||
@@ -102,7 +104,7 @@ public class InboundJsonMessageMapperTests {
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\", \"myHeader\":" + getBeanAsJson(bean) + "},\"payload\":\"myPayloadStuff\"}";
|
||||
Message<String> expected = MessageBuilder.withPayload("myPayloadStuff").
|
||||
setHeader(MessageHeaders.TIMESTAMP, new Long(1)).setHeader(MessageHeaders.ID, id).setHeader("myHeader", bean).build();
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
Map<String, Class<?>> headerTypes = new HashMap<String, Class<?>>();
|
||||
headerTypes.put("myHeader", TestBean.class);
|
||||
mapper.setHeaderTypes(headerTypes);
|
||||
@@ -116,7 +118,7 @@ public class InboundJsonMessageMapperTests {
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":[\"myPayloadStuff1\",\"myPayloadStuff2\",\"myPayloadStuff3\"]}";
|
||||
List<String> expectedList = Arrays.asList(new String[]{"myPayloadStuff1", "myPayloadStuff2", "myPayloadStuff3"});
|
||||
Message<List<String>> expected = MessageBuilder.withPayload(expectedList).setHeader(MessageHeaders.TIMESTAMP, new Long(1)).setHeader(MessageHeaders.ID, id).build();
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(new TypeReference<List<String>>(){});
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(new TypeReference<List<String>>(){});
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertThat(result, sameExceptImmutableHeaders(expected));
|
||||
}
|
||||
@@ -129,16 +131,16 @@ public class InboundJsonMessageMapperTests {
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":[" + getBeanAsJson(bean1) + "," + getBeanAsJson(bean2) + "]}";
|
||||
List<TestBean> expectedList = Arrays.asList(new TestBean[]{bean1, bean2});
|
||||
Message<List<TestBean>> expected = MessageBuilder.withPayload(expectedList).setHeader(MessageHeaders.TIMESTAMP, new Long(1)).setHeader(MessageHeaders.ID, id).build();
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(new TypeReference<List<TestBean>>(){});
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(new TypeReference<List<TestBean>>(){});
|
||||
Message<?> result = mapper.toMessage(jsonMessage);
|
||||
assertThat(result, sameExceptImmutableHeaders(expected));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToMessageInvalidFormatPayloadAndHeadersReversed() throws Exception {
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"payload\":\"myPayloadStuff\",\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"}}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
fail();
|
||||
@@ -151,7 +153,7 @@ public class InboundJsonMessageMapperTests {
|
||||
@Test
|
||||
public void testToMessageInvalidFormatPayloadNoHeaders() throws Exception {
|
||||
String jsonMessage = "{\"payload\":\"myPayloadStuff\"}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
fail();
|
||||
@@ -165,7 +167,7 @@ public class InboundJsonMessageMapperTests {
|
||||
public void testToMessageInvalidFormatHeadersNoPayload() throws Exception {
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"}}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
fail();
|
||||
@@ -179,7 +181,7 @@ public class InboundJsonMessageMapperTests {
|
||||
public void testToMessageInvalidFormatHeadersAndStringPayloadWithMapToPayload() throws Exception {
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":\"myPayloadStuff\"}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
mapper.setMapToPayload(true);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
@@ -195,7 +197,7 @@ public class InboundJsonMessageMapperTests {
|
||||
TestBean bean = new TestBean();
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":" + getBeanAsJson(bean) + "}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(TestBean.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(TestBean.class);
|
||||
mapper.setMapToPayload(true);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
@@ -211,7 +213,7 @@ public class InboundJsonMessageMapperTests {
|
||||
TestBean bean = new TestBean();
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"},\"payload\":" + getBeanAsJson(bean) + "}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(Long.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(Long.class);
|
||||
try {
|
||||
mapper.toMessage(jsonMessage);
|
||||
fail();
|
||||
@@ -226,7 +228,7 @@ public class InboundJsonMessageMapperTests {
|
||||
TestBean bean = new TestBean();
|
||||
UUID id = UUID.randomUUID();
|
||||
String jsonMessage = "{\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\",\"myHeader\":" + getBeanAsJson(bean) + "},\"payload\":\"myPayloadStuff\"}";
|
||||
InboundJsonMessageMapper mapper = new InboundJsonMessageMapper(String.class);
|
||||
JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class);
|
||||
Map<String, Class<?>> headerTypes = new HashMap<String, Class<?>>();
|
||||
headerTypes.put("myHeader", Long.class);
|
||||
mapper.setHeaderTypes(headerTypes);
|
||||
Reference in New Issue
Block a user