An example json I am trying to parse is:
[
{
"id": "123",
"a*": {
"b*": {
"prio": {
"d*": {
"id": "234",
"name": "test"
},
"d1*": {
"id": "678",
"name": "test1"
}
}
},
"b1*": {
"prio": {
"d2*": {
"id": "234",
"name": "test4"
}
},
"prio": {
"d3*": {
"id": "234",
"name": "test3"
}
}
}
},
"a1*": {
"b2*": {
"prio": {
"d5*": {
"id": "5435",
"name": "test2"
},
"d6*": {
"id": "675435438",
"name": "test15"
}
}
}
}
},
{
"id": "345",
"f*": {
"g*": {
"prio": {
"i*": {
"id": "5435",
"name": "test2"
}
}
}
}
},
{
"id": "342343"
}
]
For explanation purposes, the ones with the asterisk will always have changing keys in different json files and the actual json files may or may not have asterisk in the key. The nesting amount won't be deeper than the nest shown but some can be less deep. prio
will always be at the same level of deepness and I need all of the key names except for prio
.
How can I parse this json with gson? Any help is appreciated.
What I was trying (with names changed):
@Getter
@Setter
public class PolicyObject {
private String id;
private Map<String, First> firstMap;
@Getter
@Setter
public class First {
private Map<String, Second> secondMap;
}
@Getter
@Setter
public class Second {
private Map<String, Third> prio;
}
@Getter
@Setter
public class Third {
private String name;
}
}
public class mainClass {
public void main(InputStreamReader file) {
Type typeOfT = TypeToken.getParameterized(PolicyObject.class, clazz).getType();
List<PolicyObject> policies = gson.fromJson(file, typeOfT);
}
}
The firstMap turns out to be null. The reason I am using gson is because I'm already using it for other json files that have a simpler format in the same package.
EDIT
It was fixed using a custom TypeAdapter:
public class CustomTypeAdapter extends TypeAdapter<PolicyObject> {
private static final String KEY_ID = "id";
private static final String KEY_PRIO = "prio";
private static final String KEY_NAME = "name";
@Override
public void write(JsonWriter jsonWriter, PolicyObject policy) throws IOException {
}
@Override
public PolicyObject read(JsonReader reader) throws IOException {
PolicyObject policyObject = new PolicyObject();
PolicyObject.setFirstMap(new HashMap<>());
reader.beginObject();
PolicyObject.First first = new PolicyObject.First();
first.setSecondMap(new HashMap<>());
while (reader.hasNext()) {
String firstName = reader.nextName();
if (KEY_ID.equals(firstName)) {
policyObject.setId(reader.nextString());
} else {
reader.beginObject();
while (reader.hasNext()) {
String secondName = reader.nextName();
reader.beginObject();
PolicyObject.Second second = new PolicyObject.Second();
second.setPrio(new HashMap<>());
while (reader.hasNext()) {
String prio = reader.nextName();
if (KEY_PRIO.equals(prio)) {
reader.beginObject();
while (reader.hasNext()) {
String thirdName = reader.nextName();
reader.beginObject();
PolicyObject.Third rule = new PolicyObject.Third();
while (reader.hasNext()) {
String ruleProperty = reader.nextName();
if (KEY_NAME.equals(ruleProperty)) {
rule.setComment(reader.nextString());
} else {
reader.skipValue();
}
}
second.getPrio().put(thirdName, rule);
reader.endObject();
}
reader.endObject();
} else {
reader.skipValue();
}
}
first.getSecondMap().put(secondName, second);
reader.endObject();
}
reader.endObject();
policyObject.getFirstMap().put(firstName, first);
}
}
reader.endObject();
return policyObject;
}
}
public class mainClass {
public void main(InputStreamReader file) {
Gson gson = new GsonBuilder().registerTypeAdapter(PolicyObject.class, new CustomTypeAdapter()).create();
Type typeOfT = TypeToken.getParameterized(PolicyObject.class, clazz).getType();
List<PolicyObject> policies = gson.fromJson(file, typeOfT);
}
}
The firstMap turns out to be null.
That's because you don't have any json element name "firstMap". GSON (and most JSON parsers) work by mapping json element names to a class field. If you don't have a consistent element name, then you need a map to represent the whole object that has the variable element names.
First off looks like you have an Array of objects at the top level, so make sure you're asking GSON to parse an array object to begin with. Something like:
ItemType[] items = gson.fromJson(inputString, ItemType[].class)
So what is "ItemType" - well each item in the array has an "id" but then variable keys, so you can't use your PolicyObject
class, you need a map of String to secondary item type:
Map<String, SecondaryType>[] items =
gson.fromJson(inputString, Map<String, SecondaryType>[].class)
So what is "SecondaryType"? Again, all keys are variable so again you need a map:
Map<String, Map<String, ThirdType>[] items =
gson.fromJson(inputString, Map<String, Map<String, ThirdType[].class)
So what is "ThirdType"? Well, at this point, it seems you know you will have a key named "prio"
so you can defined a well-named class:
public class ThirdType {
public Prio prio
}
So what is "Prio"? Again it seems to contain a variable list of keys, so we're actually back to generic maps:
public class ThirdType {
public Map<String, FourthType> prio
}
So what is "FourthType"? Well that looks like a consistent "id" and "name":
public class FourthType {
public String id;
public String name;
}
With these definitions, we're back to:
Map<String, Map<String, ThirdType>[] items =
gson.fromJson(inputString, Map<String, Map<String, ThirdType[].class)
You can clean this up with a class that is the top-level map:
public class MyObject extends Map<String, Map<String, ThirdType>> { }
So then you can do something like:
MyObject[] items = gson.fromJson(inputString, MyObject[].class)
Disclaimer: I don't know if any this will actually compile, but I think it should put you on the right track.