Serializing enums with Jackson


90

Tôi có một Enum desrcibed bên dưới:

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....
}

Tôi trả về mảng enum với controller ( new OrderType[] {UNKNOWN,TYPEA,TYPEB,TYPEC};) của mình và Spring sắp xếp nó thành chuỗi json sau:

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

Cách tốt nhất để buộc Jackson phải nối tiếp các enums giống như POJO? Ví dụ:

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

Tôi đã chơi với các chú thích khác nhau nhưng không thể đạt được kết quả như vậy.


1
Có vẻ như bạn đã tìm thấy giải pháp; tuyệt quá! Có tò mò là tại sao bạn cần nó?
StaxMan

Tôi đang phát triển một ứng dụng GWT giao tiếp với phía máy chủ thông qua JSON. Enum này sẽ cung cấp các giá trị tùy chọn cho combobox.
Nofate

À được rồi. Vì vậy, loại ngắn hạn cho tập hợp các giá trị ... thú vị.
StaxMan

Câu trả lời:


87

Cuối cùng tôi đã tìm ra giải pháp cho mình.

Tôi đã phải chú thích enum với @JsonSerialize(using = OrderTypeSerializer.class)và triển khai bộ nối tiếp tùy chỉnh:

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
Lưu ý rằng để cấu hình Jackson sử dụng xử lý tuần tự hóa (de) tùy chỉnh, một giải pháp thay thế cho việc sử dụng chú thích là đăng ký (de) trình tuần tự hóa với một mô-đun cấu hình. wiki.fasterxml.com/JacksonHowToCustomSerializers
Lập trình viên Bruce

1
Điều này không hoạt động đối với tôi khi sử dụng Spring 3.1.1. @Controller của tôi vẫn trả về json mà không có thuộc tính của tôi.
Dave

Tôi có Một số Enums, Và tôi muốn có Tất cả Enums với một chức năng. Tôi làm nó như thế nào?
Morteza Malvandi

Đối với một loại enum, tôi phải xác định một bộ khử không khí tùy chỉnh. Có bất kỳ giải pháp chung chung?
Chao

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

khả dụng kể từ https://github.com/FasterXML/jackson-databind/issues/24

vừa thử nghiệm nó hoạt động với phiên bản 2.1.2

câu trả lời cho TheZuck :

Tôi đã thử ví dụ của bạn, có Json:

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

Mã của tôi:

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

và phụ thuộc là:

<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
Tôi thích giải pháp thay thế này, nó sạch hơn, tuy nhiên, tôi đã thử nó với lớp này và loại không nhận được tuần tự hóa, bất kỳ ý kiến ​​nào sai? @JsonFormat (shape = JsonFormat.Shape.OBJECT) @JsonAutoDetect () public enum Event {VISIT_WEBSITE (Type.ADMIN); @JsonProperty loại public Type; public Type getType () {return type; } Sự kiện (Loại kiểu) {this.type = type; } public enum Type {ADMIN, CONSUMER,}} Tôi đang sử dụng Jackson 2.1.2
TheZuck

Tôi đã thêm các chi tiết khác để cơ thể của câu trả lời
Vecnas

phát hiện ra điều gì sai, tôi đang sử dụng Jackson 2.1.2 nhưng phiên bản Spring của tôi vẫn là 3.1 do đó không hỗ trợ phiên bản này. Đã nâng cấp lên 3.2.1 và hiện tại tất cả đều tốt. Cảm ơn!
TheZuck

@Vecnas Tôi có thể ghi đè mặc định @JsonFormatcủa enum khi nó được sử dụng trong thực thể khác không? ví dụ một thực thể mà tôi muốn enum phải được tuần tự hóa dưới dạng một chuỗi thay vì một đối tượng. tôi cố gắng thêm một trường khác @JsonFormatvào trường trong lớp sử dụng enum nhưng nó luôn được tuần tự hóa như một đối tượng.
herau

Những gì tôi đã tìm thấy, hãy sử dụng - @JsonSerialize (using = ToStringSerializer.class) cho một trường, nó sử dụng toString (). Không giải pháp chặt chẽ, nhưng công trình
Vecnas

25

Tôi đã tìm thấy một giải pháp rất hay và ngắn gọn, đặc biệt hữu ích khi bạn không thể sửa đổi các lớp enum như trong trường hợp của tôi. Sau đó, bạn nên cung cấp một ObjectMapper tùy chỉnh với một tính năng nhất định được bật. Những tính năng đó có sẵn kể từ 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);
    }
}

Có nhiều tính năng liên quan đến enum có sẵn, xem tại đây:

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


4
Tôi đồng ý. Hơn nữa, trong Jackson 2.5, bạn không cần một trình ánh xạ đối tượng tùy chỉnh. Chỉ cần làm điều này: objMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);và điều này:objMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
Jake Toronto

14

Đây là giải pháp của tôi. Tôi muốn biến đổi enum {id: ..., name: ...}thành hình thức.

Với 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; }
    };
}

NamedEnum.java:

package my;

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

NamedEnumJsonSerializer.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);
    }
}

Với 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được dịch sang {id: "CLOSED", name: "closed rule"}.


Thông minh. Bạn đã cứu ngày của tôi :-)
sriram

4

Một cách dễ dàng để tuần tự hóa Enum là sử dụng chú thích @JsonFormat. @JsonFormat có thể định cấu hình tuần tự hóa Enum theo ba cách.

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

sử dụng OrderType :: name làm phương thức tuần tự hóa. Serialization của OrderType.TypeA là“TYPEA”

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

sử dụng OrderType :: ordinal làm phương thức tuần tự hóa. Serialization của OrderType.TypeA là1

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

coi OrderType như một POJO. Serialization của OrderType.TypeA là{"id":1,"name":"Type A"}

JsonFormat.Shape.OBJECT là thứ bạn cần trong trường hợp của mình.

Cách phức tạp hơn một chút là giải pháp của bạn, chỉ định một bộ tuần tự cho Enum.

Kiểm tra tài liệu tham khảo này: https://fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonFormat.html


3

Sử dụng chú thích @JsonCreator, tạo phương thức getType (), được tuần tự hóa với toString hoặc đối tượng hoạt động

{"ATIVO"}

hoặc là

{"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

Trong Spring Boot 2, cách dễ nhất là khai báo trong application.properties của bạn:

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

và xác định phương thức toString () của enums của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.