1 package com.fasterxml.jackson.databind.node; 2 3 import java.math.BigDecimal; 4 import java.math.BigInteger; 5 6 import com.fasterxml.jackson.core.JsonGenerator; 7 import com.fasterxml.jackson.core.JsonParser; 8 import com.fasterxml.jackson.core.JsonToken; 9 import com.fasterxml.jackson.databind.*; 10 11 /** 12 * Basic tests for {@link JsonNode} implementations that 13 * contain numeric values. 14 */ 15 public class NumberNodesTest extends NodeTestBase 16 { 17 private final ObjectMapper MAPPER = objectMapper(); 18 testShort()19 public void testShort() 20 { 21 ShortNode n = ShortNode.valueOf((short) 1); 22 assertStandardEquals(n); 23 assertTrue(0 != n.hashCode()); 24 assertEquals(JsonToken.VALUE_NUMBER_INT, n.asToken()); 25 assertEquals(JsonParser.NumberType.INT, n.numberType()); // should be SHORT 26 assertEquals(1, n.intValue()); 27 assertEquals(1L, n.longValue()); 28 assertEquals(BigDecimal.ONE, n.decimalValue()); 29 assertEquals(BigInteger.ONE, n.bigIntegerValue()); 30 assertEquals("1", n.asText()); 31 32 assertNodeNumbers(n, 1, 1.0); 33 34 assertTrue(ShortNode.valueOf((short) 0).canConvertToInt()); 35 assertTrue(ShortNode.valueOf(Short.MAX_VALUE).canConvertToInt()); 36 assertTrue(ShortNode.valueOf(Short.MIN_VALUE).canConvertToInt()); 37 38 assertTrue(ShortNode.valueOf((short) 0).canConvertToLong()); 39 assertTrue(ShortNode.valueOf(Short.MAX_VALUE).canConvertToLong()); 40 assertTrue(ShortNode.valueOf(Short.MIN_VALUE).canConvertToLong()); 41 } 42 testIntViaMapper()43 public void testIntViaMapper() throws Exception 44 { 45 int value = -90184; 46 JsonNode result = MAPPER.readTree(String.valueOf(value)); 47 assertTrue(result.isNumber()); 48 assertTrue(result.isIntegralNumber()); 49 assertTrue(result.isInt()); 50 assertType(result, IntNode.class); 51 assertFalse(result.isLong()); 52 assertFalse(result.isFloatingPointNumber()); 53 assertFalse(result.isDouble()); 54 assertFalse(result.isNull()); 55 assertFalse(result.isTextual()); 56 assertFalse(result.isMissingNode()); 57 58 assertEquals(value, result.numberValue().intValue()); 59 assertEquals(value, result.intValue()); 60 assertEquals(String.valueOf(value), result.asText()); 61 assertEquals((double) value, result.doubleValue()); 62 assertEquals((long) value, result.longValue()); 63 64 // also, equality should work ok 65 assertEquals(result, IntNode.valueOf(value)); 66 } 67 testInt()68 public void testInt() 69 { 70 IntNode n = IntNode.valueOf(1); 71 assertStandardEquals(n); 72 assertTrue(0 != n.hashCode()); 73 assertEquals(JsonToken.VALUE_NUMBER_INT, n.asToken()); 74 assertEquals(JsonParser.NumberType.INT, n.numberType()); 75 assertEquals(1, n.intValue()); 76 assertEquals(1L, n.longValue()); 77 assertEquals(BigDecimal.ONE, n.decimalValue()); 78 assertEquals(BigInteger.ONE, n.bigIntegerValue()); 79 assertEquals("1", n.asText()); 80 // 2.4 81 assertEquals("1", n.asText("foo")); 82 83 assertNodeNumbers(n, 1, 1.0); 84 85 assertTrue(IntNode.valueOf(0).canConvertToInt()); 86 assertTrue(IntNode.valueOf(Integer.MAX_VALUE).canConvertToInt()); 87 assertTrue(IntNode.valueOf(Integer.MIN_VALUE).canConvertToInt()); 88 89 assertTrue(IntNode.valueOf(0).canConvertToLong()); 90 assertTrue(IntNode.valueOf(Integer.MAX_VALUE).canConvertToLong()); 91 assertTrue(IntNode.valueOf(Integer.MIN_VALUE).canConvertToLong()); 92 93 } 94 testLong()95 public void testLong() 96 { 97 LongNode n = LongNode.valueOf(1L); 98 assertStandardEquals(n); 99 assertTrue(0 != n.hashCode()); 100 assertEquals(JsonToken.VALUE_NUMBER_INT, n.asToken()); 101 assertEquals(JsonParser.NumberType.LONG, n.numberType()); 102 assertEquals(1, n.intValue()); 103 assertEquals(1L, n.longValue()); 104 assertEquals(BigDecimal.ONE, n.decimalValue()); 105 assertEquals(BigInteger.ONE, n.bigIntegerValue()); 106 assertEquals("1", n.asText()); 107 108 assertNodeNumbers(n, 1, 1.0); 109 110 // ok if contains small enough value 111 assertTrue(LongNode.valueOf(0).canConvertToInt()); 112 assertTrue(LongNode.valueOf(Integer.MAX_VALUE).canConvertToInt()); 113 assertTrue(LongNode.valueOf(Integer.MIN_VALUE).canConvertToInt()); 114 // but not in other cases 115 assertFalse(LongNode.valueOf(1L + Integer.MAX_VALUE).canConvertToInt()); 116 assertFalse(LongNode.valueOf(-1L + Integer.MIN_VALUE).canConvertToInt()); 117 118 assertTrue(LongNode.valueOf(0L).canConvertToLong()); 119 assertTrue(LongNode.valueOf(Long.MAX_VALUE).canConvertToLong()); 120 assertTrue(LongNode.valueOf(Long.MIN_VALUE).canConvertToLong()); 121 } 122 testLongViaMapper()123 public void testLongViaMapper() throws Exception 124 { 125 // need to use something being 32-bit value space 126 long value = 12345678L << 32; 127 JsonNode result = MAPPER.readTree(String.valueOf(value)); 128 assertTrue(result.isNumber()); 129 assertTrue(result.isIntegralNumber()); 130 assertTrue(result.isLong()); 131 assertType(result, LongNode.class); 132 assertFalse(result.isInt()); 133 assertFalse(result.isFloatingPointNumber()); 134 assertFalse(result.isDouble()); 135 assertFalse(result.isNull()); 136 assertFalse(result.isTextual()); 137 assertFalse(result.isMissingNode()); 138 139 assertEquals(value, result.numberValue().longValue()); 140 assertEquals(value, result.longValue()); 141 assertEquals(String.valueOf(value), result.asText()); 142 assertEquals((double) value, result.doubleValue()); 143 144 // also, equality should work ok 145 assertEquals(result, LongNode.valueOf(value)); 146 } 147 testDouble()148 public void testDouble() throws Exception 149 { 150 DoubleNode n = DoubleNode.valueOf(0.25); 151 assertStandardEquals(n); 152 assertTrue(0 != n.hashCode()); 153 assertEquals(JsonToken.VALUE_NUMBER_FLOAT, n.asToken()); 154 assertEquals(JsonParser.NumberType.DOUBLE, n.numberType()); 155 assertEquals(0, n.intValue()); 156 assertEquals(0.25, n.doubleValue()); 157 assertNotNull(n.decimalValue()); 158 assertEquals(BigInteger.ZERO, n.bigIntegerValue()); 159 assertEquals("0.25", n.asText()); 160 161 assertNodeNumbers(DoubleNode.valueOf(4.5), 4, 4.5); 162 163 assertTrue(DoubleNode.valueOf(0).canConvertToInt()); 164 assertTrue(DoubleNode.valueOf(Integer.MAX_VALUE).canConvertToInt()); 165 assertTrue(DoubleNode.valueOf(Integer.MIN_VALUE).canConvertToInt()); 166 assertFalse(DoubleNode.valueOf(1L + Integer.MAX_VALUE).canConvertToInt()); 167 assertFalse(DoubleNode.valueOf(-1L + Integer.MIN_VALUE).canConvertToInt()); 168 169 assertTrue(DoubleNode.valueOf(0L).canConvertToLong()); 170 assertTrue(DoubleNode.valueOf(Long.MAX_VALUE).canConvertToLong()); 171 assertTrue(DoubleNode.valueOf(Long.MIN_VALUE).canConvertToLong()); 172 173 JsonNode num = objectMapper().readTree(" -0.0"); 174 assertTrue(num.isDouble()); 175 n = (DoubleNode) num; 176 assertEquals(-0.0, n.doubleValue()); 177 assertEquals("-0.0", String.valueOf(n.doubleValue())); 178 } 179 testDoubleViaMapper()180 public void testDoubleViaMapper() throws Exception 181 { 182 double value = 3.04; 183 JsonNode result = MAPPER.readTree(String.valueOf(value)); 184 assertTrue(result.isNumber()); 185 assertFalse(result.isNull()); 186 assertType(result, DoubleNode.class); 187 assertTrue(result.isFloatingPointNumber()); 188 assertTrue(result.isDouble()); 189 assertFalse(result.isInt()); 190 assertFalse(result.isLong()); 191 assertFalse(result.isIntegralNumber()); 192 assertFalse(result.isTextual()); 193 assertFalse(result.isMissingNode()); 194 195 assertEquals(value, result.doubleValue()); 196 assertEquals(value, result.numberValue().doubleValue()); 197 assertEquals((int) value, result.intValue()); 198 assertEquals((long) value, result.longValue()); 199 assertEquals(String.valueOf(value), result.asText()); 200 201 // also, equality should work ok 202 assertEquals(result, DoubleNode.valueOf(value)); 203 } 204 205 // @since 2.2 testFloat()206 public void testFloat() 207 { 208 FloatNode n = FloatNode.valueOf(0.45f); 209 assertStandardEquals(n); 210 assertTrue(0 != n.hashCode()); 211 assertEquals(JsonToken.VALUE_NUMBER_FLOAT, n.asToken()); 212 assertEquals(JsonParser.NumberType.FLOAT, n.numberType()); 213 assertEquals(0, n.intValue()); 214 215 // NOTE: conversion to double NOT as simple as with exact numbers like 0.25: 216 assertEquals(0.45f, n.floatValue()); 217 assertEquals("0.45", n.asText()); 218 219 // so; as double we'll get more complex number; however, should round-trip 220 // to something that gets printed the same way. But not exact value, alas, hence: 221 assertEquals("0.45", String.valueOf((float) n.doubleValue())); 222 223 assertNotNull(n.decimalValue()); 224 // possibly surprisingly, however, this will produce same output: 225 assertEquals(BigInteger.ZERO, n.bigIntegerValue()); 226 assertEquals("0.45", n.asText()); 227 228 // 1.6: 229 assertNodeNumbers(FloatNode.valueOf(4.5f), 4, 4.5f); 230 231 assertTrue(FloatNode.valueOf(0).canConvertToInt()); 232 assertTrue(FloatNode.valueOf(Integer.MAX_VALUE).canConvertToInt()); 233 assertTrue(FloatNode.valueOf(Integer.MIN_VALUE).canConvertToInt()); 234 235 // rounding errors if we just add/sub 1... so: 236 assertFalse(FloatNode.valueOf(1000L + Integer.MAX_VALUE).canConvertToInt()); 237 assertFalse(FloatNode.valueOf(-1000L + Integer.MIN_VALUE).canConvertToInt()); 238 239 assertTrue(FloatNode.valueOf(0L).canConvertToLong()); 240 assertTrue(FloatNode.valueOf(Integer.MAX_VALUE).canConvertToLong()); 241 assertTrue(FloatNode.valueOf(Integer.MIN_VALUE).canConvertToLong()); 242 } 243 testDecimalNode()244 public void testDecimalNode() throws Exception 245 { 246 DecimalNode n = DecimalNode.valueOf(BigDecimal.ONE); 247 assertStandardEquals(n); 248 assertTrue(n.equals(new DecimalNode(BigDecimal.ONE))); 249 assertEquals(JsonToken.VALUE_NUMBER_FLOAT, n.asToken()); 250 assertEquals(JsonParser.NumberType.BIG_DECIMAL, n.numberType()); 251 assertTrue(n.isNumber()); 252 assertFalse(n.isIntegralNumber()); 253 assertFalse(n.isArray()); 254 assertTrue(n.isBigDecimal()); 255 assertEquals(BigDecimal.ONE, n.numberValue()); 256 assertEquals(1, n.intValue()); 257 assertEquals(1L, n.longValue()); 258 assertEquals(BigDecimal.ONE, n.decimalValue()); 259 assertEquals("1", n.asText()); 260 261 assertNodeNumbers(n, 1, 1.0); 262 263 assertTrue(DecimalNode.valueOf(BigDecimal.ZERO).canConvertToInt()); 264 assertTrue(DecimalNode.valueOf(BigDecimal.valueOf(Integer.MAX_VALUE)).canConvertToInt()); 265 assertTrue(DecimalNode.valueOf(BigDecimal.valueOf(Integer.MIN_VALUE)).canConvertToInt()); 266 assertFalse(DecimalNode.valueOf(BigDecimal.valueOf(1L + Integer.MAX_VALUE)).canConvertToInt()); 267 assertFalse(DecimalNode.valueOf(BigDecimal.valueOf(-1L + Integer.MIN_VALUE)).canConvertToInt()); 268 269 assertTrue(DecimalNode.valueOf(BigDecimal.ZERO).canConvertToLong()); 270 assertTrue(DecimalNode.valueOf(BigDecimal.valueOf(Long.MAX_VALUE)).canConvertToLong()); 271 assertTrue(DecimalNode.valueOf(BigDecimal.valueOf(Long.MIN_VALUE)).canConvertToLong()); 272 273 // no "natural" way to get it, must construct 274 BigDecimal value = new BigDecimal("0.1"); 275 JsonNode result = DecimalNode.valueOf(value); 276 277 assertFalse(result.isObject()); 278 assertTrue(result.isNumber()); 279 assertFalse(result.isIntegralNumber()); 280 assertFalse(result.isLong()); 281 assertType(result, DecimalNode.class); 282 assertFalse(result.isInt()); 283 assertTrue(result.isFloatingPointNumber()); 284 assertTrue(result.isBigDecimal()); 285 assertFalse(result.isDouble()); 286 assertFalse(result.isNull()); 287 assertFalse(result.isTextual()); 288 assertFalse(result.isMissingNode()); 289 290 assertEquals(value, result.numberValue()); 291 assertEquals(value.toString(), result.asText()); 292 293 // also, equality should work ok 294 assertEquals(result, DecimalNode.valueOf(value)); 295 } 296 testDecimalNodeEqualsHashCode()297 public void testDecimalNodeEqualsHashCode() 298 { 299 // We want DecimalNodes with equivalent _numeric_ values to be equal; 300 // this is not the case for BigDecimal where "1.0" and "1" are not 301 // equal! 302 BigDecimal b1 = BigDecimal.ONE; 303 BigDecimal b2 = new BigDecimal("1.0"); 304 BigDecimal b3 = new BigDecimal("0.01e2"); 305 BigDecimal b4 = new BigDecimal("1000e-3"); 306 307 DecimalNode node1 = new DecimalNode(b1); 308 DecimalNode node2 = new DecimalNode(b2); 309 DecimalNode node3 = new DecimalNode(b3); 310 DecimalNode node4 = new DecimalNode(b4); 311 312 assertEquals(node1.hashCode(), node2.hashCode()); 313 assertEquals(node2.hashCode(), node3.hashCode()); 314 assertEquals(node3.hashCode(), node4.hashCode()); 315 316 assertEquals(node1, node2); 317 assertEquals(node2, node1); 318 assertEquals(node2, node3); 319 assertEquals(node3, node4); 320 } 321 testBigIntegerNode()322 public void testBigIntegerNode() throws Exception 323 { 324 BigIntegerNode n = BigIntegerNode.valueOf(BigInteger.ONE); 325 assertStandardEquals(n); 326 assertTrue(n.equals(new BigIntegerNode(BigInteger.ONE))); 327 assertEquals(JsonToken.VALUE_NUMBER_INT, n.asToken()); 328 assertEquals(JsonParser.NumberType.BIG_INTEGER, n.numberType()); 329 assertTrue(n.isNumber()); 330 assertTrue(n.isIntegralNumber()); 331 assertTrue(n.isBigInteger()); 332 assertEquals(BigInteger.ONE, n.numberValue()); 333 assertEquals(1, n.intValue()); 334 assertEquals(1L, n.longValue()); 335 assertEquals(BigInteger.ONE, n.bigIntegerValue()); 336 assertEquals("1", n.asText()); 337 assertNodeNumbers(n, 1, 1.0); 338 339 BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); 340 341 n = BigIntegerNode.valueOf(maxLong); 342 assertEquals(Long.MAX_VALUE, n.longValue()); 343 344 ObjectMapper mapper = new ObjectMapper(); 345 JsonNode n2 = mapper.readTree(maxLong.toString()); 346 assertEquals(Long.MAX_VALUE, n2.longValue()); 347 348 // then over long limit: 349 BigInteger beyondLong = maxLong.shiftLeft(2); // 4x max long 350 n2 = mapper.readTree(beyondLong.toString()); 351 assertEquals(beyondLong, n2.bigIntegerValue()); 352 353 assertTrue(BigIntegerNode.valueOf(BigInteger.ZERO).canConvertToInt()); 354 assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Integer.MAX_VALUE)).canConvertToInt()); 355 assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Integer.MIN_VALUE)).canConvertToInt()); 356 assertFalse(BigIntegerNode.valueOf(BigInteger.valueOf(1L + Integer.MAX_VALUE)).canConvertToInt()); 357 assertFalse(BigIntegerNode.valueOf(BigInteger.valueOf(-1L + Integer.MIN_VALUE)).canConvertToInt()); 358 359 assertTrue(BigIntegerNode.valueOf(BigInteger.ZERO).canConvertToLong()); 360 assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MAX_VALUE)).canConvertToLong()); 361 assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MIN_VALUE)).canConvertToLong()); 362 } 363 testBigDecimalAsPlain()364 public void testBigDecimalAsPlain() throws Exception 365 { 366 ObjectMapper mapper = new ObjectMapper() 367 .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) 368 .enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); 369 final String INPUT = "{\"x\":1e2}"; 370 final JsonNode node = mapper.readTree(INPUT); 371 String result = mapper.writeValueAsString(node); 372 assertEquals("{\"x\":100}", result); 373 374 // also via ObjectWriter: 375 assertEquals("{\"x\":100}", mapper.writer().writeValueAsString(node)); 376 377 // and once more for [core#175]: 378 BigDecimal bigDecimal = new BigDecimal(100); 379 JsonNode tree = mapper.valueToTree(bigDecimal); 380 assertEquals("100", mapper.writeValueAsString(tree)); 381 } 382 383 // Related to [databind#333] testCanonicalNumbers()384 public void testCanonicalNumbers() throws Exception 385 { 386 JsonNodeFactory f = new JsonNodeFactory(); 387 NumericNode n = f.numberNode(123); 388 assertTrue(n.isInt()); 389 n = f.numberNode(1L + Integer.MAX_VALUE); 390 assertFalse(n.isInt()); 391 assertTrue(n.isLong()); 392 393 // 19-May-2015, tatu: Actually, no, coercion should not happen by default. 394 // But it should be possible to change it if necessary. 395 // but "too small" number will be 'int'... 396 n = f.numberNode(123L); 397 assertTrue(n.isLong()); 398 } 399 } 400