Jackson으로 열거 형 직렬화


90

아래에 설명 된 Enum이 있습니다.

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 2011 년

JSON을 통해 서버 측과 통신하는 GWT 애플리케이션을 개발 중입니다. 이 열거 형은 콤보 상자에 대한 옵션 값을 제공합니다.
Nofate 2011 년

그래. 값 세트에 대한 일종의 속기 ... 흥미 롭습니다.
StaxMan 2011 년

답변:


87

마침내 나는 해결책을 찾았습니다.

enum에 주석을 달고 @JsonSerialize(using = OrderTypeSerializer.class)사용자 지정 serializer를 구현 해야했습니다 .

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
프로그래머 Bruce

1
이것은 Spring 3.1.1을 사용하는 나를 위해 작동하지 않았습니다. 내 @Controller는 여전히 내 속성없이 json을 반환합니다.
Dave

일부 열거 형이 있고 하나의 함수로 모든 열거 형을 얻고 싶습니다. 어떻게하니?
Morteza Malvandi 2015

하나의 열거 형 유형에 대해 사용자 지정 deserializer를 정의해야합니다. 일반적인 솔루션이 있습니까?
Chao

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 () public enum 이벤트 {VISIT_WEBSITE (Type.ADMIN); @JsonProperty 공개 유형 유형; public Type getType () {반환 유형; } Event (유형 유형) {this.type = 유형; } public enum Type {ADMIN, CONSUMER,}} Jackson 2.1.2를 사용하고 있습니다
TheZuck 2013 년

답변 본문에 추가 세부 정보를 추가했습니다
Vecnas 2013-01-27

무엇이 잘못되었는지 알아 내고 Jackson 2.1.2를 사용하고 있었지만 Spring 버전은 여전히 ​​3.1이므로이 버전을 지원하지 않았습니다. 3.2.1로 업그레이드되었으며 모든 것이 잘되었습니다. 감사!
TheZuck 2013-01-27

@Vecnas @JsonFormat다른 엔터티에서 사용될 때 enum 의 기본값 을 재정의 할 수 있습니까 ? 예를 들어 열거 형을 객체 대신 문자열로 직렬화해야하는 엔티티입니다. @JsonFormat열거 형을 사용하는 클래스의 필드에 다른 항목을 추가하려고 시도 하지만 항상 객체로 직렬화됩니다.
herau

내가 찾은 것은 필드에 대해 @JsonSerialize (using = ToStringSerializer.class)를 사용하면 toString ()을 사용합니다. 아니 엄격한 솔루션,하지만 작품
Vecnas

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

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

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


우수한. 당신은 내 하루를 구했습니다 :-)
sriram

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 () 메서드를 정의하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.