Skip to content

Commit 29f7447

Browse files
committed
Fix #2804
1 parent af78f0a commit 29f7447

File tree

10 files changed

+97
-30
lines changed

10 files changed

+97
-30
lines changed

release-notes/VERSION-2.x

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Project: jackson-databind
1313
of `ObjectMapper.treeToValue()` regarding exceptions
1414
#2880: Revert removal of 2.7-deprecated `PropertyNamingStrategy` constants
1515
(reported by brettkail-wk@github)
16+
#2804: Throw `InvalidFormatException` instead of `MismatchedInputException`
17+
for ACCEPT_FLOAT_AS_INT coercion failures
18+
(requested by mjustin@github)
1619

1720
2.12.0-rc1 (12-Oct-2020)
1821

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

+16
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,22 @@ public <T> T reportPropertyInputMismatch(JavaType targetType, String propertyNam
16541654
return reportPropertyInputMismatch(targetType.getRawClass(), propertyName, msg, msgArgs);
16551655
}
16561656

1657+
/**
1658+
* Helper method used to indicate a problem with input in cases where specific
1659+
* input coercion was not allowed.
1660+
*
1661+
* @since 2.12
1662+
*/
1663+
public <T> T reportBadCoercion(JsonDeserializer<?> src,
1664+
Class<?> targetType, Object inputValue,
1665+
String msg, Object... msgArgs) throws JsonMappingException
1666+
{
1667+
msg = _format(msg, msgArgs);
1668+
InvalidFormatException e = InvalidFormatException.from(getParser(),
1669+
msg, inputValue, targetType);
1670+
throw e;
1671+
}
1672+
16571673
public <T> T reportTrailingTokens(Class<?> targetType,
16581674
JsonParser p, JsonToken trailingToken) throws JsonMappingException
16591675
{

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ protected static String translateLowerCaseWithSeparator(final String input, fina
266266
*/
267267

268268
/**
269-
* @deprecated Since 2.12 use {@link PropertyNamingStrategies#SnakeCaseStrategy} instead
269+
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.SnakeCaseStrategy} instead
270270
* (see
271271
* <a href="https://github.com/FasterXML/jackson-databind/issues/2715">databind#2715</a>
272272
* for reason for deprecation)
@@ -310,7 +310,7 @@ public String translate(String input)
310310
}
311311

312312
/**
313-
* @deprecated Since 2.12 use {@link PropertyNamingStrategies#UpperCamelCaseStrategy} instead
313+
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.UpperCamelCaseStrategy} instead
314314
* (see
315315
* <a href="https://github.com/FasterXML/jackson-databind/issues/2715">databind#2715</a>
316316
* for reason for deprecation)
@@ -345,7 +345,7 @@ public String translate(String input) {
345345
}
346346

347347
/**
348-
* @deprecated Since 2.12 use {@link PropertyNamingStrategies#LowerCaseStrategy} instead
348+
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.LowerCaseStrategy} instead
349349
* (see
350350
* <a href="https://github.com/FasterXML/jackson-databind/issues/2715">databind#2715</a>
351351
* for reason for deprecation)
@@ -360,7 +360,7 @@ public String translate(String input) {
360360
}
361361

362362
/**
363-
* @deprecated Since 2.12 use {@link PropertyNamingStrategies#KebabCaseStrategy} instead
363+
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.KebabCaseStrategy} instead
364364
* (see
365365
* <a href="https://github.com/FasterXML/jackson-databind/issues/2715">databind#2715</a>
366366
* for reason for deprecation)
@@ -375,7 +375,7 @@ public String translate(String input) {
375375
}
376376

377377
/**
378-
* @deprecated Since 2.12 use {@link PropertyNamingStrategies#LowerDotCaseStrategy} instead
378+
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.LowerDotCaseStrategy} instead
379379
* (see
380380
* <a href="https://github.com/FasterXML/jackson-databind/issues/2715">databind#2715</a>
381381
* for reason for deprecation)
@@ -407,13 +407,13 @@ public String translate(String input){
407407
public static final PropertyNamingStrategy PASCAL_CASE_TO_CAMEL_CASE = UPPER_CAMEL_CASE;
408408

409409
/**
410-
* @deprecated In 2.7 use {@link PropertyNamingStrategies#SnakeCaseStrategy} instead
410+
* @deprecated In 2.7 use {@link PropertyNamingStrategies.SnakeCaseStrategy} instead
411411
*/
412412
@Deprecated // since 2.7
413413
public static class LowerCaseWithUnderscoresStrategy extends SnakeCaseStrategy {}
414414

415415
/**
416-
* @deprecated In 2.7 use {@link PropertyNamingStrategies#UpperCamelCaseStrategy} instead
416+
* @deprecated In 2.7 use {@link PropertyNamingStrategies.UpperCamelCaseStrategy} instead
417417
*/
418418
@Deprecated // since 2.7
419419
public static class PascalCaseStrategy extends UpperCamelCaseStrategy { }

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public final class ConstructorDetector
2626
*<p>
2727
* Default choice is {@code HEURISTIC} (which is Jackson pre-2.12 always uses)
2828
*<p>
29-
* NOTE: does NOT have any effect if explicit {@link @JsonCreator}} annotation
29+
* NOTE: does NOT have any effect if explicit {@code @JsonCreator}} annotation
3030
* is required.
3131
*
3232
* @since 2.12
@@ -187,9 +187,10 @@ public boolean singleArgCreatorDefaultsToProperties() {
187187
}
188188

189189
/**
190-
* Accessor that combines calls to {@link #allowImplicitCreators} and
191-
* {@link #allowJDKTypeConstructors} to determine whether implicit constructor
192-
* detection should be enabled or not.
190+
* Accessor that combines checks for whether implicit creators are allowed
191+
* and, if so, whether JDK type constructors are allowed (if type is JDK type)
192+
* to determine whether implicit constructor
193+
* detection should be enabled for given type or not.
193194
*
194195
* @param rawType Value type to consider
195196
*

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,9 @@ public Character deserialize(JsonParser p, DeserializationContext ctxt)
453453
CoercionAction act = ctxt.findCoercionAction(logicalType(), _valueClass, CoercionInputShape.Integer);
454454
switch (act) {
455455
case Fail:
456-
_checkCoercionActionFail(ctxt, act, "Integer value ("+p.getText()+")");
457-
break;
456+
_checkCoercionFail(ctxt, act, _valueClass, p.getNumberValue(),
457+
"Integer value ("+p.getText()+")");
458+
// fall-through in unlikely case of returning
458459
case AsNull:
459460
return getNullValue(ctxt);
460461
case AsEmpty:

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

+17-12
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,6 @@ protected final boolean _parseBooleanPrimitive(DeserializationContext ctxt,
377377
/**
378378
* @param ctxt Deserialization context for accessing configuration
379379
* @param p Underlying parser
380-
* @param targetType Actual type that is being deserialized, typically
381-
* same as {@link #handledType}, and not necessarily {@code boolean}
382-
* (may be {@code boolean[]} or {@code AtomicBoolean} for example);
383-
* used for coercion config access
384380
*/
385381
protected final boolean _parseBooleanPrimitive(JsonParser p, DeserializationContext ctxt)
386382
throws IOException
@@ -1284,10 +1280,12 @@ protected CoercionAction _checkFromStringCoercion(DeserializationContext ctxt, S
12841280
if (value.length() == 0) {
12851281
act = ctxt.findCoercionAction(logicalType, rawTargetType,
12861282
CoercionInputShape.EmptyString);
1287-
return _checkCoercionActionFail(ctxt, act, "empty String (\"\")");
1283+
return _checkCoercionFail(ctxt, act, rawTargetType, value,
1284+
"empty String (\"\")");
12881285
} else if (_isBlank(value)) {
12891286
act = ctxt.findCoercionFromBlankString(logicalType, rawTargetType, CoercionAction.Fail);
1290-
return _checkCoercionActionFail(ctxt, act, "blank String (all whitespace)");
1287+
return _checkCoercionFail(ctxt, act, rawTargetType, value,
1288+
"blank String (all whitespace)");
12911289
} else {
12921290
act = ctxt.findCoercionAction(logicalType, rawTargetType, CoercionInputShape.String);
12931291
if (act == CoercionAction.Fail) {
@@ -1310,7 +1308,8 @@ protected CoercionAction _checkFloatToIntCoercion(JsonParser p, DeserializationC
13101308
final CoercionAction act = ctxt.findCoercionAction(LogicalType.Integer,
13111309
rawTargetType, CoercionInputShape.Float);
13121310
if (act == CoercionAction.Fail) {
1313-
_checkCoercionActionFail(ctxt, act, "Floating-point value ("+p.getText()+")");
1311+
return _checkCoercionFail(ctxt, act, rawTargetType, p.getNumberValue(),
1312+
"Floating-point value ("+p.getText()+")");
13141313
}
13151314
return act;
13161315
}
@@ -1325,8 +1324,9 @@ protected Boolean _coerceBooleanFromInt(JsonParser p, DeserializationContext ctx
13251324
CoercionAction act = ctxt.findCoercionAction(LogicalType.Boolean, rawTargetType, CoercionInputShape.Integer);
13261325
switch (act) {
13271326
case Fail:
1328-
_checkCoercionActionFail(ctxt, act, "Integer value ("+p.getText()+")");
1329-
break;
1327+
_checkCoercionFail(ctxt, act, rawTargetType, p.getNumberValue(),
1328+
"Integer value ("+p.getText()+")");
1329+
return Boolean.FALSE;
13301330
case AsNull:
13311331
return null;
13321332
case AsEmpty:
@@ -1343,11 +1343,16 @@ protected Boolean _coerceBooleanFromInt(JsonParser p, DeserializationContext ctx
13431343
return !"0".equals(p.getText());
13441344
}
13451345

1346-
protected CoercionAction _checkCoercionActionFail(DeserializationContext ctxt,
1347-
CoercionAction act, String inputDesc) throws IOException
1346+
/**
1347+
* @since 2.12
1348+
*/
1349+
protected CoercionAction _checkCoercionFail(DeserializationContext ctxt,
1350+
CoercionAction act, Class<?> targetType, Object inputValue,
1351+
String inputDesc)
1352+
throws IOException
13481353
{
13491354
if (act == CoercionAction.Fail) {
1350-
ctxt.reportInputMismatch(this,
1355+
ctxt.reportBadCoercion(this, targetType, inputValue,
13511356
"Cannot coerce %s to %s (but could if coercion was enabled using `CoercionConfig`)",
13521357
inputDesc, _coercedTypeDesc());
13531358
}

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ public JavaType constructType(TypeReference<?> typeRef)
766766
* This is typically used only by code in databind itself.
767767
*
768768
* @param type Type of a {@link java.lang.reflect.Member} to resolve
769-
* @param bindings Type bindings from the context, often class in which
769+
* @param contextBindings Type bindings from the context, often class in which
770770
* member declared but may be subtype of that type (to bind actual bound
771771
* type parametrers). Not used if {@code type} is of type {@code Class<?>}.
772772
*

src/test/java/com/fasterxml/jackson/databind/convert/CoerceFloatToIntTest.java

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package com.fasterxml.jackson.databind.convert;
22

33
import java.math.BigInteger;
4+
import java.util.*;
45

6+
import com.fasterxml.jackson.core.type.TypeReference;
57
import com.fasterxml.jackson.databind.*;
68
import com.fasterxml.jackson.databind.cfg.CoercionAction;
79
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
10+
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
811
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
912
import com.fasterxml.jackson.databind.type.LogicalType;
1013

1114
public class CoerceFloatToIntTest extends BaseMapTest
1215
{
13-
private final ObjectMapper DEFAULT_MAPPER = sharedMapper();
16+
private final ObjectMapper DEFAULT_MAPPER = newJsonMapper();
1417
private final ObjectReader READER_LEGACY_FAIL = DEFAULT_MAPPER.reader()
1518
.without(DeserializationFeature.ACCEPT_FLOAT_AS_INT);
1619

@@ -104,6 +107,45 @@ public void testLegacyFailDoubleToOther() throws Exception
104107
// _verifyCoerceFail(READER_LEGACY_FAIL, AtomicLong.class, "25236.256");
105108
}
106109

110+
/*
111+
/********************************************************
112+
/* Test methods, legacy, correct exception type
113+
/********************************************************
114+
*/
115+
116+
// [databind#2804]
117+
public void testLegacyFail2804() throws Exception
118+
{
119+
_testLegacyFail2804("5.5", Integer.class);
120+
_testLegacyFail2804("5.0", Long.class);
121+
_testLegacyFail2804("1234567890123456789.0", BigInteger.class);
122+
_testLegacyFail2804("[4, 5.5, 6]", "5.5",
123+
new TypeReference<List<Integer>>() {});
124+
_testLegacyFail2804("{\"key1\": 4, \"key2\": 5.5}", "5.5",
125+
new TypeReference<Map<String, Integer>>() {});
126+
}
127+
128+
private void _testLegacyFail2804(String value, Class<?> type) throws Exception {
129+
_testLegacyFail2804(value, DEFAULT_MAPPER.constructType(type), value);
130+
}
131+
132+
private void _testLegacyFail2804(String doc, String probValue,
133+
TypeReference<?> type) throws Exception {
134+
_testLegacyFail2804(doc, DEFAULT_MAPPER.constructType(type), probValue);
135+
}
136+
137+
private void _testLegacyFail2804(String doc, JavaType targetType,
138+
String probValue) throws Exception {
139+
try {
140+
READER_LEGACY_FAIL.forType(targetType).readValue(doc);
141+
fail("Should not pass");
142+
} catch (InvalidFormatException ex) {
143+
verifyException(ex, probValue);
144+
} catch (MismatchedInputException ex) {
145+
fail("Should get subtype, got: "+ex);
146+
}
147+
}
148+
107149
/*
108150
/********************************************************
109151
/* Test methods, CoerceConfig, to null

src/test/java/com/fasterxml/jackson/databind/introspect/TestNamingStrategyStd.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public void setUp() throws Exception
190190

191191
/**
192192
* Unit test to verify translations of
193-
* {@link PropertyNamingStrategy#SNAKE_CASE}
193+
* {@link PropertyNamingStrategies#SNAKE_CASE}
194194
* outside the context of an ObjectMapper.
195195
*/
196196
public void testLowerCaseStrategyStandAlone()
@@ -265,7 +265,7 @@ public void testLowerCaseUnchangedNames() throws Exception
265265

266266
/**
267267
* Unit test to verify translations of
268-
* {@link PropertyNamingStrategy#UPPER_CAMEL_CASE }
268+
* {@link PropertyNamingStrategies#UPPER_CAMEL_CASE }
269269
* outside the context of an ObjectMapper.
270270
*/
271271
public void testPascalCaseStandAlone()

src/test/java/com/fasterxml/jackson/databind/type/TestAnnotatedClass.java

-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ public void testConstructorIntrospection()
9797
{
9898
// Need this call to ensure there is a synthetic constructor being generated
9999
// (not really needed otherwise)
100-
@SuppressWarnings("synthetic-access")
101100
Bean1005 bean = new Bean1005(13);
102101
SerializationConfig config = MAPPER.getSerializationConfig();
103102
JavaType t = MAPPER.constructType(bean.getClass());

0 commit comments

Comments
 (0)