berserk
berserk

Reputation: 2728

Gson converting int into double when parsing json string

I have this JSON file into my assets. I am parsing it using Gson into the following model class:

public class SearchRequest {

    private ArrayList<String> _source;
    private int from;
    private int size;
    private Object sort;
    private Object query;


    public void setFrom(int from) {
        this.from = from;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public void setArtist(String artistName) {
        Gson gson = new Gson();
        JsonObject object = gson.toJsonTree(query).getAsJsonObject();
        JsonArray should = object.getAsJsonObject("function_score").getAsJsonObject("query")
                .getAsJsonObject("bool").getAsJsonArray("should");
        should.get(0).getAsJsonObject().getAsJsonObject("match").addProperty("album_artist", artistName);
        should.get(1).getAsJsonObject().getAsJsonObject("nested").getAsJsonObject("query")
                .getAsJsonObject("bool").getAsJsonArray("must").get(0).getAsJsonObject()
                .getAsJsonObject("match").addProperty("tracks.artist", artistName);
        query = gson.fromJson(object.toString(), query.getClass());
    }
}

When I convert this JSON into an object of this class, the query object becomes a LinkedTreeMap. But in this conversion, the key offset which is an integer, becomes double. In my JSON (line number 50), offset is 0, but after conversion, its 0.0. Screenshot:

enter image description here

Why is this happening? How to fix this?

Upvotes: 2

Views: 5688

Answers (1)

Lyubomyr Shaydariv
Lyubomyr Shaydariv

Reputation: 21115

How to fix this?

It's not a subject to be fixed and nothing to be worried about.

Why is this happening?

Your JSON<->Java mapping does not provide any mappings except the top-most one. That makes Gson work like that due to lack of the target type information, and LinkedTreeMap is used internally. Literals like 0 that may look like integers are also legal floating point values from the JSON format point of view: the JSON specification declares numbers only, and does not make any corrections on "integerness". Having no enough information on deserializing the data types, Gson applies the default parsing policies, and chooses java.lang.Double as a type that can hold any other standard numeric values that can hold less significance bits (longs can fit the room of doubles easily; but not sure what Gson does for BigDecimals -- JSON specifications does not seem to make any limits). So this is just internal Gson representation and you have a few options on that:

  • You can declare a mapping (write or generate by a specialized tool) that would even avoid internal LinkedTreeMaps. Tedious? Maybe. But much more power in type safety, javac control, or your favorite IDE navigation and suggestions.
  • Gson provides a bunch of methods to convert a JSON tree value to a target type: getAsJsonObject(), getAsJsonArray(), getAsInt(), and more allowing to get the target object in the representation you want. For example,
final Object value = searchRequest.query
        .get("function_score").getAsJsonObject()
        .get("functions").getAsJsonArray()
        .get(0).getAsJsonObject()
        .get("linear").getAsJsonObject()
        .get("date").getAsJsonObject()
        .get("offset").getAsInt();
System.out.println(value + " " + value.getClass());

gives:

0 class java.lang.Integer

because of get("offset").getAsInt() that's internally implemented as return isNumber() ? getAsNumber().intValue() : ...; for JSON primitives.

  • You can apply partial mappings. For example, you can extract the date JSON tree and convert it to a special mapping having the private int offset; field declared: gson.fromJson(dateJsonObject, DateMapping.class).

Again, Gson just does not have enough type information and works really fine.

Upvotes: 1

Related Questions