0

I am using Gson to convert my JSON data to a Map<String, Object>. My JSON has some integer (actually long) fields, and I want them to be parsed as long (obviously). However, Gson parses them as doubles. How can I make Gson parse them as longs/integers? I've seen How to deserialize a list using GSON or another JSON library in Java? but I don't want to create a strongly-typed custom class, I'll be using a Map. I've also seen Android: Gson deserializes Integer as Double and a few other questions which I've thought might be duplicates, but all the answers either point to creating a strongly-typed class, creating extra functions that play role in deserialization or using completely another library.

Isn't there a simple way in Google's own JSON serializer/deserializer that will simply deserialize an integer (yeah, a number without a dot at all) as an integer and not double, as it should have been as default in the first place? If I wanted to send a floating point, I'd be sending 2.0, not 2 from my server JSON. Why on Earth am I getting a double and how do I get rid of it?

UPDATE: Even though I've clearly explained, some people still don't understand the simple fact that I am not in for another library (e.g. Jackson) and I'm aware of the simple fact that any parser should be able to identify 2.0 as a floating-point and 2 as a pure integer and parse accordingly, so please stop pointing me to telling why it's that way because it's simply incorrect and is not an excuse not to parse integers correctly. So, no, this is not a duplicate of Gson. Deserialize integers as integers and not as doubles.

Community
  • 1
  • 1
Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389
  • Possible duplicate of [Gson. Deserialize integers as integers and not as doubles](http://stackoverflow.com/questions/17090589/gson-deserialize-integers-as-integers-and-not-as-doubles) this question have an answer on **why** and an **alternative** to use Jackson – Yazan Apr 10 '16 at 13:23
  • FWIW, Square's Moshi seems to default to the same behavior as Gson: When asked for a `JsonAdapter> adapter = moshi.adapter(Types.newParameterizedType(Map.class, String.class, Object.class))` that adapter will then parse "1000" as the Double `1000.0`. – david.mihola Apr 10 '16 at 14:19
  • @Yazan and I've **clearly** stated that I don't want to use another library and use Gson and any decent enough library should be able to differentiate between `2.0` and `2` as a float and int so that answer on **why** is irrelevant. I've read that question and this is *not* a duplicate. if there is no way of doing this using Gson itself, then the answer would be `no`. – Can Poyrazoğlu Apr 11 '16 at 05:41
  • well, last thing i recall your title was `Why does Gson deserialize my JSON's integer fields as Double` **WHY** the question i posted is clearly states WHY, not irrelevant, JSON HAVE NO INTEGER TYPE ONLY DOUBLE if you can't understand or accept that, it's your problem – Yazan Apr 11 '16 at 16:49
  • @Yazan it's not me who changed the title, someone else edited it. i do understand what it means at least as much as you do, don't worry. it still isn't relevant anyway. – Can Poyrazoğlu Apr 11 '16 at 16:51

1 Answers1

1

You can't.

Long answer

You can't override gson's built-in numbers converters.

I've made a short code test to peek under the hood which types gson tries to find a delegated converter.

package net.sargue.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.intellij.lang.annotations.Language;

import java.io.IOException;
import java.util.Map;

public class SO36528727 {
  public static void main(String[] args) {
    @Language("JSON")
    String json = "{\n" +
            "  \"anInteger\": 2,\n" +
            "  \"aDouble\": 2.0\n" +
            "}";

    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new LongDeserializerFactory())
            .create();
    Map<String, Object> m =
            gson.fromJson(json,
                          new TypeToken<Map<String, Object>>() {}.getType());

    System.out.println(m.get("aDouble").getClass());
    System.out.println(m.get("anInteger").getClass());
  }

  private static class LongDeserializerFactory
          implements TypeAdapterFactory
  {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      System.out.println("type = " + type);

      if (type.getRawType().equals(String.class)) {
        TypeAdapter<String> stringAdapter =
                gson.getDelegateAdapter(this, TypeToken.get(String.class));
        return new TypeAdapter<T>() {
          @Override
          public void write(JsonWriter out, T value) throws IOException {
            stringAdapter.write(out, (String) value);
          }

          @SuppressWarnings("unchecked")
          @Override
          public T read(JsonReader in) throws IOException {
            String s = stringAdapter.read(in);
            System.out.println("s = " + s);
            return (T) s;
          }
        };
      } else
        return null;
    }
  }
}

The execution result is this:

type = java.util.Map<java.lang.String, java.lang.Object>
type = java.lang.String
s = anInteger
s = aDouble
class java.lang.Double
class java.lang.Double

So, you can see that gson looks just for two converters: the whole Map<> thing and the basic String. But no Double or Integer or Number or even Object. So you CAN'T override it unless you override it from a higher place like when dealing with a Map. And that was answered on the thread you reference on the question.

Community
  • 1
  • 1
sargue
  • 5,695
  • 3
  • 28
  • 43
  • thanks, i think i'll try this and if I need more converters, just use the same pattern, or if I mess up, I think I'll go with another library as the final option. – Can Poyrazoğlu Apr 11 '16 at 16:54