序列化与jackson的枚举
我有一个枚举如下:
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};
)返回枚举数组,并将其序列化到下面的jsonstring中:
["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"} ]
我玩了不同的注释,但无法得到这样的结果。
最后我自己find解决scheme。
我不得不使用@JsonSerialize(using = OrderTypeSerializer.class)
和@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(); } }
@JsonFormat(shape= JsonFormat.Shape.OBJECT) public enum SomeEnum
可从https://github.com/FasterXML/jackson-databind/issues/24
只是testing它与版本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>
我发现了一个非常好的和简洁的解决scheme,当你不能像在我的情况下那样修改枚举类的时候特别有用。 那么你应该提供一个自定义的ObjectMapper,并启用了一个特定的function。 这些function从jackson1.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); } }
有更多的枚举相关的function可用,请看这里:
https://github.com/FasterXML/jackson-databind/wiki/Serialization-features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features
这是我的解决scheme。 我想要将枚举转换为{id: ..., name: ...}
forms。
随着jackson1.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); } }
随着jackson2.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"}
。
使用@JsonCreator注解,创build方法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); } }
序列化Enum的简单方法是使用@JsonFormat注释。 @JsonFormat可以通过三种方式configurationEnum的序列化。
@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是你需要你的情况。
一个更复杂的方式是你的解决scheme,为Enum指定一个序列化器。
看看这个参考: https : //fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonFormat.html