使用Gson或Jackson </string,>将JSON字符串展平为Map <string,string =“”>

时间:2015-04-20 22:20:56

标签: java json jackson gson

例如:

{
    "id" : "123",
    "name" : "Tom",
    "class" : {
        "subject" : "Math",
        "teacher" : "Jack"
    }
}

我想获得Map<String, String>

"id" : "123",
"name" : "Tom",
"subject" : "Math",
"teacher" : "Jack"

3 个答案:

答案 0 :(得分:3)

我不确定是否存在开箱即用的东西(谈论Gson)。但是,您可以编写自定义递归反序列化器:

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

根据你的例子输出:

{id="123", name="Tom", subject="Math", teacher="Jack"}

虽然它没有处理将一个键映射到一个基元数组的情况(因为它不可能在Map<String, String>中映射一个具有多个值的键(除非你可以获取数组的String表示或者可以返回Map<String, Object>),但它适用于一个对象数组(假设每个对象都有一个唯一的键)。

所以如果你有:

{
    "id": "123",
    "name": "Tom",
    "class": {
        "keys": [
            {
                "key1": "value1"
            },
            {
                "key2": "value2"
            }
        ],
        "teacher": "Jack"
    }
}

它输出:

{id="123", name="Tom", key1="value1", key2="value2", teacher="Jack"}

如果需要处理更多案例,您可以根据需要自定义它。

希望它有所帮助! :)

答案 1 :(得分:0)

使用杰克逊:

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

您可以获得地图地图:

Map<String, Object> map = fromJsonToGenericPojo(objectMapper, json,    
                                 Map.class, String.class, Object.class);

获得地图后,您可以根据需要使用JDK将其展平。平铺地图并不是一种通用的方法;如果你有JSON怎么办:

{
    "id" : "123",
    "name" : "Tom",
    "class" : [
    {
        "subject" : "Math",
        "teacher" : "Jack"
    }, 
    {
        "subject" : "English",
        "teacher" : "John"
    }]
}

关于数组中的元素,您将拥有冲突的键。你的决议是什么?只有最后一个值,只有第一个值,您才会将密钥名称从subject更改为subject1 - &#34;数学&#34;,subject2 - &#34;英语&# 34;,你不会添加任何一个吗?

答案 2 :(得分:0)

使用ObjectMapper将Json转换为Java Class.Later将一个Map作为变量。

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("c:\\user.json"), User.class);

了解更多reference