Sometimes you get a quite nested Json response but the only thing you need is a list of classes in a certain branch of the Json document (like a response of Yahoo’s YQL query).
Assume just the following json document:
{
"fieldA": {
"fieldB": {
"fields": [
{ "foo": "test1", "bar": "test2"},
{ "foo": "test11", "bar": "test22"}
]
}
}
}
And the only thing you need is the fields array.
A Java8 way to get the fields as a list would be:
List<FooBar> quotes2 = Stream.of(gson.fromJson(json, JsonObject.class)
.getAsJsonObject("foo")
.getAsJsonObject("bar")
.getAsJsonArray("foobar"))
.flatMap(e -> Stream.of(gson.fromJson(e, FooBar[].class)))
.collect(Collectors.toList());
But that’s quite some code. Okay if you only need it once, but as soon as you need this several times it clearly violates the DRY principle. Gson (which I am using a lot) doesn’t seem to provide a simple way for doing this. Except creating the whole hierarchy as Java Classes, which might just be overkill.
Solving the problem in a more generic way is the way to go – but it als requires creating generic arrays:
class Gsons{
public static <T> List<T> asList(String json, String path, Class<T> clazz) {
Gson gson = new Gson();
String[] paths = path.split("\\.");
JsonObject o = gson.fromJson(json, JsonObject.class);
for (int i = 0; i < paths.length - 1; i++) {
o = o.getAsJsonObject(paths[i]);
}
JsonArray jsonArray = o.getAsJsonArray(paths[paths.length - 1]);
Class<T[]> clazzArray = (Class<T[]>) ((T[]) Array.newInstance(clazz, 0)).getClass();
T[] objectArray = gson.fromJson(jsonArray, clazzArray);
return Arrays.asList(objectArray);
}
}
The only things to do are creating a class for the entities and calling the method:
List<FooBar> fooBars = Gsons.asList(json, "fieldA.fieldB.fields", FooBar.class);