diff options
Diffstat (limited to 'src/test/java/com/fasterxml')
55 files changed, 2450 insertions, 720 deletions
diff --git a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java index 549e96028..13aca9c95 100644 --- a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java @@ -359,6 +359,10 @@ public abstract class BaseMapTest return json.replace("'", "\""); } + protected static String a2q(String json) { + return json.replace("'", "\""); + } + protected static String quotesToApos(String json) { return json.replace("\"", "'"); } diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java index 7e39256c5..9d84df29a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java @@ -272,7 +272,6 @@ public class ObjectMapperTest extends BaseMapTest assertTrue(dc.shouldSortPropertiesAlphabetically()); } - public void testJsonFactoryLinkage() { // first, implicit factory, giving implicit linkage @@ -363,6 +362,13 @@ public class ObjectMapperTest extends BaseMapTest .canSerialize(EmptyBean.class)); } + // for [databind#2749]: just to check there's no NPE; method really not useful + public void testCanDeserialize() + { + assertTrue(MAPPER.canDeserialize(MAPPER.constructType(EmptyBean.class))); + assertTrue(MAPPER.canDeserialize(MAPPER.constructType(Object.class))); + } + // for [databind#898] public void testSerializerProviderAccess() throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceContainersTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceContainersTest.java new file mode 100644 index 000000000..163588155 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceContainersTest.java @@ -0,0 +1,175 @@ +package com.fasterxml.jackson.databind.convert; + +import java.util.*; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.*; + +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; + +public class CoerceContainersTest extends BaseMapTest +{ + private final String JSON_EMPTY = quote(""); + + private final ObjectMapper VANILLA_MAPPER = sharedMapper(); + + private final ObjectMapper COERCING_MAPPER = newJsonMapper(); + { + COERCING_MAPPER.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty); + } + + /* + /******************************************************** + /* Tests for collections + /******************************************************** + */ + + public void testScalarCollections() throws Exception + { + final JavaType listType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<List<Double>>() { }); + _verifyNoCoercion(listType); + List<Double> result = _readWithCoercion(listType); + assertNotNull(result); + assertEquals(0, result.size()); + } + + public void testStringCollections() throws Exception + { + final JavaType listType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<List<String>>() { }); + _verifyNoCoercion(listType); + List<String> result = _readWithCoercion(listType); + assertNotNull(result); + assertEquals(0, result.size()); + } + + /* + /******************************************************** + /* Tests for Maps + /******************************************************** + */ + + public void testScalarMap() throws Exception + { + final JavaType mapType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<Map<Long, Boolean>>() { }); + _verifyNoCoercion(mapType); + Map<?,?> result = _readWithCoercion(mapType); + assertNotNull(result); + assertEquals(0, result.size()); + } + + public void testEnumMap() throws Exception + { + final JavaType mapType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<EnumMap<ABC, Boolean>>() { }); + _verifyNoCoercion(mapType); + Map<?,?> result = _readWithCoercion(mapType); + assertNotNull(result); + assertEquals(0, result.size()); + } + + /* + /******************************************************** + /* Tests for arrays + /******************************************************** + */ + + public void testObjectArray() throws Exception + { + final JavaType arrayType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<Object[]>() { }); + _verifyNoCoercion(arrayType); + Object[] result = _readWithCoercion(arrayType); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testStringArray() throws Exception + { + final JavaType arrayType = VANILLA_MAPPER.getTypeFactory() + .constructType(new TypeReference<String[]>() { }); + _verifyNoCoercion(arrayType); + String[] result = _readWithCoercion(arrayType); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testBooleanArray() throws Exception + { + _verifyNoCoercion(boolean[].class); + boolean[] result = _readWithCoercion(boolean[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testIntArray() throws Exception + { + _verifyNoCoercion(int[].class); + int[] result = _readWithCoercion(int[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testLongArray() throws Exception + { + _verifyNoCoercion(long[].class); + long[] result = _readWithCoercion(long[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testFloatArray() throws Exception + { + _verifyNoCoercion(float[].class); + float[] result = _readWithCoercion(float[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testDoubleArray() throws Exception + { + _verifyNoCoercion(double[].class); + double[] result = _readWithCoercion(double[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + public void testPOJOArray() throws Exception + { + _verifyNoCoercion(StringWrapper[].class); + StringWrapper[] result = _readWithCoercion(StringWrapper[].class); + assertNotNull(result); + assertEquals(0, result.length); + } + + /* + /******************************************************** + /* Helper methods + /******************************************************** + */ + + private void _verifyNoCoercion(Class<?> targetType) throws Exception { + _verifyNoCoercion(VANILLA_MAPPER.constructType(targetType)); + } + + private void _verifyNoCoercion(JavaType targetType) throws Exception { + try { + VANILLA_MAPPER.readerFor(targetType).readValue(JSON_EMPTY); + fail("Should not pass"); + } catch (Exception e) { + verifyException(e, "Cannot deserialize value of type"); + verifyException(e, "from empty String"); + } + } + + private <T> T _readWithCoercion(Class<?> targetType) throws Exception { + return COERCING_MAPPER.readerFor(targetType).readValue(JSON_EMPTY); + } + + private <T> T _readWithCoercion(JavaType targetType) throws Exception { + return COERCING_MAPPER.readerFor(targetType).readValue(JSON_EMPTY); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java new file mode 100644 index 000000000..ff429b8ae --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java @@ -0,0 +1,255 @@ +package com.fasterxml.jackson.databind.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.util.*; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.type.LogicalType; + +/** + * Tests to verify implementation of [databind#540]; also for + * follow up work of: + * + * - [databind#994] + */ +public class CoerceEmptyArrayTest extends BaseMapTest +{ + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + private final ObjectReader DEFAULT_READER = DEFAULT_MAPPER.reader(); + private final ObjectReader READER_WITH_ARRAYS = DEFAULT_READER + .with(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT); + + private final ObjectMapper MAPPER_TO_EMPTY; + { + MAPPER_TO_EMPTY = newJsonMapper(); + MAPPER_TO_EMPTY.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsEmpty); + } + + private final ObjectMapper MAPPER_TRY_CONVERT; + { + MAPPER_TRY_CONVERT = newJsonMapper(); + MAPPER_TRY_CONVERT.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.TryConvert); + } + + private final ObjectMapper MAPPER_TO_NULL; + { + MAPPER_TO_NULL = newJsonMapper(); + MAPPER_TO_NULL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsNull); + } + + private final ObjectMapper MAPPER_TO_FAIL; + { + MAPPER_TO_FAIL = newJsonMapper(); + MAPPER_TO_FAIL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.Fail); + } + + static class Bean { + public String a = "foo"; + + @Override + public boolean equals(Object o) { + return (o instanceof Bean) + && a.equals(((Bean) o).a); + } + } + + final static String EMPTY_ARRAY = " [\n]"; + + /* + /********************************************************** + /* Test methods, settings + /********************************************************** + */ + + public void testSettings() { + assertFalse(DEFAULT_MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + assertFalse(DEFAULT_READER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + assertTrue(READER_WITH_ARRAYS.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + } + + /* + /********************************************************** + /* Test methods, POJOs + /********************************************************** + */ + + // [databind#540] + public void testPOJOFromEmptyArray() throws Exception + { + final Class<?> targetType = Bean.class; + + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new Bean()); + + // But let's also check precedence: legacy setting allow, but mask for type + ObjectMapper mapper = jsonMapperBuilder() + .enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT) + .build(); + mapper.coercionConfigFor(targetType) + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.Fail); + _verifyFailForEmptyArray(mapper, targetType); + + // and conversely + mapper = jsonMapperBuilder() + .disable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT) + .build(); + mapper.coercionConfigFor(LogicalType.POJO) + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsEmpty); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new Bean()); + } + + /* + /********************************************************** + /* Test methods, Maps + /********************************************************** + */ + + public void testMapFromEmptyArray() throws Exception + { + final Class<?> targetType = Map.class; + + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new LinkedHashMap<>()); + + // assume overrides work ok since POJOs test it + } + + public void testEnumMapFromEmptyArray() throws Exception + { + final JavaType targetType = DEFAULT_READER.getTypeFactory() + .constructType(new TypeReference<EnumMap<ABC,String>>() { }); + + assertNull(MAPPER_TO_NULL.readerFor(targetType).readValue(EMPTY_ARRAY)); + + EnumMap<?,?> result = MAPPER_TO_EMPTY.readerFor(targetType).readValue(EMPTY_ARRAY); + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + /* + /********************************************************** + /* Test methods, scalars + /********************************************************** + */ + + public void testNumbersFromEmptyArray() throws Exception + { + for (Class<?> targetType : new Class<?>[] { + Boolean.class, Character.class, + Byte.class, Short.class, Integer.class, Long.class, + Float.class, Double.class, + BigInteger.class, BigDecimal.class + }) { + // Default, fail; explicit fail + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + } + + // But as-empty needs separate + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Boolean.class, Boolean.FALSE); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Character.class, Character.valueOf('\0')); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Byte.class, Byte.valueOf((byte) 0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Short.class, Short.valueOf((short) 0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Integer.class, Integer.valueOf(0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Long.class, Long.valueOf(0L)); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Float.class, Float.valueOf(0f)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Double.class, Double.valueOf(0d)); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, BigInteger.class, BigInteger.ZERO); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, BigDecimal.class, new BigDecimal(BigInteger.ZERO)); + } + + public void testOtherScalarsFromEmptyArray() throws Exception + { + for (Class<?> targetType : new Class<?>[] { + String.class, StringBuilder.class, + UUID.class, URL.class, URI.class, + Date.class, Calendar.class + }) { + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + } + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, String.class, ""); + StringBuilder sb = MAPPER_TO_EMPTY.readerFor(StringBuilder.class) + .readValue(EMPTY_ARRAY); + assertEquals(0, sb.length()); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, UUID.class, new UUID(0L, 0L)); + } + + /* + /********************************************************** + /* Helper methods + /********************************************************** + */ + + private void _verifyToNullCoercion(ObjectMapper mapper, Class<?> cls) throws Exception { + _verifyToNullCoercion(mapper.reader(), cls); + } + + private void _verifyToNullCoercion(ObjectReader r, Class<?> cls) throws Exception { + Object result = r.forType(cls).readValue(EMPTY_ARRAY); + if (result != null) { + fail("Expect null for "+cls.getName()+", got: "+result); + } + } + + private void _verifyToEmptyCoercion(ObjectMapper mapper, Class<?> cls, Object exp) throws Exception { + _verifyToEmptyCoercion(mapper.reader(), cls, exp); + } + + private void _verifyToEmptyCoercion(ObjectReader r, Class<?> cls, Object exp) throws Exception { + Object result = r.forType(cls).readValue(EMPTY_ARRAY); + if (!exp.equals(result)) { + fail("Expect value ["+exp+"] for "+cls.getName()+", got: "+result); + } + } + + private void _verifyFailForEmptyArray(ObjectMapper mapper, Class<?> targetType) throws Exception { + _verifyFailForEmptyArray(mapper.readerFor(targetType), targetType); + } + + private void _verifyFailForEmptyArray(ObjectReader r, Class<?> targetType) throws Exception + { + try { + r.forType(targetType).readValue(EMPTY_ARRAY); + fail("Should not accept Empty Array for "+targetType.getName()+" by default"); + } catch (MismatchedInputException e) { + verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)"); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceFloatToIntTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceFloatToIntTest.java new file mode 100644 index 000000000..5bf27e405 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceFloatToIntTest.java @@ -0,0 +1,298 @@ +package com.fasterxml.jackson.databind.convert; + +import java.math.BigInteger; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.type.LogicalType; + +public class CoerceFloatToIntTest extends BaseMapTest +{ + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + private final ObjectReader READER_LEGACY_FAIL = DEFAULT_MAPPER.reader() + .without(DeserializationFeature.ACCEPT_FLOAT_AS_INT); + + private final ObjectMapper MAPPER_TO_EMPTY; { + MAPPER_TO_EMPTY = newJsonMapper(); + MAPPER_TO_EMPTY.coercionConfigFor(LogicalType.Integer) + .setCoercion(CoercionInputShape.Float, CoercionAction.AsEmpty); + } + + private final ObjectMapper MAPPER_TRY_CONVERT; { + MAPPER_TRY_CONVERT = newJsonMapper(); + MAPPER_TRY_CONVERT.coercionConfigFor(LogicalType.Integer) + .setCoercion(CoercionInputShape.Float, CoercionAction.TryConvert); + } + + private final ObjectMapper MAPPER_TO_NULL; { + MAPPER_TO_NULL = newJsonMapper(); + MAPPER_TO_NULL.coercionConfigFor(LogicalType.Integer) + .setCoercion(CoercionInputShape.Float, CoercionAction.AsNull); + } + + private final ObjectMapper MAPPER_TO_FAIL; { + MAPPER_TO_FAIL = newJsonMapper(); + MAPPER_TO_FAIL.coercionConfigFor(LogicalType.Integer) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail); + } + + /* + /******************************************************** + /* Test methods, defaults (legacy) + /******************************************************** + */ + + public void testLegacyDoubleToIntCoercion() throws Exception + { + // by default, should be ok + Integer I = DEFAULT_MAPPER.readValue(" 1.25 ", Integer.class); + assertEquals(1, I.intValue()); + { + IntWrapper w = DEFAULT_MAPPER.readValue("{\"i\":-2.25 }", IntWrapper.class); + assertEquals(-2, w.i); + int[] arr = DEFAULT_MAPPER.readValue("[ 1.25 ]", int[].class); + assertEquals(1, arr[0]); + } + + Long L = DEFAULT_MAPPER.readValue(" 3.33 ", Long.class); + assertEquals(3L, L.longValue()); + { + LongWrapper w = DEFAULT_MAPPER.readValue("{\"l\":-2.25 }", LongWrapper.class); + assertEquals(-2L, w.l); + long[] arr = DEFAULT_MAPPER.readValue("[ 1.25 ]", long[].class); + assertEquals(1, arr[0]); + } + + Short S = DEFAULT_MAPPER.readValue("42.33", Short.class); + assertEquals(42, S.intValue()); + + BigInteger biggie = DEFAULT_MAPPER.readValue("95.3", BigInteger.class); + assertEquals(95L, biggie.longValue()); + } + + public void testLegacyFailDoubleToInt() throws Exception + { + _verifyCoerceFail(READER_LEGACY_FAIL, Integer.class, "1.5", "java.lang.Integer"); + _verifyCoerceFail(READER_LEGACY_FAIL, Integer.TYPE, "1.5", "int"); + _verifyCoerceFail(READER_LEGACY_FAIL, IntWrapper.class, "{\"i\":-2.25 }", "int"); + _verifyCoerceFail(READER_LEGACY_FAIL, int[].class, "[ 2.5 ]", "element of `int[]`"); + } + + public void testLegacyFailDoubleToLong() throws Exception + { + _verifyCoerceFail(READER_LEGACY_FAIL, Long.class, "0.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, Long.TYPE, "-2.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, LongWrapper.class, "{\"l\": 7.7 }"); + _verifyCoerceFail(READER_LEGACY_FAIL, long[].class, "[ -1.35 ]", "element of `long[]`"); + } + + public void testLegacyFailDoubleToOther() throws Exception + { + _verifyCoerceFail(READER_LEGACY_FAIL, Short.class, "0.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, Short.TYPE, "-2.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, short[].class, "[ -1.35 ]", "element of `short[]`"); + + _verifyCoerceFail(READER_LEGACY_FAIL, Byte.class, "0.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, Byte.TYPE, "-2.5"); + _verifyCoerceFail(READER_LEGACY_FAIL, byte[].class, "[ -1.35 ]", "element of `byte[]`"); + + _verifyCoerceFail(READER_LEGACY_FAIL, BigInteger.class, "25236.256"); + + // 13-Jun-2020, tatu: No explicit deserializer for `AtomicLong` yet +// _verifyCoerceFail(READER_LEGACY_FAIL, AtomicLong.class, "25236.256"); + } + + /* + /******************************************************** + /* Test methods, CoerceConfig, to null + /******************************************************** + */ + + public void testCoerceConfigFloatToNull() throws Exception + { + assertNull(MAPPER_TO_NULL.readValue("1.5", Integer.class)); + // `null` not possible for primitives, must use empty (aka default) value + assertEquals(Integer.valueOf(0), MAPPER_TO_NULL.readValue("1.5", Integer.TYPE)); + { + IntWrapper w = MAPPER_TO_NULL.readValue( "{\"i\":-2.25 }", IntWrapper.class); + assertEquals(0, w.i); + int[] ints = MAPPER_TO_NULL.readValue("[ 2.5 ]", int[].class); + assertEquals(1, ints.length); + assertEquals(0, ints[0]); + } + + assertNull(MAPPER_TO_NULL.readValue("2.5", Long.class)); + assertEquals(Long.valueOf(0L), MAPPER_TO_NULL.readValue("-4.25", Long.TYPE)); + { + LongWrapper w = MAPPER_TO_NULL.readValue( "{\"l\":-2.25 }", LongWrapper.class); + assertEquals(0L, w.l); + long[] l = MAPPER_TO_NULL.readValue("[ 2.5 ]", long[].class); + assertEquals(1, l.length); + assertEquals(0L, l[0]); + } + + assertNull(MAPPER_TO_NULL.readValue("2.5", Short.class)); + assertEquals(Short.valueOf((short) 0), MAPPER_TO_NULL.readValue("-4.25", Short.TYPE)); + { + short[] s = MAPPER_TO_NULL.readValue("[ 2.5 ]", short[].class); + assertEquals(1, s.length); + assertEquals((short) 0, s[0]); + } + + assertNull(MAPPER_TO_NULL.readValue("2.5", Byte.class)); + assertEquals(Byte.valueOf((byte) 0), MAPPER_TO_NULL.readValue("-4.25", Byte.TYPE)); + { + byte[] arr = MAPPER_TO_NULL.readValue("[ 2.5 ]", byte[].class); + assertEquals(1, arr.length); + assertEquals((byte) 0, arr[0]); + } + + assertNull(MAPPER_TO_NULL.readValue("2.5", BigInteger.class)); + { + BigInteger[] arr = MAPPER_TO_NULL.readValue("[ 2.5 ]", BigInteger[].class); + assertEquals(1, arr.length); + assertNull(arr[0]); + } + } + + /* + /******************************************************** + /* Test methods, CoerceConfig, to empty + /******************************************************** + */ + + public void testCoerceConfigFloatToEmpty() throws Exception + { + assertEquals(Integer.valueOf(0), MAPPER_TO_EMPTY.readValue("1.2", Integer.class)); + assertEquals(Integer.valueOf(0), MAPPER_TO_EMPTY.readValue("1.5", Integer.TYPE)); + { + IntWrapper w = MAPPER_TO_EMPTY.readValue( "{\"i\":-2.25 }", IntWrapper.class); + assertEquals(0, w.i); + int[] ints = MAPPER_TO_EMPTY.readValue("[ 2.5 ]", int[].class); + assertEquals(1, ints.length); + assertEquals(0, ints[0]); + } + + assertEquals(Long.valueOf(0), MAPPER_TO_EMPTY.readValue("1.2", Long.class)); + assertEquals(Long.valueOf(0), MAPPER_TO_EMPTY.readValue("1.5", Long.TYPE)); + { + LongWrapper w = MAPPER_TO_EMPTY.readValue( "{\"l\":-2.25 }", LongWrapper.class); + assertEquals(0L, w.l); + long[] l = MAPPER_TO_EMPTY.readValue("[ 2.5 ]", long[].class); + assertEquals(1, l.length); + assertEquals(0L, l[0]); + } + + assertEquals(Short.valueOf((short)0), MAPPER_TO_EMPTY.readValue("1.2", Short.class)); + assertEquals(Short.valueOf((short) 0), MAPPER_TO_EMPTY.readValue("1.5", Short.TYPE)); + + assertEquals(Byte.valueOf((byte)0), MAPPER_TO_EMPTY.readValue("1.2", Byte.class)); + assertEquals(Byte.valueOf((byte) 0), MAPPER_TO_EMPTY.readValue("1.5", Byte.TYPE)); + + assertEquals(BigInteger.valueOf(0L), MAPPER_TO_EMPTY.readValue("124.5", BigInteger.class)); + } + + /* + /******************************************************** + /* Test methods, CoerceConfig, coerce + /******************************************************** + */ + + public void testCoerceConfigFloatSuccess() throws Exception + { + assertEquals(Integer.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.2", Integer.class)); + assertEquals(Integer.valueOf(3), MAPPER_TRY_CONVERT.readValue("3.4", Integer.TYPE)); + { + IntWrapper w = MAPPER_TRY_CONVERT.readValue( "{\"i\":-2.25 }", IntWrapper.class); + assertEquals(-2, w.i); + int[] ints = MAPPER_TRY_CONVERT.readValue("[ 22.10 ]", int[].class); + assertEquals(1, ints.length); + assertEquals(22, ints[0]); + } + + assertEquals(Long.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.2", Long.class)); + assertEquals(Long.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.5", Long.TYPE)); + { + LongWrapper w = MAPPER_TRY_CONVERT.readValue( "{\"l\":-2.25 }", LongWrapper.class); + assertEquals(-2L, w.l); + long[] l = MAPPER_TRY_CONVERT.readValue("[ 2.2 ]", long[].class); + assertEquals(1, l.length); + assertEquals(2L, l[0]); + } + + assertEquals(Short.valueOf((short)1), MAPPER_TRY_CONVERT.readValue("1.2", Short.class)); + assertEquals(Short.valueOf((short) 19), MAPPER_TRY_CONVERT.readValue("19.2", Short.TYPE)); + + assertEquals(Byte.valueOf((byte)1), MAPPER_TRY_CONVERT.readValue("1.2", Byte.class)); + assertEquals(Byte.valueOf((byte) 1), MAPPER_TRY_CONVERT.readValue("1.5", Byte.TYPE)); + + assertEquals(BigInteger.valueOf(124L), MAPPER_TRY_CONVERT.readValue("124.2", BigInteger.class)); + } + + /* + /******************************************************** + /* Test methods, CoerceConfig, fail + /******************************************************** + */ + + public void testCoerceConfigFailFromFloat() throws Exception + { + _verifyCoerceFail(MAPPER_TO_FAIL, Integer.class, "1.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, Integer.TYPE, "1.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, IntWrapper.class, "{\"i\":-2.25 }", "int"); + _verifyCoerceFail(MAPPER_TO_FAIL, int[].class, "[ 2.5 ]", "element of `int[]`"); + + _verifyCoerceFail(MAPPER_TO_FAIL, Long.class, "0.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, Long.TYPE, "-2.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, LongWrapper.class, "{\"l\": 7.7 }"); + _verifyCoerceFail(MAPPER_TO_FAIL, long[].class, "[ -1.35 ]", "element of `long[]`"); + + _verifyCoerceFail(MAPPER_TO_FAIL, Short.class, "0.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, Short.TYPE, "-2.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, short[].class, "[ -1.35 ]", "element of `short[]`"); + + _verifyCoerceFail(MAPPER_TO_FAIL, Byte.class, "0.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, Byte.TYPE, "-2.5"); + _verifyCoerceFail(MAPPER_TO_FAIL, byte[].class, "[ -1.35 ]", "element of `byte[]`"); + + _verifyCoerceFail(MAPPER_TO_FAIL, BigInteger.class, "25236.256"); + } + + /* + /******************************************************** + /* Helper methods + /******************************************************** + */ + + private void _verifyCoerceFail(ObjectMapper m, Class<?> targetType, + String doc) throws Exception + { + _verifyCoerceFail(m.reader(), targetType, doc, targetType.getName()); + } + + private void _verifyCoerceFail(ObjectMapper m, Class<?> targetType, + String doc, String targetTypeDesc) throws Exception + { + _verifyCoerceFail(m.reader(), targetType, doc, targetTypeDesc); + } + + private void _verifyCoerceFail(ObjectReader r, Class<?> targetType, + String doc) throws Exception + { + _verifyCoerceFail(r, targetType, doc, targetType.getName()); + } + + private void _verifyCoerceFail(ObjectReader r, Class<?> targetType, + String doc, String targetTypeDesc) throws Exception + { + try { + r.forType(targetType).readValue(doc); + fail("Should not accept Float for "+targetType.getName()+" by default"); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot coerce Floating-point"); + verifyException(e, targetTypeDesc); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/struct/ScalarCoercionTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceJDKScalarsTest.java index 0a20c7626..0fbade77e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/struct/ScalarCoercionTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceJDKScalarsTest.java @@ -1,20 +1,22 @@ -package com.fasterxml.jackson.databind.struct; +package com.fasterxml.jackson.databind.convert; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.concurrent.atomic.AtomicBoolean; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.exc.MismatchedInputException; -public class ScalarCoercionTest extends BaseMapTest +// Tests for "old" coercions (pre-2.12), with `MapperFeature.ALLOW_COERCION_OF_SCALARS` +public class CoerceJDKScalarsTest extends BaseMapTest { static class BooleanPOJO { - public boolean value; + public Boolean value; } private final ObjectMapper COERCING_MAPPER = jsonMapperBuilder() @@ -55,6 +57,7 @@ public class ScalarCoercionTest extends BaseMapTest _verifyNullOkFromEmpty(BigInteger.class, null); _verifyNullOkFromEmpty(BigDecimal.class, null); + _verifyNullOkFromEmpty(AtomicBoolean.class, null); } private void _verifyNullOkFromEmpty(Class<?> type, Object exp) throws IOException @@ -91,6 +94,7 @@ public class ScalarCoercionTest extends BaseMapTest _verifyNullFail(BigInteger.class); _verifyNullFail(BigDecimal.class); + _verifyNullFail(AtomicBoolean.class); } private void _verifyNullFail(Class<?> type) throws IOException @@ -100,7 +104,6 @@ public class ScalarCoercionTest extends BaseMapTest fail("Should have failed for "+type); } catch (MismatchedInputException e) { verifyException(e, "Cannot coerce empty String"); - verifyException(e, "Null value for"); } } @@ -110,7 +113,7 @@ public class ScalarCoercionTest extends BaseMapTest /********************************************************** */ - public void testStringCoercionOk() throws Exception + public void testStringCoercionOkBoolean() throws Exception { // first successful coercions. Boolean has a ton... _verifyCoerceSuccess("1", Boolean.TYPE, Boolean.TRUE); @@ -119,13 +122,20 @@ public class ScalarCoercionTest extends BaseMapTest _verifyCoerceSuccess(quote("true"), Boolean.class, Boolean.TRUE); _verifyCoerceSuccess(quote("True"), Boolean.TYPE, Boolean.TRUE); _verifyCoerceSuccess(quote("True"), Boolean.class, Boolean.TRUE); + _verifyCoerceSuccess(quote("TRUE"), Boolean.TYPE, Boolean.TRUE); + _verifyCoerceSuccess(quote("TRUE"), Boolean.class, Boolean.TRUE); _verifyCoerceSuccess("0", Boolean.TYPE, Boolean.FALSE); _verifyCoerceSuccess("0", Boolean.class, Boolean.FALSE); _verifyCoerceSuccess(quote("false"), Boolean.TYPE, Boolean.FALSE); _verifyCoerceSuccess(quote("false"), Boolean.class, Boolean.FALSE); _verifyCoerceSuccess(quote("False"), Boolean.TYPE, Boolean.FALSE); _verifyCoerceSuccess(quote("False"), Boolean.class, Boolean.FALSE); + _verifyCoerceSuccess(quote("FALSE"), Boolean.TYPE, Boolean.FALSE); + _verifyCoerceSuccess(quote("FALSE"), Boolean.class, Boolean.FALSE); + } + public void testStringCoercionOkNumbers() throws Exception + { _verifyCoerceSuccess(quote("123"), Byte.TYPE, Byte.valueOf((byte) 123)); _verifyCoerceSuccess(quote("123"), Byte.class, Byte.valueOf((byte) 123)); _verifyCoerceSuccess(quote("123"), Short.TYPE, Short.valueOf((short) 123)); @@ -141,12 +151,27 @@ public class ScalarCoercionTest extends BaseMapTest _verifyCoerceSuccess(quote("123"), BigInteger.class, BigInteger.valueOf(123)); _verifyCoerceSuccess(quote("123.0"), BigDecimal.class, new BigDecimal("123.0")); + + AtomicBoolean ab = COERCING_MAPPER.readValue(quote("true"), AtomicBoolean.class); + assertNotNull(ab); + assertTrue(ab.get()); } - public void testStringCoercionFail() throws Exception + public void testStringCoercionFailBoolean() throws Exception { _verifyRootStringCoerceFail("true", Boolean.TYPE); _verifyRootStringCoerceFail("true", Boolean.class); + _verifyRootStringCoerceFail("True", Boolean.TYPE); + _verifyRootStringCoerceFail("True", Boolean.class); + _verifyRootStringCoerceFail("TRUE", Boolean.TYPE); + _verifyRootStringCoerceFail("TRUE", Boolean.class); + + _verifyRootStringCoerceFail("false", Boolean.TYPE); + _verifyRootStringCoerceFail("false", Boolean.class); + } + + public void testStringCoercionFailInteger() throws Exception + { _verifyRootStringCoerceFail("123", Byte.TYPE); _verifyRootStringCoerceFail("123", Byte.class); _verifyRootStringCoerceFail("123", Short.TYPE); @@ -155,6 +180,10 @@ public class ScalarCoercionTest extends BaseMapTest _verifyRootStringCoerceFail("123", Integer.class); _verifyRootStringCoerceFail("123", Long.TYPE); _verifyRootStringCoerceFail("123", Long.class); + } + + public void testStringCoercionFailFloat() throws Exception + { _verifyRootStringCoerceFail("123.5", Float.TYPE); _verifyRootStringCoerceFail("123.5", Float.class); _verifyRootStringCoerceFail("123.5", Double.TYPE); @@ -192,8 +221,10 @@ public class ScalarCoercionTest extends BaseMapTest { // And then we have coercions from more esoteric types too - _verifyCoerceFail("65", Character.class); - _verifyCoerceFail("65", Character.TYPE); + _verifyCoerceFail("65", Character.class, + "Cannot coerce Integer value (65) to `java.lang.Character` value"); + _verifyCoerceFail("65", Character.TYPE, + "Cannot coerce Integer value (65) to `char` value"); } /* @@ -209,16 +240,15 @@ public class ScalarCoercionTest extends BaseMapTest assertEquals(exp, result); } - private void _verifyCoerceFail(String input, Class<?> type) throws IOException + private void _verifyCoerceFail(String input, Class<?> type, + String... expMatches) throws IOException { try { NOT_COERCING_MAPPER.readerFor(type) .readValue(input); fail("Should not have allowed coercion"); } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce "); - verifyException(e, " for type `"); - verifyException(e, "enable `MapperFeature.ALLOW_COERCION_OF_SCALARS` to allow"); + verifyException(e, expMatches); } } @@ -245,8 +275,8 @@ public class ScalarCoercionTest extends BaseMapTest fail("Should not have allowed coercion"); } catch (MismatchedInputException e) { verifyException(e, "Cannot coerce "); - verifyException(e, " for type `"); - verifyException(e, "enable `MapperFeature.ALLOW_COERCION_OF_SCALARS` to allow"); + verifyException(e, " to `"); + verifyException(e, "` value"); assertNotNull(e.getProcessor()); assertSame(p, e.getProcessor()); @@ -282,7 +312,7 @@ public class ScalarCoercionTest extends BaseMapTest JsonToken tokenType, String tokenValue) throws IOException { // 2 different possibilities here - verifyException(e, "Cannot coerce Number", "Cannot deserialize instance of `"); + verifyException(e, "Cannot coerce Integer value", "Cannot deserialize value of type `"); JsonParser p = (JsonParser) e.getProcessor(); diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceMiscScalarsTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceMiscScalarsTest.java new file mode 100644 index 000000000..405dd35e3 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceMiscScalarsTest.java @@ -0,0 +1,281 @@ +package com.fasterxml.jackson.databind.convert; + +import java.io.File; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Calendar; +import java.util.Currency; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; +import java.util.UUID; +import java.util.regex.Pattern; + +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; + +public class CoerceMiscScalarsTest extends BaseMapTest +{ + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + + private final ObjectMapper MAPPER_EMPTY_TO_EMPTY; + { + MAPPER_EMPTY_TO_EMPTY = newJsonMapper(); + MAPPER_EMPTY_TO_EMPTY.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty); + } + + private final ObjectMapper MAPPER_EMPTY_TO_TRY_CONVERT; + { + MAPPER_EMPTY_TO_TRY_CONVERT = newJsonMapper(); + MAPPER_EMPTY_TO_TRY_CONVERT.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.TryConvert); + } + + private final ObjectMapper MAPPER_EMPTY_TO_NULL; + { + MAPPER_EMPTY_TO_NULL = newJsonMapper(); + MAPPER_EMPTY_TO_NULL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull); + } + + private final ObjectMapper MAPPER_EMPTY_TO_FAIL; + { + MAPPER_EMPTY_TO_FAIL = newJsonMapper(); + MAPPER_EMPTY_TO_FAIL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.Fail); + } + + private final String JSON_EMPTY = quote(""); + + /* + /******************************************************** + /* Test methods, defaults (legacy) + /******************************************************** + */ + + public void testScalarDefaultsFromEmpty() throws Exception + { + // mostly as null, with some exceptions + + _testScalarEmptyToNull(DEFAULT_MAPPER, File.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, URL.class); + + _testScalarEmptyToEmpty(DEFAULT_MAPPER, URI.class, + URI.create("")); + + _testScalarEmptyToNull(DEFAULT_MAPPER, Class.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, JavaType.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, Currency.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, Pattern.class); + + _testScalarEmptyToEmpty(DEFAULT_MAPPER, Locale.class, + Locale.ROOT); + + _testScalarEmptyToNull(DEFAULT_MAPPER, Charset.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, TimeZone.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, InetAddress.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, InetSocketAddress.class); + } + + /* + /******************************************************** + /* Test methods, successful coercions from empty String + /******************************************************** + */ + + public void testScalarEmptyToNull() throws Exception + { + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, File.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, URL.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, URI.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Class.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, JavaType.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Currency.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Pattern.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Locale.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Charset.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, TimeZone.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, InetAddress.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, InetSocketAddress.class); + } + + public void testScalarEmptyToEmpty() throws Exception + { + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, File.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, URL.class); + + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_EMPTY, URI.class, + URI.create("")); + + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, Class.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, JavaType.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, Currency.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, Pattern.class); + + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_EMPTY, Locale.class, + Locale.ROOT); + + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, Charset.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, TimeZone.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, InetAddress.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_EMPTY, InetSocketAddress.class); + } + + public void testScalarEmptyToTryConvert() throws Exception + { + // Should be same as `AsNull` for most but not all + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, File.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, URL.class); + + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_TRY_CONVERT, URI.class, + URI.create("")); + + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Class.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, JavaType.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Currency.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Pattern.class); + + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_TRY_CONVERT, Locale.class, + Locale.ROOT); + + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Charset.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, TimeZone.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, InetAddress.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, InetSocketAddress.class); + } + + /* + /******************************************************** + /* Test methods, failed coercions from empty String + /******************************************************** + */ + + public void testScalarsFailFromEmpty() throws Exception + { + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, File.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, URL.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, URI.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Class.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, JavaType.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Currency.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Pattern.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Locale.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Charset.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, TimeZone.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, InetAddress.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, InetSocketAddress.class); + } + + /* + /******************************************************** + /* Test methods, (more) special type(s) + /******************************************************** + */ + + // UUID is quite compatible, but not exactly due to historical reasons; + // also uses custom subtype, so test separately + + public void testUUIDCoercions() throws Exception + { + // Coerce to `null` both by default, "TryConvert" and explicit + _testScalarEmptyToNull(DEFAULT_MAPPER, UUID.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, UUID.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, UUID.class); + + // but allow separate "empty" value is specifically requested + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_EMPTY, UUID.class, + new UUID(0L, 0L)); + + // allow forcing failure, too + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, UUID.class); + + // and allow failure with specifically configured per-class override, too + ObjectMapper failMapper = newJsonMapper(); + failMapper.coercionConfigFor(UUID.class) + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.Fail); + _verifyScalarToFail(failMapper, UUID.class); + } + + // StringBuilder is its own special type, since it naturally maps + // from String values, hence separate testing + public void testStringBuilderCoercions() throws Exception + { + // should result in an "empty" StringBuilder for all valid settings + _checkEmptyStringBuilder(DEFAULT_MAPPER.readValue(JSON_EMPTY, StringBuilder.class)); + _checkEmptyStringBuilder(MAPPER_EMPTY_TO_EMPTY.readValue(JSON_EMPTY, StringBuilder.class)); + _checkEmptyStringBuilder(MAPPER_EMPTY_TO_TRY_CONVERT.readValue(JSON_EMPTY, StringBuilder.class)); + _checkEmptyStringBuilder(MAPPER_EMPTY_TO_NULL.readValue(JSON_EMPTY, StringBuilder.class)); + // and even alleged failure should not result in that since it's not coercion + _checkEmptyStringBuilder(MAPPER_EMPTY_TO_FAIL.readValue(JSON_EMPTY, StringBuilder.class)); + } + + private void _checkEmptyStringBuilder(StringBuilder sb) { + assertNotNull(sb); + assertEquals(0, sb.length()); + } + + // Date, Calendar also included here for convenience + + public void testLegacyDateTimeCoercions() throws Exception + { + // Coerce to `null` both by default, "TryConvert" and explicit + _testScalarEmptyToNull(DEFAULT_MAPPER, Calendar.class); + _testScalarEmptyToNull(DEFAULT_MAPPER, Date.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Calendar.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_NULL, Date.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Calendar.class); + _testScalarEmptyToNull(MAPPER_EMPTY_TO_TRY_CONVERT, Date.class); + + // but allow separate "empty" value is specifically requested + Calendar emptyCal = new GregorianCalendar(); + emptyCal.setTimeInMillis(0L); +// _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_EMPTY, Calendar.class, emptyCal); + _testScalarEmptyToEmpty(MAPPER_EMPTY_TO_EMPTY, Date.class, new Date(0L)); + + // allow forcing failure, too + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Calendar.class); + _verifyScalarToFail(MAPPER_EMPTY_TO_FAIL, Date.class); + } + + /* + /******************************************************** + /* Second-level test helper methods + /******************************************************** + */ + + private void _testScalarEmptyToNull(ObjectMapper mapper, Class<?> target) throws Exception + { + assertNull(mapper.readerFor(target).readValue(JSON_EMPTY)); + } + + private void _testScalarEmptyToEmpty(ObjectMapper mapper, + Class<?> target, Object emptyValue) throws Exception + { + Object result = mapper.readerFor(target).readValue(JSON_EMPTY); + if (result == null) { + fail("Expected empty, non-null value for "+target.getName()+", got null"); + } + assertEquals(emptyValue, result); + } + + private void _verifyScalarToFail(ObjectMapper mapper, Class<?> target) throws Exception + { + try { + /*Object result =*/ mapper.readerFor(target) + .readValue(JSON_EMPTY); + fail("Should not pass"); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot coerce empty String "); + verifyException(e, " to `"+target.getName()); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoercePojosTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoercePojosTest.java new file mode 100644 index 000000000..79d63c4d8 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoercePojosTest.java @@ -0,0 +1,188 @@ +package com.fasterxml.jackson.databind.convert; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.type.LogicalType; + +public class CoercePojosTest extends BaseMapTest +{ + static class Bean { + public String a; + } + + private final ObjectMapper MAPPER = newJsonMapper(); + + private final String JSON_EMPTY = quote(""); + private final String JSON_BLANK = quote(" "); + + /* + /******************************************************** + /* Test methods, from empty String + /******************************************************** + */ + + public void testPOJOFromEmptyStringLegacy() throws Exception + { + // first, verify default settings which do not accept empty String: + assertFalse(MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)); + + // should be ok to enable dynamically + _verifyFromEmptyPass(MAPPER.reader() + .with(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT), + JSON_EMPTY); + + } + + public void testPOJOFromEmptyGlobalConfig() throws Exception + { + _testPOJOFromEmptyGlobalConfig(CoercionInputShape.EmptyString, JSON_EMPTY, null); + } + + public void testPOJOFromEmptyLogicalTypeConfig() throws Exception + { + _testPOJOFromEmptyLogicalTypeConfig(CoercionInputShape.EmptyString, JSON_EMPTY, null); + } + + public void testPOJOFromEmptyPhysicalTypeConfig() throws Exception + { + _testPOJOFromEmptyPhysicalTypeConfig(CoercionInputShape.EmptyString, JSON_EMPTY, null); + } + + /* + /******************************************************** + /* Test methods, from blank String + /******************************************************** + */ + + public void testPOJOFromBlankGlobalConfig() throws Exception + { + _testPOJOFromEmptyGlobalConfig(CoercionInputShape.EmptyString, JSON_BLANK, Boolean.TRUE); + } + + public void testPOJOFromBlankLogicalTypeConfig() throws Exception + { + _testPOJOFromEmptyLogicalTypeConfig(CoercionInputShape.EmptyString, JSON_BLANK, Boolean.TRUE); + } + + public void testPOJOFromBlankPhysicalTypeConfig() throws Exception + { + _testPOJOFromEmptyPhysicalTypeConfig(CoercionInputShape.EmptyString, JSON_BLANK, Boolean.TRUE); + } + + /* + /******************************************************** + /* Second-level helper methods + /******************************************************** + */ + + private void _testPOJOFromEmptyGlobalConfig(final CoercionInputShape shape, final String json, + Boolean allowEmpty) + throws Exception + { + ObjectMapper mapper; + + // First, coerce to null + mapper = newJsonMapper(); + mapper.coercionConfigDefaults().setCoercion(shape, CoercionAction.AsNull) + .setAcceptBlankAsEmpty(allowEmpty); + assertNull(_verifyFromEmptyPass(mapper, json)); + + // Then coerce as empty + mapper = newJsonMapper(); + mapper.coercionConfigDefaults().setCoercion(shape, CoercionAction.AsEmpty) + .setAcceptBlankAsEmpty(allowEmpty); + Bean b = _verifyFromEmptyPass(mapper, json); + assertNotNull(b); + + // and finally, "try convert", which aliases to 'null' + mapper = newJsonMapper(); + mapper.coercionConfigDefaults().setCoercion(shape, CoercionAction.TryConvert) + .setAcceptBlankAsEmpty(allowEmpty); + assertNull(_verifyFromEmptyPass(mapper, json)); + } + + private void _testPOJOFromEmptyLogicalTypeConfig(final CoercionInputShape shape, final String json, + Boolean allowEmpty) + throws Exception + { + ObjectMapper mapper; + + // First, coerce to null + mapper = newJsonMapper(); + mapper.coercionConfigFor(LogicalType.POJO).setCoercion(shape, CoercionAction.AsNull) + .setAcceptBlankAsEmpty(allowEmpty); + assertNull(_verifyFromEmptyPass(mapper, json)); + + // Then coerce as empty + mapper = newJsonMapper(); + mapper.coercionConfigFor(LogicalType.POJO).setCoercion(shape, CoercionAction.AsEmpty) + .setAcceptBlankAsEmpty(allowEmpty); + Bean b = _verifyFromEmptyPass(mapper, json); + assertNotNull(b); + + // But also make fail again with 2-level settings + mapper = newJsonMapper(); + mapper.coercionConfigDefaults().setCoercion(shape, CoercionAction.AsNull) + .setAcceptBlankAsEmpty(allowEmpty); + mapper.coercionConfigFor(LogicalType.POJO).setCoercion(shape, + CoercionAction.Fail); + _verifyFromEmptyFail(mapper, json); + } + + private void _testPOJOFromEmptyPhysicalTypeConfig(final CoercionInputShape shape, final String json, + Boolean allowEmpty) + throws Exception + { + ObjectMapper mapper; + + // First, coerce to null + mapper = newJsonMapper(); + mapper.coercionConfigFor(Bean.class).setCoercion(shape, CoercionAction.AsNull) + .setAcceptBlankAsEmpty(allowEmpty); + assertNull(_verifyFromEmptyPass(mapper, json)); + + // Then coerce as empty + mapper = newJsonMapper(); + mapper.coercionConfigFor(Bean.class).setCoercion(shape, CoercionAction.AsEmpty) + .setAcceptBlankAsEmpty(allowEmpty); + Bean b = _verifyFromEmptyPass(mapper, json); + assertNotNull(b); + + // But also make fail again with 2-level settings, with physical having precedence + mapper = newJsonMapper(); + mapper.coercionConfigFor(LogicalType.POJO).setCoercion(shape, CoercionAction.AsEmpty) + .setAcceptBlankAsEmpty(allowEmpty); + mapper.coercionConfigFor(Bean.class).setCoercion(shape, CoercionAction.Fail); + _verifyFromEmptyFail(mapper, json); + } + + private Bean _verifyFromEmptyPass(ObjectMapper m, String json) throws Exception { + return _verifyFromEmptyPass(m.reader(), json); + } + + private Bean _verifyFromEmptyPass(ObjectReader r, String json) throws Exception + { + return r.forType(Bean.class) + .readValue(json); + } + + private void _verifyFromEmptyFail(ObjectMapper m, String json) throws Exception + { + try { + m.readValue(json, Bean.class); + fail("Should not accept Empty/Blank String for POJO with passed settings"); + } catch (MismatchedInputException e) { + _verifyFailMessage(e); + } + } + + private void _verifyFailMessage(JsonProcessingException e) + { + verifyException(e, "Cannot deserialize value of type "); + verifyException(e, " from empty String ", " from blank String "); + assertValidLocation(e.getLocation()); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceToBooleanTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceToBooleanTest.java new file mode 100644 index 000000000..f78c14db1 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceToBooleanTest.java @@ -0,0 +1,273 @@ +package com.fasterxml.jackson.databind.convert; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.type.LogicalType; + +public class CoerceToBooleanTest extends BaseMapTest +{ + static class BooleanPOJO { + public boolean value; + } + + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + + private final ObjectMapper LEGACY_NONCOERCING_MAPPER = jsonMapperBuilder() + .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS) + .build(); + + private final ObjectMapper MAPPER_TO_EMPTY; { + MAPPER_TO_EMPTY = newJsonMapper(); + MAPPER_TO_EMPTY.coercionConfigFor(LogicalType.Boolean) + .setCoercion(CoercionInputShape.Integer, CoercionAction.AsEmpty); + } + + private final ObjectMapper MAPPER_TRY_CONVERT; { + MAPPER_TRY_CONVERT = newJsonMapper(); + MAPPER_TRY_CONVERT.coercionConfigFor(LogicalType.Boolean) + .setCoercion(CoercionInputShape.Integer, CoercionAction.TryConvert); + } + + private final ObjectMapper MAPPER_TO_NULL; { + MAPPER_TO_NULL = newJsonMapper(); + MAPPER_TO_NULL.coercionConfigFor(LogicalType.Boolean) + .setCoercion(CoercionInputShape.Integer, CoercionAction.AsNull); + } + + private final ObjectMapper MAPPER_TO_FAIL; { + MAPPER_TO_FAIL = newJsonMapper(); + MAPPER_TO_FAIL.coercionConfigFor(LogicalType.Boolean) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail); + } + + private final static String DOC_WITH_0 = aposToQuotes("{'value':0}"); + private final static String DOC_WITH_1 = aposToQuotes("{'value':1}"); + + /* + /********************************************************** + /* Unit tests: default, legacy configuration + /********************************************************** + */ + + public void testToBooleanCoercionSuccessPojo() throws Exception + { + BooleanPOJO p; + final ObjectReader r = DEFAULT_MAPPER.readerFor(BooleanPOJO.class); + + p = r.readValue(DOC_WITH_0); + assertEquals(false, p.value); + p = r.readValue(utf8Bytes(DOC_WITH_0)); + assertEquals(false, p.value); + + p = r.readValue(DOC_WITH_1); + assertEquals(true, p.value); + p = r.readValue(utf8Bytes(DOC_WITH_1)); + assertEquals(true, p.value); + } + + public void testToBooleanCoercionSuccessRoot() throws Exception + { + final ObjectReader br = DEFAULT_MAPPER.readerFor(Boolean.class); + + assertEquals(Boolean.FALSE, br.readValue(" 0")); + assertEquals(Boolean.FALSE, br.readValue(utf8Bytes(" 0"))); + assertEquals(Boolean.TRUE, br.readValue(" -1")); + assertEquals(Boolean.TRUE, br.readValue(utf8Bytes(" -1"))); + + final ObjectReader atomicR = DEFAULT_MAPPER.readerFor(AtomicBoolean.class); + + AtomicBoolean ab; + + ab = atomicR.readValue(" 0"); + ab = atomicR.readValue(utf8Bytes(" 0")); + assertEquals(false, ab.get()); + + ab = atomicR.readValue(" 111"); + assertEquals(true, ab.get()); + ab = atomicR.readValue(utf8Bytes(" 111")); + assertEquals(true, ab.get()); + } + + public void testToBooleanCoercionFailBytes() throws Exception + { + _verifyBooleanCoerceFail(aposToQuotes("{'value':1}"), true, JsonToken.VALUE_NUMBER_INT, "1", BooleanPOJO.class); + + _verifyBooleanCoerceFail("1", true, JsonToken.VALUE_NUMBER_INT, "1", Boolean.TYPE); + _verifyBooleanCoerceFail("1", true, JsonToken.VALUE_NUMBER_INT, "1", Boolean.class); + } + + public void testToBooleanCoercionFailChars() throws Exception + { + _verifyBooleanCoerceFail(aposToQuotes("{'value':1}"), false, JsonToken.VALUE_NUMBER_INT, "1", BooleanPOJO.class); + + _verifyBooleanCoerceFail("1", false, JsonToken.VALUE_NUMBER_INT, "1", Boolean.TYPE); + _verifyBooleanCoerceFail("1", false, JsonToken.VALUE_NUMBER_INT, "1", Boolean.class); + } + + /* + /********************************************************** + /* Unit tests: new CoercionConfig, as-null, as-empty, try-coerce + /********************************************************** + */ + + public void testIntToNullCoercion() throws Exception + { + assertNull(MAPPER_TO_NULL.readValue("0", Boolean.class)); + assertNull(MAPPER_TO_NULL.readValue("1", Boolean.class)); + + // but due to coercion to `boolean`, can not return null here -- however, + // goes "1 -> false (no null for primitive) -> Boolean.FALSE + assertEquals(Boolean.FALSE, MAPPER_TO_NULL.readValue("0", Boolean.TYPE)); + assertEquals(Boolean.FALSE, MAPPER_TO_NULL.readValue("1", Boolean.TYPE)); + + // As to AtomicBoolean: that type itself IS nullable since it's of LogicalType.Boolean so + assertNull(MAPPER_TO_NULL.readValue("0", AtomicBoolean.class)); + assertNull(MAPPER_TO_NULL.readValue("1", AtomicBoolean.class)); + + BooleanPOJO p; + p = MAPPER_TO_NULL.readValue(DOC_WITH_0, BooleanPOJO.class); + assertFalse(p.value); + p = MAPPER_TO_NULL.readValue(DOC_WITH_1, BooleanPOJO.class); + assertFalse(p.value); + } + + public void testIntToEmptyCoercion() throws Exception + { + // "empty" value for Boolean/boolean is False/false + + assertEquals(Boolean.FALSE, MAPPER_TO_EMPTY.readValue("0", Boolean.class)); + assertEquals(Boolean.FALSE, MAPPER_TO_EMPTY.readValue("1", Boolean.class)); + + assertEquals(Boolean.FALSE, MAPPER_TO_EMPTY.readValue("0", Boolean.TYPE)); + assertEquals(Boolean.FALSE, MAPPER_TO_EMPTY.readValue("1", Boolean.TYPE)); + + AtomicBoolean ab; + ab = MAPPER_TO_EMPTY.readValue("0", AtomicBoolean.class); + assertFalse(ab.get()); + ab = MAPPER_TO_EMPTY.readValue("1", AtomicBoolean.class); + assertFalse(ab.get()); + + BooleanPOJO p; + p = MAPPER_TO_EMPTY.readValue(DOC_WITH_0, BooleanPOJO.class); + assertFalse(p.value); + p = MAPPER_TO_EMPTY.readValue(DOC_WITH_1, BooleanPOJO.class); + assertFalse(p.value); + } + + public void testIntToTryCoercion() throws Exception + { + // And "TryCoerce" should do what would be typically expected + + assertEquals(Boolean.FALSE, MAPPER_TRY_CONVERT.readValue("0", Boolean.class)); + assertEquals(Boolean.TRUE, MAPPER_TRY_CONVERT.readValue("1", Boolean.class)); + + assertEquals(Boolean.FALSE, MAPPER_TRY_CONVERT.readValue("0", Boolean.TYPE)); + assertEquals(Boolean.TRUE, MAPPER_TRY_CONVERT.readValue("1", Boolean.TYPE)); + + AtomicBoolean ab; + ab = MAPPER_TRY_CONVERT.readValue("0", AtomicBoolean.class); + assertFalse(ab.get()); + ab = MAPPER_TRY_CONVERT.readValue("1", AtomicBoolean.class); + assertTrue(ab.get()); + + BooleanPOJO p; + p = MAPPER_TRY_CONVERT.readValue(DOC_WITH_0, BooleanPOJO.class); + assertFalse(p.value); + p = MAPPER_TRY_CONVERT.readValue(DOC_WITH_1, BooleanPOJO.class); + assertTrue(p.value); + } + + /* + /********************************************************** + /* Unit tests: new CoercionConfig, failing + /********************************************************** + */ + + public void testFailFromInteger() throws Exception + { + _verifyFailFromInteger(MAPPER_TO_FAIL, BooleanPOJO.class, DOC_WITH_0, Boolean.TYPE); + _verifyFailFromInteger(MAPPER_TO_FAIL, BooleanPOJO.class, DOC_WITH_1, Boolean.TYPE); + + _verifyFailFromInteger(MAPPER_TO_FAIL, Boolean.class, "0"); + _verifyFailFromInteger(MAPPER_TO_FAIL, Boolean.class, "42"); + + _verifyFailFromInteger(MAPPER_TO_FAIL, Boolean.TYPE, "0"); + _verifyFailFromInteger(MAPPER_TO_FAIL, Boolean.TYPE, "999"); + + _verifyFailFromInteger(MAPPER_TO_FAIL, AtomicBoolean.class, "0"); + _verifyFailFromInteger(MAPPER_TO_FAIL, AtomicBoolean.class, "-123"); + } + + /* + /********************************************************** + /* Helper methods + /********************************************************** + */ + + private void _verifyBooleanCoerceFail(String doc, boolean useBytes, + JsonToken tokenType, String tokenValue, Class<?> targetType) throws IOException + { + // Test failure for root value: for both byte- and char-backed sources. + + // [databind#2635]: important, need to use `readValue()` that takes content and NOT + // JsonParser, as this forces closing of underlying parser and exposes more issues. + + final ObjectReader r = LEGACY_NONCOERCING_MAPPER.readerFor(targetType); + try { + if (useBytes) { + r.readValue(utf8Bytes(doc)); + } else { + r.readValue(doc); + } + fail("Should not have allowed coercion"); + } catch (MismatchedInputException e) { + _verifyBooleanCoerceFailReason(e, tokenType, tokenValue); + } + } + + @SuppressWarnings("resource") + private void _verifyBooleanCoerceFailReason(MismatchedInputException e, + JsonToken tokenType, String tokenValue) throws IOException + { + verifyException(e, "Cannot coerce "); + verifyException(e, " to `"); + + JsonParser p = (JsonParser) e.getProcessor(); + + assertToken(tokenType, p.currentToken()); + + final String text = p.getText(); + if (!tokenValue.equals(text)) { + String textDesc = (text == null) ? "NULL" : quote(text); + fail("Token text ("+textDesc+") via parser of type "+p.getClass().getName() + +" not as expected ("+quote(tokenValue)+")"); + } + } + + private void _verifyFailFromInteger(ObjectMapper m, Class<?> targetType, String doc) throws Exception { + _verifyFailFromInteger(m, targetType, doc, targetType); + } + + private void _verifyFailFromInteger(ObjectMapper m, Class<?> targetType, String doc, + Class<?> valueType) throws Exception + { + try { + m.readerFor(targetType).readValue(doc); + fail("Should not accept Integer for "+targetType.getName()+" by default"); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot coerce Integer value"); + verifyException(e, "to `"+valueType.getName()+"`"); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/NumericConversionTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/NumericConversionTest.java deleted file mode 100644 index 03f79cfe0..000000000 --- a/src/test/java/com/fasterxml/jackson/databind/convert/NumericConversionTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.fasterxml.jackson.databind.convert; - -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; - -public class NumericConversionTest extends BaseMapTest -{ - private final ObjectMapper MAPPER = sharedMapper(); - private final ObjectReader R = MAPPER.reader().without(DeserializationFeature.ACCEPT_FLOAT_AS_INT); - - public void testDoubleToInt() throws Exception - { - // by default, should be ok - Integer I = MAPPER.readValue(" 1.25 ", Integer.class); - assertEquals(1, I.intValue()); - IntWrapper w = MAPPER.readValue("{\"i\":-2.25 }", IntWrapper.class); - assertEquals(-2, w.i); - int[] arr = MAPPER.readValue("[ 1.25 ]", int[].class); - assertEquals(1, arr[0]); - - try { - R.forType(Integer.class).readValue("1.5"); - fail("Should not pass"); - } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - try { - R.forType(Integer.TYPE).readValue("1.5"); - fail("Should not pass"); - } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - try { - R.forType(IntWrapper.class).readValue("{\"i\":-2.25 }"); - fail("Should not pass"); - } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - try { - R.forType(int[].class).readValue("[ 2.5 ]"); - fail("Should not pass"); - } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - } - - public void testDoubleToLong() throws Exception - { - // by default, should be ok - Long L = MAPPER.readValue(" 3.33 ", Long.class); - assertEquals(3L, L.longValue()); - LongWrapper w = MAPPER.readValue("{\"l\":-2.25 }", LongWrapper.class); - assertEquals(-2L, w.l); - long[] arr = MAPPER.readValue("[ 1.25 ]", long[].class); - assertEquals(1, arr[0]); - - try { - R.forType(Long.class).readValue("1.5"); - fail("Should not pass"); - } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - - try { - R.forType(Long.TYPE).readValue("1.5"); - fail("Should not pass"); - } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - - try { - R.forType(LongWrapper.class).readValue("{\"l\": 7.7 }"); - fail("Should not pass"); - } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - try { - R.forType(long[].class).readValue("[ 2.5 ]"); - fail("Should not pass"); - } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce a floating-point"); - } - } -} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/TestArrayConversions.java b/src/test/java/com/fasterxml/jackson/databind/convert/TestArrayConversions.java index fbc4751bb..33117d4aa 100644 --- a/src/test/java/com/fasterxml/jackson/databind/convert/TestArrayConversions.java +++ b/src/test/java/com/fasterxml/jackson/databind/convert/TestArrayConversions.java @@ -12,7 +12,7 @@ public class TestArrayConversions extends com.fasterxml.jackson.databind.BaseMapTest { final static String OVERFLOW_MSG_BYTE = "out of range of Java byte"; - final static String OVERFLOW_MSG = "overflow"; + final static String OVERFLOW_MSG_SHORT = "out of range of Java short"; final static String OVERFLOW_MSG_INT = "out of range of int"; final static String OVERFLOW_MSG_LONG = "out of range of long"; @@ -103,7 +103,7 @@ public class TestArrayConversions try { MAPPER.convertValue(new int[] { -99999 }, short[].class); } catch (IllegalArgumentException e) { - verifyException(e, OVERFLOW_MSG); + verifyException(e, OVERFLOW_MSG_SHORT); } // Int overflow try { diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/TestMapConversions.java b/src/test/java/com/fasterxml/jackson/databind/convert/TestMapConversions.java index bfed9dffe..aabe0eaa3 100644 --- a/src/test/java/com/fasterxml/jackson/databind/convert/TestMapConversions.java +++ b/src/test/java/com/fasterxml/jackson/databind/convert/TestMapConversions.java @@ -70,11 +70,11 @@ public class TestMapConversions public void testMapToBean() { EnumMap<AB,String> map = new EnumMap<AB,String>(AB.class); - map.put(AB.A, " 17"); - map.put(AB.B, " -1"); + map.put(AB.A, "17"); + map.put(AB.B, "-1"); Bean bean = MAPPER.convertValue(map, Bean.class); assertEquals(Integer.valueOf(17), bean.A); - assertEquals(" -1", bean.B); + assertEquals("-1", bean.B); } public void testBeanToMap() diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/TestStringConversions.java b/src/test/java/com/fasterxml/jackson/databind/convert/TestStringConversions.java index 93a9d67b1..5f874ce93 100644 --- a/src/test/java/com/fasterxml/jackson/databind/convert/TestStringConversions.java +++ b/src/test/java/com/fasterxml/jackson/databind/convert/TestStringConversions.java @@ -35,7 +35,7 @@ public class TestStringConversions public void testSimple() { assertEquals(Boolean.TRUE, MAPPER.convertValue("true", Boolean.class)); - assertEquals(Integer.valueOf(-3), MAPPER.convertValue(" -3 ", Integer.class)); + assertEquals(Integer.valueOf(-3), MAPPER.convertValue("-3", Integer.class)); assertEquals(Long.valueOf(77), MAPPER.convertValue("77", Long.class)); int[] ints = { 1, 2, 3 }; diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeser1805Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeser1805Test.java deleted file mode 100644 index 7741337eb..000000000 --- a/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeser1805Test.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.fasterxml.jackson.databind.deser; - -import java.util.*; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.*; - -public class ReadOnlyDeser1805Test extends BaseMapTest -{ - static class Foo { - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - private List<Long> list = new ArrayList<>(); - - List<Long> getList() { - return list; - } - - public Foo setList(List<Long> list) { - this.list = list; - return this; - } - } - - // [databind#1805] - static class UserWithReadOnly { - public String name; - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public List<String> getRoles() { - return Arrays.asList("admin", "monitor"); - } - } - - // [databind#1805] - @JsonIgnoreProperties(value={ "roles" }, allowGetters=true) - static class UserAllowGetters { - public String name; - - public List<String> getRoles() { - return Arrays.asList("admin", "monitor"); - } - } - - /* - /********************************************************** - /* Test methods - /********************************************************** - */ - - private final ObjectMapper MAPPER = newJsonMapper(); - - public void testReadOnly1382() throws Exception - { - String payload = "{\"list\":[1,2,3,4]}"; - Foo foo = MAPPER.readValue(payload, Foo.class); - assertTrue("List should be empty", foo.getList().isEmpty()); - } - - // [databind#1805] - public void testViaReadOnly() throws Exception { - UserWithReadOnly user = new UserWithReadOnly(); - user.name = "foo"; - String json = MAPPER.writeValueAsString(user); - UserWithReadOnly result = MAPPER.readValue(json, UserWithReadOnly.class); - assertNotNull(result); - } - - // [databind#1805] - public void testUsingAllowGetters() throws Exception { - UserAllowGetters user = new UserAllowGetters(); - user.name = "foo"; - String json = MAPPER.writeValueAsString(user); - assertTrue(json.contains("roles")); - UserAllowGetters result = MAPPER.readValue(json, UserAllowGetters.class); - assertNotNull(result); - } -} diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeserFailOnUnknown2719Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeserFailOnUnknown2719Test.java new file mode 100644 index 000000000..7e1f6ea51 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyDeserFailOnUnknown2719Test.java @@ -0,0 +1,52 @@ +package com.fasterxml.jackson.databind.deser; + +import com.fasterxml.jackson.annotation.*; + +import com.fasterxml.jackson.databind.*; + +public class ReadOnlyDeserFailOnUnknown2719Test extends BaseMapTest +{ + // [databind#2719] + static class UserWithReadOnly { + @JsonProperty(value = "username", access = JsonProperty.Access.READ_ONLY) + public String name; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String password; + public String login; + } + + /* + /********************************************************** + /* Test methods + /********************************************************** + */ + + private final ObjectMapper MAPPER = newJsonMapper(); + + public void testFailOnIgnore() throws Exception + { + ObjectReader r = MAPPER.readerFor(UserWithReadOnly.class); + + // First, fine to get 'login' + UserWithReadOnly result = r.readValue(aposToQuotes("{'login':'foo'}")); + assertEquals("foo", result.login); + + // but not 'password' + r = r.with(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); + try { + r.readValue(aposToQuotes("{'login':'foo', 'password':'bar'}")); + fail("Should fail"); + } catch (JsonMappingException e) { + verifyException(e, "Ignored field"); + } + + // or 'username' + r = r.with(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); + try { + r.readValue(aposToQuotes("{'login':'foo', 'username':'bar'}")); + fail("Should fail"); + } catch (JsonMappingException e) { + verifyException(e, "Ignored field"); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/failing/PropertyAccessReadOnly2118Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyListDeser2118Test.java index fa7860885..0fb1e5cb9 100644 --- a/src/test/java/com/fasterxml/jackson/failing/PropertyAccessReadOnly2118Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyListDeser2118Test.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.deser; import java.util.*; @@ -6,12 +6,11 @@ import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.*; -public class PropertyAccessReadOnly2118Test extends BaseMapTest +public class ReadOnlyListDeser2118Test extends BaseMapTest { // [databind#2118] static class SecurityGroup { - - private List<SecurityGroupRule> securityGroupRules; + List<SecurityGroupRule> securityGroupRules; public SecurityGroup() { this.securityGroupRules = new ArrayList<>(); @@ -40,15 +39,21 @@ public class PropertyAccessReadOnly2118Test extends BaseMapTest public void setId(String id) { this.id = id; } + + @Override + public String toString() { + return "{SecurityGroupRule '"+id+"'}"; + } } + private final ObjectMapper mapper = newJsonMapper(); + // [databind#2118] public void testAccessReadOnly() throws Exception { - String data ="{\"security_group_rules\": [{\"id\": \"id1\"}, {\"id\": \"id2\"}, {\"id\": \"id3\"}, {\"id\": \"id4\"}]}"; - ObjectMapper mapper = new ObjectMapper(); -// This would work around the issue: + String data ="{\"security_group_rules\": [{\"id\": \"id1\"}]}"; +// This would work around the issue: // mapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS); SecurityGroup sg = mapper.readValue(data, SecurityGroup.class); - System.out.println(mapper.writeValueAsString(sg)); + assertEquals(Collections.emptyList(), sg.securityGroupRules); } } diff --git a/src/test/java/com/fasterxml/jackson/failing/ReadOnlyList2283Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyListDeser2283Test.java index 533265fc4..66e0fc527 100644 --- a/src/test/java/com/fasterxml/jackson/failing/ReadOnlyList2283Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOnlyListDeser2283Test.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.deser; import java.util.*; @@ -7,7 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.*; // [databind#2283]: ignore read-only Lists even if "getter-as-setter" enabled -public class ReadOnlyList2283Test +public class ReadOnlyListDeser2283Test extends BaseMapTest { static class RenamedToSameOnGetter { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/ReadOrWriteOnlyTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOrWriteOnlyTest.java index 0afd3ffb9..21f35c356 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/ReadOrWriteOnlyTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/ReadOrWriteOnlyTest.java @@ -1,8 +1,13 @@ package com.fasterxml.jackson.databind.deser; import java.beans.ConstructorProperties; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import com.fasterxml.jackson.databind.*; public class ReadOrWriteOnlyTest extends BaseMapTest @@ -66,6 +71,59 @@ public class ReadOrWriteOnlyTest extends BaseMapTest protected Foo1345() { } } + // [databind#1382] + static class Foo1382 { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private List<Long> list = new ArrayList<>(); + + List<Long> getList() { + return list; + } + + public Foo1382 setList(List<Long> list) { + this.list = list; + return this; + } + } + + // [databind#1805] + static class UserWithReadOnly1805 { + public String name; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public List<String> getRoles() { + return Arrays.asList("admin", "monitor"); + } + } + + // [databind#1805] + @JsonIgnoreProperties(value={ "roles" }, allowGetters=true) + static class UserAllowGetters1805 { + public String name; + + public List<String> getRoles() { + return Arrays.asList("admin", "monitor"); + } + } + + // [databind#2779]: ignorable property renaming + static class Bean2779 { + String works; + + @JsonProperty(value = "t", access = JsonProperty.Access.READ_ONLY) + public String getDoesntWork() { + return "pleaseFixThisBug"; + } + + public String getWorks() { + return works; + } + + public void setWorks(String works) { + this.works = works; + } + } + /* /********************************************************** /* Test methods @@ -93,6 +151,7 @@ public class ReadOrWriteOnlyTest extends BaseMapTest assertNotNull(result); } + // [databind#1345] public void testReadOnly1345() throws Exception { Foo1345 result = MAPPER.readValue("{\"name\":\"test\"}", Foo1345.class); @@ -100,4 +159,42 @@ public class ReadOrWriteOnlyTest extends BaseMapTest assertEquals("test", result.name); assertNull(result.id); } + + // [databind#1382] + public void testReadOnly1382() throws Exception + { + String payload = "{\"list\":[1,2,3,4]}"; + Foo1382 foo = MAPPER.readValue(payload, Foo1382.class); + assertTrue("List should be empty", foo.getList().isEmpty()); + } + + // [databind#1805] + public void testViaReadOnly() throws Exception { + UserWithReadOnly1805 user = new UserWithReadOnly1805(); + user.name = "foo"; + String json = MAPPER.writeValueAsString(user); + UserWithReadOnly1805 result = MAPPER.readValue(json, UserWithReadOnly1805.class); + assertNotNull(result); + } + + // [databind#1805] + public void testUsingAllowGetters() throws Exception { + UserAllowGetters1805 user = new UserAllowGetters1805(); + user.name = "foo"; + String json = MAPPER.writeValueAsString(user); + assertTrue(json.contains("roles")); + UserAllowGetters1805 result = MAPPER.readValue(json, UserAllowGetters1805.class); + assertNotNull(result); + } + + // [databind#2779]: ignorable property renaming + public void testIssue2779() throws Exception + { + Bean2779 bean = new Bean2779(); + bean.setWorks("works"); + + String json = MAPPER.writeValueAsString(bean); + Bean2779 newBean = MAPPER.readValue(json, Bean2779.class); + assertNotNull(newBean); + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java index 988ece38d..05850407c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java @@ -322,7 +322,7 @@ public class TestBeanDeserializer extends BaseMapTest /******************************************************** */ - private final ObjectMapper MAPPER = new ObjectMapper(); + private final ObjectMapper MAPPER = newJsonMapper(); /** * Test to verify details of how trying to deserialize into @@ -370,24 +370,6 @@ public class TestBeanDeserializer extends BaseMapTest assertEquals(2, Issue476Deserializer.propCount); } - public void testPOJOFromEmptyString() throws Exception - { - // first, verify default settings which do not accept empty String: - assertFalse(MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)); - try { - MAPPER.readValue(quote(""), Bean.class); - fail("Should not accept Empty String for POJO"); - } catch (JsonProcessingException e) { - verifyException(e, "from String value"); - assertValidLocation(e.getLocation()); - } - // should be ok to enable dynamically - ObjectReader r = MAPPER.readerFor(Bean.class) - .with(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); - Bean result = r.readValue(quote("")); - assertNull(result); - } - // [databind#120] public void testModifyArrayDeserializer() throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderErrorHandling.java b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderErrorHandling.java index f7f67b0c5..b71c1306a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderErrorHandling.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderErrorHandling.java @@ -54,7 +54,7 @@ public class BuilderErrorHandling extends BaseMapTest MAPPER.readValue(json, ValueClassXY.class); fail("Should not pass"); } catch (MismatchedInputException e) { - verifyException(e, "unrecognized field"); + verifyException(e, "Unrecognized field"); } // but pass if ok to ignore ValueClassXY result = MAPPER.readerFor(ValueClassXY.class) @@ -63,4 +63,16 @@ public class BuilderErrorHandling extends BaseMapTest assertEquals(2, result._x); assertEquals(5, result._y); } + + public void testWrongShape() throws Exception + { + try { + MAPPER.readValue("123", ValueClassXY.class); + fail("Should not pass"); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot construct instance of "); + // should report Builder class, not value here, right? + verifyException(e, "$SimpleBuilderXY"); + } + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderFailTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderFailTest.java index 55f9feb92..743d52db6 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderFailTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderFailTest.java @@ -70,7 +70,8 @@ public class BuilderFailTest extends BaseMapTest MAPPER.readValue(json, ValueClassWrongBuildType.class); fail("Missing expected InvalidDefinitionException exception"); } catch (InvalidDefinitionException e) { - verifyException(e, "Build method"); + verifyException(e, "Build method "); + verifyException(e, "#build()"); verifyException(e, "has wrong return type"); } } diff --git a/src/test/java/com/fasterxml/jackson/failing/BuilderDeserializationTest921.java b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderWithTypeParametersTest.java index 79beaee6f..7b8ddf6fa 100644 --- a/src/test/java/com/fasterxml/jackson/failing/BuilderDeserializationTest921.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderWithTypeParametersTest.java @@ -1,13 +1,17 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.deser.builder; -import java.util.List; - -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.LinkedHashMap; +import java.util.List; -public class BuilderDeserializationTest921 +// [databind#921]: support infering type parameters from Builder +public class BuilderWithTypeParametersTest extends BaseMapTest { public static class MyPOJO { @@ -33,6 +37,12 @@ public class BuilderDeserializationTest921 return data; } + // 28-Apr-2020, tatu: Note that as per [databind#921] the NAME of + // type variable here MUST match that of enclosing class. This has + // no semantic meaning to JDK or javac, but internally + // `MapperFeature.INFER_BUILDER_TYPE_BINDINGS` relies on this -- but + // can not really validate it. So user just has to rely on bit of + // black magic to use generic types with builders. public static class Builder<T> { private List<T> data; @@ -77,15 +87,30 @@ public class BuilderDeserializationTest921 } } - public void testWithBuilder() throws Exception { - final ObjectMapper mapper = new ObjectMapper(); + public void testWithBuilderInferringBindings() throws Exception { + final ObjectMapper mapper = jsonMapperBuilder() + .enable(MapperFeature.INFER_BUILDER_TYPE_BINDINGS) + .build(); + final String json = aposToQuotes("{ 'data': [ { 'x': 'x', 'y': 'y' } ] }"); + final MyGenericPOJO<MyPOJO> deserialized = + mapper.readValue(json, new TypeReference<MyGenericPOJO<MyPOJO>>() {}); + assertEquals(1, deserialized.data.size()); + Object ob = deserialized.data.get(0); + assertNotNull(ob); + assertEquals(MyPOJO.class, ob.getClass()); + } + + public void testWithBuilderWithoutInferringBindings() throws Exception { + final ObjectMapper mapper = jsonMapperBuilder() + .disable(MapperFeature.INFER_BUILDER_TYPE_BINDINGS) + .build(); final String json = aposToQuotes("{ 'data': [ { 'x': 'x', 'y': 'y' } ] }"); final MyGenericPOJO<MyPOJO> deserialized = mapper.readValue(json, new TypeReference<MyGenericPOJO<MyPOJO>>() {}); assertEquals(1, deserialized.data.size()); Object ob = deserialized.data.get(0); assertNotNull(ob); - assertEquals(MyPOJO.class, ob.getClass()); + assertEquals(LinkedHashMap.class, ob.getClass()); } public void testWithCreator() throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreatorsTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreatorsTest.java index c0ae77ca6..e33897e47 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreatorsTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreatorsTest.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.databind.BaseMapTest; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; public class DelegatingArrayCreatorsTest extends BaseMapTest { @@ -74,6 +75,20 @@ public class DelegatingArrayCreatorsTest extends BaseMapTest private Bag2324<Value2324> bagOfValues; } + static class MultipleArrayDelegators { + @JsonCreator(mode=JsonCreator.Mode.DELEGATING) + MultipleArrayDelegators(List<Integer> a) { } + + @JsonCreator(mode=JsonCreator.Mode.DELEGATING) + MultipleArrayDelegators(Set<Integer> a) { } + } + + /* + /********************************************************************** + /* Test methods + /********************************************************************** + */ + private final ObjectMapper MAPPER = sharedMapper(); // [databind#1804] @@ -96,4 +111,15 @@ public class DelegatingArrayCreatorsTest extends BaseMapTest assertEquals(3, result.getValues().size()); assertEquals(new Value2324("a"), result.getValues().iterator().next()); } + + public void testInvalidTwoArrayDelegating() throws Exception { + try { + /*MultipleArrayDelegators result =*/ MAPPER.readerFor(MultipleArrayDelegators.class) + .readValue("[ ]"); + fail("Should not pass"); + } catch (InvalidDefinitionException e) { + verifyException(e, "Conflicting array-delegate creators"); + verifyException(e, "already had explicitly marked"); + } + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreatorsDelegating.java b/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreatorsDelegating.java index 065172064..edde73955 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreatorsDelegating.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/TestCreatorsDelegating.java @@ -26,7 +26,30 @@ public class TestCreatorsDelegating extends BaseMapTest } } - // for [JACKSON-711]; should allow delegate-based one(s) too + static class IntegerBean + { + protected Integer value; + + public IntegerBean(Integer v) { value = v; } + + @JsonCreator + protected static IntegerBean create(Integer value) { + return new IntegerBean(value); + } + } + + static class LongBean + { + protected Long value; + + public LongBean(Long v) { value = v; } + + @JsonCreator + protected static LongBean create(Long value) { + return new LongBean(value); + } + } + static class CtorBean711 { protected String name; @@ -40,7 +63,6 @@ public class TestCreatorsDelegating extends BaseMapTest } } - // for [JACKSON-711]; should allow delegate-based one(s) too static class FactoryBean711 { protected String name1; @@ -116,7 +138,7 @@ public class TestCreatorsDelegating extends BaseMapTest */ private final ObjectMapper MAPPER = newJsonMapper(); - + public void testBooleanDelegate() throws Exception { // should obviously work with booleans... @@ -127,8 +149,28 @@ public class TestCreatorsDelegating extends BaseMapTest bb = MAPPER.readValue(quote("true"), BooleanBean.class); assertEquals(Boolean.TRUE, bb.value); } - - // As per [JACKSON-711]: should also work with delegate model (single non-annotated arg) + + public void testIntegerDelegate() throws Exception + { + IntegerBean bb = MAPPER.readValue("-13", IntegerBean.class); + assertEquals(Integer.valueOf(-13), bb.value); + + // but also with value conversion from String (unless blocked) + bb = MAPPER.readValue(quote("127"), IntegerBean.class); + assertEquals(Integer.valueOf(127), bb.value); + } + + public void testLongDelegate() throws Exception + { + LongBean bb = MAPPER.readValue("11", LongBean.class); + assertEquals(Long.valueOf(11L), bb.value); + + // but also with value conversion from String (unless blocked) + bb = MAPPER.readValue(quote("-99"), LongBean.class); + assertEquals(Long.valueOf(-99L), bb.value); + } + + // should also work with delegate model (single non-annotated arg) public void testWithCtorAndDelegate() throws Exception { ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/filter/IgnorePropertyOnDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/filter/IgnorePropertyOnDeserTest.java index 953ea8678..a9589daf7 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/filter/IgnorePropertyOnDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/filter/IgnorePropertyOnDeserTest.java @@ -10,6 +10,33 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class IgnorePropertyOnDeserTest extends BaseMapTest { + // [databind#426] + @JsonIgnoreProperties({ "userId" }) + static class User { + public String firstName; + Integer userId; + + public Integer getUserId() { + return userId; + } + + public void setUserId(CharSequence id) { + userId = Integer.valueOf(id.toString()); + } + + public void setUserId(Integer v) { + this.userId = v; + } + + public void setUserId(User u) { + // bogus + } + + public void setUserId(boolean b) { + // bogus + } + } + // [databind#1217] static class IgnoreObject { public int x = 1; @@ -62,6 +89,16 @@ public class IgnorePropertyOnDeserTest extends BaseMapTest private final ObjectMapper MAPPER = newJsonMapper(); + // [databind#426] + public void testIssue426() throws Exception + { + final String JSON = aposToQuotes("{'userId': 9, 'firstName': 'Mike' }"); + User result = MAPPER.readerFor(User.class).readValue(JSON); + assertNotNull(result); + assertEquals("Mike", result.firstName); + assertNull(result.userId); + } + // [databind#1217] public void testIgnoreOnProperty1217() throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/filter/ProblemHandlerTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/filter/ProblemHandlerTest.java index 85beb40b3..815029a0c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/filter/ProblemHandlerTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/filter/ProblemHandlerTest.java @@ -362,7 +362,7 @@ public class ProblemHandlerTest extends BaseMapTest mapper.readValue("true", Integer.class); fail("Should not pass"); } catch (MismatchedInputException e) { - verifyException(e, "out of VALUE_TRUE token"); + verifyException(e, "from Boolean value (token `JsonToken.VALUE_TRUE`)"); } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestArrayDeserialization.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java index b0fd99694..ac8838bd8 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/TestArrayDeserialization.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.databind.deser; +package com.fasterxml.jackson.databind.deser.jdk; import java.io.*; import java.util.*; @@ -16,7 +16,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; * This unit test suite tries to verify that the "Native" java type * mapper can properly re-construct Java array objects from Json arrays. */ -public class TestArrayDeserialization +public class ArrayDeserializationTest extends BaseMapTest { public final static class Bean1 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 2feba30b6..40a9cb958 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 @@ -702,7 +702,7 @@ public class DateDeserializationTest fail("Did not throw exception when reading a value from a single value array with the UNWRAP_SINGLE_VALUE_ARRAYS feature disabled"); } catch (MismatchedInputException exp) { verifyException(exp, "Cannot deserialize"); - verifyException(exp, "out of START_ARRAY"); + verifyException(exp, "from Array value (token `JsonToken.START_ARRAY`)"); } reader = reader.with(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberDeserTest.java index e31636741..4b551193a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberDeserTest.java @@ -7,7 +7,10 @@ import java.math.BigInteger; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.*; + import com.fasterxml.jackson.core.*; + import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.exc.MismatchedInputException; @@ -37,6 +40,42 @@ public class JDKNumberDeserTest extends BaseMapTest public MyBeanValue(BigDecimal d) { this.decimal = d; } } + // [databind#2644] + static class NodeRoot2644 { + public String type; + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type") + @JsonSubTypes(value = { + @JsonSubTypes.Type(value = NodeParent2644.class, name = "NodeParent") + }) + public Node2644 node; + } + + public static class NodeParent2644 extends Node2644 { } + + public static abstract class Node2644 { + @JsonProperty("amount") + BigDecimal val; + + public BigDecimal getVal() { + return val; + } + + public void setVal(BigDecimal val) { + this.val = val; + } + } + + // [databind#2784] + static class BigDecimalHolder2784 { + public BigDecimal value; + } + + static class NestedBigDecimalHolder2784 { + @JsonUnwrapped + public BigDecimalHolder2784 holder; + } + /* /********************************************************************** /* Helper classes, serializers/deserializers/resolvers @@ -138,7 +177,7 @@ public class JDKNumberDeserTest extends BaseMapTest noCoerceMapper.readValue(NULL_JSON, Integer.TYPE); fail("Should not have passed"); } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce String \"null\""); + verifyException(e, "Cannot coerce String value"); } } @@ -299,4 +338,28 @@ public class JDKNumberDeserTest extends BaseMapTest } assertEquals(42, node.asInt()); } + + // [databind#2644] + public void testBigDecimalSubtypes() throws Exception + { + ObjectMapper mapper = jsonMapperBuilder() + .registerSubtypes(NodeParent2644.class) + .build(); + NodeRoot2644 root = mapper.readValue( + "{\"type\": \"NodeParent\",\"node\": {\"amount\": 9999999999999999.99} }", + NodeRoot2644.class + ); + + assertEquals(new BigDecimal("9999999999999999.99"), root.node.getVal()); + } + + // [databind#2784] + public void testBigDecimalUnwrapped() throws Exception + { + final ObjectMapper mapper = newJsonMapper(); + // mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); + final String JSON = "{\"value\": 5.00}"; + NestedBigDecimalHolder2784 result = mapper.readValue(JSON, NestedBigDecimalHolder2784.class); + assertEquals(new BigDecimal("5.00"), result.holder.value); + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberLeniencyTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberLeniencyTest.java index b7269cbf7..47d8bb410 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberLeniencyTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKNumberLeniencyTest.java @@ -32,7 +32,7 @@ public class JDKNumberLeniencyTest extends BaseMapTest fail("Should not allow read in strict mode"); } catch (MismatchedInputException e) { verifyException(e, "Cannot coerce"); - verifyException(e, "for type `java.lang.Boolean`"); + verifyException(e, "to `java.lang.Boolean` value"); } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java index cdf9ec1ac..7e244a0e3 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKScalarsTest.java @@ -2,6 +2,8 @@ package com.fasterxml.jackson.databind.deser.jdk; import java.io.*; import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.List; import org.junit.Assert; @@ -12,6 +14,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.JsonMappingException.Reference; import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.util.ClassUtil; /** * Unit tests for verifying handling of simple basic non-structured @@ -120,6 +123,10 @@ public class JDKScalarsTest private final ObjectMapper MAPPER = newJsonMapper(); + private final ObjectMapper MAPPER_NO_COERCION = jsonMapperBuilder() + .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS) + .build(); + /* /********************************************************** /* Scalar tests for boolean @@ -226,12 +233,15 @@ public class JDKScalarsTest public void testCharacterWrapper() throws Exception { // First: canonical value is 1-char string - Character result = MAPPER.readValue("\"a\"", Character.class); - assertEquals(Character.valueOf('a'), result); + assertEquals(Character.valueOf('a'), MAPPER.readValue(quote("a"), Character.class)); // But can also pass in ascii code - result = MAPPER.readValue(" "+((int) 'X'), Character.class); + Character result = MAPPER.readValue(" "+((int) 'X'), Character.class); assertEquals(Character.valueOf('X'), result); + + // 22-Jun-2020, tatu: one special case turns out to be white space; + // need to avoid considering it "blank" value + assertEquals(Character.valueOf(' '), MAPPER.readValue(quote(" "), Character.class)); final CharacterWrapperBean wrapper = MAPPER.readValue("{\"v\":null}", CharacterWrapperBean.class); assertNotNull(wrapper); @@ -431,30 +441,6 @@ public class JDKScalarsTest /********************************************************** */ - public void testEmptyToNullCoercionForPrimitives() throws Exception { - _testEmptyToNullCoercion(int.class, Integer.valueOf(0)); - _testEmptyToNullCoercion(long.class, Long.valueOf(0)); - _testEmptyToNullCoercion(double.class, Double.valueOf(0.0)); - _testEmptyToNullCoercion(float.class, Float.valueOf(0.0f)); - } - - private void _testEmptyToNullCoercion(Class<?> primType, Object emptyValue) throws Exception - { - final String EMPTY = "\"\""; - - // as per [databind#1095] should only allow coercion from empty String, - // if `null` is acceptable - ObjectReader intR = MAPPER.readerFor(primType); - assertEquals(emptyValue, intR.readValue(EMPTY)); - try { - intR.with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES) - .readValue("\"\""); - fail("Should not have passed"); - } catch (MismatchedInputException e) { - verifyException(e, "Cannot coerce empty String"); - } - } - public void testBase64Variants() throws Exception { final byte[] INPUT = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890X".getBytes("UTF-8"); @@ -515,13 +501,15 @@ public class JDKScalarsTest */ // by default, should return nulls, n'est pas? - public void testEmptyStringForWrappers() throws IOException + public void testEmptyStringForBooleanWrapper() throws IOException { - WrappersBean bean; - - bean = MAPPER.readValue("{\"booleanValue\":\"\"}", WrappersBean.class); + WrappersBean bean = MAPPER.readValue("{\"booleanValue\":\"\"}", WrappersBean.class); assertNull(bean.booleanValue); - bean = MAPPER.readValue("{\"byteValue\":\"\"}", WrappersBean.class); + } + + public void testEmptyStringForIntegerWrappers() throws IOException + { + WrappersBean bean = MAPPER.readValue("{\"byteValue\":\"\"}", WrappersBean.class); assertNull(bean.byteValue); // char/Character is different... not sure if this should work or not: @@ -534,18 +522,25 @@ public class JDKScalarsTest assertNull(bean.intValue); bean = MAPPER.readValue("{\"longValue\":\"\"}", WrappersBean.class); assertNull(bean.longValue); - bean = MAPPER.readValue("{\"floatValue\":\"\"}", WrappersBean.class); + } + + public void testEmptyStringForFloatWrappers() throws IOException + { + WrappersBean bean = MAPPER.readValue("{\"floatValue\":\"\"}", WrappersBean.class); assertNull(bean.floatValue); bean = MAPPER.readValue("{\"doubleValue\":\"\"}", WrappersBean.class); assertNull(bean.doubleValue); } - public void testEmptyStringForPrimitives() throws IOException + public void testEmptyStringForBooleanPrimitive() throws IOException { - PrimitivesBean bean; - bean = MAPPER.readValue("{\"booleanValue\":\"\"}", PrimitivesBean.class); + PrimitivesBean bean = MAPPER.readValue("{\"booleanValue\":\"\"}", PrimitivesBean.class); assertFalse(bean.booleanValue); - bean = MAPPER.readValue("{\"byteValue\":\"\"}", PrimitivesBean.class); + } + + public void testEmptyStringForIntegerPrimitives() throws IOException + { + PrimitivesBean bean = MAPPER.readValue("{\"byteValue\":\"\"}", PrimitivesBean.class); assertEquals((byte) 0, bean.byteValue); bean = MAPPER.readValue("{\"charValue\":\"\"}", PrimitivesBean.class); assertEquals((char) 0, bean.charValue); @@ -555,38 +550,30 @@ public class JDKScalarsTest assertEquals(0, bean.intValue); bean = MAPPER.readValue("{\"longValue\":\"\"}", PrimitivesBean.class); assertEquals(0L, bean.longValue); - bean = MAPPER.readValue("{\"floatValue\":\"\"}", PrimitivesBean.class); + } + + public void testEmptyStringForFloatPrimitives() throws IOException + { + PrimitivesBean bean = MAPPER.readValue("{\"floatValue\":\"\"}", PrimitivesBean.class); assertEquals(0.0f, bean.floatValue); bean = MAPPER.readValue("{\"doubleValue\":\"\"}", PrimitivesBean.class); assertEquals(0.0, bean.doubleValue); } - private void _verifyEmptyStringFailForPrimitives(String propName) throws IOException + // for [databind#403] + public void testEmptyStringFailForBooleanPrimitive() throws IOException { final ObjectReader reader = MAPPER .readerFor(PrimitivesBean.class) .with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); try { - reader.readValue(aposToQuotes("{'"+propName+"':''}")); + reader.readValue(aposToQuotes("{'booleanValue':''}")); fail("Expected failure for boolean + empty String"); } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce empty String (\"\")"); - verifyException(e, "to Null value"); + verifyException(e, "Cannot coerce `null` to `boolean`"); + verifyException(e, "FAIL_ON_NULL_FOR_PRIMITIVES"); } } - - // for [databind#403] - public void testEmptyStringFailForPrimitives() throws IOException - { - _verifyEmptyStringFailForPrimitives("booleanValue"); - _verifyEmptyStringFailForPrimitives("byteValue"); - _verifyEmptyStringFailForPrimitives("charValue"); - _verifyEmptyStringFailForPrimitives("shortValue"); - _verifyEmptyStringFailForPrimitives("intValue"); - _verifyEmptyStringFailForPrimitives("longValue"); - _verifyEmptyStringFailForPrimitives("floatValue"); - _verifyEmptyStringFailForPrimitives("doubleValue"); - } /* /********************************************************** @@ -722,18 +709,18 @@ public class JDKScalarsTest final String JSON_WITH_NULL = "[ null ]"; final String SIMPLE_NAME = "`"+cls.getSimpleName()+"`"; final ObjectReader readerCoerceOk = MAPPER.readerFor(cls); - final ObjectReader readerNoCoerce = readerCoerceOk + final ObjectReader readerNoNulls = readerCoerceOk .with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); Object ob = readerCoerceOk.forType(cls).readValue(JSON_WITH_NULL); assertEquals(1, Array.getLength(ob)); assertEquals(defValue, Array.get(ob, 0)); try { - readerNoCoerce.readValue(JSON_WITH_NULL); + readerNoNulls.readValue(JSON_WITH_NULL); fail("Should not pass"); } catch (JsonMappingException e) { verifyException(e, "Cannot coerce `null`"); - verifyException(e, "as content of type "+SIMPLE_NAME); + verifyException(e, "to element of "+SIMPLE_NAME); } if (testEmptyString) { @@ -741,12 +728,14 @@ public class JDKScalarsTest assertEquals(1, Array.getLength(ob)); assertEquals(defValue, Array.get(ob, 0)); + final ObjectReader readerNoEmpty = MAPPER_NO_COERCION.readerFor(cls); try { - readerNoCoerce.readValue(EMPTY_STRING_JSON); + readerNoEmpty.readValue(EMPTY_STRING_JSON); fail("Should not pass"); } catch (JsonMappingException e) { - verifyException(e, "Cannot coerce empty String (\"\")"); - verifyException(e, "as content of type "+SIMPLE_NAME); + // 07-Jun-2020, tatu: during transition, two acceptable alternatives + verifyException(e, "Cannot coerce `null` to", "Cannot coerce empty String (\"\")"); + verifyException(e, "element of "+SIMPLE_NAME); } } } @@ -782,11 +771,11 @@ public class JDKScalarsTest // char[] is special, cannot use generalized test here // _testInvalidStringCoercionFail(char[].class); - _testInvalidStringCoercionFail(short[].class); - _testInvalidStringCoercionFail(int[].class); - _testInvalidStringCoercionFail(long[].class); - _testInvalidStringCoercionFail(float[].class); - _testInvalidStringCoercionFail(double[].class); + _testInvalidStringCoercionFail(short[].class, "short"); + _testInvalidStringCoercionFail(int[].class, "int"); + _testInvalidStringCoercionFail(long[].class, "long"); + _testInvalidStringCoercionFail(float[].class, "float"); + _testInvalidStringCoercionFail(double[].class, "double"); } private void _testInvalidStringCoercionFail(Class<?> cls) throws IOException @@ -801,9 +790,38 @@ public class JDKScalarsTest try { MAPPER.readerFor(cls).readValue(JSON); - fail("Should not pass"); + fail("Should MismatchedInputException pass"); } catch (JsonMappingException e) { verifyException(e, "Cannot deserialize value of type `"+targetTypeName+"` from String \"foobar\""); } } + + /* + /********************************************************** + /* Tests for mismatch: JSON Object for scalars (not supported + /* for JSON + /********************************************************** + */ + + public void testFailForScalarFromObject() throws Exception + { + _testFailForNumberFromObject(Byte.TYPE); + _testFailForNumberFromObject(Short.TYPE); + _testFailForNumberFromObject(Long.TYPE); + _testFailForNumberFromObject(Float.TYPE); + _testFailForNumberFromObject(Double.TYPE); + _testFailForNumberFromObject(BigInteger.class); + _testFailForNumberFromObject(BigDecimal.class); + } + + private void _testFailForNumberFromObject(Class<?> targetType) throws Exception + { + try { + MAPPER.readValue(a2q("{'value':12}"), targetType); + fail("Should not pass"); + } catch (MismatchedInputException e) { + verifyException(e, "from Object value"); + verifyException(e, ClassUtil.getClassDescription(targetType)); + } + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKStringLikeTypesTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKStringLikeTypesTest.java index b4e5892bd..9af210d3c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKStringLikeTypesTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/JDKStringLikeTypesTest.java @@ -138,10 +138,6 @@ public class JDKStringLikeTypesTest extends BaseMapTest MAPPER.readValue(quote("fi_FI_savo"), Locale.class)); assertEquals(new Locale("en", "US"), MAPPER.readValue(quote("en-US"), Locale.class)); - - // [databind#1123] - Locale loc = MAPPER.readValue(quote(""), Locale.class); - assertSame(Locale.ROOT, loc); } public void testCharSequence() throws IOException @@ -261,14 +257,9 @@ public class JDKStringLikeTypesTest extends BaseMapTest final URI value = new URI("http://foo.com"); assertEquals(value, reader.readValue("\""+value.toString()+"\"")); - // Also: empty String should be handled properly - URI result = reader.readValue(quote("")); - assertNotNull(result); - assertEquals(URI.create(""), result); - // and finally: broken URI should give proper failure try { - result = reader.readValue(quote("a b")); + URI result = reader.readValue(quote("a b")); fail("Should not accept malformed URI, instead got: "+result); } catch (InvalidFormatException e) { verifyException(e, "not a valid textual representation"); @@ -303,9 +294,9 @@ public class JDKStringLikeTypesTest extends BaseMapTest public void testUUID() throws Exception { - final ObjectMapper mapper = objectMapper(); - final String NULL_UUID = "00000000-0000-0000-0000-000000000000"; + final ObjectReader r = MAPPER.readerFor(UUID.class); + // first, couple of generated UUIDs: for (String value : new String[] { "76e6d183-5f68-4afa-b94a-922c1fdb83f8", @@ -315,12 +306,10 @@ public class JDKStringLikeTypesTest extends BaseMapTest "82994ac2-7b23-49f2-8cc5-e24cf6ed77be", "00000007-0000-0000-0000-000000000000" }) { - - mapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); - UUID uuid = UUID.fromString(value); assertEquals(uuid, - mapper.readValue(quote(value), UUID.class)); + r.without(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS) + .readValue(quote(value))); } // then use templating; note that these are not exactly valid UUIDs // wrt spec (type bits etc), but JDK UUID should deal ok @@ -330,13 +319,13 @@ public class JDKStringLikeTypesTest extends BaseMapTest for (int i = 0; i < chars.length(); ++i) { String value = TEMPL.replace('0', chars.charAt(i)); assertEquals(UUID.fromString(value).toString(), - mapper.readValue(quote(value), UUID.class).toString()); + r.readValue(quote(value)).toString()); } // also: see if base64 encoding works as expected String base64 = Base64Variants.getDefaultVariant().encode(new byte[16]); assertEquals(UUID.fromString(NULL_UUID), - mapper.readValue(quote(base64), UUID.class)); + r.readValue(quote(base64))); } public void testUUIDInvalid() throws Exception diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestGenericMapDeser.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/MapWithGenericValuesDeserTest.java index e18dd2575..db6ad7700 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/TestGenericMapDeser.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/MapWithGenericValuesDeserTest.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.databind.deser; +package com.fasterxml.jackson.databind.deser.jdk; import java.util.*; @@ -9,7 +9,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.type.TypeFactory; @SuppressWarnings("serial") -public class TestGenericMapDeser +public class MapWithGenericValuesDeserTest extends BaseMapTest { /* diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/VoidProperties2675Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/VoidProperties2675Test.java new file mode 100644 index 000000000..1aae71209 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/VoidProperties2675Test.java @@ -0,0 +1,61 @@ +package com.fasterxml.jackson.databind.deser.jdk; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; + +// [databind#2675]: Void-valued "properties" +public class VoidProperties2675Test extends BaseMapTest +{ + static class VoidBean { + protected Void value; + + public Void getValue() { return null; } + +// public void setValue(Void v) { } + } + + /* + /********************************************************************** + /* Test methods + /********************************************************************** + */ + + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + + private final ObjectMapper VOID_MAPPER = jsonMapperBuilder() + .enable(MapperFeature.ALLOW_VOID_VALUED_PROPERTIES) + .build(); + + public void testVoidBeanSerialization() throws Exception + { + // By default (2.x), not enabled: + try { + DEFAULT_MAPPER.writeValueAsString(new VoidBean()); + fail("Should not pass"); + } catch (InvalidDefinitionException e) { + verifyException(e, "no properties discovered"); + } + + // but when enabled + assertEquals("{\"value\":null}", VOID_MAPPER.writeValueAsString(new VoidBean())); + } + + public void testVoidBeanDeserialization() throws Exception { + final String DOC = "{\"value\":null}"; + VoidBean result; + + // By default (2.x), not enabled: + try { + result = DEFAULT_MAPPER.readValue(DOC, VoidBean.class); + fail("Should not pass"); + } catch (UnrecognizedPropertyException e) { + verifyException(e, "Unrecognized field \"value\""); + } + + // but when enabled + result = VOID_MAPPER.readValue(DOC, VoidBean.class); + assertNotNull(result); + assertNull(result.getValue()); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/exc/ExceptionDeserializationTest.java b/src/test/java/com/fasterxml/jackson/databind/exc/ExceptionDeserializationTest.java index 536a5b428..7e19c9a4c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/exc/ExceptionDeserializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/exc/ExceptionDeserializationTest.java @@ -157,7 +157,7 @@ public class ExceptionDeserializationTest mapper.readValue(value, IOException.class); fail("Exception not thrown when attempting to deserialize an IOException wrapped in a single value array with UNWRAP_SINGLE_VALUE_ARRAYS disabled"); } catch (JsonMappingException exp2) { - verifyException(exp2, "out of START_ARRAY"); + verifyException(exp2, "from Array value (token `JsonToken.START_ARRAY`)"); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/interop/DateJava8FallbacksTest.java b/src/test/java/com/fasterxml/jackson/databind/interop/DateJava8FallbacksTest.java new file mode 100644 index 000000000..37fd4e79c --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/interop/DateJava8FallbacksTest.java @@ -0,0 +1,45 @@ +package com.fasterxml.jackson.databind.interop; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; + +// [databind#2683]: add fallback handling for Java 8 date/time types, to +// prevent accidental serialization as POJOs, as well as give more information +// on deserialization attempts +// +// @since 2.12 +public class DateJava8FallbacksTest extends BaseMapTest +{ + private final ObjectMapper MAPPER = newJsonMapper(); + + private final OffsetDateTime DATETIME_EPOCH = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), + ZoneOffset.of("Z")); + + // Test to prevent serialization as POJO, without Java 8 date/time module: + public void testPreventSerialization() throws Exception + { + try { + String json = MAPPER.writerWithDefaultPrettyPrinter() + .writeValueAsString(DATETIME_EPOCH); + fail("Should not pass, wrote out as\n: "+json); + } catch (InvalidDefinitionException e) { + verifyException(e, "Java 8 date/time type `java.time.OffsetDateTime` not supported by default"); + verifyException(e, "add Module \"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\""); + } + } + + public void testBetterDeserializationError() throws Exception + { + try { + OffsetDateTime result = MAPPER.readValue(" 0 ", OffsetDateTime.class); + fail("Not expecting to pass, resulted in: "+result); + } catch (InvalidDefinitionException e) { + verifyException(e, "Java 8 date/time type `java.time.OffsetDateTime` not supported by default"); + verifyException(e, "add Module \"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\""); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestMultipleTypeNames.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestMultipleTypeNames.java new file mode 100644 index 000000000..021dd1cb2 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestMultipleTypeNames.java @@ -0,0 +1,136 @@ +package com.fasterxml.jackson.databind.jsontype; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; + +import java.util.List; + +// Tests for [databind#2761] (and [annotations#171] +public class TestMultipleTypeNames extends BaseMapTest +{ + private final ObjectMapper MAPPER = newJsonMapper(); + + // common classes + static class MultiTypeName { } + + static class A extends MultiTypeName { + private long x; + public long getX() { return x; } + } + + static class B extends MultiTypeName { + private float y; + public float getY() { return y; } + } + + // data for test 1 + static class WrapperForNamesTest { + private List<BaseForNamesTest> base; + public List<BaseForNamesTest> getBase() { return base; } + } + + static class BaseForNamesTest { + private String type; + public String getType() { return type; } + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXTERNAL_PROPERTY, + property = "type" + ) + @JsonSubTypes(value = { + @JsonSubTypes.Type(value = A.class, names = "a"), + @JsonSubTypes.Type(value = B.class, names = {"b","c"}), + }) + private MultiTypeName data; + public MultiTypeName getData() { return data; } + } + + static class WrapperForNameAndNamesTest { + private List<BaseForNameAndNamesTest> base; + public List<BaseForNameAndNamesTest> getBase() { return base; } + } + + static class BaseForNameAndNamesTest { + private String type; + public String getType() { return type; } + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXTERNAL_PROPERTY, + property = "type" + ) + @JsonSubTypes(value = { + @JsonSubTypes.Type(value = A.class, name = "a"), + @JsonSubTypes.Type(value = B.class, names = {"b","c"}), + }) + private MultiTypeName data; + public MultiTypeName getData() { return data; } + } + + /* + /********************************************************** + /* Test methods + /********************************************************** + */ + + public void testOnlyNames() throws Exception + { + String json; + WrapperForNamesTest w; + + // TC 1 : all KV serialisation + json = "{\"base\": [{\"type\":\"a\", \"data\": {\"x\": 5}}, {\"type\":\"b\", \"data\": {\"y\": 3.1}}, {\"type\":\"c\", \"data\": {\"y\": 33.8}}]}"; + w = MAPPER.readValue(json, WrapperForNamesTest.class); + assertNotNull(w); + assertEquals(3, w.base.size()); + assertTrue(w.base.get(0).data instanceof A); + assertEquals(5l, ((A) w.base.get(0).data).x); + assertTrue(w.base.get(1).data instanceof B); + assertEquals(3.1f, ((B) w.base.get(1).data).y, 0); + assertTrue(w.base.get(2).data instanceof B); + assertEquals(33.8f, ((B) w.base.get(2).data).y, 0); + + + // TC 2 : incorrect serialisation + json = "{\"data\": [{\"type\":\"a\", \"data\": {\"x\": 2.2}}, {\"type\":\"b\", \"data\": {\"y\": 5.3}}, {\"type\":\"c\", \"data\": {\"y\": 9.8}}]}"; + try { + MAPPER.readValue(json, WrapperForNamesTest.class); + fail("This serialisation should fail 'coz of x being float"); + } catch (UnrecognizedPropertyException e) { + verifyException(e, "Unrecognized field \"data\""); + } + } + + public void testNameAndNames() throws Exception + { + String json; + WrapperForNameAndNamesTest w; + + // TC 1 : all KV serialisation + json = "{\"base\": [{\"type\":\"a\", \"data\": {\"x\": 5}}, {\"type\":\"b\", \"data\": {\"y\": 3.1}}, {\"type\":\"c\", \"data\": {\"y\": 33.8}}]}"; + w = MAPPER.readValue(json, WrapperForNameAndNamesTest.class); + assertNotNull(w); + assertEquals(3, w.base.size()); + assertTrue(w.base.get(0).data instanceof A); + assertEquals(5l, ((A) w.base.get(0).data).x); + assertTrue(w.base.get(1).data instanceof B); + assertEquals(3.1f, ((B) w.base.get(1).data).y, 0); + assertTrue(w.base.get(2).data instanceof B); + assertEquals(33.8f, ((B) w.base.get(2).data).y, 0); + + + // TC 2 : incorrect serialisation + json = "{\"data\": [{\"type\":\"a\", \"data\": {\"x\": 2.2}}, {\"type\":\"b\", \"data\": {\"y\": 5.3}}, {\"type\":\"c\", \"data\": {\"y\": 9.8}}]}"; + try { + MAPPER.readValue(json, WrapperForNameAndNamesTest.class); + fail("This serialisation should fail 'coz of x being float"); + } catch (UnrecognizedPropertyException e) { + verifyException(e, "Unrecognized field \"data\""); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java index c6fa2bb35..4557e0840 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java @@ -4,12 +4,9 @@ import com.fasterxml.jackson.core.Version; import java.util.*; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; -import com.fasterxml.jackson.databind.JsonMappingException; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; @@ -95,7 +92,9 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="type") @JsonSubTypes({ @JsonSubTypes.Type(ImplX.class), - @JsonSubTypes.Type(ImplY.class) }) + @JsonSubTypes.Type(ImplY.class), + @JsonSubTypes.Type(ImplAbs.class) + }) static abstract class BaseX { } @JsonTypeName("x") @@ -111,6 +110,11 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest public int y; } + // for [databind#919] testing + @JsonTypeName("abs") + abstract static class ImplAbs extends BaseX { + } + // [databind#663] static class AtomicWrapper { public BaseX value; @@ -372,16 +376,16 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest bean = mapper.readValue("{\"#type\":\"foobar\"}", SuperTypeWithoutDefault.class); assertEquals(DefaultImpl505.class, bean.getClass()); assertEquals(0, ((DefaultImpl505) bean).a); - } - + public void testErrorMessage() throws Exception { ObjectMapper mapper = new ObjectMapper(); try { mapper.readValue("{ \"type\": \"z\"}", BaseX.class); fail("Should have failed"); - } catch (JsonMappingException e) { - verifyException(e, "known type ids ="); + } catch (InvalidTypeIdException e) { + verifyException(e, "Could not resolve type id 'z' as a subtype of"); + verifyException(e, "known type ids = [x, y]"); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java index 15d95f82d..8a066f6d2 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java @@ -126,7 +126,7 @@ public class TestWithGenerics extends BaseMapTest otherAnimal = a2; } } - + /* /********************************************************** /* Unit tests diff --git a/src/test/java/com/fasterxml/jackson/databind/misc/CaseInsensitiveDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/misc/CaseInsensitiveDeserTest.java index 362039391..dbb738ca7 100644 --- a/src/test/java/com/fasterxml/jackson/databind/misc/CaseInsensitiveDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/misc/CaseInsensitiveDeserTest.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; public class CaseInsensitiveDeserTest extends BaseMapTest { @@ -93,13 +94,31 @@ public class CaseInsensitiveDeserTest extends BaseMapTest } } + // [databind#1886]: allow case-insensitivity by default on a class + @JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES }) + static class CaseInsensitiveRole { + public String ID; + public String Name; + } + + // [databind#1886]: allow case-insensitivity by default on a class + static class CaseInsensitiveRoleContainer { + public CaseInsensitiveRole role; + } + + // [databind#1886]: ... but also overrides + static class CaseSensitiveRoleContainer { + @JsonFormat(without={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES }) + public CaseInsensitiveRole role; + } + /* /******************************************************** /* Test methods /******************************************************** */ - private final ObjectMapper MAPPER = new ObjectMapper(); + private final ObjectMapper MAPPER = newJsonMapper(); private final ObjectMapper INSENSITIVE_MAPPER = jsonMapperBuilder() .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) .build(); @@ -158,7 +177,7 @@ public class CaseInsensitiveDeserTest extends BaseMapTest } // And allow config overrides too - public void testCaseInsensitiveWithClassFormat() throws Exception + public void testCaseInsensitiveViaConfigOverride() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.configOverride(Role.class) @@ -181,4 +200,34 @@ public class CaseInsensitiveDeserTest extends BaseMapTest assertNotNull(result.getItems()); assertEquals(1, result.getItems().size()); } + + + // [databind#1886]: allow case-insensitivity by default on a class + public void testCaseInsensitiveViaClassAnnotation() throws Exception + { + final String CONTAINED = aposToQuotes("{'role': {'id':'3','name':'Bob'}}"); + + // First: via wrapper/container: + CaseInsensitiveRoleContainer cont = MAPPER.readValue(CONTAINED, + CaseInsensitiveRoleContainer.class); + assertEquals("3", cont.role.ID); + assertEquals("Bob", cont.role.Name); + + // second: directly as root value + CaseInsensitiveRole role = MAPPER.readValue + (aposToQuotes("{'id':'12','name':'Billy'}"), + CaseInsensitiveRole.class); + assertEquals("12", role.ID); + assertEquals("Billy", role.Name); + + // and finally, more complicated; should be possible to force sensitivity: + try { + /*CaseSensitiveRoleContainer r =*/ MAPPER.readValue(CONTAINED, + CaseSensitiveRoleContainer.class); + fail("Should not pass"); + } catch (UnrecognizedPropertyException e) { + verifyException(e, "Unrecognized "); + verifyException(e, "\"id\""); + } + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/node/ArrayNodeTest.java b/src/test/java/com/fasterxml/jackson/databind/node/ArrayNodeTest.java index e129dcf56..08bd47d98 100644 --- a/src/test/java/com/fasterxml/jackson/databind/node/ArrayNodeTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/node/ArrayNodeTest.java @@ -359,7 +359,7 @@ public class ArrayNodeTest mapper.readValue(" 123 ", ArrayNode.class); fail("Should not pass"); } catch (MismatchedInputException e) { - verifyException(e, "out of VALUE_NUMBER_INT token"); + verifyException(e, "from Integer value (token `JsonToken.VALUE_NUMBER_INT`)"); } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java b/src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java index 260e93ecc..cd15ee687 100644 --- a/src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java @@ -463,7 +463,7 @@ public class ObjectNodeTest mapper.readValue("[ 1, 2, 3 ]", ObjectNode.class); fail("Should not pass"); } catch (MismatchedInputException e) { - verifyException(e, "out of START_ARRAY token"); + verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)"); } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId687Test.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId687Test.java index 972a5fa8f..91eda5e44 100644 --- a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId687Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId687Test.java @@ -63,7 +63,7 @@ public class ObjectId687Test extends BaseMapTest /***************************************************** */ - private final ObjectMapper MAPPER = objectMapper(); + private final ObjectMapper MAPPER = newJsonMapper(); // for [databind#687] public void testSerializeDeserializeWithCreator() throws IOException { diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId825BTest.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId825BTest.java index af173eede..171f1ded1 100644 --- a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId825BTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectId825BTest.java @@ -136,10 +136,15 @@ public class ObjectId825BTest extends BaseMapTest private static final long serialVersionUID = 1L; } + /* + /***************************************************** + /* Test methods + /***************************************************** + */ + public void testFull825() throws Exception { final ObjectMapper mapper = jsonMapperBuilder() - .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT) .activateDefaultTyping(NoCheckSubTypeValidator.instance, ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE) .build(); diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/TestArraySerialization.java b/src/test/java/com/fasterxml/jackson/databind/ser/TestArraySerialization.java index 10baa8ef6..e1cd38d69 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/TestArraySerialization.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/TestArraySerialization.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.*; public class TestArraySerialization extends BaseMapTest { - private final ObjectMapper MAPPER = newJsonMapper(); + private final ObjectMapper MAPPER = sharedMapper(); public void testLongStringArray() throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/databind/struct/EmptyArrayAsNullTest.java b/src/test/java/com/fasterxml/jackson/databind/struct/EmptyArrayAsNullTest.java deleted file mode 100644 index 71aba3253..000000000 --- a/src/test/java/com/fasterxml/jackson/databind/struct/EmptyArrayAsNullTest.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.fasterxml.jackson.databind.struct; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import java.util.*; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.*; - -/** - * Tests to verify implementation of [databind#540]; also for - * follow up work of: - * - * - [databind#994] - */ -public class EmptyArrayAsNullTest extends BaseMapTest -{ - private final ObjectMapper MAPPER = new ObjectMapper(); - private final ObjectReader DEFAULT_READER = MAPPER.reader(); - private final ObjectReader READER_WITH_ARRAYS = DEFAULT_READER - .with(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT); - - static class Bean { - public String a = "foo"; - } - - final static String EMPTY_ARRAY = " [\n]"; - - /* - /********************************************************** - /* Test methods, settings - /********************************************************** - */ - - public void testSettings() { - assertFalse(MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - assertFalse(DEFAULT_READER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - assertTrue(READER_WITH_ARRAYS.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - } - - /* - /********************************************************** - /* Test methods, POJOs - /********************************************************** - */ - - // [databind#540] - public void testPOJOFromEmptyArray() throws Exception - { - // first, verify default settings which do not accept empty Array - try { - DEFAULT_READER.forType(Bean.class) - .readValue(EMPTY_ARRAY); - fail("Should not accept Empty Array for POJO by default"); - } catch (JsonMappingException e) { - verifyException(e, "START_ARRAY token"); - assertValidLocation(e.getLocation()); - } - - // should be ok to enable dynamically: - Bean result = READER_WITH_ARRAYS.forType(Bean.class) - .readValue(EMPTY_ARRAY); - assertNull(result); - } - - /* - /********************************************************** - /* Test methods, Maps - /********************************************************** - */ - - public void testMapFromEmptyArray() throws Exception - { - // first, verify default settings which do not accept empty Array - try { - DEFAULT_READER.forType(Map.class) - .readValue(EMPTY_ARRAY); - fail("Should not accept Empty Array for Map by default"); - } catch (JsonMappingException e) { - verifyException(e, "START_ARRAY token"); - } - // should be ok to enable dynamically: - Map<?,?> result = READER_WITH_ARRAYS.forType(Map.class) - .readValue(EMPTY_ARRAY); - assertNull(result); - } - - public void testEnumMapFromEmptyArray() throws Exception - { - - EnumMap<?,?> result2 = READER_WITH_ARRAYS.forType(new TypeReference<EnumMap<ABC,String>>() { }) - .readValue(EMPTY_ARRAY); - assertNull(result2); - } - - /* - /********************************************************** - /* Test methods, primitives/wrappers - /********************************************************** - */ - - public void testWrapperFromEmptyArray() throws Exception - { - _testNullWrapper(Boolean.class); - _testNullWrapper(Byte.class); - _testNullWrapper(Character.class); - _testNullWrapper(Short.class); - _testNullWrapper(Integer.class); - _testNullWrapper(Long.class); - _testNullWrapper(Float.class); - _testNullWrapper(Double.class); - } - - /* - /********************************************************** - /* Test methods, other - /********************************************************** - */ - - public void testNullStringFromEmptyArray() throws Exception { - _testNullWrapper(String.class); - } - - public void testNullEnumFromEmptyArray() throws Exception { - _testNullWrapper(ABC.class); - } - - public void testStdJdkTypesFromEmptyArray() throws Exception - { - _testNullWrapper(BigInteger.class); - _testNullWrapper(BigDecimal.class); - - _testNullWrapper(UUID.class); - - _testNullWrapper(Date.class); - _testNullWrapper(Calendar.class); - } - - /* - /********************************************************** - /* Helper methods - /********************************************************** - */ - - private void _testNullWrapper(Class<?> cls) throws Exception - { - Object result = READER_WITH_ARRAYS.forType(cls).readValue(EMPTY_ARRAY); - assertNull(result); - } -} diff --git a/src/test/java/com/fasterxml/jackson/databind/struct/UnwrapSingleArrayScalarsTest.java b/src/test/java/com/fasterxml/jackson/databind/struct/UnwrapSingleArrayScalarsTest.java index a13988e90..cb06cd559 100644 --- a/src/test/java/com/fasterxml/jackson/databind/struct/UnwrapSingleArrayScalarsTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/struct/UnwrapSingleArrayScalarsTest.java @@ -80,7 +80,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest .readValue("{\"v\":[3]}"); fail("Did not throw exception when reading a value from a single value array with the UNWRAP_SINGLE_VALUE_ARRAYS feature disabled"); } catch (MismatchedInputException e) { - verifyException(e, "Cannot deserialize instance of `int`"); + verifyException(e, "Cannot deserialize value of type `int`"); } ObjectReader r = UNWRAPPING_READER.forType(IntBean.class); @@ -117,7 +117,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest noUnwrapR.readValue("{\"v\":[3]}"); fail("Did not throw exception when reading a value from a single value array"); } catch (MismatchedInputException e) { - verifyException(e, "Cannot deserialize instance of `long`"); + verifyException(e, "Cannot deserialize value of type `long`"); } LongBean result = unwrapR.readValue("{\"v\":[3]}"); @@ -154,7 +154,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest noUnwrapR.readValue("{\"v\":[" + value + "]}"); fail("Did not throw exception when reading a value from a single value array"); } catch (MismatchedInputException e) { - verifyException(e, "Cannot deserialize instance of `double`"); + verifyException(e, "Cannot deserialize value of type `double`"); } DoubleBean result = unwrapR.readValue("{\"v\":[" + value + "]}"); @@ -359,8 +359,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest NO_UNWRAPPING_READER.readValue("[\""+value+"\"]", String.class); fail("Exception not thrown when attempting to unwrap a single value 'String' array into a simple String"); } catch (MismatchedInputException exp) { - verifyException(exp, "Cannot deserialize"); - verifyException(exp, "out of START_ARRAY"); + _verifyNoDeserFromArray(exp); } try { @@ -385,8 +384,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest r.readValue("[" + value.toString() + "]"); fail("Exception was not thrown when attempting to read a single value array of BigDecimal when UNWRAP_SINGLE_VALUE_ARRAYS feature is disabled"); } catch (MismatchedInputException exp) { - verifyException(exp, "Cannot deserialize"); - verifyException(exp, "out of START_ARRAY"); + _verifyNoDeserFromArray(exp); } r = UNWRAPPING_READER.forType(BigDecimal.class); @@ -411,8 +409,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest NO_UNWRAPPING_READER.readValue("[" + value.toString() + "]", BigInteger.class); fail("Exception was not thrown when attempting to read a single value array of BigInteger when UNWRAP_SINGLE_VALUE_ARRAYS feature is disabled"); } catch (MismatchedInputException exp) { - verifyException(exp, "Cannot deserialize"); - verifyException(exp, "out of START_ARRAY"); + _verifyNoDeserFromArray(exp); } result = UNWRAPPING_READER.readValue("[" + value.toString() + "]", BigInteger.class); @@ -438,7 +435,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest .readValue("[" + quote(String.class.getName()) + "]"); fail("Did not throw exception when UNWRAP_SINGLE_VALUE_ARRAYS feature was disabled and attempted to read a Class array containing one element"); } catch (MismatchedInputException e) { - verifyException(e, "out of START_ARRAY token"); + _verifyNoDeserFromArray(e); } _verifyMultiValueArrayFail("[" + quote(Object.class.getName()) + "," + quote(Object.class.getName()) +"]", @@ -456,7 +453,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest .readValue("[\""+value.toString()+"\"]"); fail("Did not throw exception for single value array when UNWRAP_SINGLE_VALUE_ARRAYS is disabled"); } catch (MismatchedInputException e) { - verifyException(e, "out of START_ARRAY token"); + _verifyNoDeserFromArray(e); } _verifyMultiValueArrayFail("[\""+value.toString()+"\",\""+value.toString()+"\"]", URI.class); @@ -471,7 +468,7 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest .readValue("[" + quote(uuidStr) + "]"); fail("Exception was not thrown as expected"); } catch (MismatchedInputException e) { - verifyException(e, "out of START_ARRAY token"); + _verifyNoDeserFromArray(e); } assertEquals(uuid, UNWRAPPING_READER.forType(UUID.class) @@ -485,6 +482,12 @@ public class UnwrapSingleArrayScalarsTest extends BaseMapTest /********************************************************** */ + private void _verifyNoDeserFromArray(Exception e) { + verifyException(e, "Cannot deserialize"); + verifyException(e, "from Array value"); + verifyException(e, "JsonToken.START_ARRAY"); + } + private void _verifyMultiValueArrayFail(String input, Class<?> type) throws IOException { try { UNWRAPPING_READER.forType(type).readValue(input); diff --git a/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java b/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java index def53ce11..5487a4c7f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java +++ b/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java @@ -280,7 +280,12 @@ public class TestJavaType assertTrue(t.hasContentType()); assertEquals(Long.class, t.getContentType().getRawClass()); - // 26-Mar-2020, tatu: [databind#2019] suggest this should be 1... -// assertEquals(1, t.containedTypeCount()); + // 26-Mar-2020, tatu: [databind#2019] made this work + assertEquals(1, t.containedTypeCount()); + TypeBindings bindings = t.getBindings(); + assertEquals(1, bindings.size()); + assertEquals(refdType, bindings.getBoundType(0)); + // Should we even verify this or not? + assertEquals("V", bindings.getBoundName(0)); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java b/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java index e78c15d1a..dc326d5d1 100644 --- a/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java +++ b/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java @@ -160,7 +160,7 @@ public class TestTypeFactory { TypeFactory tf = TypeFactory.defaultInstance(); // first, simple class based - JavaType t = tf.constructParametrizedType(ArrayList.class, Collection.class, String.class); // ArrayList<String> + final JavaType t = tf.constructParametrizedType(ArrayList.class, Collection.class, String.class); // ArrayList<String> assertEquals(CollectionType.class, t.getClass()); JavaType strC = tf.constructType(String.class); assertEquals(1, t.containedTypeCount()); @@ -176,6 +176,13 @@ public class TestTypeFactory assertEquals(t, t2.containedType(1)); assertNull(t2.containedType(2)); + // [databind#921]: using type bindings + JavaType t3 = tf.constructParametricType(HashSet.class, t.getBindings()); // HashSet<String> + assertEquals(CollectionType.class, t3.getClass()); + assertEquals(1, t3.containedTypeCount()); + assertEquals(strC, t3.containedType(0)); + assertNull(t3.containedType(1)); + // and then custom generic type as well JavaType custom = tf.constructParametrizedType(SingleArgGeneric.class, SingleArgGeneric.class, String.class); @@ -184,10 +191,24 @@ public class TestTypeFactory assertEquals(strC, custom.containedType(0)); assertNull(custom.containedType(1)); + // and then custom generic type from TypeBindings ([databind#921]) + JavaType custom2 = tf.constructParametricType(SingleArgGeneric.class, t.getBindings()); + assertEquals(SimpleType.class, custom2.getClass()); + assertEquals(1, custom2.containedTypeCount()); + assertEquals(strC, custom2.containedType(0)); + assertNull(custom2.containedType(1)); + // should also be able to access variable name: assertEquals("X", custom.containedTypeName(0)); + } - // And finally, ensure that we can't create invalid combinations + @SuppressWarnings("deprecation") + public void testInvalidParametricTypes() + { + final TypeFactory tf = TypeFactory.defaultInstance(); + final JavaType strC = tf.constructType(String.class); + + // ensure that we can't create invalid combinations try { // Maps must take 2 type parameters, not just one tf.constructParametrizedType(Map.class, Map.class, strC); @@ -202,7 +223,7 @@ public class TestTypeFactory verifyException(e, "Cannot create TypeBindings for class "); } } - + /** * Test for checking that canonical name handling works ok */ diff --git a/src/test/java/com/fasterxml/jackson/failing/BuilderWithIgnored1214Test.java b/src/test/java/com/fasterxml/jackson/failing/BuilderWithIgnored1214Test.java deleted file mode 100644 index 54c6d6a76..000000000 --- a/src/test/java/com/fasterxml/jackson/failing/BuilderWithIgnored1214Test.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.fasterxml.jackson.failing; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -public class BuilderWithIgnored1214Test extends BaseMapTest -{ - @JsonDeserialize(builder = TestObject1214.Builder.class) - @JsonIgnoreProperties(ignoreUnknown = true) - static class TestObject1214 { - final String property1; - - private TestObject1214(Builder builder) { - property1 = builder.property1; - } - - public static Builder builder() { - return new Builder(); - } - - public String getProperty1() { - return property1; - } - - static class Builder { - - private String property1; - - public Builder withProperty1(String p1) { - property1 = p1; - return this; - } - - public TestObject1214 build() { - return new TestObject1214(this); - } - } - } - - public void testUnknown1214() throws Exception - { - ObjectMapper mapper = new ObjectMapper(); - TestObject1214 value = mapper.readValue(aposToQuotes - ("{'property1':'a', 'property2':'b'}"), - TestObject1214.class); - assertEquals("a", value.property1); - } -} diff --git a/src/test/java/com/fasterxml/jackson/failing/JDKNumberDeser2644Test.java b/src/test/java/com/fasterxml/jackson/failing/JDKNumberDeser2644Test.java deleted file mode 100644 index d92300a35..000000000 --- a/src/test/java/com/fasterxml/jackson/failing/JDKNumberDeser2644Test.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.fasterxml.jackson.failing; - -import java.math.BigDecimal; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.databind.*; - -// Tests for -// -// [databind#2644] -// [databind#2785] -public class JDKNumberDeser2644Test extends BaseMapTest -{ - // [databind#2644] - static class NodeRoot2644 { - public String type; - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type") - @JsonSubTypes(value = { - @JsonSubTypes.Type(value = NodeParent2644.class, name = "NodeParent") - }) - public Node2644 node; - } - - public static class NodeParent2644 extends Node2644 { } - - public static abstract class Node2644 { - @JsonProperty("amount") - BigDecimal val; - - public BigDecimal getVal() { - return val; - } - - public void setVal(BigDecimal val) { - this.val = val; - } - } - - // [databind#2785] - static class BigDecimalHolder2785 { - public BigDecimal value; - } - - static class NestedBigDecimalHolder2785 { - @JsonUnwrapped - public BigDecimalHolder2785 holder; - } - - // [databind#2644] - public void testBigDecimalSubtypes() throws Exception - { - ObjectMapper mapper = newJsonMapper(); - - // NOTE: uncommenting this does work around the issue: -// mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); - mapper.registerSubtypes(NodeParent2644.class); - - NodeRoot2644 root = mapper.readValue( - "{\"type\": \"NodeParent\",\"node\": {\"amount\": 9999999999999999.99} }", - NodeRoot2644.class - ); - - assertEquals(new BigDecimal("9999999999999999.99"), root.node.getVal()); - } - - // [databind#2785] - - public void testBigDecimalUnwrapped() throws Exception - { - final ObjectMapper mapper = newJsonMapper(); - // mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); - final String JSON = "{\"value\": 5.00}"; - - // first simple working case: - BigDecimalHolder2785 holder = mapper.readValue(JSON, BigDecimalHolder2785.class); - assertEquals(new BigDecimal("5.00"), holder.value); - - // and then one that doesn't - NestedBigDecimalHolder2785 result = mapper.readValue(JSON, NestedBigDecimalHolder2785.class); - assertEquals(new BigDecimal("5.00"), result.holder.value); - } -} diff --git a/src/test/java/com/fasterxml/jackson/failing/NumberNodes1770Test.java b/src/test/java/com/fasterxml/jackson/failing/NumberNodes1770Test.java index 192feb4ec..a2e18f0ff 100644 --- a/src/test/java/com/fasterxml/jackson/failing/NumberNodes1770Test.java +++ b/src/test/java/com/fasterxml/jackson/failing/NumberNodes1770Test.java @@ -19,7 +19,7 @@ public class NumberNodes1770Test extends BaseMapTest final JsonNode jsonNode = MAPPER.reader() .with(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) .readTree("7976931348623157e309"); - assertTrue(jsonNode.isBigDecimal()); + assertTrue("Expected DecimalNode, got: "+jsonNode.getClass().getName()+": "+jsonNode, jsonNode.isBigDecimal()); // the following fails with NumberFormatException, because jsonNode is a DoubleNode with a value of POSITIVE_INFINITY // Assert.assertTrue(jsonNode.decimalValue().compareTo(new BigDecimal("7976931348623157e309")) == 0); } diff --git a/src/test/java/com/fasterxml/jackson/failing/ParsingContextExtTypeId2747Test.java b/src/test/java/com/fasterxml/jackson/failing/ParsingContextExtTypeId2747Test.java new file mode 100644 index 000000000..3bc900f5a --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/failing/ParsingContextExtTypeId2747Test.java @@ -0,0 +1,65 @@ +package com.fasterxml.jackson.failing; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.*; + +import com.fasterxml.jackson.core.*; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +public class ParsingContextExtTypeId2747Test extends BaseMapTest +{ + static class Wrapper { + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", + include = JsonTypeInfo.As.EXTERNAL_PROPERTY) + public Tag wrapped; + + public String type; + } + + @JsonSubTypes(@JsonSubTypes.Type(Location.class)) + interface Tag {} + + @JsonTypeName("location") + @JsonDeserialize(using = LocationDeserializer.class) + static class Location implements Tag + { + String value; + + protected Location() { } + Location(String v) { value = v; } + } + + static class LocationDeserializer extends JsonDeserializer<Location> + { + @Override + public Location deserialize(JsonParser p, DeserializationContext ctxt) throws IOException + { + p.skipChildren(); + return new Location(getCurrentLocationAsString(p)); + } + } + + static String getCurrentLocationAsString(JsonParser p) + { + // This suffices to give actual path + return p.getParsingContext().pathAsPointer().toString(); + } + + // [databind#2747] + public void testLocationAccessWithExtTypeId() throws Exception + { + ObjectReader objectReader = newJsonMapper().readerFor(Wrapper.class); + + Wrapper wrapper = objectReader.readValue("{" + + "\"type\":\"location\"," + + "\"wrapped\": 1" + + "}"); + // expecting wrapper.wrapped.value == "wrapped" but is "wrapped[1]" + // due to way `ExternalTypeHandler` exposes value as if "wrapper-array" was used for + // type id, value + assertEquals("/wrapped", ((Location) wrapper.wrapped).value); + } +} diff --git a/src/test/java/com/fasterxml/jackson/failing/TestUnknownProperty426.java b/src/test/java/com/fasterxml/jackson/failing/TestUnknownProperty426.java deleted file mode 100644 index 09b3226b7..000000000 --- a/src/test/java/com/fasterxml/jackson/failing/TestUnknownProperty426.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.fasterxml.jackson.failing; - -import com.fasterxml.jackson.annotation.*; - -import com.fasterxml.jackson.databind.*; - -/** - * Unit tests for checking handling of unknown properties - */ -public class TestUnknownProperty426 extends BaseMapTest -{ - // For [databind#426] - @JsonIgnoreProperties({ "userId" }) - static class User { - public String firstName; - Integer userId; - - public void setUserId(CharSequence id) { - // 21-Dec-2015, tatu: With a fix in 2.7, use of String would not - // trigger the problem, so use CharSequence... - setUserId(Integer.valueOf(id.toString())); - } - - public Integer getUserId() { - return userId; - } - - public void setUserId(Integer v) { - this.userId = v; - } - } - - /* - /********************************************************** - /* Test methods - /********************************************************** - */ - - private final ObjectMapper MAPPER = new ObjectMapper(); - - // Aside from [databind#426], also relevant: [databind#1044]? - public void testIssue426() throws Exception - { - final String JSON = aposToQuotes("{'userId': 9, 'firstName': 'Mike' }"); - User result = MAPPER.readerFor(User.class).readValue(JSON); - assertNotNull(result); - assertEquals("Mike", result.firstName); - } -} - diff --git a/src/test/java/com/fasterxml/jackson/failing/VoidProperties2675Test.java b/src/test/java/com/fasterxml/jackson/failing/VoidProperties2675Test.java deleted file mode 100644 index c7727eb48..000000000 --- a/src/test/java/com/fasterxml/jackson/failing/VoidProperties2675Test.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.fasterxml.jackson.failing; - -import com.fasterxml.jackson.databind.*; - -public class VoidProperties2675Test extends BaseMapTest -{ - static class VoidBean { - public Void getValue() { return null; } - } - - /* - /********************************************************************** - /* Test methods - /********************************************************************** - */ - - private final ObjectMapper MAPPER = new ObjectMapper(); - - public void testVoidBean() throws Exception { - final String EXP = "{\"value\":null}"; - assertEquals(EXP, MAPPER.writeValueAsString(new VoidBean())); - VoidBean result = MAPPER.readValue(EXP, VoidBean.class); - assertNotNull(result); - } -} |