• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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