使用 Moshi 1.2.0 时,HashMap from/to JSON 列表的转换失败
Conversion of a List of HashMaps from/to JSON fails with Moshi 1.2.0
我想将我的代码从 GSon 迁移到 MOSHI,以便获得 OK-Libraries 的常见底层用法的好处,因为我也将它与 OKHTTP 和 Retrofit 一起使用。
但是用 Gson 简单的任务用 MOSHI 似乎很复杂:
我有一个 class,其中包含 objects 的列表。
这些 objects 由 fieldname/value 对组成 - 我将其实现为 HashMap。在这个 class 中还有一些构造函数和方法,但是对于 JSON 只有 field/value-pairs 是相关的。
精简到最低限度,我的 JSON 应该是这样的:
{"children":[{"f1":"v11","f2":"v12"},{"f1":"v21","f2":"v22"}]}
当我尝试使用 MOSHI 将这些 class 转换为 JSON 并返回时,children 为空。
转换为 JSON 得到
{"children":[{},{}]}
并且 json-string 从上面到 Class2 的反序列化得到 2 children,但是 children 是空的。
在我的真实代码中,parent-object 还包含其他 classes 的 objects 列表 - 这些 classes 按预期工作。这里的问题似乎是我的 child-class 从 HashMap 扩展而来。
有了 Gson,一切都按预期进行。
这是 Unit-Test,我写信是为了测试行为。
public class Test_Moshi {
private final Moshi moshi = new Moshi.Builder().build();
private static class Class1 extends HashMap<String, Object> {
//Some Constructors and methods omitted for the test.
//Relevant for the serilisation to JSON are only the keys and values in the map.
}
private static class Class2 {
List<Class1> children = new ArrayList<>();
}
@Test public void test1() {
Class1 child;
Class2 parent = new Class2();
child = new Class1();
child.put("f1", "v11");
child.put("f2", "v12");
parent.children.add(child);
child = new Class1();
child.put("f1", "v21");
child.put("f2", "v22");
parent.children.add(child);
String json_gson = new Gson().toJson(parent);
String json_moshi = moshi.adapter(Class2.class).toJson(parent);
assertEquals(json_gson, json_moshi);
}
@Test public void test2() throws IOException {
String json = "{\"children\":[{\"f1\":\"v11\",\"f2\":\"v12\"},{\"f1\":\"v21\",\"f2\":\"v22\"}]}";
Class2 class2 = moshi.adapter(Class2.class).fromJson(json);
assertEquals(2, class2.children.size());
assertEquals("Child 1 contains expected number of fields", 2, class2.children.get(0).size());
assertEquals("Child 2 contains expected number of fields", 2, class2.children.get(1).size());
}
}
睡了一觉后我找到了解决方案(虽然我认为 Moshi 应该开箱即用地处理这种情况):
正如您在此处的答案中所读到的,Moshi 正确处理了 Map<> 接口。解决方案是提供将 class 映射到 Map-Interface 并返回的自定义类型适配器。剩下的就交给Moshi了。
我的问题中的代码必须更改如下:
创建一个适配器-class,映射到 Moshi 文档中描述的映射接口。
private static class Class1 extends HashMap<String, Object> {
public static class class1ToJsonAdapter {
@ToJson
public Map<String, Object> toJson(Class1 dat) {
return (Map<String,Object>)dat;
}
@FromJson
public Class1 fromJson(Map<String,Object> json) {
Class1 result = new Class1();
for (String key : json.keySet())
result.put(key, json.get(key));
return result;
}
}
//Some Constructors and methods omitted for the test.
//Relevant for the serilisation to JSON are only the keys and values in the map.
}
并且必须将此适配器添加到 moshi 对象
private final Moshi moshi = new Moshi.Builder()
.add(new Class1.class1ToJsonAdapter())
.build();
现在从 JSON 到 JSON 的转换按预期工作。
我想将我的代码从 GSon 迁移到 MOSHI,以便获得 OK-Libraries 的常见底层用法的好处,因为我也将它与 OKHTTP 和 Retrofit 一起使用。
但是用 Gson 简单的任务用 MOSHI 似乎很复杂:
我有一个 class,其中包含 objects 的列表。
这些 objects 由 fieldname/value 对组成 - 我将其实现为 HashMap。在这个 class 中还有一些构造函数和方法,但是对于 JSON 只有 field/value-pairs 是相关的。
精简到最低限度,我的 JSON 应该是这样的:
{"children":[{"f1":"v11","f2":"v12"},{"f1":"v21","f2":"v22"}]}
当我尝试使用 MOSHI 将这些 class 转换为 JSON 并返回时,children 为空。
转换为 JSON 得到
{"children":[{},{}]}
并且 json-string 从上面到 Class2 的反序列化得到 2 children,但是 children 是空的。
在我的真实代码中,parent-object 还包含其他 classes 的 objects 列表 - 这些 classes 按预期工作。这里的问题似乎是我的 child-class 从 HashMap 扩展而来。
有了 Gson,一切都按预期进行。
这是 Unit-Test,我写信是为了测试行为。
public class Test_Moshi {
private final Moshi moshi = new Moshi.Builder().build();
private static class Class1 extends HashMap<String, Object> {
//Some Constructors and methods omitted for the test.
//Relevant for the serilisation to JSON are only the keys and values in the map.
}
private static class Class2 {
List<Class1> children = new ArrayList<>();
}
@Test public void test1() {
Class1 child;
Class2 parent = new Class2();
child = new Class1();
child.put("f1", "v11");
child.put("f2", "v12");
parent.children.add(child);
child = new Class1();
child.put("f1", "v21");
child.put("f2", "v22");
parent.children.add(child);
String json_gson = new Gson().toJson(parent);
String json_moshi = moshi.adapter(Class2.class).toJson(parent);
assertEquals(json_gson, json_moshi);
}
@Test public void test2() throws IOException {
String json = "{\"children\":[{\"f1\":\"v11\",\"f2\":\"v12\"},{\"f1\":\"v21\",\"f2\":\"v22\"}]}";
Class2 class2 = moshi.adapter(Class2.class).fromJson(json);
assertEquals(2, class2.children.size());
assertEquals("Child 1 contains expected number of fields", 2, class2.children.get(0).size());
assertEquals("Child 2 contains expected number of fields", 2, class2.children.get(1).size());
}
}
睡了一觉后我找到了解决方案(虽然我认为 Moshi 应该开箱即用地处理这种情况):
正如您在此处的答案中所读到的,Moshi 正确处理了 Map<> 接口。解决方案是提供将 class 映射到 Map-Interface 并返回的自定义类型适配器。剩下的就交给Moshi了。
我的问题中的代码必须更改如下: 创建一个适配器-class,映射到 Moshi 文档中描述的映射接口。
private static class Class1 extends HashMap<String, Object> {
public static class class1ToJsonAdapter {
@ToJson
public Map<String, Object> toJson(Class1 dat) {
return (Map<String,Object>)dat;
}
@FromJson
public Class1 fromJson(Map<String,Object> json) {
Class1 result = new Class1();
for (String key : json.keySet())
result.put(key, json.get(key));
return result;
}
}
//Some Constructors and methods omitted for the test.
//Relevant for the serilisation to JSON are only the keys and values in the map.
}
并且必须将此适配器添加到 moshi 对象
private final Moshi moshi = new Moshi.Builder()
.add(new Class1.class1ToJsonAdapter())
.build();
现在从 JSON 到 JSON 的转换按预期工作。