aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2019-08-19 19:12:06 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2019-08-19 19:12:06 -0700
commitab9413aec6de9c50a77b716fccd0c198d98a6951 (patch)
treeb13c2ed3746fbc0f8f0f105c2ca8f7995299ab2d
parentc326c1358fd2d52e7c6be7b119b6ce1bf220b8a5 (diff)
downloadjackson-databind-ab9413aec6de9c50a77b716fccd0c198d98a6951.tar.gz
Fix #2424
-rw-r--r--release-notes/VERSION-2.x1
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java8
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java97
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java9
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java2
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java38
9 files changed, 136 insertions, 25 deletions
diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x
index 8a2fc57b9..c43e028aa 100644
--- a/release-notes/VERSION-2.x
+++ b/release-notes/VERSION-2.x
@@ -18,6 +18,7 @@ Project: jackson-databind
to `handleUnknownVanilla()`
(proposed by Vladimir T, follow up to #822)
#2416: Optimize `ValueInstantiator` construction for default `Collection`, `Map` types
+#2425: Add global config override setting for `@JsonFormat.lenient()`
2.10.0.pr1 (19-Jul-2019)
diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java
index 564854905..457f3825b 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java
@@ -1526,6 +1526,14 @@ public class ObjectMapper
return this;
}
+ /**
+ * @since 2.10
+ */
+ public ObjectMapper setDefaultLeniency(Boolean b) {
+ _configOverrides.setDefaultLeniency(b);
+ return this;
+ }
+
/*
/**********************************************************
/* Subtype registration
diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java b/src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java
index 49c622cc6..dfc87e80e 100644
--- a/src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java
+++ b/src/main/java/com/fasterxml/jackson/databind/cfg/ConfigOverrides.java
@@ -2,6 +2,7 @@ package com.fasterxml.jackson.databind.cfg;
import java.util.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
@@ -43,10 +44,20 @@ public class ConfigOverrides
*/
protected Boolean _defaultMergeable;
+ /**
+ * Global default setting (if any) for leniency: if disabled ({link Boolean#TRUE}),
+ * "strict" (not lenient): default setting if absence of value is considered "lenient"
+ * in Jackson 2.x. Default setting may be overridden by per-type and per-property
+ * settings.
+ *
+ * @since 2.10
+ */
+ protected Boolean _defaultLeniency;
+
/*
- /**********************************************************
+ /**********************************************************************
/* Life cycle
- /**********************************************************
+ /**********************************************************************
*/
public ConfigOverrides() {
@@ -55,22 +66,35 @@ public class ConfigOverrides
JsonInclude.Value.empty(),
JsonSetter.Value.empty(),
VisibilityChecker.Std.defaultInstance(),
- null
+ null, null
);
}
+ /**
+ * @since 2.10
+ */
protected ConfigOverrides(Map<Class<?>, MutableConfigOverride> overrides,
- JsonInclude.Value defIncl,
- JsonSetter.Value defSetter,
- VisibilityChecker<?> defVisibility,
- Boolean defMergeable) {
+ JsonInclude.Value defIncl, JsonSetter.Value defSetter,
+ VisibilityChecker<?> defVisibility, Boolean defMergeable, Boolean defLeniency)
+ {
_overrides = overrides;
_defaultInclusion = defIncl;
_defaultSetterInfo = defSetter;
_visibilityChecker = defVisibility;
_defaultMergeable = defMergeable;
+ _defaultLeniency = defLeniency;
}
+ /**
+ * @deprecated Since 2.10
+ */
+ @Deprecated // since 2.10
+ protected ConfigOverrides(Map<Class<?>, MutableConfigOverride> overrides,
+ JsonInclude.Value defIncl, JsonSetter.Value defSetter,
+ VisibilityChecker<?> defVisibility, Boolean defMergeable) {
+ this(overrides, defIncl, defSetter, defVisibility, defMergeable, null);
+ }
+
public ConfigOverrides copy()
{
Map<Class<?>, MutableConfigOverride> newOverrides;
@@ -83,15 +107,16 @@ public class ConfigOverrides
}
}
return new ConfigOverrides(newOverrides,
- _defaultInclusion, _defaultSetterInfo, _visibilityChecker, _defaultMergeable);
+ _defaultInclusion, _defaultSetterInfo, _visibilityChecker,
+ _defaultMergeable, _defaultLeniency);
}
/*
- /**********************************************************
+ /**********************************************************************
/* Per-type override access
- /**********************************************************
+ /**********************************************************************
*/
-
+
public ConfigOverride findOverride(Class<?> type) {
if (_overrides == null) {
return null;
@@ -111,10 +136,38 @@ public class ConfigOverrides
return override;
}
+ /**
+ * Specific accessor for finding {code JsonFormat.Value} for given type,
+ * considering global default for leniency as well as per-type format
+ * override (if any).
+ *
+ * @return Default format settings for type; never null.
+ *
+ * @since 2.10
+ */
+ public JsonFormat.Value findFormatDefaults(Class<?> type) {
+ if (_overrides != null) {
+ ConfigOverride override = _overrides.get(type);
+ if (override != null) {
+ JsonFormat.Value format = override.getFormat();
+ if (format != null) {
+ if (!format.hasLenient()) {
+ return format.withLenient(_defaultLeniency);
+ }
+ return format;
+ }
+ }
+ }
+ if (_defaultLeniency == null) {
+ return JsonFormat.Value.empty();
+ }
+ return JsonFormat.Value.forLeniency(_defaultLeniency);
+ }
+
/*
- /**********************************************************
+ /**********************************************************************
/* Global defaults access
- /**********************************************************
+ /**********************************************************************
*/
public JsonInclude.Value getDefaultInclusion() {
@@ -130,6 +183,13 @@ public class ConfigOverrides
}
/**
+ * @since 2.10
+ */
+ public Boolean getDefaultLeniency() {
+ return _defaultLeniency;
+ }
+
+ /**
* @since 2.9
*/
public VisibilityChecker<?> getDefaultVisibility() {
@@ -158,6 +218,13 @@ public class ConfigOverrides
}
/**
+ * @since 2.10
+ */
+ public void setDefaultLeniency(Boolean v) {
+ _defaultLeniency = v;
+ }
+
+ /**
* @since 2.9
*/
public void setDefaultVisibility(VisibilityChecker<?> v) {
@@ -165,9 +232,9 @@ public class ConfigOverrides
}
/*
- /**********************************************************
+ /**********************************************************************
/* Helper methods
- /**********************************************************
+ /**********************************************************************
*/
protected Map<Class<?>, MutableConfigOverride> _newMap() {
diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java
index a7ca2e5ad..044d13bcf 100644
--- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java
@@ -637,14 +637,7 @@ public abstract class MapperConfigBase<CFG extends ConfigFeature,
@Override
public final JsonFormat.Value getDefaultPropertyFormat(Class<?> type) {
- ConfigOverride overrides = _configOverrides.findOverride(type);
- if (overrides != null) {
- JsonFormat.Value v = overrides.getFormat();
- if (v != null) {
- return v;
- }
- }
- return EMPTY_FORMAT;
+ return _configOverrides.findFormatDefaults(type);
}
@Override
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java
index be32d08d2..ac47b1abf 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonLocationInstantiator.java
@@ -18,6 +18,8 @@ import com.fasterxml.jackson.databind.deser.ValueInstantiator;
public class JsonLocationInstantiator
extends ValueInstantiator.Base
{
+ private static final long serialVersionUID = 1L;
+
public JsonLocationInstantiator() {
super(JsonLocation.class);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java b/src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java
index cf6653785..919219c13 100644
--- a/src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java
+++ b/src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java
@@ -15,6 +15,8 @@ public abstract class ContainerNode<T extends ContainerNode<T>>
extends BaseJsonNode
implements JsonNodeCreator
{
+ private static final long serialVersionUID = 1L;
+
/**
* We will keep a reference to the Object (usually TreeMapper)
* that can construct instances of nodes to add to this container
diff --git a/src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java b/src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java
index a70a6b1f9..d131e61db 100644
--- a/src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java
+++ b/src/main/java/com/fasterxml/jackson/databind/node/NumericNode.java
@@ -11,6 +11,8 @@ import com.fasterxml.jackson.core.JsonParser;
public abstract class NumericNode
extends ValueNode
{
+ private static final long serialVersionUID = 1L;
+
protected NumericNode() { }
@Override
diff --git a/src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java b/src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java
index 322fe0294..d62023a8f 100644
--- a/src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java
+++ b/src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java
@@ -17,6 +17,8 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
public abstract class ValueNode
extends BaseJsonNode
{
+ private static final long serialVersionUID = 1L;
+
protected ValueNode() { }
@Override
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java
index 5ec830eb2..ef2c88867 100644
--- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/DateDeserializationTest.java
@@ -725,7 +725,7 @@ public class DateDeserializationTest
/**********************************************************
*/
- public void testLenientCalendar() throws Exception
+ public void testLenientJDKDateTypes() throws Exception
{
final String JSON = aposToQuotes("{'value':'2015-11-32'}");
@@ -743,8 +743,10 @@ public class DateDeserializationTest
verifyException(e, "from String \"2015-11-32\"");
verifyException(e, "expected format");
}
+ }
- // similarly with Date...
+ public void testLenientJDKDateTypesViaTypeOverride() throws Exception
+ {
ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(java.util.Date.class)
.setFormat(JsonFormat.Value.forLeniency(Boolean.FALSE));
@@ -758,6 +760,38 @@ public class DateDeserializationTest
}
}
+ public void testLenientJDKDateTypesViaGlobal() throws Exception
+ {
+ final String JSON = quote("2015-11-32");
+
+ // with lenient, can parse fine
+ Calendar value = MAPPER.readValue(JSON, Calendar.class);
+ assertEquals(Calendar.DECEMBER, value.get(Calendar.MONTH));
+ assertEquals(2, value.get(Calendar.DAY_OF_MONTH));
+
+ // but not so if default leniency disabled
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setDefaultLeniency(false);
+ try {
+ mapper.readValue(JSON, java.util.Date.class);
+ fail("Should not pass with invalid (with strict) date value");
+ } catch (MismatchedInputException e) {
+ verifyException(e, "Cannot deserialize value of type `java.util.Date`");
+ verifyException(e, "from String \"2015-11-32\"");
+ verifyException(e, "expected format");
+ }
+
+ // Unless we actually had per-type override too
+ mapper = new ObjectMapper();
+ mapper.configOverride(Calendar.class)
+ .setFormat(JsonFormat.Value.forLeniency(Boolean.TRUE));
+ mapper.setDefaultLeniency(false);
+
+ value = mapper.readValue(JSON, Calendar.class);
+ assertEquals(Calendar.DECEMBER, value.get(Calendar.MONTH));
+ assertEquals(2, value.get(Calendar.DAY_OF_MONTH));
+ }
+
/*
/**********************************************************
/* Tests to verify failing cases