如何使用Jackson将Java类转换为Map<String, String>并将非字符串成员转换为JSON?

4

我有一些Java类,我想把它们转换成Map<String,String>。但问题是,我的Java类中的任何字段如果没有明显的String表示(集合,其他类),都应该被转换为json字符串。

以下是一个示例:

@Data
@AllArgsConstructor
class MyClass {
    String field1;
    Long field2;
    Set<String> field3;
    OtherClass field4;
}

@Data
@AllArgsConstructor
class OtherClass {
    String field1;
    String field2;
}

ObjectMapper mapper = new ObjectMapper();
MyClass myClass = new MyClass("value", 
                              123L, 
                              Sets.newHashSet("item1", "item2"),
                              new OtherClass("value1", "value2"));
Map<String, String> converted =
        mapper.convertValue(myClass, new TypeReference<Map<String, String>>(){});

此时,converted 应该长这样:

"field1" -> "value"
"field2" -> "123"
"field3" -> "[\"item1\", \"item2\"]"
"field4" -> "{\"field1\":\"value1\",\"field2\":\"value2\"}"

反而,当使用 mapper.convertValue 尝试反序列化 Set 时,会因为异常 java.lang.IllegalArgumentException: Can not deserialize instance of java.lang.String out of START_ARRAY token 而失败。

是否有任何特殊的配置我可以注释在 MyClass 上或者配置 ObjectMapper 以使其按照我的要求工作?


你正在告诉映射器查找一个String->String的映射,但实际上你有一个String->Object的映射。尝试使用mapper.convertValue(myClass, new TypeReference<Map<String, Object>>(){}); - IanGabes
1
这确实可以防止异常,但它并没有达到我想要的效果。我希望得到一个字符串->字符串映射表,只是希望那些通常无法反序列化为字符串的对象仍然保留其JSON形式。 - Brian Schlenker
1个回答

1
这是一种实现方式。
private static final ObjectMapper mapper = new ObjectMapper();

public Map<String, String> toMap(Object obj) {
    // Convert the object to an intermediate form (map of strings to JSON nodes)
    Map<String, JsonNode> intermediateMap = mapper.convertValue(obj, new TypeReference<Map<String, JsonNode>>() {});

    // Convert the json nodes to strings
    Map<String, String> finalMap = new HashMap<>(intermediateMap.size() + 1); // Start out big enough to prevent resizing
    for (Map.Entry<String, JsonNode> e : intermediateMap.entrySet()) {
        String key = e.getKey();
        JsonNode val = e.getValue();

        // Get the text value of textual nodes, and convert non-textual nodes to JSON strings
        String stringVal = val.isTextual() ? val.textValue() : val.toString();

        finalMap.put(key, stringVal);
    }

    return finalMap;
}

如果您想将Map<String, String>转换回原始类...
public static <T> T fromMap(Map<String, String> map, Class<T> clazz) throws IOException {
    // Convert the data to a map of strings to JSON nodes
    Map<String, JsonNode> intermediateMap = new HashMap<>(map.size() + 1); // Start out big enough to prevent resizing
    for (Map.Entry<String, String> e : map.entrySet()) {
        String key = e.getKey();
        String val = e.getValue();

        // Convert the value to the right type of JsonNode
        JsonNode jsonVal;
        if (val.startsWith("{") || val.startsWith("[") || "null".equals(val)) {
            jsonVal = mapper.readValue(val, JsonNode.class);
        } else {
            jsonVal = mapper.convertValue(val, JsonNode.class);
        }

        intermediateMap.put(key, jsonVal);
    }

    // Convert the intermediate map to an object
    T result = mapper.convertValue(intermediateMap, clazz);

    return result;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接