Skip to content

Commit ab9413a

Browse files
committed
Fix #2424
1 parent c326c13 commit ab9413a

File tree

9 files changed

+136
-25
lines changed

9 files changed

+136
-25
lines changed

release-notes/VERSION-2.x

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Project: jackson-databind
1818
to `handleUnknownVanilla()`
1919
(proposed by Vladimir T, follow up to #822)
2020
#2416: Optimize `ValueInstantiator` construction for default `Collection`, `Map` types
21+
#2425: Add global config override setting for `@JsonFormat.lenient()`
2122

2223
2.10.0.pr1 (19-Jul-2019)
2324

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

+8
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,14 @@ public ObjectMapper setDefaultMergeable(Boolean b) {
15261526
return this;
15271527
}
15281528

1529+
/**
1530+
* @since 2.10
1531+
*/
1532+
public ObjectMapper setDefaultLeniency(Boolean b) {
1533+
_configOverrides.setDefaultLeniency(b);
1534+
return this;
1535+
}
1536+
15291537
/*
15301538
/**********************************************************
15311539
/* Subtype registration

src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java

+82-15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.*;
44

5+
import com.fasterxml.jackson.annotation.JsonFormat;
56
import com.fasterxml.jackson.annotation.JsonInclude;
67
import com.fasterxml.jackson.annotation.JsonSetter;
78
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
@@ -43,10 +44,20 @@ public class ConfigOverrides
4344
*/
4445
protected Boolean _defaultMergeable;
4546

47+
/**
48+
* Global default setting (if any) for leniency: if disabled ({link Boolean#TRUE}),
49+
* "strict" (not lenient): default setting if absence of value is considered "lenient"
50+
* in Jackson 2.x. Default setting may be overridden by per-type and per-property
51+
* settings.
52+
*
53+
* @since 2.10
54+
*/
55+
protected Boolean _defaultLeniency;
56+
4657
/*
47-
/**********************************************************
58+
/**********************************************************************
4859
/* Life cycle
49-
/**********************************************************
60+
/**********************************************************************
5061
*/
5162

5263
public ConfigOverrides() {
@@ -55,22 +66,35 @@ public ConfigOverrides() {
5566
JsonInclude.Value.empty(),
5667
JsonSetter.Value.empty(),
5768
VisibilityChecker.Std.defaultInstance(),
58-
null
69+
null, null
5970
);
6071
}
6172

73+
/**
74+
* @since 2.10
75+
*/
6276
protected ConfigOverrides(Map<Class<?>, MutableConfigOverride> overrides,
63-
JsonInclude.Value defIncl,
64-
JsonSetter.Value defSetter,
65-
VisibilityChecker<?> defVisibility,
66-
Boolean defMergeable) {
77+
JsonInclude.Value defIncl, JsonSetter.Value defSetter,
78+
VisibilityChecker<?> defVisibility, Boolean defMergeable, Boolean defLeniency)
79+
{
6780
_overrides = overrides;
6881
_defaultInclusion = defIncl;
6982
_defaultSetterInfo = defSetter;
7083
_visibilityChecker = defVisibility;
7184
_defaultMergeable = defMergeable;
85+
_defaultLeniency = defLeniency;
7286
}
7387

88+
/**
89+
* @deprecated Since 2.10
90+
*/
91+
@Deprecated // since 2.10
92+
protected ConfigOverrides(Map<Class<?>, MutableConfigOverride> overrides,
93+
JsonInclude.Value defIncl, JsonSetter.Value defSetter,
94+
VisibilityChecker<?> defVisibility, Boolean defMergeable) {
95+
this(overrides, defIncl, defSetter, defVisibility, defMergeable, null);
96+
}
97+
7498
public ConfigOverrides copy()
7599
{
76100
Map<Class<?>, MutableConfigOverride> newOverrides;
@@ -83,15 +107,16 @@ public ConfigOverrides copy()
83107
}
84108
}
85109
return new ConfigOverrides(newOverrides,
86-
_defaultInclusion, _defaultSetterInfo, _visibilityChecker, _defaultMergeable);
110+
_defaultInclusion, _defaultSetterInfo, _visibilityChecker,
111+
_defaultMergeable, _defaultLeniency);
87112
}
88113

89114
/*
90-
/**********************************************************
115+
/**********************************************************************
91116
/* Per-type override access
92-
/**********************************************************
117+
/**********************************************************************
93118
*/
94-
119+
95120
public ConfigOverride findOverride(Class<?> type) {
96121
if (_overrides == null) {
97122
return null;
@@ -111,10 +136,38 @@ public MutableConfigOverride findOrCreateOverride(Class<?> type) {
111136
return override;
112137
}
113138

139+
/**
140+
* Specific accessor for finding {code JsonFormat.Value} for given type,
141+
* considering global default for leniency as well as per-type format
142+
* override (if any).
143+
*
144+
* @return Default format settings for type; never null.
145+
*
146+
* @since 2.10
147+
*/
148+
public JsonFormat.Value findFormatDefaults(Class<?> type) {
149+
if (_overrides != null) {
150+
ConfigOverride override = _overrides.get(type);
151+
if (override != null) {
152+
JsonFormat.Value format = override.getFormat();
153+
if (format != null) {
154+
if (!format.hasLenient()) {
155+
return format.withLenient(_defaultLeniency);
156+
}
157+
return format;
158+
}
159+
}
160+
}
161+
if (_defaultLeniency == null) {
162+
return JsonFormat.Value.empty();
163+
}
164+
return JsonFormat.Value.forLeniency(_defaultLeniency);
165+
}
166+
114167
/*
115-
/**********************************************************
168+
/**********************************************************************
116169
/* Global defaults access
117-
/**********************************************************
170+
/**********************************************************************
118171
*/
119172

120173
public JsonInclude.Value getDefaultInclusion() {
@@ -129,6 +182,13 @@ public Boolean getDefaultMergeable() {
129182
return _defaultMergeable;
130183
}
131184

185+
/**
186+
* @since 2.10
187+
*/
188+
public Boolean getDefaultLeniency() {
189+
return _defaultLeniency;
190+
}
191+
132192
/**
133193
* @since 2.9
134194
*/
@@ -157,6 +217,13 @@ public void setDefaultMergeable(Boolean v) {
157217
_defaultMergeable = v;
158218
}
159219

220+
/**
221+
* @since 2.10
222+
*/
223+
public void setDefaultLeniency(Boolean v) {
224+
_defaultLeniency = v;
225+
}
226+
160227
/**
161228
* @since 2.9
162229
*/
@@ -165,9 +232,9 @@ public void setDefaultVisibility(VisibilityChecker<?> v) {
165232
}
166233

167234
/*
168-
/**********************************************************
235+
/**********************************************************************
169236
/* Helper methods
170-
/**********************************************************
237+
/**********************************************************************
171238
*/
172239

173240
protected Map<Class<?>, MutableConfigOverride> _newMap() {

src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -637,14 +637,7 @@ public final JsonInclude.Value getDefaultInclusion(Class<?> baseType,
637637

638638
@Override
639639
public final JsonFormat.Value getDefaultPropertyFormat(Class<?> type) {
640-
ConfigOverride overrides = _configOverrides.findOverride(type);
641-
if (overrides != null) {
642-
JsonFormat.Value v = overrides.getFormat();
643-
if (v != null) {
644-
return v;
645-
}
646-
}
647-
return EMPTY_FORMAT;
640+
return _configOverrides.findFormatDefaults(type);
648641
}
649642

650643
@Override

src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
public class JsonLocationInstantiator
1919
extends ValueInstantiator.Base
2020
{
21+
private static final long serialVersionUID = 1L;
22+
2123
public JsonLocationInstantiator() {
2224
super(JsonLocation.class);
2325
}

src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public abstract class ContainerNode<T extends ContainerNode<T>>
1515
extends BaseJsonNode
1616
implements JsonNodeCreator
1717
{
18+
private static final long serialVersionUID = 1L;
19+
1820
/**
1921
* We will keep a reference to the Object (usually TreeMapper)
2022
* that can construct instances of nodes to add to this container

src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
public abstract class NumericNode
1212
extends ValueNode
1313
{
14+
private static final long serialVersionUID = 1L;
15+
1416
protected NumericNode() { }
1517

1618
@Override

src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
public abstract class ValueNode
1818
extends BaseJsonNode
1919
{
20+
private static final long serialVersionUID = 1L;
21+
2022
protected ValueNode() { }
2123

2224
@Override

src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java

+36-2
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ public void testCalendarArrayUnwrap() throws Exception
725725
/**********************************************************
726726
*/
727727

728-
public void testLenientCalendar() throws Exception
728+
public void testLenientJDKDateTypes() throws Exception
729729
{
730730
final String JSON = aposToQuotes("{'value':'2015-11-32'}");
731731

@@ -743,8 +743,10 @@ public void testLenientCalendar() throws Exception
743743
verifyException(e, "from String \"2015-11-32\"");
744744
verifyException(e, "expected format");
745745
}
746+
}
746747

747-
// similarly with Date...
748+
public void testLenientJDKDateTypesViaTypeOverride() throws Exception
749+
{
748750
ObjectMapper mapper = new ObjectMapper();
749751
mapper.configOverride(java.util.Date.class)
750752
.setFormat(JsonFormat.Value.forLeniency(Boolean.FALSE));
@@ -758,6 +760,38 @@ public void testLenientCalendar() throws Exception
758760
}
759761
}
760762

763+
public void testLenientJDKDateTypesViaGlobal() throws Exception
764+
{
765+
final String JSON = quote("2015-11-32");
766+
767+
// with lenient, can parse fine
768+
Calendar value = MAPPER.readValue(JSON, Calendar.class);
769+
assertEquals(Calendar.DECEMBER, value.get(Calendar.MONTH));
770+
assertEquals(2, value.get(Calendar.DAY_OF_MONTH));
771+
772+
// but not so if default leniency disabled
773+
ObjectMapper mapper = new ObjectMapper();
774+
mapper.setDefaultLeniency(false);
775+
try {
776+
mapper.readValue(JSON, java.util.Date.class);
777+
fail("Should not pass with invalid (with strict) date value");
778+
} catch (MismatchedInputException e) {
779+
verifyException(e, "Cannot deserialize value of type `java.util.Date`");
780+
verifyException(e, "from String \"2015-11-32\"");
781+
verifyException(e, "expected format");
782+
}
783+
784+
// Unless we actually had per-type override too
785+
mapper = new ObjectMapper();
786+
mapper.configOverride(Calendar.class)
787+
.setFormat(JsonFormat.Value.forLeniency(Boolean.TRUE));
788+
mapper.setDefaultLeniency(false);
789+
790+
value = mapper.readValue(JSON, Calendar.class);
791+
assertEquals(Calendar.DECEMBER, value.get(Calendar.MONTH));
792+
assertEquals(2, value.get(Calendar.DAY_OF_MONTH));
793+
}
794+
761795
/*
762796
/**********************************************************
763797
/* Tests to verify failing cases

0 commit comments

Comments
 (0)