当前位置: 首页 > 知识库问答 >
问题:

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

仲浩旷
2023-03-14
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);
    }
}

我有上面的列举

@JsonValue公共字符串getValue(){return value;}

部分和一个示例测试类,如。。。

公开课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();
    }
} }

这个测试类打印出来

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

@jsonValue在作为map键的枚举字段上使用时不工作。

序列化映射时是否有方法将此枚举用作键?

谢谢

共有2个答案

易品
2023-03-14

Jackson使用MapSerializerMap类型进行序列化,并使用StdKeySerializer对键进行序列化。它实现为

@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());
    }
}

您可以看到它只获取对象的toString()值。因此,您可以在enum中重写toString()方法

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

@JsonValue将变得无用。

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

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

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

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

并使用自定义的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());
    }

}

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

呼延曜灿
2023-03-14

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

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

因此,@JsonValue在反序列化方面可以很好地用于枚举,但在序列化方面还不起作用。若有人有时间来解决这个问题,那个么这个项目总是可以接受捐款的——它不应该是一个大项目。

 类似资料:
  • 我想映射2个模型,其中每个模型都有几乎相同的枚举。让我展示: 第一个模型有枚举: 第二个模型具有枚举: 我有这样的自定义映射方法: 然后我用: 但是你可以得到: 我还创建了枚举映射器,如: 但我不需要单独设置,只希望枚举字段映射到内部映射中。简单地说,当我做枚举时,也应该映射。 谢谢 p、 对不起我的英语,希望我的问题有意义:)

  • 问题内容: 我需要预先将未实现接口的枚举映射到现有数据库,该数据库使用将该枚举存储在与所有者类相同的表中。 在这种情况下应如何处理映射?持久化到数据库不会改变,因为实现该接口的所有枚举都将具有不同的值,但是我不确定应如何从数据库中检索对象(我是否需要自定义映射器,它将尝试实例化一个使用指定的enum类进行枚举吗?Hibernate本身是否支持此功能?)。 问题答案: 可以创建一个自定义(例如thi

  • 问题内容: Hibernate提供的注释支持使用或的两种类型的映射。当我们使用映射时,它使用的“名称” 而不是Enum的表示形式。在数据库列仅包含一个字符的情况下,这是一个问题。例如,我有以下枚举: 当我坚持枚举使用,即hibernate尝试在数据库中存储的值是开放的。但是,我的数据库列仅包含一个字符,因此会引发异常。 克服这个问题的一个办法是改变枚举类型持有单个字符(如,代替,)。但是,这降低了

  • Spring 3.x、JPA 2.0、Hibernate 4.x、Postgresql 9.x. 使用希望映射到Postgresql枚举的枚举属性处理Hibernate映射类。 使用枚举列上的where子句进行查询会引发异常。 SQL: Hibernate xml查询: > 按而不是按枚举查询工作正常。 没有数据库交互的Java工作良好: 不是,与和相同,异常更改为: 在查看https://sta

  • 问题内容: 我需要预先将没有实现接口的枚举映射到现有数据库,该数据库使用将该枚举存储在与所有者类相同的表中。 在这种情况下应如何处理映射?持久化到数据库不会改变,因为实现该接口的所有枚举都将具有不同的值,但是我不确定应如何从数据库中检索对象(我是否需要自定义映射器,它将尝试实例化一个使用指定的enum类进行枚举吗?Hibernate是否本身支持此功能?)。 问题答案: 可以创建一个自定义(例如th

  • 问题内容: Hibernate提供的注释支持使用或两种类型的映射。当我们使用映射时,它使用的“名称” 而不是Enum 的表示形式。在数据库列仅包含一个字符的情况下,这是一个问题。例如,我有以下枚举: 当我坚持枚举使用,即休眠尝试在数据库中存储的值是开放的。但是,我的数据库列仅包含一个字符,因此会引发异常。 克服这个问题的一个办法是改变枚举类型持有单个字符(如,代替,)。但是,这降低了可读性。有什么