Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonReader API call to determine whether Number was specified as whole number (no period) or floating-point (period) #2217

Closed
jernst opened this issue Oct 8, 2022 · 6 comments

Comments

@jernst
Copy link

jernst commented Oct 8, 2022

I'd like to be able to tell the difference between
{ "x" : 17 }
and
{ "x" : 17.0 }
You internally distinguish between those two, but there is no API that exposes this. It might be as simple as adding a call:
boolean peekIsWholeNumber()

@Marcono1234
Copy link
Collaborator

Marcono1234 commented Oct 8, 2022

Possibly a duplicate of #1621

Are you really working directly with JsonReader or are you using one of the Gson methods and actually want to deserialize a Java Number (or Object)? In the latter case you can probably use ToNumberStrategy / ToNumberPolicy introduced by #1290.

If you are working directly with a JsonReader you could use its nextString() method. This will also work for JSON numbers and lets you determine whether the number is an integer or a floating point number and perform the parsing yourself.

It would be good if you could explain your use case a bit more in detail or provide the code you have so far.

@jernst
Copy link
Author

jernst commented Oct 9, 2022

I'm attempting to make best possible sense out of a wide variety of JSON files whose provenance is not entirely clear, and there is no documentation. First thing I need is to faithfully "read it in" so then I can throw some smarts at it to figure out what it might possibly mean. If the first step is already losing information, the second steps become harder.

I read through the code and I'm now attempting to read as Long, and if that throws, I retry as Double. That gives me a workaround.

@Marcono1234
Copy link
Collaborator

I read through the code and I'm now attempting to read as Long, and if that throws, I retry as Double. That gives me a workaround.

Your workaround might not work as desired when the number has 0 as decimal place, such as the 17.0 in your example. nextLong() internally falls back to reading as Double:

double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
long result = (long) asDouble;
if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
throw new NumberFormatException("Expected a long but was " + peekedString + locationString());
}

I think checking first for peek() == JsonToken.NUMBER and then calling nextString() as proposed above would give you better results. You could then also check if the number has an exponent, maybe that provides further insight into the structure of your data.

@jernst
Copy link
Author

jernst commented Oct 11, 2022

Gotcha. You are right :-)

@Marcono1234
Copy link
Collaborator

Do you think this issue can be closed? I think for inspecting the exact number format the approach of checking nextString() is the most versatile one.

One issue with a peekIsWholeNumber() method (or similar) is that its name might be misleading; for example one might consider 17.0 a whole number, but in your use case that is not desired.

I am not sure what other situations exist where it is really necessary to peek the number type. In all cases the nextString() approach will likely give you more possibilities and allows you to decide how to parse it, e.g. as BigDecimal. peekIsWholeNumber() might also give the wrong impression that calling nextDouble() will succeed while it could in theory be the case that the number is too large for a double, causing precision loss.

@jernst
Copy link
Author

jernst commented Oct 12, 2022

Whatever I can suggest now would break the existing API, and so I won't. Ok, closing.

@jernst jernst closed this as completed Oct 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants