Reputation: 367
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
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