使用Gson反序列化Map<String,Object>字段

17

我有一个具有以下结构的用户对象:

class User {
    private String id;
    private String name;
    private Map<String, Object> properties;

    // GETTERS & SETTERS
}

我有一个具有以下结构的JSON字符串:

{
    "user": {
        "id:"123456789",
        "name:"azerty",
        "emailHash":"123456789", // not used in User class
        "properties": {
            "p1":1,
            "p2":"test",
            "p3":[1, 2, 3, 4],
            "p4":{
               etc...
            }
        }
    }
}

属性的键是字符串,属性的值可以是字符串、整数、数组、布尔值、映射等。

我试着用Gson将这个JSON字符串反序列化:

JsonParser parser = new JsonParser();
JsonElement element = parser.parse(jsonString);
JsonObject object = element.getAsJsonObject();

GsonBuilder builder = new GsonBuilder();
builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = builder.create();
User user = (User) gson.fromJson(object.get("user"), new TypeToken<User>() {}.getType());

'id' 和 'name' 字段已正确注入,但 'properties' 字段仍为空。

您知道我做错了什么吗?感谢您的帮助!


我建议把属性定义为JsonObject,然后直接将JSON转换为Map<String,Object> - Srinivas
你的代码运行得很好,只有一个小问题:你似乎创建了一个名为builderGsonBuilder,但是后来使用了一个名为gsonBuilderGsonBuilder。如果这实际上可以编译,那么你之前创建了另一个GsonBuilder并错误地使用了它。除此之外...在我的机器上反序列化得很好。 - Brian Roach
当我写主题时,gsonBuilder 是一个错误。我在代码中使用的是 builder。我将编辑我的主题进行更正。properties 字段是否已正确注入您的测试?对我来说它保持为空很奇怪... - Franck Anso
你试过这个吗:Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();?在同样的情况下对我有效。 - Mateus
1个回答

9

对我来说,这段代码是:

public class Main {
    public static void main(String[] args) throws IOException {
    GsonBuilder builder = new GsonBuilder();
    builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    Gson gson = builder.create();
    FileInputStream inputStream = new FileInputStream(new File("bobi.json"));
    InputStreamReader reader = new InputStreamReader(inputStream);
    User user = gson.fromJson(reader, User.class);
    System.out.println(user.getName());
    System.out.println(user.getId());
    for (String property : user.getProperties().keySet()) {
        System.out.println("Key: " + property + " value: " + user.getProperties().get(property));
    }
    reader.close();
}

打印出这个:
azerty
123456789
Key: p1 value: 1.0
Key: p2 value: test
Key: p3 value: [1.0, 2.0, 3.0, 4.0]
Key: p4 value: {}

请注意,我在解析的文件中已经去除了包装的json对象。该文件为:

{
        "id":"123456789",
        "name" : "azerty",
        "emailHash":"123456789", 
        "properties": {
            "p1":1,
            "p2":"test",
            "p3":[1, 2, 3, 4],
            "p4":{

            }
        }
}

此外,我为nameid添加了闭合双引号,在您的示例中没有。

根据OP的要求,这是User类。我添加了getter和setter以便打印:

import java.util.Map;

class User {
    private String id;
    private String name;
    private Map<String, Object> properties;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Map<String, Object> getProperties() {
        return properties;
    }
    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
    }
}

你能发一下你用的 user 对象吗?我试了你的代码但是 properties 总是为 null... 我使用的是 JDK7 和 Gson 2.2.2,如果有帮助的话... - Franck Anso
@FranckYapadesouciAnso:已添加。Gson 2.1,Java 1.7。 - Boris Strandjev
实际上,这是我的错。对于这个主题,我简化了字段名称。主题中的“property”字段在我的代码中是“dynProp”。命名策略设置为“LOWER_CASE_WITH_UNDERSCORES”,尝试在json中搜索“dyn_prop”而不是“dynProp”。因此,我将命名策略切换为“IDENTITY”,现在它可以正常工作了! - Franck Anso
顺便提一下,身份验证是默认的字段命名策略,你不需要指定它。另外,我注意到你在这里是新手。如果我帮到了你,请接受并支持我的回答——这就是 SO 的工作方式。 - Boris Strandjev
我已经接受了答案,但是我不能点赞。我的声望不够。抱歉。谢谢你的帮助! - Franck Anso
显示剩余3条评论

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