Serializing enums with Jackson

后端 未结 7 1318
借酒劲吻你
借酒劲吻你 2020-11-28 01:50

I have an Enum desrcibed below:

public enum OrderType {

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


        
相关标签:
7条回答
  • 2020-11-28 02:15

    Here is my solution. I want transform enum to {id: ..., name: ...} form.

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

    With 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 translated to {id: "CLOSED", name: "closed rule"}.

    0 讨论(0)
  • 2020-11-28 02:16

    In Spring Boot 2, the easiest way is to declare in your application.properties:

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

    and define the toString() method of your enums.

    0 讨论(0)
  • 2020-11-28 02:23

    Finally I found solution myself.

    I had to annotate enum with @JsonSerialize(using = OrderTypeSerializer.class) and implement custom 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();
      }
    }
    
    0 讨论(0)
  • 2020-11-28 02:24

    An easy way to serialize Enum is using @JsonFormat annotation. @JsonFormat can configure the serialization of a Enum in three ways.

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

    uses OrderType::name as the serialization method. Serialization of OrderType.TypeA is “TYPEA”

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

    uses OrderType::ordinal as the serialization method. Serialization of OrderType.TypeA is 1

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

    treats OrderType as a POJO. Serialization of OrderType.TypeA is {"id":1,"name":"Type A"}

    JsonFormat.Shape.OBJECT is what you need in your case.

    A little more complicated way is your solution, specifying a serializer for the Enum.

    Check out this reference: https://fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonFormat.html

    0 讨论(0)
  • 2020-11-28 02:25

    Use @JsonCreator annotation, create method getType(), is serialize with toString or object working

    {"ATIVO"}
    

    or

    {"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 讨论(0)
  • 2020-11-28 02:26

    I've found a very nice and concise solution, especially useful when you cannot modify enum classes as it was in my case. Then you should provide a custom ObjectMapper with a certain feature enabled. Those features are available since 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);
        }
    }
    

    There are more enum-related features available, see here:

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

    0 讨论(0)
提交回复
热议问题