Skip to content

Commit 11ecff1

Browse files
authored
add asShort(), asFloat() conversion methods with tests (#5138)
1 parent 9a2db4e commit 11ecff1

23 files changed

+1024
-136
lines changed

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

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,19 @@ public final boolean isBinary() {
461461
return getNodeType() == JsonNodeType.BINARY;
462462
}
463463

464+
/**
465+
* Method that can be used to check whether this node is a numeric
466+
* node ({@link #isNumber} would return true)
467+
* AND can be converted without loss to {@code short} (that is, its value fits
468+
* in Java's 16-bit signed integer type, {@code short} and
469+
* if it is a floating-point number, it does not have fractional part).
470+
*<p>
471+
* NOTE: this method does not consider possible value type conversion
472+
* from non-number types like JSON String into Number; so even if this method returns false,
473+
* it is possible that {@link #asShort} could still succeed.
474+
*/
475+
public boolean canConvertToShort() { return false; }
476+
464477
/**
465478
* Method that can be used to check whether this node is a numeric
466479
* node ({@link #isNumber} would return true)
@@ -730,6 +743,51 @@ public String asText(String defaultValue) {
730743
*/
731744
public abstract short shortValue();
732745

746+
/**
747+
* Method similar to {@link #shortValue()}, but that will return specified
748+
* {@code defaultValue} if this node cannot be converted to Java {@code short}.
749+
*
750+
* @param defaultValue Value to return if this node cannot be converted to Java {@code short}
751+
*
752+
* @return Java {@code short} value this node represents, if possible to accurately represent;
753+
* {@code defaultValue} otherwise
754+
*/
755+
public abstract short shortValue(short defaultValue);
756+
757+
/**
758+
* Method similar to {@link #shortValue()} but in addition to coercing Number
759+
* values (same as {@link #shortValue()}), will also try to coerce a
760+
* couple of additional types (or cases):
761+
* <ul>
762+
* <li>JSON Floating-point numbers with fractions (ones without fractions
763+
* are ok for {@link #shortValue()}) will be truncated to {@code short}
764+
* (if (and only if) they fit in {@code short} range).
765+
* </li>
766+
* <li>JSON Strings that represent JSON Numbers ("stringified" numbers)
767+
* </li>
768+
* <li>JSON Null (converted to {@code 0}))
769+
* </li>
770+
* <li>POJO nodes that contain Number values
771+
* </li>
772+
* </ul>
773+
*
774+
* @return {@code short} value this node represents, if possible to accurately represent
775+
*
776+
* @throws JsonNodeException if node value cannot be converted to {@code short}
777+
*/
778+
public abstract short asShort();
779+
780+
/**
781+
* Method similar to {@link #shortValue()}, but that will return specified
782+
* {@code defaultValue} if this node cannot be converted to {@code short}.
783+
*
784+
* @param defaultValue Value to return if this node cannot be converted to {@code short}
785+
*
786+
* @return {@code short} value this node represents, if possible to accurately represent;
787+
* {@code defaultValue} otherwise
788+
*/
789+
public abstract short asShort(short defaultValue);
790+
733791
// // Scalar access: Numbers, Java int
734792

735793
/**
@@ -1013,6 +1071,45 @@ public String asText(String defaultValue) {
10131071
*/
10141072
public abstract float floatValue();
10151073

1074+
/**
1075+
* Method similar to {@link #floatValue()}, but that will return specified
1076+
* {@code defaultValue} if this node cannot be converted to {@code float}.
1077+
*
1078+
* @param defaultValue Value to return if this node cannot be converted to {@code float}
1079+
*
1080+
* @return {@code float} value this node represents, if possible to accurately represent;
1081+
* {@code defaultValue} otherwise
1082+
*/
1083+
public abstract float floatValue(float defaultValue);
1084+
1085+
/**
1086+
* Method similar to {@link #floatValue()} but in addition to coercing Number
1087+
* values will also try coerce couple of additional types:
1088+
* <ul>
1089+
* <li>JSON String that represents JSON Numbers ("stringified" numbers)
1090+
* </li>
1091+
* <li>JSON Null (converted to {@code 0.0f})
1092+
* </li>
1093+
* <li>POJO nodes that contain Number values
1094+
* </li>
1095+
* </ul>
1096+
*<p>
1097+
*
1098+
* @return {@code float} value this node represents, if possible to accurately represent
1099+
*
1100+
* @throws JsonNodeException if node value cannot be converted to {@code float}
1101+
*/
1102+
public abstract float asFloat();
1103+
1104+
/**
1105+
* Method similar to {@link #asFloat()}, but that will return {@code defaultValue}
1106+
* if this node cannot be coerced to {@code float}.
1107+
*
1108+
* @return {@code float} value this node represents,
1109+
* if possible to accurately represent; {@code defaultValue} otherwise
1110+
*/
1111+
public abstract float asFloat(float defaultValue);
1112+
10161113
// // Scalar access: Numbers, Java double
10171114

10181115
/**

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ public short shortValue() {
7070
return _reportCoercionFail("shortValue()", Short.TYPE, "value type not numeric");
7171
}
7272

73+
@Override
74+
public short shortValue(short defaultValue) {
75+
// Overridden by NumericNode, for other types return default
76+
return defaultValue;
77+
}
78+
79+
@Override
80+
public short asShort() {
81+
return _reportCoercionFail("asShort()", Short.TYPE, "value type not numeric");
82+
}
83+
84+
@Override
85+
public short asShort(short defaultValue) {
86+
// Overridden by NumericNode, for other types return default
87+
return defaultValue;
88+
}
89+
7390
@Override
7491
public int intValue() {
7592
return _reportCoercionFail("intValue()", Integer.TYPE, "value type not numeric");
@@ -177,6 +194,23 @@ public float floatValue() {
177194
return _reportCoercionFail("floatValue()", Float.TYPE, "value type not numeric");
178195
}
179196

197+
@Override
198+
public float floatValue(float defaultValue) {
199+
// Overridden by NumericNode, for other types return default
200+
return defaultValue;
201+
}
202+
203+
@Override
204+
public float asFloat() {
205+
return _reportCoercionFail("asFloat()", Float.TYPE, "value type not numeric");
206+
}
207+
208+
@Override
209+
public float asFloat(float defaultValue) {
210+
// Overridden by NumericNode, for other types return default
211+
return defaultValue;
212+
}
213+
180214
@Override
181215
public double doubleValue() {
182216
return _reportCoercionFail("doubleValue()", Double.TYPE, "value type not numeric");

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

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ public class BigIntegerNode
1919
{
2020
private static final long serialVersionUID = 3L;
2121

22-
private final static BigInteger MIN_INTEGER = BigInteger.valueOf(Integer.MIN_VALUE);
23-
private final static BigInteger MAX_INTEGER = BigInteger.valueOf(Integer.MAX_VALUE);
24-
private final static BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
25-
private final static BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
26-
2722
final protected BigInteger _value;
2823

2924
/*
@@ -72,6 +67,32 @@ public Number numberValue() {
7267
return _value;
7368
}
7469

70+
@Override
71+
public short shortValue() {
72+
if (_inShortRange()) {
73+
return (short) _value.intValue();
74+
}
75+
return _reportShortCoercionRangeFail("shortValue()");
76+
}
77+
78+
@Override
79+
public short shortValue(short defaultValue) {
80+
return _inShortRange() ? (short) _value.intValue() : defaultValue;
81+
}
82+
83+
@Override
84+
public short asShort() {
85+
if (_inShortRange()) {
86+
return (short) _value.intValue();
87+
}
88+
return _reportShortCoercionRangeFail("asShort()");
89+
}
90+
91+
@Override
92+
public short asShort(short defaultValue) {
93+
return _inShortRange() ? (short) _value.intValue() : defaultValue;
94+
}
95+
7596
@Override
7697
public int intValue() {
7798
if (_inIntRange()) {
@@ -166,6 +187,27 @@ public float floatValue() {
166187
return _reportFloatCoercionRangeFail("floatValue()");
167188
}
168189

190+
@Override
191+
public float floatValue(float defaultValue) {
192+
float f = _asFloatValueUnchecked();
193+
return (Float.isFinite(f)) ? f : defaultValue;
194+
}
195+
196+
@Override
197+
public float asFloat() {
198+
float f = _asFloatValueUnchecked();
199+
if (Float.isFinite(f)) {
200+
return f;
201+
}
202+
return _reportFloatCoercionRangeFail("asFloat()");
203+
}
204+
205+
@Override
206+
public float asFloat(float defaultValue) {
207+
float f = _asFloatValueUnchecked();
208+
return (Float.isFinite(f)) ? f : defaultValue;
209+
}
210+
169211
@Override
170212
public double doubleValue() {
171213
double d = _asDoubleValueUnchecked();
@@ -252,23 +294,20 @@ protected double _asDoubleValueUnchecked() {
252294

253295
@Override
254296
protected boolean _inShortRange() {
255-
if (_inIntRange()) {
256-
int v = _value.intValue();
257-
return (v >= Short.MIN_VALUE && v <= Short.MAX_VALUE);
258-
}
259-
return false;
297+
return (_value.compareTo(BI_MIN_SHORT) >= 0)
298+
&& (_value.compareTo(BI_MAX_SHORT) <= 0);
260299
}
261300

262301
@Override
263302
public boolean _inIntRange() {
264-
return (_value.compareTo(MIN_INTEGER) >= 0)
265-
&& (_value.compareTo(MAX_INTEGER) <= 0);
303+
return (_value.compareTo(BI_MIN_INTEGER) >= 0)
304+
&& (_value.compareTo(BI_MAX_INTEGER) <= 0);
266305
}
267306

268307
@Override
269308
protected boolean _inLongRange() {
270-
return (_value.compareTo(MIN_LONG) >= 0)
271-
&& (_value.compareTo(MAX_LONG) <= 0);
309+
return (_value.compareTo(BI_MIN_LONG) >= 0)
310+
&& (_value.compareTo(BI_MAX_LONG) <= 0);
272311
}
273312

274313
/*

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@ protected String _asString() {
111111
return _value ? "true" : "false";
112112
}
113113

114-
@Override
115-
public long asLong(long defaultValue) {
116-
return _value ? 1L : 0L;
117-
}
118-
119114
/*
120115
/**********************************************************************
121116
/* Overridden JsonNode methods, other

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ public class DecimalNode
2020

2121
public static final DecimalNode ZERO = new DecimalNode(BigDecimal.ZERO);
2222

23-
private final static BigDecimal MIN_SHORT = BigDecimal.valueOf(Short.MIN_VALUE);
24-
private final static BigDecimal MAX_SHORT = BigDecimal.valueOf(Short.MAX_VALUE);
25-
private final static BigDecimal MIN_INTEGER = BigDecimal.valueOf(Integer.MIN_VALUE);
26-
private final static BigDecimal MAX_INTEGER = BigDecimal.valueOf(Integer.MAX_VALUE);
27-
private final static BigDecimal MIN_LONG = BigDecimal.valueOf(Long.MIN_VALUE);
28-
private final static BigDecimal MAX_LONG = BigDecimal.valueOf(Long.MAX_VALUE);
29-
3023
final protected BigDecimal _value;
3124

3225
/*
@@ -87,6 +80,33 @@ public float floatValue() {
8780
return _reportFloatCoercionRangeFail("floatValue()");
8881
}
8982

83+
@Override
84+
public float floatValue(float defaultValue) {
85+
float f = _value.floatValue();
86+
if (Float.isFinite(f)) {
87+
return f;
88+
}
89+
return defaultValue;
90+
}
91+
92+
@Override
93+
public float asFloat() {
94+
float f = _value.floatValue();
95+
if (Float.isFinite(f)) {
96+
return f;
97+
}
98+
return _reportFloatCoercionRangeFail("asFloat()");
99+
}
100+
101+
@Override
102+
public float asFloat(float defaultValue) {
103+
float f = _value.floatValue();
104+
if (Float.isFinite(f)) {
105+
return f;
106+
}
107+
return defaultValue;
108+
}
109+
90110
@Override
91111
public double doubleValue() {
92112
double d = _value.doubleValue();
@@ -201,17 +221,17 @@ protected boolean _hasFractionalPart() {
201221

202222
@Override
203223
protected boolean _inShortRange() {
204-
return (_value.compareTo(MIN_SHORT) >= 0) && (_value.compareTo(MAX_SHORT) <= 0);
224+
return (_value.compareTo(BD_MIN_SHORT) >= 0) && (_value.compareTo(BD_MAX_SHORT) <= 0);
205225
}
206226

207227
@Override
208228
protected boolean _inIntRange() {
209-
return (_value.compareTo(MIN_INTEGER) >= 0) && (_value.compareTo(MAX_INTEGER) <= 0);
229+
return _inLongRange() && (_value.compareTo(BD_MIN_INTEGER) >= 0) && (_value.compareTo(BD_MAX_INTEGER) <= 0);
210230
}
211231

212232
@Override
213233
protected boolean _inLongRange() {
214-
return (_value.compareTo(MIN_LONG) >= 0) && (_value.compareTo(MAX_LONG) <= 0);
234+
return (_value.compareTo(BD_MIN_LONG) >= 0) && (_value.compareTo(BD_MAX_LONG) <= 0);
215235
}
216236

217237
/*

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,33 @@ public float floatValue() {
7777
return _reportFloatCoercionRangeFail("floatValue()");
7878
}
7979

80+
@Override
81+
public float floatValue(float defaultValue) {
82+
float f = (float) _value;
83+
if (Float.isFinite(f)) {
84+
return f;
85+
}
86+
return defaultValue;
87+
}
88+
89+
@Override
90+
public float asFloat() {
91+
float f = (float) _value;
92+
if (Float.isFinite(f)) {
93+
return f;
94+
}
95+
return _reportFloatCoercionRangeFail("asFloat()");
96+
}
97+
98+
@Override
99+
public float asFloat(float defaultValue) {
100+
float f = (float) _value;
101+
if (Float.isFinite(f)) {
102+
return f;
103+
}
104+
return defaultValue;
105+
}
106+
80107
@Override
81108
public double doubleValue() {
82109
return _value;

0 commit comments

Comments
 (0)