Permalink
Browse files

o making the default Json transport match the default Xml transport, …

…the user can choose to provide their own XStream or ObjectMapper instance/provider respectively
  • Loading branch information...
1 parent 7202ee5 commit e6ccdfd13d4d4ce842079b3d5d5893394cbb5459 Jason van Zyl committed Mar 1, 2012
@@ -3,167 +3,38 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.Set;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
-import org.codehaus.jackson.map.deser.StdDeserializerProvider;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import com.google.common.primitives.Primitives;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.google.sitebricks.conversion.Converter;
-import com.google.sitebricks.conversion.ConverterRegistry;
-import com.google.sitebricks.conversion.StandardTypeConverter;
-import com.google.sitebricks.conversion.generics.Generics;
/**
* @author Dhanji R. Prasanna (dhanji@gmail.com)
- * @author John Patterson (jdpatterson@gmail.com)
- * @author JRodriguez
*/
@Singleton
public class JacksonJsonTransport extends Json {
private final ObjectMapper objectMapper;
- private Collection<Class<?>> exceptions = Sets.newHashSet();
-
- @Inject
- public JacksonJsonTransport(ConverterRegistry registry) {
- this.objectMapper = new ObjectMapper();
- CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory();
-
- // leave these for Jackson to handle
- exceptions.add(String.class);
- exceptions.add(Object.class);
- exceptions.addAll(Primitives.allWrapperTypes());
- //
- Multimap<Type, ConverterDirection> typeToConverterDirection = ArrayListMultimap.create();
- addConverterDirections(registry, true, typeToConverterDirection);
- addConverterDirections(registry, false, typeToConverterDirection);
- createJacksonDeserializers(deserializerFactory, typeToConverterDirection);
-
- objectMapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
- }
+ @Inject
+ public JacksonJsonTransport(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
public ObjectMapper getObjectMapper() {
- return objectMapper;
+ return objectMapper;
}
- // keep track of which direction we want to use
- private static class ConverterDirection
- {
- Converter<?, ?> converter;
- boolean forward;
- }
-
- private void addConverterDirections(ConverterRegistry registry, boolean forward, Multimap<Type, ConverterDirection> typeToConverterDirections) {
- Multimap<Type, Converter<?, ?>> typeToConverters = forward ? registry.getConvertersByTarget() : registry.getConvertersBySource();
- Set<Type> types = typeToConverters.keySet();
- for (Type type : types) {
- if (exceptions.contains(type)) continue;
- Collection<Converter<?, ?>> converters = typeToConverters.get(type);
- for (Converter<?, ?> converter : converters) {
- ConverterDirection converterDirection = new ConverterDirection();
- converterDirection.converter = converter;
- converterDirection.forward = forward;
- typeToConverterDirections.put(type, converterDirection);
- }
- }
- }
-
- private void createJacksonDeserializers(CustomDeserializerFactory deserializerFactory, Multimap<Type, ConverterDirection> typeToConverterDirections)
- {
- Set<Type> targetTypes = typeToConverterDirections.keySet();
- for (Type targetType : targetTypes) {
- Collection<ConverterDirection> converterDirections = typeToConverterDirections.get(targetType);
- Class<?> targetClass = Generics.erase(targetType);
- ConvertersDeserializer jds = new ConvertersDeserializer(converterDirections);
- typesafeAddMapping(targetClass, jds, deserializerFactory);
- }
- }
-
- @SuppressWarnings("unchecked")
- private <T> void typesafeAddMapping(Class<?> type, JsonDeserializer<T> deserializer,
- CustomDeserializerFactory factory) {
- factory.addSpecificMapping((Class<T>) type, deserializer);
- }
-
public <T> T in(InputStream in, Class<T> type) throws IOException {
return objectMapper.readValue(in, type);
}
public <T> void out(OutputStream out, Class<T> type, T data) {
try {
objectMapper.writeValue(out, data);
- }
- catch (IOException e) {
+ } catch (IOException e) {
throw new RuntimeException(e);
}
}
-
- public class ConvertersDeserializer extends JsonDeserializer<Object> {
-
- private final Collection<ConverterDirection> converterDirections;
-
- public ConvertersDeserializer(Collection<ConverterDirection> converterDirections) {
- this.converterDirections = converterDirections;
- }
-
- public Object deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException {
-
- Object source = getSourceObject(jp, ctxt);
-
- for (ConverterDirection converterDirection : converterDirections) {
-
- Type sourceType = converterDirection.forward ?
- StandardTypeConverter.sourceType(converterDirection.converter) :
- StandardTypeConverter.targetType(converterDirection.converter);
-
- // assume that Jackson only gives us non-generic types
- Class<?> converterSourceClass = Generics.erase(sourceType);
-
- if (converterSourceClass.isAssignableFrom(source.getClass())) {
- return converterDirection.forward ?
- StandardTypeConverter.typeSafeTo(converterDirection.converter, source) :
- StandardTypeConverter.typeSafeFrom(converterDirection.converter, source);
- }
- }
-
- throw new IllegalStateException("Cannot convert from " + source);
- }
-
- private Object getSourceObject(JsonParser jp, DeserializationContext ctxt) throws JsonParseException, IOException {
- JsonToken t = jp.getCurrentToken();
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return jp.getLongValue();
- }
- else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
- return jp.getDoubleValue();
- }
- else if (t == JsonToken.VALUE_TRUE) {
- return Boolean.TRUE;
- }
- else if (t == JsonToken.VALUE_FALSE) {
- return Boolean.FALSE;
- }
- else if (t == JsonToken.VALUE_STRING) {
- return jp.getText();
- }
- else throw new IllegalStateException();
- }
- }
}
@@ -0,0 +1,169 @@
+package com.google.sitebricks.client.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Set;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
+import org.codehaus.jackson.map.deser.StdDeserializerProvider;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.primitives.Primitives;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.sitebricks.conversion.Converter;
+import com.google.sitebricks.conversion.ConverterRegistry;
+import com.google.sitebricks.conversion.StandardTypeConverter;
+import com.google.sitebricks.conversion.generics.Generics;
+
+/**
+ * @author Dhanji R. Prasanna (dhanji@gmail.com)
+ * @author John Patterson (jdpatterson@gmail.com)
+ * @author JRodriguez
+ */
+@Singleton
+public class JacksonJsonTransportWithConverters extends Json {
+
+ private final ObjectMapper objectMapper;
+ private Collection<Class<?>> exceptions = Sets.newHashSet();
+
+ @Inject
+ public JacksonJsonTransportWithConverters(ConverterRegistry registry) {
+ this.objectMapper = new ObjectMapper();
+ CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory();
+
+ // leave these for Jackson to handle
+ exceptions.add(String.class);
+ exceptions.add(Object.class);
+ exceptions.addAll(Primitives.allWrapperTypes());
+
+ //
+ Multimap<Type, ConverterDirection> typeToConverterDirection = ArrayListMultimap.create();
+ addConverterDirections(registry, true, typeToConverterDirection);
+ addConverterDirections(registry, false, typeToConverterDirection);
+ createJacksonDeserializers(deserializerFactory, typeToConverterDirection);
+
+ objectMapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
+ }
+
+ public ObjectMapper getObjectMapper() {
+ return objectMapper;
+ }
+
+ // keep track of which direction we want to use
+ private static class ConverterDirection
+ {
+ Converter<?, ?> converter;
+ boolean forward;
+ }
+
+ private void addConverterDirections(ConverterRegistry registry, boolean forward, Multimap<Type, ConverterDirection> typeToConverterDirections) {
+ Multimap<Type, Converter<?, ?>> typeToConverters = forward ? registry.getConvertersByTarget() : registry.getConvertersBySource();
+ Set<Type> types = typeToConverters.keySet();
+ for (Type type : types) {
+ if (exceptions.contains(type)) continue;
+ Collection<Converter<?, ?>> converters = typeToConverters.get(type);
+ for (Converter<?, ?> converter : converters) {
+ ConverterDirection converterDirection = new ConverterDirection();
+ converterDirection.converter = converter;
+ converterDirection.forward = forward;
+ typeToConverterDirections.put(type, converterDirection);
+ }
+ }
+ }
+
+ private void createJacksonDeserializers(CustomDeserializerFactory deserializerFactory, Multimap<Type, ConverterDirection> typeToConverterDirections)
+ {
+ Set<Type> targetTypes = typeToConverterDirections.keySet();
+ for (Type targetType : targetTypes) {
+ Collection<ConverterDirection> converterDirections = typeToConverterDirections.get(targetType);
+ Class<?> targetClass = Generics.erase(targetType);
+ ConvertersDeserializer jds = new ConvertersDeserializer(converterDirections);
+ typesafeAddMapping(targetClass, jds, deserializerFactory);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> void typesafeAddMapping(Class<?> type, JsonDeserializer<T> deserializer,
+ CustomDeserializerFactory factory) {
+ factory.addSpecificMapping((Class<T>) type, deserializer);
+ }
+
+ public <T> T in(InputStream in, Class<T> type) throws IOException {
+ return objectMapper.readValue(in, type);
+ }
+
+ public <T> void out(OutputStream out, Class<T> type, T data) {
+ try {
+ objectMapper.writeValue(out, data);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public class ConvertersDeserializer extends JsonDeserializer<Object> {
+
+ private final Collection<ConverterDirection> converterDirections;
+
+ public ConvertersDeserializer(Collection<ConverterDirection> converterDirections) {
+ this.converterDirections = converterDirections;
+ }
+
+ public Object deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+
+ Object source = getSourceObject(jp, ctxt);
+
+ for (ConverterDirection converterDirection : converterDirections) {
+
+ Type sourceType = converterDirection.forward ?
+ StandardTypeConverter.sourceType(converterDirection.converter) :
+ StandardTypeConverter.targetType(converterDirection.converter);
+
+ // assume that Jackson only gives us non-generic types
+ Class<?> converterSourceClass = Generics.erase(sourceType);
+
+ if (converterSourceClass.isAssignableFrom(source.getClass())) {
+ return converterDirection.forward ?
+ StandardTypeConverter.typeSafeTo(converterDirection.converter, source) :
+ StandardTypeConverter.typeSafeFrom(converterDirection.converter, source);
+ }
+ }
+
+ throw new IllegalStateException("Cannot convert from " + source);
+ }
+
+ private Object getSourceObject(JsonParser jp, DeserializationContext ctxt) throws JsonParseException, IOException {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return jp.getLongValue();
+ }
+ else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ return jp.getDoubleValue();
+ }
+ else if (t == JsonToken.VALUE_TRUE) {
+ return Boolean.TRUE;
+ }
+ else if (t == JsonToken.VALUE_FALSE) {
+ return Boolean.FALSE;
+ }
+ else if (t == JsonToken.VALUE_STRING) {
+ return jp.getText();
+ }
+ else throw new IllegalStateException();
+ }
+ }
+}
@@ -9,7 +9,7 @@
*
* @author dhanji@google.com (Dhanji R. Prasanna)
*/
-@ImplementedBy(SimpleJacksonJsonTransport.class)
+@ImplementedBy(JacksonJsonTransport.class)
public abstract class Json implements Transport {
public String contentType() {
@@ -1,42 +0,0 @@
-package com.google.sitebricks.client.transport;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.codehaus.jackson.map.ObjectMapper;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-/**
- * @author Dhanji R. Prasanna (dhanji@gmail.com)
- * @author John Patterson (jdpatterson@gmail.com)
- * @author JRodriguez
- */
-@Singleton
-public class SimpleJacksonJsonTransport extends Json {
-
- private final ObjectMapper objectMapper;
-
- @Inject
- public SimpleJacksonJsonTransport() {
- this.objectMapper = new ObjectMapper();
- }
-
- public ObjectMapper getObjectMapper() {
- return objectMapper;
- }
-
- public <T> T in(InputStream in, Class<T> type) throws IOException {
- return objectMapper.readValue(in, type);
- }
-
- public <T> void out(OutputStream out, Class<T> type, T data) {
- try {
- objectMapper.writeValue(out, data);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-}

0 comments on commit e6ccdfd

Please sign in to comment.