2011-10-14 309 views
82

序列化枚举我有一个枚举下面desrcibed:与杰克逊

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

什么是迫使杰克逊像POJO一样序列化枚举的最佳方法?例如:

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

我玩过不同的注释但无法获得这样的结果。

+1

看起来你已经找到了解决办法;大!很好奇你为什么需要它? – StaxMan

+0

我正在开发一个通过JSON与服务器端通信的GWT应用程序。此枚举将为组合框提供选项值。 – Nofate

+0

好的。所以对于一组价值观来说,这很有意思。 – StaxMan

回答

85

最后我自己找到了解决方案。

我不得不注释枚举与@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使用自定义(反)序列化处理,使用注释的替代方法是使用配置模块注册(解除)序列化器。 http://wiki.fasterxml.com/JacksonHowToCustomSerializers –

+1

这对我使用Spring 3.1.1不起作用。我的@Controller仍然返回没有我的属性的json。 – Dave

+0

我有一些枚举,并且我想要使用一个函数获取所有枚举。我该怎么做? –

73
@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事件{ \t VISIT_WEBSITE(Type.ADMIN); \t \t @JsonProperty \t \t public Type type; \t \t public Type getType(){ \t \t return type; \t} \t \t 事件(类型类型){ \t \t this.type =类型; \t} \t \t公共枚举类型{ \t \t ADMIN, \t \t消费者 \t}} 我使用杰克逊2.1.2 – TheZuck

+0

我已经添加了额外的细节来回答 – Vecnas

+0

的身体发现了什么是错误的,我使用杰克逊2.1.2,但我的春天版本仍然是3.1因此不支持这个版本。升级到3.2.1,现在一切正常。谢谢! – TheZuck

11

这里是我的解决方案。我想要将枚举转换为{id: ..., name: ...}表单。

随着杰克逊的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); 
    } 
} 

杰克逊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> 

规则。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"}

+0

优秀。你救了我的一天:-) – sriram

21

我发现了一个非常好的简洁的解决方案,当你不能像修改我的情况那样修改枚举类时特别有用。然后,您应该提供一个自定义的ObjectMapper,并启用某个功能。这些功能从杰克逊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

+2

这是正确的答案。 – ccleve

+3

我同意。而且,在Jackson 2.5中,您不需要自定义对象映射器。只需执行以下操作:'objMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);'和this:'objMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);' –

2

使用@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); 
    } 

} 
2

一个简单的方法来序列化枚举使用@JsonFormat注解。 @JsonFormat可以通过三种方式配置Enum的序列化。

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

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

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

使用订单类型::序号作为序列化方法。 OrderType.TypeA的串行化是1

@JsonFormat.Shape.OBJECT 
Public Enum 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