Skip to content

Commit 23a610d

Browse files
committed
Further improvements related to #1711 to both catch problem AND to allow handling via DeserializationProblemHandler
1 parent 659408c commit 23a610d

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

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

+41-1
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
944944
if ((key == null) || targetClass.isInstance(key)) {
945945
return key;
946946
}
947-
throw weirdNumberException(value, targetClass, String.format(
947+
throw weirdNumberException(value, targetClass, _format(
948948
"DeserializationProblemHandler.handleWeirdNumberValue() for type %s returned value of type %s",
949949
targetClass, key.getClass()));
950950
}
@@ -953,6 +953,28 @@ public Object handleWeirdNumberValue(Class<?> targetClass, Number value,
953953
throw weirdNumberException(value, targetClass, msg);
954954
}
955955

956+
public Object handleWeirdNativeValue(JavaType targetType, Object badValue,
957+
JsonParser p)
958+
throws IOException
959+
{
960+
LinkedNode<DeserializationProblemHandler> h = _config.getProblemHandlers();
961+
final Class<?> raw = targetType.getRawClass();
962+
for (; h != null; h = h.next()) {
963+
// Can bail out if it's handled
964+
Object goodValue = h.value().handleWeirdNativeValue(this, targetType, badValue, p);
965+
if (goodValue != DeserializationProblemHandler.NOT_HANDLED) {
966+
// Sanity check for broken handlers, otherwise nasty to debug:
967+
if ((goodValue == null) || raw.isInstance(goodValue)) {
968+
return goodValue;
969+
}
970+
throw JsonMappingException.from(p, _format(
971+
"DeserializationProblemHandler.handleWeirdNativeValue() for type %s returned value of type %s",
972+
targetType, goodValue.getClass()));
973+
}
974+
}
975+
throw weirdNativeValueException(badValue, raw);
976+
}
977+
956978
/**
957979
* Method that deserializers should call if they fail to instantiate value
958980
* due to lack of viable instantiator (usually creator, that is, constructor
@@ -1531,6 +1553,24 @@ public JsonMappingException weirdNumberException(Number value, Class<?> instClas
15311553
value, instClass);
15321554
}
15331555

1556+
/**
1557+
* Helper method for constructing exception to indicate that input JSON
1558+
* token of type "native value" (see {@link JsonToken#VALUE_EMBEDDED_OBJECT})
1559+
* is of incompatible type (and there is no delegating creator or such to use)
1560+
* and can not be used to construct value of specified type (usually POJO).
1561+
* Note that most of the time this method should NOT be called; instead,
1562+
* {@link #handleWeirdNativeValue} should be called which will call this method
1563+
*
1564+
* @since 2.9
1565+
*/
1566+
public JsonMappingException weirdNativeValueException(Object value, Class<?> instClass)
1567+
{
1568+
return InvalidFormatException.from(_parser, String.format(
1569+
"Cannot deserialize value of type %s from native value (`JsonToken.VALUE_EMBEDDED_OBJECT`) of type %s: incompatible types",
1570+
ClassUtil.nameOf(instClass), ClassUtil.classNameOf(value)),
1571+
value, instClass);
1572+
}
1573+
15341574
/**
15351575
* Helper method for constructing instantiation exception for specified type,
15361576
* to indicate problem with physically constructing instance of

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -1459,10 +1459,19 @@ public Object deserializeFromEmbedded(JsonParser p, DeserializationContext ctxt)
14591459
return bean;
14601460
}
14611461
}
1462-
14631462
// TODO: maybe add support for ValueInstantiator, embedded?
1464-
1465-
return p.getEmbeddedObject();
1463+
1464+
// 26-Jul-2017, tatu: related to [databind#1711], let's actually verify assignment
1465+
// compatibility before returning. Bound to catch misconfigured cases and produce
1466+
// more meaningful exceptions.
1467+
Object value = p.getEmbeddedObject();
1468+
if (value != null) {
1469+
if (!_beanType.getClass().isInstance(value)) {
1470+
// allow this to be handled...
1471+
value = ctxt.handleWeirdNativeValue(_beanType, value, p);
1472+
}
1473+
}
1474+
return value;
14661475
}
14671476

14681477
/**

src/main/java/com/fasterxml/jackson/databind/deser/DeserializationProblemHandler.java

+33-6
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ public Object handleWeirdKey(DeserializationContext ctxt,
127127
* to indicate type of failure unless handler produces key to use
128128
*
129129
* @return Either {@link #NOT_HANDLED} to indicate that handler does not know
130-
* what to do (and exception may be thrown), or value to use as key (possibly
131-
* <code>null</code>
130+
* what to do (and exception may be thrown), or value to use as (possibly
131+
* <code>null</code>)
132132
*
133133
* @since 2.8
134134
*/
@@ -161,14 +161,41 @@ public Object handleWeirdStringValue(DeserializationContext ctxt,
161161
* to indicate type of failure unless handler produces key to use
162162
*
163163
* @return Either {@link #NOT_HANDLED} to indicate that handler does not know
164-
* what to do (and exception may be thrown), or value to use as key (possibly
165-
* <code>null</code>
164+
* what to do (and exception may be thrown), or value to use as (possibly
165+
* <code>null</code>)
166166
*
167167
* @since 2.8
168168
*/
169169
public Object handleWeirdNumberValue(DeserializationContext ctxt,
170-
Class<?> targetType, Number valueToConvert,
171-
String failureMsg)
170+
Class<?> targetType, Number valueToConvert, String failureMsg)
171+
throws IOException
172+
{
173+
return NOT_HANDLED;
174+
}
175+
176+
/**
177+
* Method called when an embedded (native) value ({@link JsonToken#VALUE_EMBEDDED_OBJECT})
178+
* cannot be converted directly into expected value type (usually POJO).
179+
* Handler may choose to do one of 3 things:
180+
*<ul>
181+
* <li>Indicate it does not know what to do by returning {@link #NOT_HANDLED}
182+
* </li>
183+
* <li>Throw a {@link IOException} to indicate specific fail message (instead of
184+
* standard exception caller would throw
185+
* </li>
186+
* <li>Return actual converted value (of type <code>targetType</code>) to use as
187+
* replacement, and continue processing.
188+
* </li>
189+
* </ul>
190+
*
191+
* @return Either {@link #NOT_HANDLED} to indicate that handler does not know
192+
* what to do (and exception may be thrown), or value to use (possibly
193+
* <code>null</code>)
194+
*
195+
* @since 2.9
196+
*/
197+
public Object handleWeirdNativeValue(DeserializationContext ctxt,
198+
JavaType targetType, Object valueToConvert, JsonParser p)
172199
throws IOException
173200
{
174201
return NOT_HANDLED;

0 commit comments

Comments
 (0)