簡體   English   中英

如何使用 Jackson 反序列化枚舉?

[英]How to deserialize Enum with Jackson?

用戶將{"lang": ["en_US", "en_UK"]}發送到 REST API。我想填寫一個具有此屬性的 object List<EnmLanguage> lang; . 除 JSON arrays 外,其他所有東西都有效。

我的 EnmLanguage.java 是:

@JsonSerialize(
    using = BaseEnumSerializer.class
)
@JsonDeserialize(
    using = BaseEnumDeserializer.class
)
public enum EnmLanguage implements BaseEnum, Serializable {
    en_US {
        public String getCode() {
            return "en_US";
        }

        public String getText(EnmLanguage s) {
            return s == EnmLanguage.en_US ? "English" : "İngilizce";
        }
    },

我的 BaseEnum.java 是:

public interface BaseEnum {
    Object getCode();

    String getText(EnmLanguage lang);

    default String getText() {
        return this.getText(EnmLanguage.tr_TR);
    }

    default Map<String, Object> getMap(EnmLanguage lang) {
        return new HashMap<String, Object>() {
            {
                this.put("name", BaseEnum.this.getText(lang));
                this.put("id", BaseEnum.this.getCode());
            }
        };
    }

    default Map<String, Object> getMap() {
        return this.getMap(EnmLanguage.tr_TR);
    }

    static <T extends Enum<T> & BaseEnum> T fromCode(Class<T> parent, Object code) {
        Map<Object, T> lookup = new HashMap();
        Enum[] var3 = (Enum[])parent.getEnumConstants();
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            T d = var3[var5];
            lookup.put(((BaseEnum)d).getCode().toString(), d);
        }

        return (Enum)lookup.get(code.toString());
    }
}

我的 BaseEnumDeserialiazer 是:

public class BaseEnumDeserializer<T extends Enum<T> & BaseEnum> extends StdDeserializer<T> {
    public BaseEnumDeserializer() {
        this((Class)null);
    }

    public BaseEnumDeserializer(Class<T> vc) {
        super(vc);
    }

    public T deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException {
        Field field = this.findField(jsonparser.getCurrentName(), jsonparser.getCurrentValue().getClass());
        Class<T> javaType = field.getType();
        return BaseEnum.fromCode(javaType, jsonparser.getText());
    }

    public Field findField(String name, Class<?> c) {
        while(c != null) {
            Field[] var3 = c.getDeclaredFields();
            int var4 = var3.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                Field field = var3[var5];
                if (!Modifier.isStatic(field.getModifiers()) && field.getName().equals(name)) {
                    return field;
                }
            }

            c = c.getSuperclass();
        }

        return null;
    }
}

但最后它不會將"lang": ["en_US", "en_UK"]轉換為EnmLanguage List 我認為它不知道轉換為哪個BaseEnum 我應該如何讓它知道它應該將其轉換為List<EnmLanguage>

對於您的特定情況,在基本類型中添加 static @JsonCreator方法可能就足夠了。

interface Lang {
    @JsonCreator
    static Lang valueOf(String value) {
        return Languages.valueOf(value);
    }
}

@JsonFormat(shape = JsonFormat.Shape.STRING)
enum Languages implements Lang {
    en_US,
    en_GB
}

然后您可以將其解析為任何其他 class

class LangTest {
    private final ObjectMapper mapper = new ObjectMapper()
            .setAnnotationIntrospector(new JacksonAnnotationIntrospector());

    @Test
    void readsJson() throws IOException {
        final Lang[] tree = this.mapper
                .readerFor(Lang[].class)
                .readValue("[\"en_US\", \"en_GB\"]");
        Assertions.assertArrayEquals(
                tree,
                new Lang[]{
                        Languages.en_US,
                        Languages.en_GB
                }
        );
    }
}

這是一個簡單的BaseEnum接口,

public interface BaseEnum {
    Object getCode();

    String getText();
}

這是實現BaseEnum接口的EnmLanguage

public enum EnmLanguage implements BaseEnum {

    en_US("en_US", "English"),
    en_UK("en_UK", "English"),
    tr_TR("tr_TR", "Turkish");

    private String code;

    private String text;

    EnmLanguage(String code, String text) {
        this.code = code;
        this.text = text;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public String getText() {
        return text;
    }
}

這是另一個實現EnmElement接口的BaseEnum

public enum EnmElement implements BaseEnum {

    H("H", "Hydrogen"),
    He("He", "Helium"),
    Li("Li", "Lithium");

    private String code;

    private String text;

    EnmElement(String code, String text) {
        this.code = code;
        this.text = text;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public String getText() {
        return text;
    }
}

這是一個簡單的單元測試,

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.io.IOException;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class EnumTest {

    @Test
    public void testDeserializeLanguage() throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        EnmLanguage[] expected = {EnmLanguage.en_US, EnmLanguage.tr_TR};
        EnmLanguage[] actual = mapper
                .readerFor(EnmLanguage[].class)
                .readValue(mapper.writeValueAsString(expected));
        assertNotNull(actual);
        assertArrayEquals(expected, actual);
    }

    @Test
    public void testDeserializeElement() throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        EnmElement[] expected = {EnmElement.H, EnmElement.He, EnmElement.Li};
        EnmElement[] actual = mapper
                .readerFor(EnmElement[].class)
                .readValue(mapper.writeValueAsString(expected));
        assertNotNull(actual);
        assertArrayEquals(expected, actual);
    }
}

使用枚舉的稍微復雜一點的例子,

import lombok.Data;

@Data
public class CompositeExample {

    private String name;

    private EnmLanguage[] lands;

    private EnmElement[] elements;
}

一個示例單元測試片段,

 @Test
 public void testDeserialize() throws IOException {
     CompositeExample expected = new CompositeExample();

     String name = "Hello";
     expected.setName(name);

     EnmLanguage[] langs = {EnmLanguage.en_US, EnmLanguage.tr_TR};
     expected.setLangs(langs);

     EnmElement[] elements = {EnmElement.H, EnmElement.He,  EnmElement.Li};
     expected.setElements(elements);

     ObjectMapper mapper = new ObjectMapper();
     String json = mapper.writeValueAsString(expected);
     //{"name":"Hello","langs":["en_US","tr_TR"],"elements":["H","He","Li"]}

     CompositeExample actual = mapper
             .readerFor(CompositeExample.class)
             .readValue(json);
     assertNotNull(actual);
     assertEquals(expected, actual);
 }

嘗試使用toString()啟用讀寫枚舉:

objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM