3

Summary

I've been using Retrofit and Gson in my android app for a while but the IDs I get from the server are 13 digit numbers. Gson automatically converts those numbers to scientific notation, then casts it to String/Long, whatever I specify.

Here is a sample Retrofit class with an ID

public class User implements Serializable {

    @SerializedName("accessToken")
    @Expose
    public String accessToken;

    @SerializedName("userId")
    @Expose
    public String userId; //This is where it casts it into a Scientific notation

    @SerializedName("userRole")
    @Expose
    public int userRole;

    @SerializedName("name")
    @Expose
    public String name;

    @SerializedName("mobile")
    @Expose
    public String mobile;

    @SerializedName("countryId")
    @Expose
    public String countryId; //Here too

    @SerializedName("email")
    @Expose
    public String email;

    @SerializedName("username")
    @Expose
    public String username;


}

This is the Screenshot I got from the debugger

User implements Serializable Response

Solutions I've tried

This doesn't work for some reason

How to prevent Gson from converting a long number (a json string ) to scientific notation format?

As I've checked the debugger, my control flow never goes into serialize(Double src, Type typeOfSrc, JsonSerializationContext context)

switch off scientific notation in Gson double serialization

    @Override
    public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
        if(src == src.longValue())
            return new JsonPrimitive(src.longValue());          
        return new JsonPrimitive(src);
    }

Another solution I've tried

How to prevent Gson from expressing integers as floats

And this is my current RetrofitBuilder Method

        Retrofit.Builder rBuilder = new Builder();
        rBuilder.baseUrl(API_URL);
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {
                @Override
                public JsonElement serialize(final Double src, final Type typeOfSrc, final JsonSerializationContext context) {
                    BigDecimal value = BigDecimal.valueOf(src);
                    return new JsonPrimitive(value);
                }
            });
        gsonBuilder.registerTypeAdapter(Long.class,  new JsonSerializer<Long>() {
                @Override
                public JsonElement serialize(final Long src, final Type typeOfSrc, final JsonSerializationContext context) {
                    BigDecimal value = BigDecimal.valueOf(src);
                    return new JsonPrimitive(value);
                }
            });

        rBuilder.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()));

Any kind of help anywhere would be highly appreciated.

Sharukh Mohammed
  • 365
  • 2
  • 16
  • 1
    But where is the Long coming from? Both `countryId` and `userId` are Strings. Gson should not try to serialize these are Longs. – Fred Oct 22 '18 at 09:04
  • Exactly. It still does catch them as long, then to a Scientific notation and then casts it to String or Long as I've specified. – Sharukh Mohammed Oct 23 '18 at 05:44
  • Ok, so just to make sure. In the Json you receive they are longs, but you treat them as strings. Correct? – Fred Oct 23 '18 at 06:05
  • Right, because I don't want to do any operations on it, just store them or send back to the server. – Sharukh Mohammed Oct 23 '18 at 06:55
  • 1
    I can't really reproduce this. If I try `gson.fromJson("""{"countryId": 1234567891234}""", User::class.java)` and print out the serialization witht the same `gson` instance, everything serializes as you want (no scientific notation). The only way I get scientific notation is by using a map `gson.fromJson("""{"countryId": 1234567891234}""", Map::class.java)`, which from the debugger screenshot looks like what you're doing. It says `LinkedTreeMap`. Can you confirm this? – Fred Oct 23 '18 at 08:19
  • I am using Retrofit along with the parser as Gson Converter, so it _automatically_ takes it as a `LinkedHashMap`. I tried adding a `TypeAdapter` with gsonBuilder.registerTypeAdapter (as shown in tried solutions) at the time of Retrofit creation, but it never gets called for some reason. – Sharukh Mohammed Oct 23 '18 at 09:43
  • But if the return type of the retrofit call is `User`, then retrofit should use `User` as far as I know. How's your call declared? – Fred Oct 23 '18 at 12:47
  • Please let us continue this discussion in the chat – Sharukh Mohammed Oct 23 '18 at 13:19

1 Answers1

0

Just in case someone might run into the same problem,

I was using a Wrapper-Class for the response, of which the Data Type was specified was Object. For this, Gson was trying to convert it to Scientific notation no matter what.

I must actually use JsonElement from Gson

public class GenericResponse_ implements Serializable {

    @SerializedName("status")
    @Expose
    public int status;

    @SerializedName("error")
    @Expose
    public String error;

    @SerializedName("data")
    @Expose
    public JsonElement data; //This was of type Object, changed to JsonElement
}
Sharukh Mohammed
  • 365
  • 2
  • 16