diff --git a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java index e01c9629..15998ab7 100644 --- a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java +++ b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java @@ -262,6 +262,9 @@ public JsonDeserializer findReferenceDeserializer(ReferenceType refType, public JsonDeserializer findBeanDeserializer(final JavaType type, DeserializationConfig config, BeanDescription beanDesc) { + if (type.hasRawClass(RangeSet.class)) { + return new RangeSetDeserializer(); + } if (type.hasRawClass(Range.class)) { return new RangeDeserializer(_defaultBoundType, type); } diff --git a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaSerializers.java b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaSerializers.java index e3d5f430..b5ba654a 100644 --- a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaSerializers.java +++ b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/GuavaSerializers.java @@ -14,12 +14,14 @@ import com.fasterxml.jackson.databind.type.ReferenceType; import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer; import com.fasterxml.jackson.databind.util.StdConverter; +import com.fasterxml.jackson.datatype.guava.ser.RangeSetSerializer; import com.google.common.base.Optional; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilderSpec; import com.google.common.collect.FluentIterable; import com.google.common.collect.Multimap; import com.google.common.collect.Range; +import com.google.common.collect.RangeSet; import com.google.common.collect.Table; import com.google.common.hash.HashCode; import com.google.common.net.HostAndPort; @@ -63,6 +65,9 @@ public JsonSerializer findSerializer(SerializationConfig config, JavaType typ BeanDescription beanDesc, JsonFormat.Value formatOverrides) { Class raw = type.getRawClass(); + if (RangeSet.class.isAssignableFrom(raw)) { + return new RangeSetSerializer(); + } if (Range.class.isAssignableFrom(raw)) { return new RangeSerializer(_findDeclared(type, Range.class)); } diff --git a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/deser/RangeSetDeserializer.java b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/deser/RangeSetDeserializer.java new file mode 100644 index 00000000..8a08befd --- /dev/null +++ b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/deser/RangeSetDeserializer.java @@ -0,0 +1,45 @@ +package com.fasterxml.jackson.datatype.guava.deser; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.google.common.collect.ImmutableRangeSet; +import com.google.common.collect.Range; +import com.google.common.collect.RangeSet; + +import java.io.IOException; +import java.util.List; + +public class RangeSetDeserializer extends JsonDeserializer>> { + private JavaType genericRangeListType; + + @Override + public RangeSet> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (genericRangeListType == null) { + throw new JsonParseException(p, "RangeSetJsonSerializer was not contextualized (no deserialize target type). " + + "You need to specify the generic type down to the generic parameter of RangeSet."); + } else { + @SuppressWarnings("unchecked") final Iterable>> ranges + = (Iterable>>) ctxt + .findContextualValueDeserializer(genericRangeListType, null).deserialize(p, ctxt); + ImmutableRangeSet.Builder> builder = ImmutableRangeSet.builder(); + for (Range> range : ranges) { + builder.add(range); + } + return builder.build(); + } + } + + @Override + public JsonDeserializer createContextual(DeserializationContext ctxt, BeanProperty property) { + final JavaType genericType = ctxt.getContextualType().containedType(0); + if (genericType == null) return this; + final RangeSetDeserializer deserializer = new RangeSetDeserializer(); + deserializer.genericRangeListType = ctxt.getTypeFactory().constructCollectionType(List.class, + ctxt.getTypeFactory().constructParametricType(Range.class, genericType)); + return deserializer; + } +} diff --git a/guava/src/main/java/com/fasterxml/jackson/datatype/guava/ser/RangeSetSerializer.java b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/ser/RangeSetSerializer.java new file mode 100644 index 00000000..67bc64df --- /dev/null +++ b/guava/src/main/java/com/fasterxml/jackson/datatype/guava/ser/RangeSetSerializer.java @@ -0,0 +1,36 @@ +package com.fasterxml.jackson.datatype.guava.ser; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.google.common.collect.Range; +import com.google.common.collect.RangeSet; + +import java.io.IOException; +import java.util.List; + +public class RangeSetSerializer extends JsonSerializer>> { + private JavaType genericRangeListType; + + @Override + public void serialize(RangeSet> value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (genericRangeListType == null) { + serializers.findValueSerializer(List.class).serialize(value.asRanges(), gen, serializers); + } else { + serializers.findValueSerializer(genericRangeListType).serialize(value.asRanges(), gen, serializers); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) { + if (property == null) return this; + final RangeSetSerializer serializer = new RangeSetSerializer(); + serializer.genericRangeListType = prov.getTypeFactory() + .constructCollectionType(List.class, + prov.getTypeFactory().constructParametricType( + Range.class, property.getType().containedType(0))); + return serializer; + } +} diff --git a/guava/src/test/java/com/fasterxml/jackson/datatype/guava/TestRangeSet.java b/guava/src/test/java/com/fasterxml/jackson/datatype/guava/TestRangeSet.java new file mode 100644 index 00000000..0e12d75f --- /dev/null +++ b/guava/src/test/java/com/fasterxml/jackson/datatype/guava/TestRangeSet.java @@ -0,0 +1,35 @@ +package com.fasterxml.jackson.datatype.guava; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.collect.Range; +import com.google.common.collect.RangeSet; +import com.google.common.collect.TreeRangeSet; + +import java.io.IOException; + +public class TestRangeSet extends ModuleTestBase { + + private final ObjectMapper MAPPER = mapperWithModule(); + + public void testSerializeDeserialize() throws IOException { + + final RangeSet rangeSet = TreeRangeSet.create(); + rangeSet.add(Range.closedOpen(1, 2)); + rangeSet.add(Range.openClosed(3, 4)); + + final String json = MAPPER.writeValueAsString(rangeSet); + + final TypeFactory tf = MAPPER.getTypeFactory(); + final JavaType type = tf.constructParametricType(RangeSet.class, Integer.class); + final ObjectReader reader = MAPPER.readerFor(type); + + final RangeSet deserialized = reader.readValue(json); + + assertEquals(rangeSet, deserialized); + + } + +}