I've had some trouble deserializing an object that contains 0 to many child objects that can either contains a string or a string array for a particular value.
Here's an example JSON
{
"name": "process name",
"tasks": [{
"name": "task 1",
"fields": [{
"name": "field 1",
"value": "123abc"
},
{
"name": "field 2",
"value": ["value 1", "value 2"]
}
]
},
{
"name": "task 2",
"fields": []
}]
}
I have a Java entity setup to match this structure like this:
public class Process {
public Process() {}
public String name;
public Task[] tasks;
}
public class Task {
public Task() {}
public String name;
public Field[] fields;
}
public class Field {
public Field() field;
public String name;
public String value;
}
And I deserialize like such:
static <T> T fetch(MyHttpRequest request, Class<T> entity)
{
String response = sendRequestAndParse(request);
if (response == null) {
log.debug(String.format("API response was null %n)"));
return null;
}
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
return gson.fromJson(response, entity);
}
I use dynamic types because there's a number of other entities other than Process that I use this same method for. But I can't figure out how to handle the case where the field value can be either a string to an array of string. Any pointers would be appreciated.
Probably the most simple option is to use custom serializer and deserializer and change value
type from String
to List<String>
Here is basic idea how you can solve this:
private static class MyJsonAdapter implements JsonSerializer<List<String>>,
JsonDeserializer<List<String>>{
@Override
public JsonElement serialize(List<String> list, Type t,
JsonSerializationContext jsc) {
if (list.size() == 1) {
return jsc.serialize(list.get(0));
} else {
return jsc.serialize(list);
}
}
@Override
public List<String> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext jsc)
throws JsonParseException {
List<String> result;
if (json.isJsonArray()) {
result = jsc.deserialize(json, typeOfT);
}else {
result = new ArrayList<>();
result.add((String) jsc.deserialize(json, String.class));
}
return result;
}
}
And Field POJO
public static class Field {
public String name;
// Use @JsonAdapter(MyJsonAdapter.class)
// or register serializer and deserializer in
// new GsonBuilder().registerTypeAdapter(new MyJsonAdapter())
@JsonAdapter(MyJsonAdapter.class)
public List<String> value; // need to change value type to list
}
Ps. If you could switch to Jackson from Gson, this problem could be solved with 1 line of code DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With