如何使用Jackson进行序列化和反序列化枚举|猿教程

 

如何使用Jackson进行序列化和反序列化枚举|猿教程|在这个快速教程中,我们将学习如何使用 Jackson 2 控制 Java 枚举的序列化和反序列化。icon-default.png?t=M85Bhttps://yuanjiaoc.com/tutorial/article/10237

概述

在这个快速教程中,我们将学习如何使用 Jackson 2 控制 Java 枚举的序列化和反序列化。

控制枚举表示

让我们定义以下枚举:

public enum Distance {
    KILOMETER("km", 1000), 
    MILE("miles", 1609.34),
    METER("meters", 1), 
    INCH("inches", 0.0254),
    CENTIMETER("cm", 0.01), 
    MILLIMETER("mm", 0.001);

    private String unit;
    private final double meters;

    private Distance(String unit, double meters) {
        this.unit = unit;
        this.meters = meters;
    }

    // standard getters and setters
}

将枚举序列化为 JSON

默认枚举表示

默认情况下,Jackson会将Java Enums表现为一个简单的字符串。比如说:

new ObjectMapper().writeValueAsString(Distance.MILE);

将导致:

"MILE"

但是,当将此 Enum 编组为 JSON 对象时,我们希望得到如下内容:

{"unit":"miles","meters":1609.34}

枚举作为 JSON 对象

从 Jackson 2.1.2 开始,现在有一个可以处理这种表示的配置选项。这可以通过类级别的 @JsonFormat 注释来完成:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Distance { ... }

这将在为 Distance.MILE 序列化此枚举时产生所需的结果:

{"unit":"miles","meters":1609.34}

枚举和@JsonValue

另一个控制枚举输出的简单方法是在一个getter上使用@JsonValue注解:

public enum Distance { 
    ...
 
    @JsonValue
    public String getMeters() {
        return meters;
    }
}

我们在这里表达的是,getMeters()是这个枚举的实际表示。所以序列化的结果将是:

1609.34

枚举的自定义序列化器

如果我们使用的是早于2.1.2的Jackson版本,或者需要对枚举进行更多的定制,我们可以使用一个自定义的Jackson序列化器。首先,我们需要定义它:

public class DistanceSerializer extends StdSerializer {
    
    public DistanceSerializer() {
        super(Distance.class);
    }

    public DistanceSerializer(Class t) {
        super(t);
    }

    public void serialize(
      Distance distance, JsonGenerator generator, SerializerProvider provider) 
      throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("name");
        generator.writeString(distance.name());
        generator.writeFieldName("unit");
        generator.writeString(distance.getUnit());
        generator.writeFieldName("meters");
        generator.writeNumber(distance.getMeters());
        generator.writeEndObject();
    }
}

然后我们可以将序列化器应用于将要被序列化的类:

@JsonSerialize(using = DistanceSerializer.class)
public enum TypeEnum { ... }

这导致:

{"name":"MILE","unit":"miles","meters":1609.34}

将JSON反序列化为Enum

首先,让我们定义一个拥有Distance成员的City类:

public class City {
    
    private Distance distance;
    ...    
}

然后我们将讨论将JSON字符串反序列化为Enum的不同方法.

默认行为

默认情况下,Jackson将使用Enum名称从JSON中反序列化。

例如,它将反序列化JSON:

{"distance":"KILOMETER"}

到 Distance.KILOMETER 对象:

City city = new ObjectMapper().readValue(json, City.class);
assertEquals(Distance.KILOMETER, city.getDistance());

使用@JsonValue

我们已经学会了如何使用@JsonValue来序列化Enums。我们也可以使用同样的注解来反序列化。这是有可能的,因为Enum的值是常数。

首先,让我们将@JsonValue与其中一个getter方法getMeters()一起使用:

public enum Distance {
    ...

    @JsonValue
    public double getMeters() {
        return meters;
    }
}

getMeters() 方法的返回值表示 Enum 对象。因此,在反序列化示例 JSON 时:

{"distance":"0.0254"}

Jackson 将寻找getMeters()返回值为0.0254的Enum对象。在这种情况下,该对象是Distance.INCH:

assertEquals(Distance.INCH, city.getDistance());

使用@JsonProperty

@JsonProperty 注解用于枚举实例:

public enum Distance {
    @JsonProperty("distance-in-km")
    KILOMETER("km", 1000), 
    @JsonProperty("distance-in-miles")
    MILE("miles", 1609.34);
 
    ...
}

通过使用这个注解,我们只是告诉Jackson将@JsonProperty的值映射到用这个值注解的对象。

作为上述声明的结果,例子中的JSON字符串:

{"distance": "distance-in-km"}

将映射到 Distance.KILOMETER 对象:

assertEquals(Distance.KILOMETER, city.getDistance());

使用@JsonCreator

Jackson 调用带有 @JsonCreator 注释的方法来获取封闭类的实例。

考虑 JSON 表示:

{
    "distance": {
        "unit":"miles", 
        "meters":1609.34
    }
}

然后我们将使用 @JsonCreator 注解定义 forValues() 工厂方法:

public enum Distance {
   
    @JsonCreator
    public static Distance forValues(@JsonProperty("unit") String unit,
      @JsonProperty("meters") double meters) {
        for (Distance distance : Distance.values()) {
            if (
              distance.unit.equals(unit) && Double.compare(distance.meters, meters) == 0) {
                return distance;
            }
        }

        return null;
    }

    ...
}

请注意使用 @JsonProperty 注释将 JSON 字段与方法参数绑定。 然后,当我们反序列化 JSON 样本时,我们将得到结果:

assertEquals(Distance.MILE, city.getDistance());

使用自定义反序列化器

如果所描述的技术都无法使用,我们可以使用一个自定义的反序列化器。例如,我们可能无法获得Enum的源代码,或者我们可能使用的是旧的Jackson版本,不支持到目前为止所涉及的一个或多个注释。

根据我们的自定义反序列化文章,为了反序列化上一节中提供的JSON,我们将从创建反序列化类开始。

public class CustomEnumDeserializer extends StdDeserializer {

    @Override
    public Distance deserialize(JsonParser jsonParser, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);

        String unit = node.get("unit").asText();
        double meters = node.get("meters").asDouble();

        for (Distance distance : Distance.values()) {
           
            if (distance.getUnit().equals(unit) && Double.compare(
              distance.getMeters(), meters) == 0) {
                return distance;
            }
        }

        return null;
    }
}

然后我们将使用 Enum 上的 @JsonDeserialize 注释来指定我们的自定义反序列化器:

@JsonDeserialize(using = CustomEnumDeserializer.class)
public enum Distance {
   ...
}

我们的结果是:

assertEquals(Distance.MILE, city.getDistance());

结论

本文说明了如何更好地控制 Java 枚举的序列化和反序列化过程和格式。

你可能感兴趣的:(json,java,开发语言)