diff --git a/spring-integration-core/src/main/java/org/springframework/integration/json/JsonInboundMessageMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/json/JsonInboundMessageMapper.java index cedd59d4f2..278b949fcf 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/json/JsonInboundMessageMapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/json/JsonInboundMessageMapper.java @@ -43,7 +43,7 @@ import org.springframework.util.Assert; */ public class JsonInboundMessageMapper implements InboundMessageMapper { - private static final String MESSAGE_FORMAT_ERROR = "JSON message is invalid. Expected a message in the format of {\"headers\":{...},\"payload\":{...}} but was "; + private static final String MESSAGE_FORMAT_ERROR = "JSON message is invalid. Expected a message in the format of either {\"headers\":{...},\"payload\":{...}} or {\"payload\":{...}.\"headers\":{...}} but was "; private static Map> DEFAULT_HEADER_TYPES; @@ -72,7 +72,6 @@ public class JsonInboundMessageMapper implements InboundMessageMapper { this.payloadType = TypeFactory.type(typeReference); } - public void setHeaderTypes(Map> headerTypes) { this.headerTypes.putAll(headerTypes); } @@ -85,8 +84,7 @@ public class JsonInboundMessageMapper implements InboundMessageMapper { JsonParser parser = new JsonFactory().createJsonParser(jsonMessage); if (this.mapToPayload) { try { - Object payload = objectMapper.readValue(parser, payloadType); - return MessageBuilder.withPayload(payload).build(); + return MessageBuilder.withPayload(readPayload(parser, jsonMessage)).build(); } catch (JsonMappingException ex) { throw new IllegalArgumentException("Mapping of JSON message "+jsonMessage+" directly to payload of type "+payloadType.getRawClass().getName()+" failed.", ex); @@ -95,33 +93,48 @@ public class JsonInboundMessageMapper implements InboundMessageMapper { else { String error = MESSAGE_FORMAT_ERROR + jsonMessage; Assert.isTrue(parser.nextToken() == JsonToken.START_OBJECT, error); - Assert.isTrue(parser.nextToken() == JsonToken.FIELD_NAME, error); - Assert.isTrue(parser.getCurrentName().equals("headers"), error); - Assert.isTrue(parser.nextToken() == JsonToken.START_OBJECT, error); - Map headers = new LinkedHashMap(); - while (parser.nextToken() != JsonToken.END_OBJECT) { - String headerName = parser.getCurrentName(); - parser.nextToken(); - Class headerType = this.headerTypes.containsKey(headerName) ? - this.headerTypes.get(headerName) : Object.class; - try { - 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); + + Map headers = null; + Object payload = null; + while(parser.nextToken() != JsonToken.END_OBJECT) { + Assert.isTrue(parser.getCurrentToken() == JsonToken.FIELD_NAME, error); + Assert.isTrue(parser.getCurrentName().equals("headers") || parser.getCurrentName().equals("payload"), error); + if (parser.getCurrentName().equals("headers")) { + Assert.isTrue(parser.nextToken() == JsonToken.START_OBJECT, error); + headers = readHeaders(parser, jsonMessage); + } else if (parser.getCurrentName().equals("payload")) { + parser.nextToken(); + try { + payload = readPayload(parser, jsonMessage); + } + catch (JsonMappingException ex) { + throw new IllegalArgumentException("Mapping payload of JSON message "+jsonMessage+" to payload type "+payloadType.getRawClass().getName()+" failed.", ex); + } } } - Assert.isTrue(parser.nextToken() == JsonToken.FIELD_NAME, error); - Assert.isTrue(parser.getCurrentName().equals("payload"), error); - parser.nextToken(); - try { - Object payload = this.objectMapper.readValue(parser, this.payloadType); - return MessageBuilder.withPayload(payload).copyHeaders(headers).build(); - } - catch (JsonMappingException ex) { - throw new IllegalArgumentException("Mapping payload of JSON message "+jsonMessage+" to payload type "+payloadType.getRawClass().getName()+" failed.", ex); - } + Assert.notNull(headers, error); + return MessageBuilder.withPayload(payload).copyHeaders(headers).build(); } } - + + protected Object readPayload(JsonParser parser, String jsonMessage) throws Exception { + return objectMapper.readValue(parser, payloadType); + } + + protected Map readHeaders(JsonParser parser, String jsonMessage) throws Exception{ + Map headers = new LinkedHashMap(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + String headerName = parser.getCurrentName(); + parser.nextToken(); + Class headerType = this.headerTypes.containsKey(headerName) ? + this.headerTypes.get(headerName) : Object.class; + try { + 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); + } + } + return headers; + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/json/JsonInboundMessageMapperTests.java b/spring-integration-core/src/test/java/org/springframework/integration/json/JsonInboundMessageMapperTests.java index 33c2fc51c9..7141b1a116 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/json/JsonInboundMessageMapperTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/json/JsonInboundMessageMapperTests.java @@ -135,17 +135,13 @@ public class JsonInboundMessageMapperTests { } @Test - public void testToMessageInvalidFormatPayloadAndHeadersReversed() throws Exception { + public void testToMessageWithPayloadAndHeadersReversed() throws Exception { UUID id = UUID.randomUUID(); - String jsonMessage = "{\"payload\":\"myPayloadStuff\",\"headers\":{\"$timestamp\":1,\"$id\":\"" + id + "\"}}"; + String jsonMessage = "{\"payload\":\"myPayloadStuff\",\"headers\":{\"timestamp\":1,\"id\":\"" + id + "\",\"foo\":123,\"bar\":\"abc\"}}"; + Message expected = MessageBuilder.withPayload("myPayloadStuff").setHeader("foo", 123).setHeader("bar", "abc").build(); JsonInboundMessageMapper mapper = new JsonInboundMessageMapper(String.class); - try { - mapper.toMessage(jsonMessage); - fail(); - } - catch(IllegalArgumentException ex) { - //Expected - } + Message result = mapper.toMessage(jsonMessage); + assertThat(result, sameExceptImmutableHeaders(expected)); } @Test diff --git a/spring-integration-core/src/test/java/org/springframework/integration/json/JsonSymmetricalMessageMappingTests.java b/spring-integration-core/src/test/java/org/springframework/integration/json/JsonSymmetricalMessageMappingTests.java new file mode 100644 index 0000000000..e0a19953fb --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/json/JsonSymmetricalMessageMappingTests.java @@ -0,0 +1,67 @@ +package org.springframework.integration.json; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import org.codehaus.jackson.JsonFactory; +import org.codehaus.jackson.map.ObjectMapper; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import org.junit.Test; +import org.springframework.integration.Message; +import org.springframework.integration.context.NamedComponent; +import org.springframework.integration.history.MessageHistory; +import org.springframework.integration.message.MessageMatcher; +import org.springframework.integration.support.MessageBuilder; + + +public class JsonSymmetricalMessageMappingTests { + + private final JsonFactory jsonFactory = new JsonFactory(); + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Factory + public static Matcher> sameExceptImmutableHeaders(Message operand) { + return new MessageMatcher(operand); + } + + @Test + public void testSymmetricalMappingWithHistory() throws Exception { + Message testMessage = MessageBuilder.withPayload("myPayloadStuff").build(); + testMessage = MessageHistory.write(testMessage, new TestNamedComponent(1)); + testMessage = MessageHistory.write(testMessage, new TestNamedComponent(2)); + testMessage = MessageHistory.write(testMessage, new TestNamedComponent(3)); + JsonOutboundMessageMapper outboundMapper = new JsonOutboundMessageMapper(); + + String outboundJson = outboundMapper.fromMessage(testMessage); + System.out.println(outboundJson); + + JsonInboundMessageMapper inboundMapper = new JsonInboundMessageMapper(String.class); + Message result = (Message) inboundMapper.toMessage(outboundJson); + + assertThat(result, sameExceptImmutableHeaders(testMessage)); + //assertEquals(testMessage, result); + + outboundJson = outboundMapper.fromMessage(result); + System.out.println(outboundJson); + } + + private static class TestNamedComponent implements NamedComponent { + + private final int id; + + private TestNamedComponent(int id) { + this.id = id; + } + + public String getComponentName() { + return "testName-" + this.id; + } + + public String getComponentType() { + return "testType-" + this.id; + } + + } +}