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);