用Jackson序列化枚举


90

我下面有一个枚举:

public enum OrderType {

  UNKNOWN(0, "Undefined"),
  TYPEA(1, "Type A"),
  TYPEB(2, "Type B"),
  TYPEC(3, "Type C");

  private Integer id;
  private String name;

  private WorkOrderType(Integer id, String name) {
    this.id = id;
    this.name = name;
  }

  //Setters, getters....
}

我用控制器(new OrderType[] {UNKNOWN,TYPEA,TYPEB,TYPEC};)返回枚举数组,Spring将其序列化为以下json字符串:

["UNKNOWN", "TYPEA", "TYPEB", "TYPEC"] 

强迫Jackson像POJO一样序列化枚举的最佳方法是什么?例如:

[
  {"id": 1, "name": "Undefined"},
  {"id": 2, "name": "Type A"},
  {"id": 3, "name": "Type B"},
  {"id": 4, "name": "Type C"}
]

我使用了不同的注释,但无法获得这样的结果。


1
看起来您已经找到了解决方案;大!好奇为什么需要它?
StaxMan

我正在开发一个GWT应用程序,该应用程序通过JSON与服务器端进行通信。该枚举将为组合框提供选项值。
Nofate 2011年

喔好吧。如此简而言之是一组值...很有趣。
StaxMan 2011年

Answers:


87

终于我找到了解决方案。

我必须用注释枚举@JsonSerialize(using = OrderTypeSerializer.class)并实现自定义序列化程序:

public class OrderTypeSerializer extends JsonSerializer<OrderType> {

  @Override
  public void serialize(OrderType value, JsonGenerator generator,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {

    generator.writeStartObject();
    generator.writeFieldName("id");
    generator.writeNumber(value.getId());
    generator.writeFieldName("name");
    generator.writeString(value.getName());
    generator.writeEndObject();
  }
}

4
请注意,要配置Jackson使用自定义(反)序列化处理,使用注释的另一种方法是向配置模块注册(反)序列化器。wiki.fasterxml.com/JacksonHowToCustomSerializers
程序员布鲁斯

1
使用Spring 3.1.1对我不起作用。我的@Controller仍然返回没有我的属性的json。
戴夫2014年

我有一些枚举,并且我想用一个函数来获取所有枚举。我该怎么做?
Morteza Malvandi 2015年

对于一种枚举类型,我必须定义一个自定义反序列化器。有没有通用的解决方案?

78
@JsonFormat(shape= JsonFormat.Shape.OBJECT)
public enum SomeEnum

https://github.com/FasterXML/jackson-databind/issues/24开始提供

刚刚测试过,它可以与版本2.1.2一起使用

回答TheZuck

我尝试了您的示例,得到了Json:

{"events":[{"type":"ADMIN"}]}

我的代码:

@RequestMapping(value = "/getEvent") @ResponseBody
  public EventContainer getEvent() {
    EventContainer cont = new EventContainer();
    cont.setEvents(Event.values());
    return cont;
 }

class EventContainer implements Serializable {

  private Event[] events;

  public Event[] getEvents() {
    return events;
 }

 public void setEvents(Event[] events) {
   this.events = events;
 }
}

和依赖项是:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>${jackson.version}</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>${jackson.version}</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>${jackson.version}</version>
  <exclusions>
    <exclusion>
      <artifactId>jackson-annotations</artifactId>
      <groupId>com.fasterxml.jackson.core</groupId>
    </exclusion>
    <exclusion>
      <artifactId>jackson-core</artifactId>
      <groupId>com.fasterxml.jackson.core</groupId>
    </exclusion>
  </exclusions>
</dependency>

<jackson.version>2.1.2</jackson.version>

2
我喜欢这种替代方法,它更清洁,但是,我使用此类进行了尝试,并且类型未进行序列化,知道发生了什么问题吗?@JsonFormat(shape = JsonFormat.Shape.OBJECT)@JsonAutoDetect()公共枚举事件{VISIT_WEBSITE(Type.ADMIN); @JsonProperty public Type类型;public Type getType(){返回类型;}事件(类型类型){this.type = type; } public enum Type {ADMIN,CONSUMER,}}我正在使用Jackson 2.1.2
TheZuck 2013年

我已在答案正文中添加了其他详细信息
Vecnas 2013年

发现出了什么问题,我使用的是Jackson 2.1.2,但我的Spring版本仍然是3.1,因此不支持该版本。升级到3.2.1,现在一切正常。谢谢!
TheZuck

@Vecnas @JsonFormat在另一个实体中使用枚举时可以覆盖它的默认值吗?例如,在一个实体中,我希望枚举应序列化为字符串而不是对象。我尝试@JsonFormat在使用枚举的类的字段中添加另一个,但始终将其序列化为对象。
2014年

我发现的是,使用-@JsonSerialize(using = ToStringSerializer.class)作为字段,它使用toString()。不是严格的解决方案,但是可以工作
Vecnas 2014年

25

我找到了一个非常简洁的解决方案,当您无法像我这样修改枚举类时,它特别有用。然后,您应该提供一个启用了某些功能的自定义ObjectMapper。这些功能自Jackson 1.6起可用。

public class CustomObjectMapper extends ObjectMapper {
    @PostConstruct
    public void customConfiguration() {
        // Uses Enum.toString() for serialization of an Enum
        this.enable(WRITE_ENUMS_USING_TO_STRING);
        // Uses Enum.toString() for deserialization of an Enum
        this.enable(READ_ENUMS_USING_TO_STRING);
    }
}

还有更多与枚举相关的功能,请参见此处:

https://github.com/FasterXML/jackson-databind/wiki/Serialization-features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features


4
我同意。此外,在Jackson 2.5中,您不需要自定义对象映射器。只是这样做:objMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);和这样的:objMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
杰克多伦多

14

这是我的解决方案。我要转换枚举{id: ..., name: ...}形式。

使用Jackson 1.x

pom.xml:

<properties>
    <jackson.version>1.9.13</jackson.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>

Rule.java:

import org.codehaus.jackson.map.annotate.JsonSerialize;
import my.NamedEnumJsonSerializer;
import my.NamedEnum;

@Entity
@Table(name = "RULE")
public class Rule {
    @Column(name = "STATUS", nullable = false, updatable = true)
    @Enumerated(EnumType.STRING)
    @JsonSerialize(using = NamedEnumJsonSerializer.class)
    private Status status;
    public Status getStatus() { return status; }
    public void setStatus(Status status) { this.status = status; }

    public static enum Status implements NamedEnum {
        OPEN("open rule"),
        CLOSED("closed rule"),
        WORKING("rule in work");

        private String name;
        Status(String name) { this.name = name; }
        public String getName() { return this.name; }
    };
}

名为Enum.java:

package my;

public interface NamedEnum {
    String name();
    String getName();
}

名为EnumJsonSerializer.java:

package my;

import my.NamedEnum;
import java.io.IOException;
import java.util.*;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class NamedEnumJsonSerializer extends JsonSerializer<NamedEnum> {
    @Override
    public void serialize(NamedEnum value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        Map<String, String> map = new HashMap<>();
        map.put("id", value.name());
        map.put("name", value.getName());
        jgen.writeObject(map);
    }
}

使用Jackson 2.x

pom.xml:

<properties>
    <jackson.version>2.3.3</jackson.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>

Rule.java:

import com.fasterxml.jackson.annotation.JsonFormat;

@Entity
@Table(name = "RULE")
public class Rule {
    @Column(name = "STATUS", nullable = false, updatable = true)
    @Enumerated(EnumType.STRING)
    private Status status;
    public Status getStatus() { return status; }
    public void setStatus(Status status) { this.status = status; }

    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    public static enum Status {
        OPEN("open rule"),
        CLOSED("closed rule"),
        WORKING("rule in work");

        private String name;
        Status(String name) { this.name = name; }
        public String getName() { return this.name; }
        public String getId() { return this.name(); }
    };
}

Rule.Status.CLOSED转换为{id: "CLOSED", name: "closed rule"}


优秀的。您救了我的一天:-)
斯里兰卡,2016年

4

序列化Enum的一种简单方法是使用@JsonFormat批注。@JsonFormat可以通过三种方式配置Enum的序列化。

@JsonFormat.Shape.STRING
public Enum OrderType {...}

使用OrderType :: name作为序列化方法。OrderType.TypeA的序列化为“TYPEA”

@JsonFormat.Shape.NUMBER
Public Enum OrderTYpe{...}

使用OrderType :: ordinal作为序列化方法。OrderType.TypeA的序列化为1

@JsonFormat.Shape.OBJECT
Public Enum OrderType{...}

将OrderType视为POJO。OrderType.TypeA的序列化为{"id":1,"name":"Type A"}

JsonFormat.Shape.OBJECT是您所需要的。

解决方案稍微复杂一点,为Enum指定一个序列化器。

查看此参考:https : //fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonFormat.html


3

使用@JsonCreator批注,创建方法getType(),通过toString或对象工作进行序列化

{"ATIVO"}

要么

{"type": "ATIVO", "descricao": "Ativo"}

...

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

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

    ATIVO("Ativo"),
    PENDENTE_VALIDACAO("Pendente de Validação"),
    INATIVO("Inativo"),
    BLOQUEADO("Bloqueado"),
    /**
     * Usuarios cadastrados pelos clientes que não possuem acesso a aplicacao,
     * caso venham a se cadastrar este status deve ser alterado
     */
    NAO_REGISTRADO("Não Registrado");

    private SituacaoUsuario(String descricao) {
        this.descricao = descricao;
    }

    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    // TODO - Adicionar metodos dinamicamente
    public String getType() {
        return this.toString();
    }

    public String getPropertieKey() {
        StringBuilder sb = new StringBuilder("enum.");
        sb.append(this.getClass().getName()).append(".");
        sb.append(toString());
        return sb.toString().toLowerCase();
    }

    @JsonCreator
    public static SituacaoUsuario fromObject(JsonNode node) {
        String type = null;
        if (node.getNodeType().equals(JsonNodeType.STRING)) {
            type = node.asText();
        } else {
            if (!node.has("type")) {
                throw new IllegalArgumentException();
            }
            type = node.get("type").asText();
        }
        return valueOf(type);
    }

}

0

在Spring Boot 2中,最简单的方法是在application.properties中声明:

spring.jackson.serialization.WRITE_ENUMS_USING_TO_STRING=true
spring.jackson.deserialization.READ_ENUMS_USING_TO_STRING=true

并定义枚举的toString()方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.