1 package com.fasterxml.jackson.databind.convert; 2 3 import java.math.BigInteger; 4 5 import com.fasterxml.jackson.databind.*; 6 import com.fasterxml.jackson.databind.cfg.CoercionAction; 7 import com.fasterxml.jackson.databind.cfg.CoercionInputShape; 8 import com.fasterxml.jackson.databind.exc.MismatchedInputException; 9 import com.fasterxml.jackson.databind.type.LogicalType; 10 11 public class CoerceFloatToIntTest extends BaseMapTest 12 { 13 private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); 14 private final ObjectReader READER_LEGACY_FAIL = DEFAULT_MAPPER.reader() 15 .without(DeserializationFeature.ACCEPT_FLOAT_AS_INT); 16 17 private final ObjectMapper MAPPER_TO_EMPTY; { 18 MAPPER_TO_EMPTY = newJsonMapper(); 19 MAPPER_TO_EMPTY.coercionConfigFor(LogicalType.Integer) 20 .setCoercion(CoercionInputShape.Float, CoercionAction.AsEmpty); 21 } 22 23 private final ObjectMapper MAPPER_TRY_CONVERT; { 24 MAPPER_TRY_CONVERT = newJsonMapper(); 25 MAPPER_TRY_CONVERT.coercionConfigFor(LogicalType.Integer) 26 .setCoercion(CoercionInputShape.Float, CoercionAction.TryConvert); 27 } 28 29 private final ObjectMapper MAPPER_TO_NULL; { 30 MAPPER_TO_NULL = newJsonMapper(); 31 MAPPER_TO_NULL.coercionConfigFor(LogicalType.Integer) 32 .setCoercion(CoercionInputShape.Float, CoercionAction.AsNull); 33 } 34 35 private final ObjectMapper MAPPER_TO_FAIL; { 36 MAPPER_TO_FAIL = newJsonMapper(); 37 MAPPER_TO_FAIL.coercionConfigFor(LogicalType.Integer) 38 .setCoercion(CoercionInputShape.Float, CoercionAction.Fail); 39 } 40 41 /* 42 /******************************************************** 43 /* Test methods, defaults (legacy) 44 /******************************************************** 45 */ 46 testLegacyDoubleToIntCoercion()47 public void testLegacyDoubleToIntCoercion() throws Exception 48 { 49 // by default, should be ok 50 Integer I = DEFAULT_MAPPER.readValue(" 1.25 ", Integer.class); 51 assertEquals(1, I.intValue()); 52 { 53 IntWrapper w = DEFAULT_MAPPER.readValue("{\"i\":-2.25 }", IntWrapper.class); 54 assertEquals(-2, w.i); 55 int[] arr = DEFAULT_MAPPER.readValue("[ 1.25 ]", int[].class); 56 assertEquals(1, arr[0]); 57 } 58 59 Long L = DEFAULT_MAPPER.readValue(" 3.33 ", Long.class); 60 assertEquals(3L, L.longValue()); 61 { 62 LongWrapper w = DEFAULT_MAPPER.readValue("{\"l\":-2.25 }", LongWrapper.class); 63 assertEquals(-2L, w.l); 64 long[] arr = DEFAULT_MAPPER.readValue("[ 1.25 ]", long[].class); 65 assertEquals(1, arr[0]); 66 } 67 68 Short S = DEFAULT_MAPPER.readValue("42.33", Short.class); 69 assertEquals(42, S.intValue()); 70 71 BigInteger biggie = DEFAULT_MAPPER.readValue("95.3", BigInteger.class); 72 assertEquals(95L, biggie.longValue()); 73 } 74 testLegacyFailDoubleToInt()75 public void testLegacyFailDoubleToInt() throws Exception 76 { 77 _verifyCoerceFail(READER_LEGACY_FAIL, Integer.class, "1.5", "java.lang.Integer"); 78 _verifyCoerceFail(READER_LEGACY_FAIL, Integer.TYPE, "1.5", "int"); 79 _verifyCoerceFail(READER_LEGACY_FAIL, IntWrapper.class, "{\"i\":-2.25 }", "int"); 80 _verifyCoerceFail(READER_LEGACY_FAIL, int[].class, "[ 2.5 ]", "element of `int[]`"); 81 } 82 testLegacyFailDoubleToLong()83 public void testLegacyFailDoubleToLong() throws Exception 84 { 85 _verifyCoerceFail(READER_LEGACY_FAIL, Long.class, "0.5"); 86 _verifyCoerceFail(READER_LEGACY_FAIL, Long.TYPE, "-2.5"); 87 _verifyCoerceFail(READER_LEGACY_FAIL, LongWrapper.class, "{\"l\": 7.7 }"); 88 _verifyCoerceFail(READER_LEGACY_FAIL, long[].class, "[ -1.35 ]", "element of `long[]`"); 89 } 90 testLegacyFailDoubleToOther()91 public void testLegacyFailDoubleToOther() throws Exception 92 { 93 _verifyCoerceFail(READER_LEGACY_FAIL, Short.class, "0.5"); 94 _verifyCoerceFail(READER_LEGACY_FAIL, Short.TYPE, "-2.5"); 95 _verifyCoerceFail(READER_LEGACY_FAIL, short[].class, "[ -1.35 ]", "element of `short[]`"); 96 97 _verifyCoerceFail(READER_LEGACY_FAIL, Byte.class, "0.5"); 98 _verifyCoerceFail(READER_LEGACY_FAIL, Byte.TYPE, "-2.5"); 99 _verifyCoerceFail(READER_LEGACY_FAIL, byte[].class, "[ -1.35 ]", "element of `byte[]`"); 100 101 _verifyCoerceFail(READER_LEGACY_FAIL, BigInteger.class, "25236.256"); 102 103 // 13-Jun-2020, tatu: No explicit deserializer for `AtomicLong` yet 104 // _verifyCoerceFail(READER_LEGACY_FAIL, AtomicLong.class, "25236.256"); 105 } 106 107 /* 108 /******************************************************** 109 /* Test methods, CoerceConfig, to null 110 /******************************************************** 111 */ 112 testCoerceConfigFloatToNull()113 public void testCoerceConfigFloatToNull() throws Exception 114 { 115 assertNull(MAPPER_TO_NULL.readValue("1.5", Integer.class)); 116 // `null` not possible for primitives, must use empty (aka default) value 117 assertEquals(Integer.valueOf(0), MAPPER_TO_NULL.readValue("1.5", Integer.TYPE)); 118 { 119 IntWrapper w = MAPPER_TO_NULL.readValue( "{\"i\":-2.25 }", IntWrapper.class); 120 assertEquals(0, w.i); 121 int[] ints = MAPPER_TO_NULL.readValue("[ 2.5 ]", int[].class); 122 assertEquals(1, ints.length); 123 assertEquals(0, ints[0]); 124 } 125 126 assertNull(MAPPER_TO_NULL.readValue("2.5", Long.class)); 127 assertEquals(Long.valueOf(0L), MAPPER_TO_NULL.readValue("-4.25", Long.TYPE)); 128 { 129 LongWrapper w = MAPPER_TO_NULL.readValue( "{\"l\":-2.25 }", LongWrapper.class); 130 assertEquals(0L, w.l); 131 long[] l = MAPPER_TO_NULL.readValue("[ 2.5 ]", long[].class); 132 assertEquals(1, l.length); 133 assertEquals(0L, l[0]); 134 } 135 136 assertNull(MAPPER_TO_NULL.readValue("2.5", Short.class)); 137 assertEquals(Short.valueOf((short) 0), MAPPER_TO_NULL.readValue("-4.25", Short.TYPE)); 138 { 139 short[] s = MAPPER_TO_NULL.readValue("[ 2.5 ]", short[].class); 140 assertEquals(1, s.length); 141 assertEquals((short) 0, s[0]); 142 } 143 144 assertNull(MAPPER_TO_NULL.readValue("2.5", Byte.class)); 145 assertEquals(Byte.valueOf((byte) 0), MAPPER_TO_NULL.readValue("-4.25", Byte.TYPE)); 146 { 147 byte[] arr = MAPPER_TO_NULL.readValue("[ 2.5 ]", byte[].class); 148 assertEquals(1, arr.length); 149 assertEquals((byte) 0, arr[0]); 150 } 151 152 assertNull(MAPPER_TO_NULL.readValue("2.5", BigInteger.class)); 153 { 154 BigInteger[] arr = MAPPER_TO_NULL.readValue("[ 2.5 ]", BigInteger[].class); 155 assertEquals(1, arr.length); 156 assertNull(arr[0]); 157 } 158 } 159 160 /* 161 /******************************************************** 162 /* Test methods, CoerceConfig, to empty 163 /******************************************************** 164 */ 165 testCoerceConfigFloatToEmpty()166 public void testCoerceConfigFloatToEmpty() throws Exception 167 { 168 assertEquals(Integer.valueOf(0), MAPPER_TO_EMPTY.readValue("1.2", Integer.class)); 169 assertEquals(Integer.valueOf(0), MAPPER_TO_EMPTY.readValue("1.5", Integer.TYPE)); 170 { 171 IntWrapper w = MAPPER_TO_EMPTY.readValue( "{\"i\":-2.25 }", IntWrapper.class); 172 assertEquals(0, w.i); 173 int[] ints = MAPPER_TO_EMPTY.readValue("[ 2.5 ]", int[].class); 174 assertEquals(1, ints.length); 175 assertEquals(0, ints[0]); 176 } 177 178 assertEquals(Long.valueOf(0), MAPPER_TO_EMPTY.readValue("1.2", Long.class)); 179 assertEquals(Long.valueOf(0), MAPPER_TO_EMPTY.readValue("1.5", Long.TYPE)); 180 { 181 LongWrapper w = MAPPER_TO_EMPTY.readValue( "{\"l\":-2.25 }", LongWrapper.class); 182 assertEquals(0L, w.l); 183 long[] l = MAPPER_TO_EMPTY.readValue("[ 2.5 ]", long[].class); 184 assertEquals(1, l.length); 185 assertEquals(0L, l[0]); 186 } 187 188 assertEquals(Short.valueOf((short)0), MAPPER_TO_EMPTY.readValue("1.2", Short.class)); 189 assertEquals(Short.valueOf((short) 0), MAPPER_TO_EMPTY.readValue("1.5", Short.TYPE)); 190 191 assertEquals(Byte.valueOf((byte)0), MAPPER_TO_EMPTY.readValue("1.2", Byte.class)); 192 assertEquals(Byte.valueOf((byte) 0), MAPPER_TO_EMPTY.readValue("1.5", Byte.TYPE)); 193 194 assertEquals(BigInteger.valueOf(0L), MAPPER_TO_EMPTY.readValue("124.5", BigInteger.class)); 195 } 196 197 /* 198 /******************************************************** 199 /* Test methods, CoerceConfig, coerce 200 /******************************************************** 201 */ 202 testCoerceConfigFloatSuccess()203 public void testCoerceConfigFloatSuccess() throws Exception 204 { 205 assertEquals(Integer.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.2", Integer.class)); 206 assertEquals(Integer.valueOf(3), MAPPER_TRY_CONVERT.readValue("3.4", Integer.TYPE)); 207 { 208 IntWrapper w = MAPPER_TRY_CONVERT.readValue( "{\"i\":-2.25 }", IntWrapper.class); 209 assertEquals(-2, w.i); 210 int[] ints = MAPPER_TRY_CONVERT.readValue("[ 22.10 ]", int[].class); 211 assertEquals(1, ints.length); 212 assertEquals(22, ints[0]); 213 } 214 215 assertEquals(Long.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.2", Long.class)); 216 assertEquals(Long.valueOf(1), MAPPER_TRY_CONVERT.readValue("1.5", Long.TYPE)); 217 { 218 LongWrapper w = MAPPER_TRY_CONVERT.readValue( "{\"l\":-2.25 }", LongWrapper.class); 219 assertEquals(-2L, w.l); 220 long[] l = MAPPER_TRY_CONVERT.readValue("[ 2.2 ]", long[].class); 221 assertEquals(1, l.length); 222 assertEquals(2L, l[0]); 223 } 224 225 assertEquals(Short.valueOf((short)1), MAPPER_TRY_CONVERT.readValue("1.2", Short.class)); 226 assertEquals(Short.valueOf((short) 19), MAPPER_TRY_CONVERT.readValue("19.2", Short.TYPE)); 227 228 assertEquals(Byte.valueOf((byte)1), MAPPER_TRY_CONVERT.readValue("1.2", Byte.class)); 229 assertEquals(Byte.valueOf((byte) 1), MAPPER_TRY_CONVERT.readValue("1.5", Byte.TYPE)); 230 231 assertEquals(BigInteger.valueOf(124L), MAPPER_TRY_CONVERT.readValue("124.2", BigInteger.class)); 232 } 233 234 /* 235 /******************************************************** 236 /* Test methods, CoerceConfig, fail 237 /******************************************************** 238 */ 239 testCoerceConfigFailFromFloat()240 public void testCoerceConfigFailFromFloat() throws Exception 241 { 242 _verifyCoerceFail(MAPPER_TO_FAIL, Integer.class, "1.5"); 243 _verifyCoerceFail(MAPPER_TO_FAIL, Integer.TYPE, "1.5"); 244 _verifyCoerceFail(MAPPER_TO_FAIL, IntWrapper.class, "{\"i\":-2.25 }", "int"); 245 _verifyCoerceFail(MAPPER_TO_FAIL, int[].class, "[ 2.5 ]", "element of `int[]`"); 246 247 _verifyCoerceFail(MAPPER_TO_FAIL, Long.class, "0.5"); 248 _verifyCoerceFail(MAPPER_TO_FAIL, Long.TYPE, "-2.5"); 249 _verifyCoerceFail(MAPPER_TO_FAIL, LongWrapper.class, "{\"l\": 7.7 }"); 250 _verifyCoerceFail(MAPPER_TO_FAIL, long[].class, "[ -1.35 ]", "element of `long[]`"); 251 252 _verifyCoerceFail(MAPPER_TO_FAIL, Short.class, "0.5"); 253 _verifyCoerceFail(MAPPER_TO_FAIL, Short.TYPE, "-2.5"); 254 _verifyCoerceFail(MAPPER_TO_FAIL, short[].class, "[ -1.35 ]", "element of `short[]`"); 255 256 _verifyCoerceFail(MAPPER_TO_FAIL, Byte.class, "0.5"); 257 _verifyCoerceFail(MAPPER_TO_FAIL, Byte.TYPE, "-2.5"); 258 _verifyCoerceFail(MAPPER_TO_FAIL, byte[].class, "[ -1.35 ]", "element of `byte[]`"); 259 260 _verifyCoerceFail(MAPPER_TO_FAIL, BigInteger.class, "25236.256"); 261 } 262 263 /* 264 /******************************************************** 265 /* Helper methods 266 /******************************************************** 267 */ 268 _verifyCoerceFail(ObjectMapper m, Class<?> targetType, String doc)269 private void _verifyCoerceFail(ObjectMapper m, Class<?> targetType, 270 String doc) throws Exception 271 { 272 _verifyCoerceFail(m.reader(), targetType, doc, targetType.getName()); 273 } 274 _verifyCoerceFail(ObjectMapper m, Class<?> targetType, String doc, String targetTypeDesc)275 private void _verifyCoerceFail(ObjectMapper m, Class<?> targetType, 276 String doc, String targetTypeDesc) throws Exception 277 { 278 _verifyCoerceFail(m.reader(), targetType, doc, targetTypeDesc); 279 } 280 _verifyCoerceFail(ObjectReader r, Class<?> targetType, String doc)281 private void _verifyCoerceFail(ObjectReader r, Class<?> targetType, 282 String doc) throws Exception 283 { 284 _verifyCoerceFail(r, targetType, doc, targetType.getName()); 285 } 286 _verifyCoerceFail(ObjectReader r, Class<?> targetType, String doc, String targetTypeDesc)287 private void _verifyCoerceFail(ObjectReader r, Class<?> targetType, 288 String doc, String targetTypeDesc) throws Exception 289 { 290 try { 291 r.forType(targetType).readValue(doc); 292 fail("Should not accept Float for "+targetType.getName()+" by default"); 293 } catch (MismatchedInputException e) { 294 verifyException(e, "Cannot coerce Floating-point"); 295 verifyException(e, targetTypeDesc); 296 } 297 } 298 } 299