Java 枚举字段上的 @JsonValue,当此枚举用作映射键时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22023377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:07:54  来源:igfitidea点击:

@JsonValue on an enum field, when this enum used as map key

javaenumsHymanson

提问by acemrek

public enum ClusterType {
    TEMPERATURE("0402"),
    HUMIDITY("0405"),
    ENERGY_DETAILS("0702"),
    SMART_SOCKET_STATUS("0006"),
    ALARMED("0500");

    private String value = null;

    ClusterType(String byteStr) {
        this.value = byteStr;
    }

    @JsonCreator
    public static ClusterType fromValue(final String val){
        return (ClusterType) CollectionUtils.find(Arrays.asList(ClusterType.values()), new Predicate() {
            public boolean evaluate(Object object) {
                ClusterType candidate = (ClusterType) object;
                return StringUtils.equals(candidate.value, val);
            }
        });
    }

    @JsonValue
    public String getValue(){
        return value;
    }

    public byte[] get() {
        return ByteUtils.hexStringToByteArray(value);
    }

    public boolean equals(String cluster) {
        return StringUtils.equals(cluster, value);
    }
}

I have the above enumeration with

我有上面的枚举

@JsonValue public String getValue(){ return value; }

@JsonValue public String getValue(){ 返回值;}

part and a sample test class like...

部分和示例测试类,如...

public class Foo {

public static void main(String[] args) {
    try {
        ObjectMapper objectMapper = new ObjectMapper();

        ClusterType []arrayRep = new ClusterType[]{ClusterType.ALARMED, ClusterType.TEMPERATURE};

        Map<String, ClusterType>  mapRepAsValue = new HashMap<>();
        mapRepAsValue.put("1", ClusterType.ALARMED);
        mapRepAsValue.put("2", ClusterType.TEMPERATURE);

        Map<ClusterType, String>  mapRepAsKey = new HashMap<>();
        mapRepAsKey.put(ClusterType.ALARMED, "1");
        mapRepAsKey.put(ClusterType.TEMPERATURE, "2");

        System.out.println(objectMapper.writeValueAsString(arrayRep));
        System.out.println(objectMapper.writeValueAsString(mapRepAsValue));
        System.out.println(objectMapper.writeValueAsString(mapRepAsKey));

    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
} }

公共类 Foo {

public static void main(String[] args) {
    try {
        ObjectMapper objectMapper = new ObjectMapper();

        ClusterType []arrayRep = new ClusterType[]{ClusterType.ALARMED, ClusterType.TEMPERATURE};

        Map<String, ClusterType>  mapRepAsValue = new HashMap<>();
        mapRepAsValue.put("1", ClusterType.ALARMED);
        mapRepAsValue.put("2", ClusterType.TEMPERATURE);

        Map<ClusterType, String>  mapRepAsKey = new HashMap<>();
        mapRepAsKey.put(ClusterType.ALARMED, "1");
        mapRepAsKey.put(ClusterType.TEMPERATURE, "2");

        System.out.println(objectMapper.writeValueAsString(arrayRep));
        System.out.println(objectMapper.writeValueAsString(mapRepAsValue));
        System.out.println(objectMapper.writeValueAsString(mapRepAsKey));

    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
} }

This test class prints out

这个测试类打印出来

["0500","0402"]
{"2":"0402","1":"0500"}
{"TEMPERATURE":"2","ALARMED":"1"}

@JsonValue is not working when used on an enum field which is a key of map.

@JsonValue 在作为地图键的枚举字段上使用时不起作用。

Is there a way to use this enum as key when serializing maps?

有没有办法在序列化地图时使用这个枚举作为键?

Thanks.

谢谢。

采纳答案by Sotirios Delimanolis

Hymanson uses a MapSerializerto serialize Maptypes and uses a StdKeySerializerto serialize the keys. It's implemented as

Hymanson 使用 aMapSerializer序列化Map类型并使用 aStdKeySerializer序列化键。它被实现为

@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
    throws IOException, JsonGenerationException
{
    if (value instanceof Date) {
        provider.defaultSerializeDateKey((Date) value, jgen);
    } else {
        jgen.writeFieldName(value.toString());
    }
}

which you can see just gets the toString()value of your object. So you can override the toString()method in your enumas such

您可以看到它只是获取toString()对象的值。所以你可以像这样覆盖你的toString()方法enum

public String toString() {
    return getValue();
}

The @JsonValuebecomes useless.

@JsonValue变得无用。

Alternatively, if you need the toString()to remain the same (or default), you can create a custom type that wraps your Map

或者,如果您需要toString()保持不变(或默认),您可以创建一个自定义类型来包装您的Map

class CustomType {
    private Map<ClusterType, String> map;

    @JsonAnyGetter // necessary to unwrap the Map to the root object, see here: http://jira.codehaus.org/browse/HymanSON-765
    @JsonSerialize(keyUsing = ClusterTypeKeySerializer.class)
    public Map<ClusterType, String> getMap() {
        return map;
    }

    public void setMap(Map<ClusterType, String> map) {
        this.map = map;
    }
}

and uses a custom JsonSerializer

并使用自定义 JsonSerializer

class ClusterTypeKeySerializer extends StdSerializer<ClusterType> {

    protected ClusterTypeKeySerializer() {
        super(ClusterType.class);
    }

    @Override
    public void serialize(ClusterType value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonGenerationException {
        jgen.writeFieldName(value.getValue());
    }

}

that uses the ClusterType#getValue()method. Again, we don't use @JsonValue.

使用该ClusterType#getValue()方法。同样,我们不使用@JsonValue.

回答by StaxMan

Actually, I think this is just a feature that hasn't been added, as per:

实际上,我认为这只是一个尚未添加的功能,如下所示:

https://github.com/FasterXML/Hymanson-databind/issues/47

https://github.com/FasterXML/Hymanson-databind/issues/47

so whereas @JsonValueworks fine for Enums with respect to deserialization, it does not yet work for serialization. Project is always open for contributions, if anyone has time to tackle this -- it should not be big undertaking.

因此,虽然@JsonValue在反序列化方面对 Enums 工作正常,但它还不适用于序列化。项目总是对贡献开放,如果有人有时间解决这个问题——它不应该是一项艰巨的任务。