1

Getting Gson NumberFormatExcepption even if Json is correct

{
    "IsMissCallLogin": true,
    "IsOfficialSurname": true,
    "IsGotraInRegRequest": false,
    "SubCasteLabel": "SubCaste",
    "MissCallWaitSeconds": 7,
    "IsFBAccountKit": true,
    "Status": 1,
    "Message": "Success",
    "Navigation": "KeepSame"
}

Using Gson gradle as

compile 'com.google.code.gson:gson:2.7'

And the exception is

NumberFormatException : Thread:main
Exception:com.google.gson.JsonSyntaxException:
java.lang.NumberFormatException: empty String at
com.google.gson.internal.a.s$34.b(Unknown Source) at
com.google.gson.internal.a.s$34.a(Unknown Source) at
com.google.gson.internal.a.k$1.a(Unknown Source) at
com.google.gson.internal.a.l.a(Unknown Source) at
com.google.gson.d.a(Unknown Source) at
com.google.gson.d.a(Unknown Source) at 
com.google.gson.d.a(Unknown Source)

Model Class

public class GetUIConfigResponse {
    public boolean IsMissCallLogin;
    public boolean IsOfficialSurname;
    public boolean IsGotraInRegRequest;
    public String SubCasteLabel;
    public int MissCallWaitSeconds;
    public boolean IsFBAccountKit;
    public int Status;
    public String Message;
    public String Navigation;

    public GetUIConfigResponse() {
        IsMissCallLogin = true;
        IsOfficialSurname = true;
        IsGotraInRegRequest = false;
        SubCasteLabel = "SubCaste";

        Status = 0;
        Message = "";
        Navigation = "";
        MissCallWaitSeconds = 5;

        IsFBAccountKit = false;
    }
}
Community
  • 1
  • 1
Giru Bhai
  • 14,370
  • 5
  • 46
  • 74

3 Answers3

0

This is how you should make your pojo class when using Gson. The provided annotation are good and handy to use.

 public class GroupMemberListingResponse {

    @SerializedName("IsMissCallLogin")
    @Expose
    private boolean isMissCallLogin;
    @SerializedName("IsOfficialSurname")
    @Expose
    private boolean isOfficialSurname;
    @SerializedName("IsGotraInRegRequest")
    @Expose
    private boolean isGotraInRegRequest;
    @SerializedName("SubCasteLabel")
    @Expose
    private String subCasteLabel;
    @SerializedName("MissCallWaitSeconds")
    @Expose
    private int missCallWaitSeconds;
    @SerializedName("IsFBAccountKit")
    @Expose
    private boolean isFBAccountKit;
    @SerializedName("Status")
    @Expose
    private int status;
    @SerializedName("Message")
    @Expose
    private String message;
    @SerializedName("Navigation")
    @Expose
    private String navigation;

    public boolean isIsMissCallLogin() {
    return isMissCallLogin;
    }

    public void setIsMissCallLogin(boolean isMissCallLogin) {
    this.isMissCallLogin = isMissCallLogin;
    }

    public boolean isIsOfficialSurname() {
    return isOfficialSurname;
    }

    public void setIsOfficialSurname(boolean isOfficialSurname) {
    this.isOfficialSurname = isOfficialSurname;
    }

    public boolean isIsGotraInRegRequest() {
    return isGotraInRegRequest;
    }

    public void setIsGotraInRegRequest(boolean isGotraInRegRequest) {
    this.isGotraInRegRequest = isGotraInRegRequest;
    }

    public String getSubCasteLabel() {
    return subCasteLabel;
    }

    public void setSubCasteLabel(String subCasteLabel) {
    this.subCasteLabel = subCasteLabel;
    }

    public int getMissCallWaitSeconds() {
    return missCallWaitSeconds;
    }

    public void setMissCallWaitSeconds(int missCallWaitSeconds) {
    this.missCallWaitSeconds = missCallWaitSeconds;
    }

    public boolean isIsFBAccountKit() {
    return isFBAccountKit;
    }

    public void setIsFBAccountKit(boolean isFBAccountKit) {
    this.isFBAccountKit = isFBAccountKit;
    }

    public int getStatus() {
    return status;
    }

    public void setStatus(int status) {
    this.status = status;
    }

    public String getMessage() {
    return message;
    }

    public void setMessage(String message) {
    this.message = message;
    }

    public String getNavigation() {
    return navigation;
    }

    public void setNavigation(String navigation) {
    this.navigation = navigation;
    }

    }
Amardeep
  • 1,414
  • 11
  • 18
  • There are things which are not mandatory but we follow them for good code practices.Hence act accordingly. Its good and up to you whether you harness the power which a library gives to you or not. – Amardeep Feb 07 '18 at 08:05
  • But using Annotation it will take more time in respect to without annotation.BTW the question is about numberformatexception of Gson and this answer not relate to it. – Giru Bhai Feb 07 '18 at 08:10
  • I have to agree with @GiruBhai here. It only makes sense to provide annotations when your variable name is different than the key in the json. This is not the case, so providing the annotations won't solve the problem – Iulian Popescu Feb 07 '18 at 08:26
  • In that case please check for your JSON , Either you are using a wrong key to parse the data(JsonSyntaxException) or you are trying to parse an String value in a number, where that number might be an int , a float , or any other Java numeric type.(NumberFormatException). Rest the information provided is insufficient to find anything out of it. Either you are parsing it incorrect or the server is sending the incorrect json which is not similar to one you posted. – Amardeep Feb 07 '18 at 08:48
  • This was my assumption too. I provided an answer that should in theory solve this issue. – Iulian Popescu Feb 07 '18 at 08:53
  • I have gone through it. it seems correct, but it is a tiresome solution considering the fact that there will be large json files too and has to be applied for all web-service too as well as we will have to write too much boiler plate code. If you consider this particular case it might be a solution that will work but we cant gaurente it wont occur in other hence the same custom deserializer thing will have to be done for all. – Amardeep Feb 07 '18 at 08:57
  • @Amardeep as you told `Either you are parsing it incorrect or the server is sending the incorrect json`. I am Parsing correctly if not then how it work for 99% users.And the JSON I posted is actually JSON. – Giru Bhai Feb 07 '18 at 10:00
0

I think that there are two solutions for this:

  1. Talk with the person responsible for the Json and ask them to double check that in all cases they are responding with the proper value for a given field. I had this issue a while back, but I was receiving null instead of an integer. This is the easiest solution and you don't have to do code anything. Also, this solution will fix the crash for all users.
  2. Write a custom parser for that class. When you are using Gson to parse a given class, you can write a custom TypeAdapter that instructs Gson how to parse your Json. My implementation for your class looks like this:

    public static class ResponseAdapter extends TypeAdapter<GetUIConfigResponse> {
    
    @Override
    public void write(JsonWriter jsonWriter, GetUIConfigResponse response) throws IOException {
        // In case that you need to serialize the class again
        // take a look at http://www.javacreed.com/gson-typeadapter-example/
    }
    
    @Override
    public GetUIConfigResponse read(JsonReader jsonReader) throws IOException {
        GetUIConfigResponse response = new GetUIConfigResponse();
        jsonReader.beginObject();
        while (jsonReader.hasNext()) {
            switch (jsonReader.nextName()) {
                case "IsMissCallLogin":
                    response.setIsMissCallLogin(jsonReader.nextBoolean());
                    break;
                case "IsOfficialSurname":
                    response.setIsOfficialSurname(jsonReader.nextBoolean());
                    break;
                case "IsGotraInRegRequest":
                    response.setIsGotraInRegRequest(jsonReader.nextBoolean());
                    break;
                case "SubCasteLabel":
                    response.setSubCasteLabel(jsonReader.nextString());
                    break;
                case "MissCallWaitSeconds":
                    String waitString = jsonReader.nextString();
                    try {
                        int number = Integer.parseInt(waitString);
                        response.setMissCallWaitSeconds(number);
                    } catch (NumberFormatException ex) {
                        // in case of string set the field to a default value
                        response.setMissCallWaitSeconds(5);
                    }
                    break;
                case "IsFBAccountKit":
                    response.setIsFBAccountKit(jsonReader.nextBoolean());
                    break;
                case "Status":
                    String statusString = jsonReader.nextString();
                    try {
                        int number = Integer.parseInt(statusString);
                        response.setStatus(number);
                    } catch (NumberFormatException ex) {
                        // in case of string set the field to a default value
                        response.setStatus(0);
                    }
                    break;
                case "Message":
                    response.setMessage(jsonReader.nextString());
                    break;
                case "Navigation":
                    response.setNavigation(jsonReader.nextString());
                    break;
                default:
                    jsonReader.skipValue();
    
            }
        }
        jsonReader.endObject();
        return response;
    }
    }
    

Then I parsed the Json like this (I read the Json from a local file, hence the variable inputStreamReader):

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(GetUIConfigResponse.class, new ResponseAdapter());
Gson gson = gsonBuilder.create();
GetUIConfigResponse model =  gson.fromJson(inputStreamReader, GetUIConfigResponse.class);

With this code, everything should be parsed properly and if a integer field has a string value, it is converted to int (if possible). If it is not possible to convert it, then I set some default values found in the constructor of your class. An advantage of this solution is that it prevents future scenarios like this (only for these fields), but if your app is already launched, then you might find this crash again for the users that didn't update the app yet.

Iulian Popescu
  • 2,595
  • 4
  • 23
  • 31
0
    public class LongTypeAdapter extends TypeAdapter<Long>{
    @Override
    public Long read(JsonReader reader) throws IOException {
        if(reader.peek() == JsonToken.NULL){
            reader.nextNull();
            return null;
        }
        String stringValue = reader.nextString();
        try{
            Long value = Long.valueOf(stringValue);
            return value;
        }catch(NumberFormatException e){
            return null;
        }
    }
    @Override
    public void write(JsonWriter writer, Long value) throws IOException {
        if (value == null) {
            writer.nullValue();
            return;
        }
        writer.value(value);
    }
}

Use it like

 Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new LongTypeAdapter()).create();
Amardeep
  • 1,414
  • 11
  • 18
  • Thanks to answer, why to create one more class if this JSON is working for 99% users.It gives exception **occasionally**. – Giru Bhai Feb 07 '18 at 10:04