将字段映射为键值对

时间:2018-04-13 21:01:49

标签: java json jackson

在阅读JSON文件时,我想按照以下方式映射我的课程:

public class Effect {
    private final String type;
    private final Map<String, String> parameters;

    public Effect(String type, Map<String, String> parameters) {
        this.type = type;
        this.parameters = parameters;
    }

    public String getType() {
        return this.type;
    }

    public Map<String, String> getParameters() {
        return this.parameters;
    }
}

{
    "type": {
        "key1": "value1", 
        "key2": "value2", 
    }
}

因此,映射的JSON对象包含type作为唯一键,parameters作为其值。

我想在构造函数上使用@JsonCreator,但无法弄清楚如何映射字段。我是否需要编写自定义反序列化器,或者是否有更简单的方法来映射我想要的类?

我写了一个自定义反序列化器,它可以实现我想要的功能,但可能有一种更简单的方法,可能只有注释,我想知道:

public class EffectDeserializer extends StdDeserializer<Effect> {
    private static final long serialVersionUID = 1L;

    public EffectDeserializer() {
        super(Effect.class);
    }

    @Override
    public Effect deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
        JsonNode node = parser.getCodec().readTree(parser);
        Iterator<String> fieldNames = node.fieldNames();
        if(fieldNames.hasNext()) {
            String type = fieldNames.next();
            Map<String, String> parameters = new HashMap<>();
            for(Iterator<Entry<String, JsonNode>> fields = node.get(type).fields(); fields.hasNext(); ) {
                Entry<String, JsonNode> field = fields.next();
                parameters.put(field.getKey(), field.getValue().textValue());
            }
            return new Effect(type, parameters);
        }
        return null;
    }
}

我发现的另一种方法是添加JsonCreator(本例中为构造函数),它使用Map.Entry<String, Map<String, String>并使用它来初始化值,如下所示:

@JsonCreator
public Effect(Map.Entry<String, Map<String, String>> entry) {
    this.type = entry.getKey();
    this.parameters = entry.getValue();
}

如果没有办法用“普通”构造函数完成它,我可能会最终使用它,因为它使用Jackson的Map.Entry默认映射,减少了可能的误差范围。

1 个答案:

答案 0 :(得分:1)

添加一个静态工厂方法,该方法接受带有动态密钥的Map

@JsonCreator
public static Effect create(Map<String, Map<String, String>> map) {
    String type = map.keySet().iterator().next();
    return new Effect(type, map.get(type));
}

编辑:刚刚注意到这基本上是使用Map.Entry的自己解决方案的丑陋版本。我会改用它。