Skip to content

Commit 99d0ab6

Browse files
authored
Implement #4958: improve/add number accessors to JsonNode [JSTEP-3] (#4970)
1 parent c4719a8 commit 99d0ab6

34 files changed

+2626
-230
lines changed

release-notes/VERSION

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ Versions: 3.x (for earlier see VERSION-2.x)
9898
`JsonNode.xxxStringYyy()` [JSTEP-3]
9999
#4891: Change 3.0 to use `module-info.java` directly for build (instead of via Moditect)
100100
#4956: Rename `JsonNode.isContainerNode()` as `isContainerNode()`
101+
#4958: Extend, improve set of number value accessors for `JsonNode`
102+
(`JsonNode.intValue()` etc) [JSTEP-3]
101103
#4992: Rename `JsonNodeFactory.textNode()` as `JsonNodeFactory.stringNode()` [JSTEP-3]
102104
- Remove `MappingJsonFactory`
103105
- Add context parameter for `TypeSerializer` contextualization (`forProperty()`)

src/main/java/tools/jackson/databind/JsonNode.java

+225-103
Large diffs are not rendered by default.

src/main/java/tools/jackson/databind/deser/jdk/ThreadGroupDeserializer.java

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package tools.jackson.databind.deser.jdk;
22

3-
import java.io.IOException;
4-
53
import tools.jackson.databind.DeserializationContext;
64
import tools.jackson.databind.JsonNode;
75
import tools.jackson.databind.deser.std.StdNodeBasedDeserializer;

src/main/java/tools/jackson/databind/node/ArrayNode.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,20 @@ public class ArrayNode
2727

2828
private final List<JsonNode> _children;
2929

30+
/*
31+
/**********************************************************************
32+
/* Construction
33+
/**********************************************************************
34+
*/
35+
3036
public ArrayNode(JsonNodeFactory nf) {
3137
super(nf);
32-
_children = new ArrayList<JsonNode>();
38+
_children = new ArrayList<>();
3339
}
3440

3541
public ArrayNode(JsonNodeFactory nf, int capacity) {
3642
super(nf);
37-
_children = new ArrayList<JsonNode>(capacity);
43+
_children = new ArrayList<>(capacity);
3844
}
3945

4046
public ArrayNode(JsonNodeFactory nf, List<JsonNode> children) {
@@ -43,11 +49,22 @@ public ArrayNode(JsonNodeFactory nf, List<JsonNode> children) {
4349
"Must not pass `null` for 'children' argument");
4450
}
4551

52+
/*
53+
/**********************************************************************
54+
/* Overridden JsonNode methods
55+
/**********************************************************************
56+
*/
57+
4658
@Override
4759
protected JsonNode _at(JsonPointer ptr) {
4860
return get(ptr.getMatchingIndex());
4961
}
5062

63+
@Override
64+
protected String _valueDesc() {
65+
return "[...(" + _children.size() + " elements)]";
66+
}
67+
5168
// note: co-variant to allow caller-side type safety
5269
@Override
5370
public ArrayNode deepCopy()

src/main/java/tools/jackson/databind/node/BaseJsonNode.java

+229-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import java.math.BigDecimal;
44
import java.math.BigInteger;
5+
import java.util.Optional;
6+
import java.util.OptionalDouble;
7+
import java.util.OptionalInt;
8+
import java.util.OptionalLong;
59

610
import tools.jackson.core.*;
711
import tools.jackson.databind.JacksonSerializable;
@@ -47,6 +51,172 @@ protected BaseJsonNode() { }
4751
@Override
4852
public boolean isEmbeddedValue() { return false; }
4953

54+
/*
55+
/**********************************************************************
56+
/* Defaulting for number access
57+
/**********************************************************************
58+
*/
59+
60+
@Override
61+
public Number numberValue() {
62+
return _reportCoercionFail("numberValue()", Number.class, "value type not numeric");
63+
}
64+
65+
@Override
66+
public short shortValue() {
67+
return _reportCoercionFail("shortValue()", Short.TYPE, "value type not numeric");
68+
}
69+
70+
@Override
71+
public int intValue() {
72+
return _reportCoercionFail("intValue()", Integer.TYPE, "value type not numeric");
73+
}
74+
75+
@Override
76+
public int intValue(int defaultValue) {
77+
// Overridden by NumericNode, for other types return default
78+
return defaultValue;
79+
}
80+
81+
@Override
82+
public OptionalInt intValueOpt() {
83+
// Overridden by NumericNode, for other types return default
84+
return OptionalInt.empty();
85+
}
86+
87+
@Override
88+
public int asInt() {
89+
return asInt(0);
90+
}
91+
92+
@Override
93+
public int asInt(int defaultValue) {
94+
return defaultValue;
95+
}
96+
97+
@Override
98+
public long longValue() {
99+
return _reportCoercionFail("longValue()", Long.TYPE, "value type not numeric");
100+
}
101+
102+
@Override
103+
public long longValue(long defaultValue) {
104+
// Overridden by NumericNode, for other types return default
105+
return defaultValue;
106+
}
107+
108+
@Override
109+
public OptionalLong longValueOpt() {
110+
// Overridden by NumericNode, for other types return default
111+
return OptionalLong.empty();
112+
}
113+
114+
@Override
115+
public long asLong() {
116+
return asLong(0L);
117+
}
118+
119+
@Override
120+
public long asLong(long defaultValue) {
121+
return defaultValue;
122+
}
123+
124+
@Override
125+
public BigInteger bigIntegerValue() {
126+
return _reportCoercionFail("bigIntegerValue()", BigInteger.class, "value type not numeric");
127+
}
128+
129+
@Override
130+
public float floatValue() {
131+
return _reportCoercionFail("floatValue()", Float.TYPE, "value type not numeric");
132+
}
133+
134+
@Override
135+
public double doubleValue() {
136+
return _reportCoercionFail("doubleValue()", Double.TYPE, "value type not numeric");
137+
}
138+
139+
@Override
140+
public double doubleValue(double defaultValue) {
141+
// Overridden by NumericNode, for other types return default
142+
return defaultValue;
143+
}
144+
145+
@Override
146+
public OptionalDouble doubleValueOpt() {
147+
// Overridden by NumericNode, for other types return default
148+
return OptionalDouble.empty();
149+
}
150+
151+
@Override
152+
public double asDouble() {
153+
return asDouble(0.0);
154+
}
155+
156+
@Override
157+
public double asDouble(double defaultValue) {
158+
return defaultValue;
159+
}
160+
161+
@Override
162+
public BigDecimal decimalValue() {
163+
return _reportCoercionFail("decimalValue()", BigDecimal.class, "value type not numeric");
164+
}
165+
166+
@Override
167+
public BigDecimal decimalValue(BigDecimal defaultValue) {
168+
// Overridden by NumericNode, for other types return default
169+
return defaultValue;
170+
}
171+
172+
@Override
173+
public Optional<BigDecimal> decimalValueOpt() {
174+
return Optional.empty();
175+
}
176+
177+
@Override
178+
public BigDecimal asDecimal() {
179+
return asDecimal(BigDecimal.ZERO);
180+
}
181+
182+
@Override
183+
public BigDecimal asDecimal(BigDecimal defaultValue) {
184+
// !!! TODO
185+
return decimalValue(defaultValue);
186+
}
187+
188+
/*
189+
/**********************************************************************
190+
/* Defaulting for non-number scalar access
191+
/**********************************************************************
192+
*/
193+
194+
@Override
195+
public byte[] binaryValue() {
196+
return null;
197+
}
198+
199+
@Override
200+
public boolean booleanValue() {
201+
return false;
202+
}
203+
204+
@Override
205+
public boolean asBoolean() {
206+
return asBoolean(false);
207+
}
208+
209+
@Override
210+
public boolean asBoolean(boolean defaultValue) {
211+
return defaultValue;
212+
}
213+
214+
@Override
215+
public String asString(String defaultValue) {
216+
String str = asString();
217+
return (str == null) ? defaultValue : str;
218+
}
219+
50220
/*
51221
/**********************************************************************
52222
/* Basic definitions for non-container types
@@ -261,6 +431,59 @@ public String toPrettyString() {
261431
/**********************************************************************
262432
*/
263433

434+
protected <T> T _reportCoercionFail(String method, Class<?> targetType,
435+
String message)
436+
{
437+
throw JsonNodeException.from(this, "'%s' method `%s` cannot convert value %s to %s: %s",
438+
getClass().getSimpleName(), method,
439+
_valueDesc(), ClassUtil.nameOf(targetType), message);
440+
}
441+
442+
protected short _reportShortCoercionRangeFail(String method) {
443+
return _reportCoercionFail(method, Short.TYPE,
444+
"value not in 16-bit `short` range");
445+
}
446+
447+
protected int _reportIntCoercionRangeFail(String method) {
448+
return _reportCoercionFail(method, Integer.TYPE,
449+
"value not in 32-bit `int` range");
450+
}
451+
452+
protected long _reportLongCoercionRangeFail(String method) {
453+
return _reportCoercionFail(method, Long.TYPE,
454+
"value not in 64-bit `long` range");
455+
}
456+
457+
protected float _reportFloatCoercionRangeFail(String method) {
458+
return _reportCoercionFail(method, Float.TYPE,
459+
"value not in 32-bit `float` range");
460+
}
461+
462+
protected double _reportDoubleCoercionRangeFail(String method) {
463+
return _reportCoercionFail(method, Double.TYPE,
464+
"value not in 64-bit `double` range");
465+
}
466+
467+
protected short _reportShortCoercionFractionFail(String method) {
468+
return _reportCoercionFail(method, Short.TYPE,
469+
"value has fractional part");
470+
}
471+
472+
protected int _reportIntCoercionFractionFail(String method) {
473+
return _reportCoercionFail(method, Integer.TYPE,
474+
"value has fractional part");
475+
}
476+
477+
protected long _reportLongCoercionFractionFail(String method) {
478+
return _reportCoercionFail(method, Long.TYPE,
479+
"value has fractional part");
480+
}
481+
482+
protected BigInteger _reportBigIntegerCoercionFractionFail(String method) {
483+
return _reportCoercionFail(method, BigInteger.class,
484+
"value has fractional part");
485+
}
486+
264487
/**
265488
* Helper method that throws {@link JsonNodeException} as a result of
266489
* this node being of wrong type
@@ -275,15 +498,16 @@ protected <T> T _reportWrongNodeType(String msgTemplate, Object...args) {
275498
/**********************************************************************
276499
*/
277500

278-
protected BigInteger _bigIntFromBigDec(BigDecimal value) {
279-
StreamReadConstraints.defaults().validateBigIntegerScale(value.scale());
280-
return value.toBigInteger();
281-
}
282-
283501
protected JsonPointer _jsonPointerIfValid(String exprOrProperty) {
284502
if (exprOrProperty.isEmpty() || exprOrProperty.charAt(0) == '/') {
285503
return JsonPointer.compile(exprOrProperty);
286504
}
287505
return null;
288506
}
507+
508+
/**
509+
* Method for implementation classes to return a short description of contained
510+
* value, to be used in error messages.
511+
*/
512+
protected abstract String _valueDesc();
289513
}

0 commit comments

Comments
 (0)