For example:
{
"id" : "123",
"name" : "Tom",
"class" : {
"subject" : "Math",
"teacher" : "Jack"
}
}
I want to get the Map<String, String>
:
"id" : "123",
"name" : "Tom",
"subject" : "Math",
"teacher" : "Jack"
For example:
{
"id" : "123",
"name" : "Tom",
"class" : {
"subject" : "Math",
"teacher" : "Jack"
}
}
I want to get the Map<String, String>
:
"id" : "123",
"name" : "Tom",
"subject" : "Math",
"teacher" : "Jack"
I'm not sure if something exists out of the box (speaking about Gson). However you could write a custom recursive deserializer:
Type t = new TypeToken<Map<String, String>>(){}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(t, new FlattenDeserializer()).create();
Map<String, String> map = gson.fromJson(new FileReader(new File("file")), t);
...
class FlattenDeserializer implements JsonDeserializer<Map<String, String>> {
@Override
public Map<String, String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Map<String, String> map = new LinkedHashMap<>();
if (json.isJsonArray()) {
for (JsonElement e : json.getAsJsonArray()) {
map.putAll(deserialize(e, typeOfT, context));
}
} else if (json.isJsonObject()) {
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
if (entry.getValue().isJsonPrimitive()) {
map.put(entry.getKey(), entry.getValue().getAsString());
} else {
map.putAll(deserialize(entry.getValue(), typeOfT, context));
}
}
}
return map;
}
}
Given your example it outputs:
{id="123", name="Tom", subject="Math", teacher="Jack"}
although it doesn't handle the case when a key is mapped to an array of primitives (because it's not possible to map a key with multiple values in a Map<String, String>
(unless you can take the String representation of the array or that you can return a Map<String, Object>
) but it works for an array of objects (given that each object has a unique key).
So if you have:
{
"id": "123",
"name": "Tom",
"class": {
"keys": [
{
"key1": "value1"
},
{
"key2": "value2"
}
],
"teacher": "Jack"
}
}
it'll output:
{id="123", name="Tom", key1="value1", key2="value2", teacher="Jack"}
You can customize it as you need if more cases are needed to be handled.
Hope it helps! :)
Using Jackson:
private static <T> T fromJsonToGenericPojo(ObjectMapper objectMapper,
String json, Class<?> classType, Class<?>... genericTypes)
{
JavaType javaType = TypeFactory.defaultInstance()
.constructParametricType(classType, genericTypes);
try {
return objectMapper.readValue(json, javaType);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
throw new IllegalStateException(e);
}
}
you can get a map of maps:
Map<String, Object> map = fromJsonToGenericPojo(objectMapper, json,
Map.class, String.class, Object.class);
Once you have the map you can flatten it using the JDK as you wish. There isn't a generic way to flatten a map; what if you have the JSON:
{
"id" : "123",
"name" : "Tom",
"class" : [
{
"subject" : "Math",
"teacher" : "Jack"
},
{
"subject" : "English",
"teacher" : "John"
}]
}
Regarding elements in an array you will have conflicting keys. What will your resolution be? Only the last value, only the first value, will you change the key name from subject
to subject1
- "Math", subject2
- "English", will you not add any of them?
Use ObjectMapper to convert Json to an Java Class.Later have an Map in it as a variable.
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("c:\\user.json"), User.class);
For more reference.