First pass at inbound/outbound JSON mapping for INT-1000 and INT-1001. Needs complete Javadoc'ing and still has some TODO's to address.

This commit is contained in:
Jeremy Grelle
2010-03-05 22:38:58 +00:00
parent 0757df5b33
commit 4374a3da20
9 changed files with 585 additions and 1 deletions

View File

@@ -0,0 +1,102 @@
package org.springframework.integration.json;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.InboundMessageMapper;
import org.springframework.integration.message.MessageBuilder;
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>
*
* @author Jeremy Grelle
*/
public class InboundJsonMessageMapper 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.TIMESTAMP, Long.class);
DEFAULT_HEADER_TYPES.put(MessageHeaders.EXPIRATION_DATE, Long.class);
}
public InboundJsonMessageMapper(Class<?> payloadType) {
this.payloadType = TypeFactory.type(payloadType);
}
public InboundJsonMessageMapper(TypeReference<?> typeReference) {
this.payloadType = TypeFactory.type(typeReference);
}
public void setHeaderTypes(Map<String, Class<?>> headerTypes) {
this.headerTypes.putAll(headerTypes);
}
public void setMapToPayload(boolean mapToPayload) {
this.mapToPayload = mapToPayload;
}
public Message<?> toMessage(String jsonMessage) throws Exception {
JsonParser parser = new JsonFactory().createJsonParser(jsonMessage);
if (mapToPayload) {
try {
Object payload = objectMapper.readValue(parser, payloadType);
return MessageBuilder.withPayload(payload).build();
} catch (JsonMappingException ex) {
throw new IllegalArgumentException("Mapping of JSON message "+jsonMessage+" directly to payload of type "+payloadType.getRawClass().getName()+" failed.", ex);
}
} 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<String, Object> headers = new LinkedHashMap<String, Object>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
String headerName = parser.getCurrentName();
parser.nextToken();
Class<?> headerType = headerTypes.containsKey(headerName) ? headerTypes.get(headerName) : Object.class;
try {
headers.put(headerName, 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);
}
}
Assert.isTrue(parser.nextToken() == JsonToken.FIELD_NAME, error);
Assert.isTrue(parser.getCurrentName().equals("payload"), error);
parser.nextToken();
try {
Object payload = objectMapper.readValue(parser, 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);
}
}
}
}

View File

@@ -0,0 +1,35 @@
package org.springframework.integration.json;
import java.io.StringWriter;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.OutboundMessageMapper;
/**
* {@link OutboundMessageMapper} implementation the converts a {@link Message} to a JSON string representation.
*
* TODO - We might need to add special handling for MessageHistory
*
* @author Jeremy Grelle
*/
public class OutboundJsonMessageMapper implements OutboundMessageMapper<String> {
private boolean shouldExtractPayload = false;
private ObjectMapper objectMapper = new ObjectMapper();
public String fromMessage(Message<?> message) throws Exception {
StringWriter writer = new StringWriter();
if (shouldExtractPayload) {
objectMapper.writeValue(writer, message.getPayload());
} else {
objectMapper.writeValue(writer, message);
}
return writer.toString();
}
public void setShouldExtractPayload(boolean shouldExtractPayload) {
this.shouldExtractPayload = shouldExtractPayload;
}
}