poo*_*man 208 java enums jsonserializer jackson
我正在使用JAVA 1.6和Jackson 1.9.9我有一个枚举
public enum Event {
FORGOT_PASSWORD("forgot password");
private final String value;
private Event(final String description) {
this.value = description;
}
@JsonValue
final String value() {
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
我添加了一个@JsonValue,这似乎完成了将对象序列化为:
{"event":"forgot password"}
Run Code Online (Sandbox Code Playgroud)
但是当我尝试反序列化时,我得到了一个
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.globalrelay.gas.appsjson.authportal.Event from String value 'forgot password': value not one of declared Enum instance names
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?
Agu*_*hez 266
xbakesx指出的串行器/解串器解决方案是一个很好的解决方案,如果你想完全解耦yor枚举类和它的JSON表示.
或者,如果您更喜欢自包含的解决方案,则基于@JsonCreator和@JsonValue注释的实现将更加方便.
因此,利用Stanley的示例,以下是一个完整的自包含解决方案(Java 6,Jackson 1.9):
public enum DeviceScheduleFormat {
Weekday,
EvenOdd,
Interval;
private static Map<String, DeviceScheduleFormat> namesMap = new HashMap<String, DeviceScheduleFormat>(3);
static {
namesMap.put("weekday", Weekday);
namesMap.put("even-odd", EvenOdd);
namesMap.put("interval", Interval);
}
@JsonCreator
public static DeviceScheduleFormat forValue(String value) {
return namesMap.get(StringUtils.lowerCase(value));
}
@JsonValue
public String toValue() {
for (Entry<String, DeviceScheduleFormat> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}
return null; // or fail
}
}
Run Code Online (Sandbox Code Playgroud)
小智 194
请注意,截至2015年6月(Jackson 2.6.2及更高版本)的提交,您现在可以简单地写道:
public enum Event {
@JsonProperty("forgot password")
FORGOT_PASSWORD;
}
Run Code Online (Sandbox Code Playgroud)
Sta*_*ley 86
你应该创建一个静态工厂方法,它接受单个参数并用它注释@JsonCreator(从Jackson 1.2开始可用)
@JsonCreator
public static Event forValue(String value) { ... }
Run Code Online (Sandbox Code Playgroud)
在这里阅读有关JsonCreator注释的更多信息.
xba*_*esx 41
实际答案:
枚举的默认反序列化程序用于.name()反序列化,因此它不使用@JsonValue.所以@OldCurmudgeon指出,你需要传入{"event": "FORGOT_PASSWORD"}以匹配该.name()值.
另一个选项(假设您希望写入和读取json值相同)...
更多信息:
还有另一种管理Jackson的序列化和反序列化过程的方法.您可以指定这些注释以使用您自己的自定义序列化程序和反序列化程序:
@JsonSerialize(using = MySerializer.class)
@JsonDeserialize(using = MyDeserializer.class)
public final class MyClass {
...
}
Run Code Online (Sandbox Code Playgroud)
然后,你必须编写MySerializer和MyDeserializer它看起来像这样:
MySerializer
public final class MySerializer extends JsonSerializer<MyClass>
{
@Override
public void serialize(final MyClass yourClassHere, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
// here you'd write data to the stream with gen.write...() methods
}
}
Run Code Online (Sandbox Code Playgroud)
MyDeserializer
public final class MyDeserializer extends org.codehaus.jackson.map.JsonDeserializer<MyClass>
{
@Override
public MyClass deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
// then you'd do something like parser.getInt() or whatever to pull data off the parser
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
最后一点,特别是对于JsonEnum使用该方法序列化的枚举这样做getYourValue(),您的序列化器和反序列化器可能如下所示:
public void serialize(final JsonEnum enumValue, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
gen.writeString(enumValue.getYourValue());
}
public JsonEnum deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
final String jsonValue = parser.getText();
for (final JsonEnum enumValue : JsonEnum.values())
{
if (enumValue.getYourValue().equals(jsonValue))
{
return enumValue;
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
lag*_*van 31
我找到了一个非常简洁的解决方案,当你不能像我的情况那样修改枚举类时特别有用.然后,您应该提供自定义的ObjectMapper,并启用某个功能.自Jackson 1.6以来,这些功能可用.所以你只需要toString()在枚举中编写方法.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
有更多与枚举相关的功能,请参见此处:
https://github.com/FasterXML/jackson-databind/wiki/Serialization-Features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features
小智 15
我喜欢接受的答案。不过,我会稍微改进一下(考虑到现在有高于版本 6 的 Java 可用)。
例子:
public enum Operation {
EQUAL("eq"),
NOT_EQUAL("ne"),
LESS_THAN("lt"),
GREATER_THAN("gt");
private final String value;
Operation(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
@JsonCreator
public static Operation forValue(String value) {
return Arrays.stream(Operation.values())
.filter(op -> op.getValue().equals(value))
.findFirst()
.orElseThrow(); // depending on requirements: can be .orElse(null);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以为任何属性定制反序列化。
使用注解JsonDeserialize(import com.fasterxml.jackson.databind.annotation.JsonDeserialize)声明将要反序列化的类的属性。如果这是一个枚举:
@JsonDeserialize(using = MyEnumDeserialize.class)
private MyEnum myEnum;
Run Code Online (Sandbox Code Playgroud)
这样,您的类将用于反序列化属性。这是一个完整的示例:
public class MyEnumDeserialize extends JsonDeserializer<MyEnum> {
@Override
public MyEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
MyEnum type = null;
try{
if(node.get("attr") != null){
type = MyEnum.get(Long.parseLong(node.get("attr").asText()));
if (type != null) {
return type;
}
}
}catch(Exception e){
type = null;
}
return type;
}
}
Run Code Online (Sandbox Code Playgroud)
这是另一个使用字符串值而不是映射的示例。
public enum Operator {
EQUAL(new String[]{"=","==","==="}),
NOT_EQUAL(new String[]{"!=","<>"}),
LESS_THAN(new String[]{"<"}),
LESS_THAN_EQUAL(new String[]{"<="}),
GREATER_THAN(new String[]{">"}),
GREATER_THAN_EQUAL(new String[]{">="}),
EXISTS(new String[]{"not null", "exists"}),
NOT_EXISTS(new String[]{"is null", "not exists"}),
MATCH(new String[]{"match"});
private String[] value;
Operator(String[] value) {
this.value = value;
}
@JsonValue
public String toStringOperator(){
return value[0];
}
@JsonCreator
public static Operator fromStringOperator(String stringOperator) {
if(stringOperator != null) {
for(Operator operator : Operator.values()) {
for(String operatorString : operator.value) {
if (stringOperator.equalsIgnoreCase(operatorString)) {
return operator;
}
}
}
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以采用多种方法将 JSON 对象反序列化为枚举。我最喜欢的风格是做一个内部类:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.fasterxml.jackson.annotation.JsonFormat.Shape.OBJECT;
@JsonFormat(shape = OBJECT)
public enum FinancialAccountSubAccountType {
MAIN("Main"),
MAIN_DISCOUNT("Main Discount");
private final static Map<String, FinancialAccountSubAccountType> ENUM_NAME_MAP;
static {
ENUM_NAME_MAP = Arrays.stream(FinancialAccountSubAccountType.values())
.collect(Collectors.toMap(
Enum::name,
Function.identity()));
}
private final String displayName;
FinancialAccountSubAccountType(String displayName) {
this.displayName = displayName;
}
@JsonCreator
public static FinancialAccountSubAccountType fromJson(Request request) {
return ENUM_NAME_MAP.get(request.getCode());
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
private static class Request {
@NotEmpty(message = "Financial account sub-account type code is required")
private final String code;
private final String displayName;
@JsonCreator
private Request(@JsonProperty("code") String code,
@JsonProperty("name") String displayName) {
this.code = code;
this.displayName = displayName;
}
public String getCode() {
return code;
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在枚举的上下文中,使用@JsonValuenow(自 2.0 起)可用于序列化和反序列化。
根据Jackson-annotations javadoc@JsonValue:
注意:当用于 Java 枚举时,另一个特性是带注释的方法返回的值也被视为要反序列化的值,而不仅仅是要序列化的 JSON 字符串。这是可能的,因为 Enum 值集是常量,并且可以定义映射,但对于 POJO 类型通常不能这样做;因此,这不用于 POJO 反序列化。
因此,Event在 Jackson 2.0+ 中,按照上面的方式注释枚举(对于序列化和反序列化)。
小智 5
尝试这个。
公共枚举事件{
FORGOT_PASSWORD(“忘记密码”);
私有最终String值;
私人事件(最终字符串描述){
this.value =说明;
}
私人Event(){
this.value = this.name();
}
@JsonValue
最终的String value(){
返回this.value;
}
}
| 归档时间: |
|
| 查看次数: |
220286 次 |
| 最近记录: |