package com.fasterxml.jackson.databind.deser.jdk; import java.io.*; import java.lang.reflect.Array; import org.junit.Assert; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; /** * Unit tests for verifying handling of simple basic non-structured * types; primitives (and/or their wrappers), Strings. */ public class JDKScalarsTest extends BaseMapTest { final static String NAN_STRING = "NaN"; final static class BooleanBean { boolean _v; void setV(boolean v) { _v = v; } } static class BooleanWrapper { public Boolean wrapper; public boolean primitive; protected Boolean ctor; @JsonCreator public BooleanWrapper(@JsonProperty("ctor") Boolean foo) { ctor = foo; } } static class IntBean { int _v; void setV(int v) { _v = v; } } static class LongBean { long _v; void setV(long v) { _v = v; } } final static class DoubleBean { double _v; void setV(double v) { _v = v; } } final static class FloatBean { float _v; void setV(float v) { _v = v; } } final static class CharacterBean { char _v; void setV(char v) { _v = v; } char getV() { return _v; } } final static class CharacterWrapperBean { Character _v; void setV(Character v) { _v = v; } Character getV() { return _v; } } /** * Also, let's ensure that it's ok to override methods. */ static class IntBean2 extends IntBean { @Override void setV(int v2) { super.setV(v2+1); } } static class PrimitivesBean { public boolean booleanValue = true; public byte byteValue = 3; public char charValue = 'a'; public short shortValue = 37; public int intValue = 1; public long longValue = 100L; public float floatValue = 0.25f; public double doubleValue = -1.0; } static class WrappersBean { public Boolean booleanValue; public Byte byteValue; public Character charValue; public Short shortValue; public Integer intValue; public Long longValue; public Float floatValue; public Double doubleValue; } private final ObjectMapper MAPPER = new ObjectMapper(); /* /********************************************************** /* Scalar tests for boolean /********************************************************** */ public void testBooleanPrimitive() throws Exception { // first, simple case: BooleanBean result = MAPPER.readValue("{\"v\":true}", BooleanBean.class); assertTrue(result._v); result = MAPPER.readValue("{\"v\":null}", BooleanBean.class); assertNotNull(result); assertFalse(result._v); result = MAPPER.readValue("{\"v\":1}", BooleanBean.class); assertNotNull(result); assertTrue(result._v); // should work with arrays too.. boolean[] array = MAPPER.readValue("[ null, false ]", boolean[].class); assertNotNull(array); assertEquals(2, array.length); assertFalse(array[0]); assertFalse(array[1]); } /** * Simple unit test to verify that we can map boolean values to * java.lang.Boolean. */ public void testBooleanWrapper() throws Exception { Boolean result = MAPPER.readValue("true", Boolean.class); assertEquals(Boolean.TRUE, result); result = MAPPER.readValue("false", Boolean.class); assertEquals(Boolean.FALSE, result); // should accept ints too, (0 == false, otherwise true) result = MAPPER.readValue("0", Boolean.class); assertEquals(Boolean.FALSE, result); result = MAPPER.readValue("1", Boolean.class); assertEquals(Boolean.TRUE, result); } // Test for verifying that Long values are coerced to boolean correctly as well public void testLongToBoolean() throws Exception { long value = 1L + Integer.MAX_VALUE; BooleanWrapper b = MAPPER.readValue("{\"primitive\" : "+value+", \"wrapper\":"+value+", \"ctor\":"+value+"}", BooleanWrapper.class); assertEquals(Boolean.TRUE, b.wrapper); assertTrue(b.primitive); assertEquals(Boolean.TRUE, b.ctor); // but ensure we can also get `false` b = MAPPER.readValue("{\"primitive\" : 0 , \"wrapper\":0, \"ctor\":0}", BooleanWrapper.class); assertEquals(Boolean.FALSE, b.wrapper); assertFalse(b.primitive); assertEquals(Boolean.FALSE, b.ctor); boolean[] boo = MAPPER.readValue("[ 0, 15, \"\", \"false\", \"True\" ]", boolean[].class); assertEquals(5, boo.length); assertFalse(boo[0]); assertTrue(boo[1]); assertFalse(boo[2]); assertFalse(boo[3]); assertTrue(boo[4]); } /* /********************************************************** /* Scalar tests for integral types /********************************************************** */ public void testByteWrapper() throws Exception { Byte result = MAPPER.readValue(" -42\t", Byte.class); assertEquals(Byte.valueOf((byte)-42), result); // Also: should be able to coerce floats, strings: result = MAPPER.readValue(" \"-12\"", Byte.class); assertEquals(Byte.valueOf((byte)-12), result); result = MAPPER.readValue(" 39.07", Byte.class); assertEquals(Byte.valueOf((byte)39), result); } public void testShortWrapper() throws Exception { Short result = MAPPER.readValue("37", Short.class); assertEquals(Short.valueOf((short)37), result); // Also: should be able to coerce floats, strings: result = MAPPER.readValue(" \"-1009\"", Short.class); assertEquals(Short.valueOf((short)-1009), result); result = MAPPER.readValue("-12.9", Short.class); assertEquals(Short.valueOf((short)-12), result); } public void testCharacterWrapper() throws Exception { // First: canonical value is 1-char string Character result = MAPPER.readValue("\"a\"", Character.class); assertEquals(Character.valueOf('a'), result); // But can also pass in ascii code result = MAPPER.readValue(" "+((int) 'X'), Character.class); assertEquals(Character.valueOf('X'), result); final CharacterWrapperBean wrapper = MAPPER.readValue("{\"v\":null}", CharacterWrapperBean.class); assertNotNull(wrapper); assertNull(wrapper.getV()); final ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); try { mapper.readValue("{\"v\":null}", CharacterBean.class); fail("Attempting to deserialize a 'null' JSON reference into a 'char' property did not throw an exception"); } catch (JsonMappingException e) { verifyException(e, "can not map `null`"); //Exception thrown as required } mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); final CharacterBean charBean = MAPPER.readValue("{\"v\":null}", CharacterBean.class); assertNotNull(wrapper); assertEquals('\u0000', charBean.getV()); } public void testIntWrapper() throws Exception { Integer result = MAPPER.readValue(" -42\t", Integer.class); assertEquals(Integer.valueOf(-42), result); // Also: should be able to coerce floats, strings: result = MAPPER.readValue(" \"-1200\"", Integer.class); assertEquals(Integer.valueOf(-1200), result); result = MAPPER.readValue(" 39.07", Integer.class); assertEquals(Integer.valueOf(39), result); } public void testIntPrimitive() throws Exception { // first, simple case: IntBean result = MAPPER.readValue("{\"v\":3}", IntBean.class); assertEquals(3, result._v); result = MAPPER.readValue("{\"v\":null}", IntBean.class); assertNotNull(result); assertEquals(0, result._v); // should work with arrays too.. int[] array = MAPPER.readValue("[ null ]", int[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0, array[0]); // [databind#381] final ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); try { mapper.readValue("{\"v\":[3]}", IntBean.class); fail("Did not throw exception when reading a value from a single value array with the UNWRAP_SINGLE_VALUE_ARRAYS feature disabled"); } catch (JsonMappingException exp) { //Correctly threw exception } mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); result = mapper.readValue("{\"v\":[3]}", IntBean.class); assertEquals(3, result._v); result = mapper.readValue("[{\"v\":[3]}]", IntBean.class); assertEquals(3, result._v); try { mapper.readValue("[{\"v\":[3,3]}]", IntBean.class); fail("Did not throw exception while reading a value from a multi value array with UNWRAP_SINGLE_VALUE_ARRAY feature enabled"); } catch (JsonMappingException exp) { //threw exception as required } result = mapper.readValue("{\"v\":[null]}", IntBean.class); assertNotNull(result); assertEquals(0, result._v); array = mapper.readValue("[ [ null ] ]", int[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0, array[0]); } public void testLongWrapper() throws Exception { Long result = MAPPER.readValue("12345678901", Long.class); assertEquals(Long.valueOf(12345678901L), result); // Also: should be able to coerce floats, strings: result = MAPPER.readValue(" \"-9876\"", Long.class); assertEquals(Long.valueOf(-9876), result); result = MAPPER.readValue("1918.3", Long.class); assertEquals(Long.valueOf(1918), result); } public void testLongPrimitive() throws Exception { // first, simple case: LongBean result = MAPPER.readValue("{\"v\":3}", LongBean.class); assertEquals(3, result._v); result = MAPPER.readValue("{\"v\":null}", LongBean.class); assertNotNull(result); assertEquals(0, result._v); // should work with arrays too.. long[] array = MAPPER.readValue("[ null ]", long[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0, array[0]); // [databind#381] final ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); try { mapper.readValue("{\"v\":[3]}", LongBean.class); fail("Did not throw exception when reading a value from a single value array with the UNWRAP_SINGLE_VALUE_ARRAYS feature disabled"); } catch (JsonMappingException exp) { //Correctly threw exception } mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); result = mapper.readValue("{\"v\":[3]}", LongBean.class); assertEquals(3, result._v); result = mapper.readValue("[{\"v\":[3]}]", LongBean.class); assertEquals(3, result._v); try { mapper.readValue("[{\"v\":[3,3]}]", LongBean.class); fail("Did not throw exception while reading a value from a multi value array with UNWRAP_SINGLE_VALUE_ARRAY feature enabled"); } catch (JsonMappingException exp) { //threw exception as required } result = mapper.readValue("{\"v\":[null]}", LongBean.class); assertNotNull(result); assertEquals(0, result._v); array = mapper.readValue("[ [ null ] ]", long[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0, array[0]); } /** * Beyond simple case, let's also ensure that method overriding works as * expected. */ public void testIntWithOverride() throws Exception { IntBean2 result = MAPPER.readValue("{\"v\":8}", IntBean2.class); assertEquals(9, result._v); } /* /********************************************************** /* Scalar tests for floating point types /********************************************************** */ public void testDoublePrimitive() throws Exception { // first, simple case: // bit tricky with binary fps but... final double value = 0.016; DoubleBean result = MAPPER.readValue("{\"v\":"+value+"}", DoubleBean.class); assertEquals(value, result._v); // then [JACKSON-79]: result = MAPPER.readValue("{\"v\":null}", DoubleBean.class); assertNotNull(result); assertEquals(0.0, result._v); // should work with arrays too.. double[] array = MAPPER.readValue("[ null ]", double[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0.0, array[0]); } /* Note: dealing with floating-point values is tricky; not sure if * we can really use equality tests here... JDK does have decent * conversions though, to retain accuracy and round-trippability. * But still... */ public void testFloatWrapper() throws Exception { // Also: should be able to coerce floats, strings: String[] STRS = new String[] { "1.0", "0.0", "-0.3", "0.7", "42.012", "-999.0", NAN_STRING }; for (String str : STRS) { Float exp = Float.valueOf(str); Float result; if (NAN_STRING != str) { // First, as regular floating point value result = MAPPER.readValue(str, Float.class); assertEquals(exp, result); } // and then as coerced String: result = MAPPER.readValue(" \""+str+"\"", Float.class); assertEquals(exp, result); } } public void testDoubleWrapper() throws Exception { // Also: should be able to coerce doubles, strings: String[] STRS = new String[] { "1.0", "0.0", "-0.3", "0.7", "42.012", "-999.0", NAN_STRING }; for (String str : STRS) { Double exp = Double.valueOf(str); Double result; // First, as regular double value if (NAN_STRING != str) { result = MAPPER.readValue(str, Double.class); assertEquals(exp, result); } // and then as coerced String: result = MAPPER.readValue(" \""+str+"\"", Double.class); assertEquals(exp, result); } } public void testDoubleAsArray() throws Exception { final ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); final double value = 0.016; try { mapper.readValue("{\"v\":[" + value + "]}", DoubleBean.class); fail("Did not throw exception when reading a value from a single value array with the UNWRAP_SINGLE_VALUE_ARRAYS feature disabled"); } catch (JsonMappingException exp) { //Correctly threw exception } mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); DoubleBean result = mapper.readValue("{\"v\":[" + value + "]}", DoubleBean.class); assertEquals(value, result._v); result = mapper.readValue("[{\"v\":[" + value + "]}]", DoubleBean.class); assertEquals(value, result._v); try { mapper.readValue("[{\"v\":[" + value + "," + value + "]}]", DoubleBean.class); fail("Did not throw exception while reading a value from a multi value array with UNWRAP_SINGLE_VALUE_ARRAY feature enabled"); } catch (JsonMappingException exp) { //threw exception as required } result = mapper.readValue("{\"v\":[null]}", DoubleBean.class); assertNotNull(result); assertEquals(0d, result._v); double[] array = mapper.readValue("[ [ null ] ]", double[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(0d, array[0]); } public void testDoublePrimitiveNonNumeric() throws Exception { // first, simple case: // bit tricky with binary fps but... double value = Double.POSITIVE_INFINITY; DoubleBean result = MAPPER.readValue("{\"v\":\""+value+"\"}", DoubleBean.class); assertEquals(value, result._v); // should work with arrays too.. double[] array = MAPPER.readValue("[ \"Infinity\" ]", double[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(Double.POSITIVE_INFINITY, array[0]); } public void testFloatPrimitiveNonNumeric() throws Exception { // bit tricky with binary fps but... float value = Float.POSITIVE_INFINITY; FloatBean result = MAPPER.readValue("{\"v\":\""+value+"\"}", FloatBean.class); assertEquals(value, result._v); // should work with arrays too.. float[] array = MAPPER.readValue("[ \"Infinity\" ]", float[].class); assertNotNull(array); assertEquals(1, array.length); assertEquals(Float.POSITIVE_INFINITY, array[0]); } /* /********************************************************** /* Scalar tests, other /********************************************************** */ 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 (JsonMappingException e) { verifyException(e, "Can not coerce empty String"); } } public void testBase64Variants() throws Exception { final byte[] INPUT = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890X".getBytes("UTF-8"); // default encoding is "MIME, no linefeeds", so: Assert.assertArrayEquals(INPUT, MAPPER.readValue( quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA=="), byte[].class)); ObjectReader reader = MAPPER.readerFor(byte[].class); Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MIME_NO_LINEFEEDS).readValue( quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA==" ))); // but others should be slightly different Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MIME).readValue( quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1\\ndnd4eXoxMjM0NTY3ODkwWA==" ))); Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MODIFIED_FOR_URL).readValue( quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA" ))); // PEM mandates 64 char lines: Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.PEM).readValue( quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamts\\nbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA==" ))); } /* /********************************************************** /* Sequence tests /********************************************************** */ /** * Then a unit test to verify that we can conveniently bind sequence of * space-separate simple values */ public void testSequenceOfInts() throws Exception { final int NR_OF_INTS = 100; StringBuilder sb = new StringBuilder(); for (int i = 0; i < NR_OF_INTS; ++i) { sb.append(" "); sb.append(i); } JsonParser jp = MAPPER.getFactory().createParser(sb.toString()); for (int i = 0; i < NR_OF_INTS; ++i) { Integer result = MAPPER.readValue(jp, Integer.class); assertEquals(Integer.valueOf(i), result); } jp.close(); } /* /********************************************************** /* Empty String coercion, handling /********************************************************** */ // by default, should return nulls, n'est pas? public void testEmptyStringForWrappers() throws IOException { WrappersBean bean; bean = MAPPER.readValue("{\"booleanValue\":\"\"}", WrappersBean.class); assertNull(bean.booleanValue); bean = MAPPER.readValue("{\"byteValue\":\"\"}", WrappersBean.class); assertNull(bean.byteValue); // char/Character is different... not sure if this should work or not: bean = MAPPER.readValue("{\"charValue\":\"\"}", WrappersBean.class); assertNull(bean.charValue); bean = MAPPER.readValue("{\"shortValue\":\"\"}", WrappersBean.class); assertNull(bean.shortValue); bean = MAPPER.readValue("{\"intValue\":\"\"}", WrappersBean.class); assertNull(bean.intValue); bean = MAPPER.readValue("{\"longValue\":\"\"}", WrappersBean.class); assertNull(bean.longValue); bean = MAPPER.readValue("{\"floatValue\":\"\"}", WrappersBean.class); assertNull(bean.floatValue); bean = MAPPER.readValue("{\"doubleValue\":\"\"}", WrappersBean.class); assertNull(bean.doubleValue); } public void testEmptyStringForPrimitives() throws IOException { PrimitivesBean bean; bean = MAPPER.readValue("{\"booleanValue\":\"\"}", PrimitivesBean.class); assertFalse(bean.booleanValue); bean = MAPPER.readValue("{\"byteValue\":\"\"}", PrimitivesBean.class); assertEquals((byte) 0, bean.byteValue); bean = MAPPER.readValue("{\"charValue\":\"\"}", PrimitivesBean.class); assertEquals((char) 0, bean.charValue); bean = MAPPER.readValue("{\"shortValue\":\"\"}", PrimitivesBean.class); assertEquals((short) 0, bean.shortValue); bean = MAPPER.readValue("{\"intValue\":\"\"}", PrimitivesBean.class); assertEquals(0, bean.intValue); bean = MAPPER.readValue("{\"longValue\":\"\"}", PrimitivesBean.class); assertEquals(0L, bean.longValue); 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 { final ObjectReader reader = MAPPER .readerFor(PrimitivesBean.class) .with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); try { reader.readValue(aposToQuotes("{'"+propName+"':''}")); fail("Expected failure for boolean + empty String"); } catch (JsonMappingException e) { verifyException(e, "Can not coerce empty String (\"\")"); verifyException(e, "to Null value"); } } // for [databind#403] public void testEmptyStringFailForPrimitives() throws IOException { _verifyEmptyStringFailForPrimitives("booleanValue"); _verifyEmptyStringFailForPrimitives("byteValue"); _verifyEmptyStringFailForPrimitives("charValue"); _verifyEmptyStringFailForPrimitives("shortValue"); _verifyEmptyStringFailForPrimitives("intValue"); _verifyEmptyStringFailForPrimitives("longValue"); _verifyEmptyStringFailForPrimitives("floatValue"); _verifyEmptyStringFailForPrimitives("doubleValue"); } /* /********************************************************** /* Null handling for scalars in POJO /********************************************************** */ public void testNullForPrimitives() throws IOException { // by default, ok to rely on defaults PrimitivesBean bean = MAPPER.readValue( "{\"intValue\":null, \"booleanValue\":null, \"doubleValue\":null}", PrimitivesBean.class); assertNotNull(bean); assertEquals(0, bean.intValue); assertEquals(false, bean.booleanValue); assertEquals(0.0, bean.doubleValue); bean = MAPPER.readValue("{\"byteValue\":null, \"longValue\":null, \"floatValue\":null}", PrimitivesBean.class); assertNotNull(bean); assertEquals((byte) 0, bean.byteValue); assertEquals(0L, bean.longValue); assertEquals(0.0f, bean.floatValue); // but not when enabled final ObjectReader reader = MAPPER .readerFor(PrimitivesBean.class) .with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); // boolean try { reader.readValue("{\"booleanValue\":null}"); fail("Expected failure for boolean + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type boolean"); } // byte/char/short/int/long try { reader.readValue("{\"byteValue\":null}"); fail("Expected failure for byte + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type byte"); } try { reader.readValue("{\"charValue\":null}"); fail("Expected failure for char + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type char"); } try { reader.readValue("{\"shortValue\":null}"); fail("Expected failure for short + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type short"); } try { reader.readValue("{\"intValue\":null}"); fail("Expected failure for int + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type int"); } try { reader.readValue("{\"longValue\":null}"); fail("Expected failure for long + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type long"); } // float/double try { reader.readValue("{\"floatValue\":null}"); fail("Expected failure for float + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type float"); } try { reader.readValue("{\"doubleValue\":null}"); fail("Expected failure for double + null"); } catch (JsonMappingException e) { verifyException(e, "Can not map `null` into type double"); } } public void testNullForPrimitiveArrays() throws IOException { _testNullForPrimitiveArrays(boolean[].class, Boolean.FALSE); _testNullForPrimitiveArrays(byte[].class, Byte.valueOf((byte) 0)); _testNullForPrimitiveArrays(char[].class, Character.valueOf((char) 0), false); _testNullForPrimitiveArrays(short[].class, Short.valueOf((short)0)); _testNullForPrimitiveArrays(int[].class, Integer.valueOf(0)); _testNullForPrimitiveArrays(long[].class, Long.valueOf(0L)); _testNullForPrimitiveArrays(float[].class, Float.valueOf(0f)); _testNullForPrimitiveArrays(double[].class, Double.valueOf(0d)); } private void _testNullForPrimitiveArrays(Class<?> cls, Object defValue) throws IOException { _testNullForPrimitiveArrays(cls, defValue, true); } private void _testNullForPrimitiveArrays(Class<?> cls, Object defValue, boolean testEmptyString) throws IOException { final String EMPTY_STRING_JSON = "[ \"\" ]"; final String JSON_WITH_NULL = "[ null ]"; final String SIMPLE_NAME = cls.getSimpleName(); final ObjectReader readerCoerceOk = MAPPER.readerFor(cls); final ObjectReader readerNoCoerce = 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); fail("Should not pass"); } catch (JsonMappingException e) { verifyException(e, "Can not coerce `null`"); verifyException(e, "as content of type `"+SIMPLE_NAME+"`"); } if (testEmptyString) { ob = readerCoerceOk.forType(cls).readValue(EMPTY_STRING_JSON); assertEquals(1, Array.getLength(ob)); assertEquals(defValue, Array.get(ob, 0)); try { readerNoCoerce.readValue(EMPTY_STRING_JSON); fail("Should not pass"); } catch (JsonMappingException e) { verifyException(e, "Can not coerce empty String (\"\")"); verifyException(e, "as content of type `"+SIMPLE_NAME+"`"); } } } /* /********************************************************** /* Test for invalid String values /********************************************************** */ public void testInvalidStringCoercionFail() throws IOException { _testInvalidStringCoercionFail(boolean[].class); _testInvalidStringCoercionFail(byte[].class); // char[] is special, can not use generalized test here // _testInvalidStringCoercionFail(char[].class); _testInvalidStringCoercionFail(short[].class); _testInvalidStringCoercionFail(int[].class); _testInvalidStringCoercionFail(long[].class); _testInvalidStringCoercionFail(float[].class); _testInvalidStringCoercionFail(double[].class); } private void _testInvalidStringCoercionFail(Class<?> cls) throws IOException { final String JSON = "[ \"foobar\" ]"; final String SIMPLE_NAME = cls.getSimpleName(); try { MAPPER.readerFor(cls).readValue(JSON); fail("Should not pass"); } catch (JsonMappingException e) { verifyException(e, "Can not deserialize value of type "+SIMPLE_NAME+" from String \"foobar\""); } } }