将字段映射为键-值对

时间:2022-02-23 19:16:56

When reading a JSON file, i would like to map my class as follows:

在读取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", 
    }
}

So, the mapped JSON object consists of type as the only key and parameters as its value.

因此,映射的JSON对象由类型作为惟一的键,参数作为其值。

I would like to use @JsonCreator on the constructor, but can't figure out, how to map the fields. Do i need to write a custom deserializer or is there an easier way to map the class like i want?

我想在构造函数中使用@JsonCreator,但不知道如何映射字段。我需要编写一个自定义反序列化器,还是有一种更简单的方法可以像我想要的那样映射类?


I wrote a custom deserializer, which does what i want, but there might be an easier way, maybe with annotations alone, which i would like to know:

我写了一个自定义反序列化器,它可以做我想做的事,但是可能有一种更简单的方法,也许只有注释,我想知道:

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;
    }
}

Another way i found would be adding a JsonCreator (constructor in this case), that takes a Map.Entry<String, Map<String, String> and uses that to initialize the values, like this:

我发现的另一种方法是添加一个JsonCreator(本例中为构造函数),它具有一个映射。条目 ,使用它初始化值,如下所示: ,>

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

If there's no way to get it done with a "normal" constructor, i will probably end up using this, as it uses Jackson's default mapping for Map.Entry, reducing possible error margin.

如果没有办法用“普通”构造函数来完成,我可能会使用这个,因为它使用Jackson的默认映射映射。进入,减少可能的误差幅度。

1 个解决方案

#1


1  

Add a static factory method that accepts a Map with a dynamic key:

添加一个静态工厂方法,该方法接受带有动态键的映射:

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

EDIT: Just noticed this is basically an uglier version of your own solution using Map.Entry. I would go with that instead.

编辑:注意到这基本上是一个更丑陋的版本,您自己的解决方案使用Map.Entry。我宁愿选择那个。

#1


1  

Add a static factory method that accepts a Map with a dynamic key:

添加一个静态工厂方法,该方法接受带有动态键的映射:

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

EDIT: Just noticed this is basically an uglier version of your own solution using Map.Entry. I would go with that instead.

编辑:注意到这基本上是一个更丑陋的版本,您自己的解决方案使用Map.Entry。我宁愿选择那个。