Open 239 opened 10 years ago
Would a method isInteger
be supposed to indicate whether
(a) the value is a number without fractional part (as opposed to isFloatingPoint
)
This would include numbers that are out of range, the implementation would probably only check for the existence of a dot.
(b) the value fits into a Java integer (as opposed to isLong
, isFloat
, etc)
This would include values like 1e3
that cannot be parsed by Integer.parseInt()
. In order to provide those methods, minimal-json would have to implement parsing algorithms for different number types.
(c) the value can be parsed as int
Since parsing is the responsibility of the parser, this option doesn't seem to make a lot of sense.
Since (c) implies (a) and (b) I assume it would need to indicate both cases.
Using minimal-json values it's easy to check the value type before getting the value by using isObject()/isString()/...
so you can then use asObject()/asString()/...
.
But how to check properly whether the value can be transformed to integer, long, float or double if isNumber()
is true in all cases? Would this be a better workaround?
if (v.isNumber()) {
Long l = null;
Double d = null;
try {
l = v.asLong();
} catch (NumberFormatException e) {
d = v.asDouble();
}
}
It seems that you are trying to transform JSON into a corresponding Java model without knowing the "metamodel", i.e. the expected format for each key. You don't use the values right away (otherwise you'd know which type to expect). Instead you store them for later use, e.g. in a hash map. By doing so, you discard type information and need an instanceof switch again to process the values when you look them up later.
Instead of transforming values back and forth, how about keeping them as JsonValue
? In fact, JsonValue
is exactly this: a Java model that represents the parsed JSON without taking any information away.
As I commented in #25 I have a simple JSON editor that creates a JSpinner
for number values with a SpinnerNumberModel
according to the "number type":
SpinnerNumberModel(int value, int minimum, int maximum, int stepSize)
SpinnerNumberModel(double value, double minimum, double maximum, double stepSize)
After editing, the new value from the JSpinner
replaces the old value so I can't see a way to avoid transforming it. Although it's not a full transformation since the JSON value is kept all the time and only updated if the user wants to change it. There is no intanceof
involved thanks to the is...()
checking.
Maybe a corresponding asNumber()
method would fit better into the current system?
public Number asNumber() { return Double.parseDouble(string); }
A) If I do know what number type to expect from a value then I also could use:
Number n = v.asNumber();
int i = n.intValue(); / long l = n.longValue(); / double d = n.doubleValue();
B) If I don't know what type to expect then I still can use any of the methods above since they involve rounding or truncation when needed without worrying about exceptions.
Of course it would not solve my problem but I also don't see the meaning of isNumber()
in conjunction with asInt()
, asLong()
, asFloat()
and asDouble()
:
1) If a certain number type for a value is expected then there is no need for isNumber()
.
2) If the value type is not known then isNumber()
tells me only that it probably can be transformed by asDouble()
if the value is in double range. But then it's the same as v.asNumber().doubleValue()
.
Good points. I agree that a method Number asNumber()
would fit better with isNumber()
. We could parse numbers as BigDecimal
which extends Number
. asInt()
, asDouble()
etc. could remain as shortcuts for asNumber().intValue()
, asNumber().doubleValue()
etc.
Yes, BigDecimal
is even better suited for JSON numbers. Using lazy loading to avoid repeated parsing?
private BigDecimal number;
public Number asNumber() { return number == null ? number = new BigDecimal(string) : number; }
I thought about that too. The idea of minimal-json is to parse as fast as possible and to keep the footprint of the Java representation as small as possible. So yes, for the sake of parsing speed, number parsing should be done on demand when asNumber()
is called. Since BigDecimal
is immutable, the value could be cached and returned again. This would add at least the reference to the BigInteger
the footprint of the number class, even if the value is still null
. I'm not sure if this is worthwhile - however, I think I'll do some experiments and measurements over the weekend...
Why are methods like
isInteger()
missing? Are simplicity and minimalism the reasons? Right now there is onlyisNumber()
so I useadditionally as a workaround to check whether the number is an "integer" or not.