Skip to content
This repository was archived by the owner on Jan 20, 2025. It is now read-only.

Commit d00da16

Browse files
committed
Merge pull request #79 from jorool/master
New configuration for Guava Range default bound type.
2 parents f02cafc + ff60380 commit d00da16

File tree

4 files changed

+197
-4
lines changed

4 files changed

+197
-4
lines changed

src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
public class GuavaDeserializers
2626
extends Deserializers.Base
2727
{
28+
private BoundType _defaultBoundType;
29+
30+
public GuavaDeserializers(BoundType defaultBoundType) {
31+
_defaultBoundType = defaultBoundType;
32+
}
33+
2834
/**
2935
* We have plenty of collection types to support...
3036
*/
@@ -251,7 +257,7 @@ public JsonDeserializer<?> findBeanDeserializer(final JavaType type, Deserializa
251257
return new GuavaOptionalDeserializer(type, refType, typeDeser, valueDeser);
252258
}
253259
if (raw == Range.class) {
254-
return new RangeDeserializer(type);
260+
return new RangeDeserializer(_defaultBoundType, type);
255261
}
256262
if (raw == HostAndPort.class) {
257263
return HostAndPortDeserializer.std;

src/main/java/com/fasterxml/jackson/datatype/guava/GuavaModule.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import com.fasterxml.jackson.core.Version;
44

55
import com.fasterxml.jackson.databind.*;
6+
import com.fasterxml.jackson.databind.cfg.PackageVersion;
67
import com.fasterxml.jackson.datatype.guava.ser.GuavaBeanSerializerModifier;
8+
import com.google.common.collect.BoundType;
9+
10+
import static com.google.common.base.Preconditions.checkNotNull;
711

812
/**
913
* Basic Jackson {@link Module} that adds support for Guava types.
@@ -37,6 +41,7 @@ public class GuavaModule extends Module // can't use just SimpleModule, due to g
3741
* changes after registration will have no effect.
3842
*/
3943
protected boolean _cfgHandleAbsentAsNull = true;
44+
protected BoundType _defaultBoundType;
4045

4146
public GuavaModule() {
4247
super();
@@ -48,7 +53,7 @@ public GuavaModule() {
4853
@Override
4954
public void setupModule(SetupContext context)
5055
{
51-
context.addDeserializers(new GuavaDeserializers());
56+
context.addDeserializers(new GuavaDeserializers(_defaultBoundType));
5257
context.addSerializers(new GuavaSerializers());
5358
context.addTypeModifier(new GuavaTypeModifier());
5459

@@ -75,6 +80,24 @@ public GuavaModule configureAbsentsAsNulls(boolean state) {
7580
_cfgHandleAbsentAsNull = state;
7681
return this;
7782
}
83+
84+
/**
85+
* Configuration method that may be used to change the {@link BoundType} to be used
86+
* when deserializing {@link com.google.common.collect.Range} objects. This configuration
87+
* will is used when the object to be deserialied has no bound type attribute.
88+
* The default {@link BoundType} is CLOSED.
89+
*
90+
* @param boundType {@link BoundType}
91+
*
92+
* @return This module instance, useful for chaining calls
93+
*
94+
* @since 2.6.1 ? FIXME
95+
*/
96+
public GuavaModule defaultBoundType(BoundType boundType) {
97+
checkNotNull(boundType);
98+
_defaultBoundType = boundType;
99+
return this;
100+
}
78101

79102
@Override
80103
public int hashCode()

src/main/java/com/fasterxml/jackson/datatype/guava/deser/RangeDeserializer.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ public class RangeDeserializer
3333

3434
protected final JsonDeserializer<Object> _endpointDeserializer;
3535

36+
private BoundType _defaultBoundType;
37+
3638
/*
3739
/**********************************************************
3840
/* Life-cycle
3941
/**********************************************************
4042
*/
4143

42-
public RangeDeserializer(JavaType rangeType) {
44+
public RangeDeserializer(BoundType defaultBoundType, JavaType rangeType) {
4345
this(rangeType, null);
46+
this._defaultBoundType = defaultBoundType;
4447
}
4548

4649
@SuppressWarnings("unchecked")
@@ -51,6 +54,15 @@ public RangeDeserializer(JavaType rangeType, JsonDeserializer<?> endpointDeser)
5154
_endpointDeserializer = (JsonDeserializer<Object>) endpointDeser;
5255
}
5356

57+
@SuppressWarnings("unchecked")
58+
public RangeDeserializer(JavaType rangeType, JsonDeserializer<?> endpointDeser, BoundType defaultBoundType)
59+
{
60+
super(rangeType);
61+
_rangeType = rangeType;
62+
_endpointDeserializer = (JsonDeserializer<Object>) endpointDeser;
63+
_defaultBoundType = defaultBoundType;
64+
}
65+
5466
@Override
5567
public JavaType getValueType() { return _rangeType; }
5668

@@ -64,7 +76,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
6476
endpointType = TypeFactory.unknownType();
6577
}
6678
JsonDeserializer<Object> deser = ctxt.findContextualValueDeserializer(endpointType, property);
67-
return new RangeDeserializer(_rangeType, deser);
79+
return new RangeDeserializer(_rangeType, deser, _defaultBoundType);
6880
}
6981
return this;
7082
}
@@ -126,6 +138,12 @@ public Range<?> deserialize(JsonParser parser, DeserializationContext context)
126138
}
127139
}
128140

141+
if (lowerBoundType == null)
142+
lowerBoundType = _defaultBoundType;
143+
144+
if (upperBoundType == null)
145+
upperBoundType = _defaultBoundType;
146+
129147
try {
130148
if ((lowerEndpoint != null) && (upperEndpoint != null)) {
131149
Preconditions.checkState(lowerEndpoint.getClass() == upperEndpoint.getClass(),

src/test/java/com/fasterxml/jackson/datatype/guava/TestRange.java

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import com.fasterxml.jackson.annotation.JsonTypeInfo;
44

5+
import com.fasterxml.jackson.databind.JsonMappingException;
56
import com.fasterxml.jackson.databind.ObjectMapper;
67
import com.fasterxml.jackson.datatype.guava.deser.util.RangeFactory;
78

9+
import com.google.common.collect.BoundType;
810
import com.google.common.collect.Range;
911

1012
import java.io.IOException;
@@ -103,4 +105,148 @@ public void testUntyped() throws Exception
103105
assertNotNull(out);
104106
assertEquals(Range.class, out.range.getClass());
105107
}
108+
109+
public void testDefaultBoundTypeNoBoundTypeInformed() throws Exception
110+
{
111+
String json = "{\"lowerEndpoint\": 2, \"upperEndpoint\": 3}";
112+
113+
try {
114+
MAPPER.readValue(json, Range.class);
115+
fail("Should have failed");
116+
} catch (JsonMappingException e) {
117+
verifyException(e, "'lowerEndpoint' field found, but not 'lowerBoundType'");
118+
}
119+
}
120+
121+
public void testDefaultBoundTypeNoBoundTypeInformedWithClosedConfigured() throws Exception
122+
{
123+
String json = "{\"lowerEndpoint\": 2, \"upperEndpoint\": 3}";
124+
125+
GuavaModule mod = new GuavaModule().defaultBoundType(BoundType.CLOSED);
126+
ObjectMapper mapper = new ObjectMapper().registerModule(mod);
127+
128+
@SuppressWarnings("unchecked")
129+
Range<Integer> r = (Range<Integer>) mapper.readValue(json, Range.class);
130+
131+
assertEquals(Integer.valueOf(2), r.lowerEndpoint());
132+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
133+
assertEquals(BoundType.CLOSED, r.lowerBoundType());
134+
assertEquals(BoundType.CLOSED, r.upperBoundType());
135+
}
136+
137+
public void testDefaultBoundTypeOnlyLowerBoundTypeInformed() throws Exception
138+
{
139+
String json = "{\"lowerEndpoint\": 2, \"lowerBoundType\": \"OPEN\", \"upperEndpoint\": 3}";
140+
141+
try {
142+
MAPPER.readValue(json, Range.class);
143+
fail("Should have failed");
144+
} catch (JsonMappingException e) {
145+
verifyException(e, "'upperEndpoint' field found, but not 'upperBoundType'");
146+
}
147+
}
148+
149+
public void testDefaultBoundTypeOnlyLowerBoundTypeInformedWithClosedConfigured() throws Exception
150+
{
151+
String json = "{\"lowerEndpoint\": 2, \"lowerBoundType\": \"OPEN\", \"upperEndpoint\": 3}";
152+
153+
GuavaModule mod = new GuavaModule().defaultBoundType(BoundType.CLOSED);
154+
ObjectMapper mapper = new ObjectMapper().registerModule(mod);
155+
156+
@SuppressWarnings("unchecked")
157+
Range<Integer> r = (Range<Integer>) mapper.readValue(json, Range.class);
158+
159+
assertEquals(Integer.valueOf(2), r.lowerEndpoint());
160+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
161+
assertEquals(BoundType.OPEN, r.lowerBoundType());
162+
assertEquals(BoundType.CLOSED, r.upperBoundType());
163+
}
164+
165+
public void testDefaultBoundTypeOnlyUpperBoundTypeInformed() throws Exception
166+
{
167+
String json = "{\"lowerEndpoint\": 2, \"upperEndpoint\": 3, \"upperBoundType\": \"OPEN\"}";
168+
169+
try {
170+
MAPPER.readValue(json, Range.class);
171+
fail("Should have failed");
172+
} catch (JsonMappingException e) {
173+
verifyException(e, "'lowerEndpoint' field found, but not 'lowerBoundType'");
174+
}
175+
}
176+
177+
public void testDefaultBoundTypeOnlyUpperBoundTypeInformedWithClosedConfigured() throws Exception
178+
{
179+
String json = "{\"lowerEndpoint\": 1, \"upperEndpoint\": 3, \"upperBoundType\": \"OPEN\"}";
180+
181+
GuavaModule mod = new GuavaModule().defaultBoundType(BoundType.CLOSED);
182+
ObjectMapper mapper = new ObjectMapper().registerModule(mod);
183+
184+
@SuppressWarnings("unchecked")
185+
Range<Integer> r = (Range<Integer>) mapper.readValue(json, Range.class);
186+
187+
assertEquals(Integer.valueOf(1), r.lowerEndpoint());
188+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
189+
assertEquals(BoundType.CLOSED, r.lowerBoundType());
190+
assertEquals(BoundType.OPEN, r.upperBoundType());
191+
}
192+
193+
public void testDefaultBoundTypeBothBoundTypesOpen() throws Exception
194+
{
195+
String json = "{\"lowerEndpoint\": 2, \"lowerBoundType\": \"OPEN\", \"upperEndpoint\": 3, \"upperBoundType\": \"OPEN\"}";
196+
@SuppressWarnings("unchecked")
197+
Range<Integer> r = (Range<Integer>) MAPPER.readValue(json, Range.class);
198+
199+
assertEquals(Integer.valueOf(2), r.lowerEndpoint());
200+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
201+
202+
assertEquals(BoundType.OPEN, r.lowerBoundType());
203+
assertEquals(BoundType.OPEN, r.upperBoundType());
204+
}
205+
206+
public void testDefaultBoundTypeBothBoundTypesOpenWithClosedConfigured() throws Exception
207+
{
208+
String json = "{\"lowerEndpoint\": 1, \"lowerBoundType\": \"OPEN\", \"upperEndpoint\": 3, \"upperBoundType\": \"OPEN\"}";
209+
210+
GuavaModule mod = new GuavaModule().defaultBoundType(BoundType.CLOSED);
211+
ObjectMapper mapper = new ObjectMapper().registerModule(mod);
212+
213+
@SuppressWarnings("unchecked")
214+
Range<Integer> r = (Range<Integer>) mapper.readValue(json, Range.class);
215+
216+
assertEquals(Integer.valueOf(1), r.lowerEndpoint());
217+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
218+
219+
assertEquals(BoundType.OPEN, r.lowerBoundType());
220+
assertEquals(BoundType.OPEN, r.upperBoundType());
221+
}
222+
223+
public void testDefaultBoundTypeBothBoundTypesClosed() throws Exception
224+
{
225+
String json = "{\"lowerEndpoint\": 1, \"lowerBoundType\": \"CLOSED\", \"upperEndpoint\": 3, \"upperBoundType\": \"CLOSED\"}";
226+
@SuppressWarnings("unchecked")
227+
Range<Integer> r = (Range<Integer>) MAPPER.readValue(json, Range.class);
228+
229+
assertEquals(Integer.valueOf(1), r.lowerEndpoint());
230+
assertEquals(Integer.valueOf(3), r.upperEndpoint());
231+
232+
assertEquals(BoundType.CLOSED, r.lowerBoundType());
233+
assertEquals(BoundType.CLOSED, r.upperBoundType());
234+
}
235+
236+
public void testDefaultBoundTypeBothBoundTypesClosedWithOpenConfigured() throws Exception
237+
{
238+
String json = "{\"lowerEndpoint\": 12, \"lowerBoundType\": \"CLOSED\", \"upperEndpoint\": 33, \"upperBoundType\": \"CLOSED\"}";
239+
240+
GuavaModule mod = new GuavaModule().defaultBoundType(BoundType.CLOSED);
241+
ObjectMapper mapper = new ObjectMapper().registerModule(mod);
242+
243+
@SuppressWarnings("unchecked")
244+
Range<Integer> r = (Range<Integer>) mapper.readValue(json, Range.class);
245+
246+
assertEquals(Integer.valueOf(12), r.lowerEndpoint());
247+
assertEquals(Integer.valueOf(33), r.upperEndpoint());
248+
249+
assertEquals(BoundType.CLOSED, r.lowerBoundType());
250+
assertEquals(BoundType.CLOSED, r.upperBoundType());
251+
}
106252
}

0 commit comments

Comments
 (0)