如何将 java.util.Properties 序列化到 JSON 文件和从 JSON 文件序列化?

Say*_*Pal 4 java serialization json jackson gson

我有类型的变量java.util.Properties。我正在尝试将其写入 JSON 文件,并从该文件中读取。

Properties变量如下所示:

Properties inner3 = new Properties();
inner3.put("i1", 1);
inner3.put("i2", 100);

Properties inner2 = new Properties();
inner2.put("aStringProp", "aStringValue");
inner2.put("inner3", inner3);

Properties inner1 = new Properties();
inner1.put("aBoolProp", true);
inner1.put("inner2", inner2);

Properties topLevelProp = new Properties();
topLevelProp.put("count", 1000000);
topLevelProp.put("size", 1);
topLevelProp.put("inner1", inner1);
Run Code Online (Sandbox Code Playgroud)

当然,当我将 序列化为topLevelPropJSON 时,我希望结果如下所示。

{
  "inner1": {
    "inner2": {
      "aStringProp": "aStringValue",
      "inner3": {
        "i2": 100,
        "i1": 1
      }
    },
    "aBoolProp": true
  },
  "size": 1,
  "count": 1000000
}
Run Code Online (Sandbox Code Playgroud)

上面的 JSON 结果可以通过使用Gson以非常直接的方式生成,但是当它被馈送相同的 JSON 字符串进行反序列化时,它会失败。

Gson gson = new GsonBuilder().create();
String json = gson.toJson(topLevelProp); //{"inner1":{"inner2":{"aStringProp":"aStringValue","inner3":{"i2":100,"i1":1}},"aBoolProp":true},"size":1,"count":1000000}

//following line throws error: Expected a string but was BEGIN_OBJECT at line 1 column 12 path $.
Properties propObj = gson.fromJson(json, Properties.class); 
Run Code Online (Sandbox Code Playgroud)

也与杰克逊一起尝试过:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
File file = new File("configs/config1.json");
mapper.writeValue(file, topLevelProp);
Run Code Online (Sandbox Code Playgroud)

最后一行抛出错误:

com.fasterxml.jackson.databind.JsonMappingException:java.util.Properties 不能转换为 java.lang.String(通过引用链:java.util.Properties["inner1"])

尝试从字符串反序列化如下,但失败并出现以下错误:

Properties jckProp = JsonSerializer.mapper.readValue(json, Properties.class);
Run Code Online (Sandbox Code Playgroud)

无法在 [Source: {"inner1":{"inner2":{"aStringProp":"aStringValue","inner3":{"i2":100,"i1 ":1}},"aBoolProp":true},"size":1,"count":1000000}; 行:1,列:11](通过引用链:java.util.Properties["inner1"])

如何处理?

更新:遵循cricket_007想法, found com.fasterxml.jackson.databind.node.ObjectNode,可以如下使用:

ObjectNode jckProp = JsonSerializer.mapper.readValue(json, ObjectNode.class);
System.out.println(jckProp.get("size").asInt());
System.out.println("jckProp: " + jckProp);
System.out.println("jckProp.inner: " + jckProp.get("inner1"));
Run Code Online (Sandbox Code Playgroud)

我认为这对我来说可能是前进的方向,因为我主要必须从 JSON 文件中读取。

Sta*_*Man 6

您遇到的问题是您误用了java.util.Properties:它不是多级树结构,而是简单的字符串到字符串映射。因此,虽然在技术上可能添加非字符串属性值(部分原因是这个类是在 Java 泛型之前添加的,这使得类型安全性更好),但不应该这样做。对于嵌套结构化,使用java.util.Map或特定的树数据结构。

至于Properties,javadocs 说例如:

The Properties class represents a persistent set of properties.
The Properties can be saved to a stream or loaded from a stream.
Each key and its corresponding value in the property list is a string.
...
If the store or save method is called on a "compromised" Properties    
object that contains a non-String key or value, the call will fail. 
Run Code Online (Sandbox Code Playgroud)

现在:如果你有这样的“妥协”Properties实例,你最好的选择是构建一个java.util.Map(或者可能是更旧的Hashtable),并序列化它。这应该没有问题。