如何使用 Jackson json 注释枚举字段以进行反序列化

Posted

技术标签:

【中文标题】如何使用 Jackson json 注释枚举字段以进行反序列化【英文标题】:How to annotate enum fields for deserialization using Jackson json 【发布时间】:2012-03-07 04:43:02 【问题描述】:

我在 Jackson 1.6.2 中使用 REST Web 服务/Apache Wink。如何注释枚举字段以便 Jackson 反序列化它?

内部类

public enum BooleanField

    BOOLEAN_TRUE         public String value()  return "1"; ,
    BOOLEAN_FALSE        public String value()  return "0"; ,

Java Bean/请求对象

BooleanField locked;
public BooleanField getLocked() return locked;

Jackson 文档声明它可以通过 @JsonValue/@JsonCreator 执行此操作,但没有提供示例。

有谁愿意将 (java) bean 泄露出去?

【问题讨论】:

类似:Jackson enum Serializing and DeSerializer 【参考方案1】:

如果您使用的是 Jackson 1.9,序列化将由以下人员完成:

public enum BooleanField 
   BOOLEAN_TRUE("1")
   ;

   // either add @JsonValue here (if you don't need getter)
   private final String value;

   private BooleanField(String value)  this.value = value; 

   // or here
   @JsonValue public String value()  return value; 

所以你需要的改变是向 Enum 类型本身添加方法,所以所有值都有它。不确定它是否适用于子类型。

对于@JsonCreator,使用静态工厂方法就可以了;所以添加类似:

@JsonCreator
public static BooleanField forValue(String v)  ... 

Jackson 2.0 实际上将支持两者都只使用 @JsonValue,包括反序列化。

【讨论】:

【参考方案2】:

使用 Jackson 2.6 或更高版本,@JsonProperty 注释可以直接应用于枚举常量以更改其序列化:

public enum BooleanField

    @JsonProperty("1")
    BOOLEAN_TRUE,
    @JsonProperty("0")
    BOOLEAN_FALSE

【讨论】:

这个已经停产了,不知道具体的版本。 @SimrandeepSingh:我正在使用 Jackson 2.9.9(通过 Spring Boot 2.1.6),它工作得很好。 @SimrandeepSingh 根据@JsonProperty Javadocs,这仍然可用,并且自 Jackson 2.6 以来一直可用。【参考方案3】:

不要注释它们,只需配置您的 ObjectMapper 实例:

private ObjectMapper createObjectMapper() 
    final ObjectMapper mapper = new ObjectMapper();
    // enable toString method of enums to return the value to be mapped
    mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
    return mapper;

并在您的枚举中覆盖 toString() 方法:

public enum SectionType 
START("start"),
MORE("more");

    // the value which is used for matching
    // the json node value with this enum
    private final String value;

    SectionType(final String type) 
        value = type;
    

    @Override
    public String toString() 
        return value;
    

您不需要任何注释或自定义反序列化程序。

【讨论】:

我需要在哪里配置对象映射器?你能帮忙吗 toString 方法对我来说是关键。没有更多的改变,所以伙计们,看看你的 toString 方法! 如果您希望同一个映射器中的不同类有不同的行为怎么办?【参考方案4】:

实际上,根据 JsonValue (Jackson 2.3.3) 的文档:

NOTE: when use for Java enums, one additional feature is
 * that value returned by annotated method is also considered to be the
 * value to deserialize from, not just JSON String to serialize as.
 * This is possible since set of Enum values is constant and it is possible
 * to define mapping, but can not be done in general for POJO types; as such,
 * this is not used for POJO deserialization. 

因此,对于枚举,您的反序列化将无法使用 JsonCreator 进行,因为 JsonValue 将用于序列化和反序列化。 对枚举执行此操作的一种方法是使用 JsonSetter 和 JsonGetter。

【讨论】:

【参考方案5】:
public enum BooleanField

    BOOLEAN_TRUE("1"),      
    BOOLEAN_FALSE("0");
    
    private final String value;

    BooleanField( int value )  this.value = value; 
    

反序列化器

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

public class BooleanFieldDeserializer extends Json Deserializer<BooleanField> 
    
    public BooleanField deserialize( JsonParser p, DeserializationContext ctx )
    throws IOException 
    
        // boilerplate code for every deserializer
        ObjectCodec objectCodec = p.getCodec();
        JsonNode node = objectCodec.readTree(p);

        // customizable part for your impl
        String booleanFieldString = node.asText();
        return valueOf( booleanFieldString ); <- Enum-supplied method
    

然后,在你的 JavaBean 中...

@JsonDeserialize(using = BooleanFieldDeserializer.class)
BooleanField locked;

【讨论】:

【参考方案6】:

如果枚举是否为数组,以下可能会起作用。 (仅用于反序列化)

package com.stack.model;

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder( "success", "my-enums" )
public class MyObjectJSON 

    @JsonProperty("sucess")
    private boolean success;

    @JsonProperty("my-enums")
    private MyEnum[] myEnums;


    static enum MyEnum 
        Enum1, Enum2, Enum3, Enum4, EnumN;

        private static Map<String, MyEnum> myEnumsMap = new HashMap<String, MyEnum>(5);

        static 
            myEnumsMap.put("enum1-val", Enum1);
            myEnumsMap.put("enum2-val", Enum2);
            myEnumsMap.put("enum3-val", Enum3);
            myEnumsMap.put("enum4-val", Enum4);
            myEnumsMap.put("enumn-val", EnumN);
        

        @JsonCreator
        public static MyEnum forValue(String value) 
            return myEnumsMap.get(value.toLowerCase());
        
    

考虑:

    @Data 注解生成 setter、getter、toString 等。

    @JsonProperty("my-enums") private MyEnum[] myEnums,这是用 jackson 注释 Enum 类型字段的方法( 不管它是不是一个数组都有效)。

    MyEnum是JSON对象要映射的值的枚举,假设如下对象:

    “成功”:是的, “我的枚举”:[“enum1-val”,“enum3-val”]

    forValue函数允许将数组的字符串值映射到Enum,用@JsonCreator注解表示反序列化使用的构造工厂。

【讨论】:

以上是关于如何使用 Jackson json 注释枚举字段以进行反序列化的主要内容,如果未能解决你的问题,请参考以下文章

将 Jersey/Jackson 配置为不使用 @XmlElement 字段注释进行 JSON 字段命名

如何在没有jackson注释的情况下忽略反序列化的某些字段?

反序列化 null 值以使用 Jackson 枚举

如何使用 Jackson 更改 JSON 中的字段名称

配置 Wildfly 10 以使用 Jackson(作为 JSON 提供程序)

json之jackson序列化反序列化探究(二)