Chathura Edirisinghe
Chathura Edirisinghe

Reputation: 367

Retrofit Call has same name different data type

API call

@GET("users/{user_id}/grid")
    Call<ArrayList<Grid>> getGrid(@Path("user_id") Integer id, @Header("Authorization") String authHeader);

Grid.class
public class Grid {

        @SerializedName("category")
        @Expose
        private String category;

        @SerializedName("type")
        @Expose
        private String type;

        @SerializedName("title")
        @Expose
        private String title;

        @SerializedName("equation_list")
        @Expose
        private List<Integer> equationList = null;  // This is the issue
}

API response equation_list field contains Integer array or string. ex:

"equation_list": "7", or 
"equation_list": [7],

But i got exception

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 1586 path $[5].equation_list

How do i fulfill my requirement?

Upvotes: 1

Views: 1316

Answers (1)

Yavuz Tas
Yavuz Tas

Reputation: 354

I think you can create a type to handle both data types String and ArrayList. Then you can implement a custom JsonAdapter for GSON to handle the custom deserialization for this type.

Let's create EquationList derived from java.util.ArrayList

/**
 * Custom type to handle both String and ArrayList<Integer> types
 *
 * @author Yavuz Tas
 *
 */
public class EquationList extends ArrayList<Integer> {

}

After we implement JsonAdapter for EquationList type

/**
 * Custom JsonAdapter for GSON to handle {@link EquationList} converstion
 * 
 * @author Yavuz Tas
 *
 */
public class EquationListJsonAdapter extends TypeAdapter<EquationList> {

    @Override
    public void write(JsonWriter out, EquationList user) throws IOException {

        // Since we do not serialize EquationList by gson we can omit this part.
        // If you need you can check
        // com.google.gson.internal.bind.ObjectTypeAdapter class
        // read method for a basic object serialize implementation

    }

    @Override
    public EquationList read(JsonReader in) throws IOException {

        EquationList deserializedObject = new EquationList();

        // type of next token
        JsonToken peek = in.peek();

        // if the json field is string
        if (JsonToken.STRING.equals(peek)) {
            String stringValue = in.nextString();
            // convert string to integer and add to list as a value
            deserializedObject.add(Integer.valueOf(stringValue));
        }

        // if it is array then implement normal array deserialization
        if (JsonToken.BEGIN_ARRAY.equals(peek)) {
            in.beginArray();

            while (in.hasNext()) {
                String element = in.nextString();
                deserializedObject.add(Integer.valueOf(element));
            }

            in.endArray();
        }

        return deserializedObject;
    }
}

And last we register our adapter to our equationList field in Grid

public class Grid {

    @SerializedName("category")
    @Expose
    private String category;

    @SerializedName("type")
    @Expose
    private String type;

    @SerializedName("title")
    @Expose
    private String title;

    @JsonAdapter(value = EquationListJsonAdapter.class)
    @SerializedName("equation_list")
    @Expose
    private EquationList equationList;

}

This should handle your responses correctly like below

"equation_list": "7", or "equation_list": [7]

Please note that any String response automatically converted to Integer and added to EquationList as an list element. You can alter this behaivor by changing the implementation in read method of EquationListJsonAdapter.

I hope this helps. Cheers!

Upvotes: 2

Related Questions