簡體   English   中英

使用沒有注釋的 Jackson 將列表序列化為 xml?

[英]Serialize List to xml with Jackson without Annotation?

我正在尋找一種在不使用 Jackson 注釋的情況下(反)序列化項目List的方法。 這可能嗎? 到目前為止,我正在做的是嘗試將<item> -tag 替換為一個說明項目類別的標簽,但無濟於事。 即使這行得通,我也不確定 Jackson 是否會提供處理此標簽信息的方法。

為了更好地了解我的目標,這里有一個示例:

public class JacksonTest {

    private static class ListElement {
        private boolean value;
        // getters, setters, constructors omitted
    }

    @Test
    public void testDeSerialization() throws Exception {
        final List<ListElement> existing = Arrays.asList(new ListElement(true));
        final ObjectMapper mapper = new XmlMapper();
        final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
        final String listString = mapper.writerFor(listJavaType).writeValueAsString(existing);
        System.out.println(listString);
        // "<List><item><value>true</value></item></List>"
    }

}

因此,結果是<List><item><value>true</value></item></List> ,而我希望將<item> -tag 替換為(限定的)類名或提供一個type屬性。 當然,如果 Jackson 沒有辦法處理這個類名,即使這樣也無濟於事。

我在這里已經走到了死胡同還是有路可走?

您可以定義自己的 JsonSerializer(也用於 XML)並將其添加到 JacksonXmlModule。

ToXmlGenerator 有一個 setNextName 函數,允許你覆蓋默認的項目名稱

private class MyListSerializer extends JsonSerializer<List> {
    @Override
    public void serialize(List list, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException {
        for (Object obj : list) {
            if (jsonGenerator instanceof ToXmlGenerator) {
                ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
                String className = obj.getClass().getSimpleName();
                xmlGenerator.setNextName(new QName(className));
            }
            jsonGenerator.writeObject(obj);
            // this is overridden at the next iteration
            // and ignored at the last
            jsonGenerator.writeFieldName("dummy");
        }
    }

    @Override
    public Class<List> handledType() {
        return List.class;
    }
}

@Test
public void testDeSerialization() throws Exception {
    final List<ListElement> existing = Arrays.asList(new ListElement(true));
    JacksonXmlModule module = new JacksonXmlModule();
    module.addSerializer(new MyListSerializer());
    final ObjectMapper mapper = new XmlMapper(module);
    final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
    final ObjectWriter writer = mapper.writerFor(listJavaType);
    final String listString = writer.writeValueAsString(existing);
    System.out.println(listString);
    // "<List><ListElement><value>true</value></ListElement></List>"
}

好的,在對 Evertude 的提議進行一些修補和調試之后,我找到了一個解決方案。 我對序列化部分不太滿意,老實說我不知道​​為什么我應該這樣做。 調試時我注意到XmlGenerator::setNextName需要被調用一次,但對下一次調用沒有任何影響,所以我不得不在那里實現一個開關並直接為循環中的下一個項目設置字段名稱。

如果有人知道我做錯了什么,我會很高興,但至少我現在的嘗試是有效的:

@Test
public void testDeSerialization() throws Exception {
    final List<ListElement> existing = Arrays.asList(new ListElement(true), new ListElement(false));
    JacksonXmlModule module = new JacksonXmlModule();
    module.addSerializer(new MyListSerializer());
    final ObjectMapper mapper = new XmlMapper(module);
    final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
    final ObjectWriter writer = mapper.writerFor(listJavaType);
    final String listString = writer.writeValueAsString(existing);
    module.addDeserializer(List.class, new MyListDeserializer());
    List<ListElement> deserialized = mapper.readValue(listString, List.class);
    assertEquals(existing, deserialized); // provided there're proper hash() and equals() methods
}

private class MyListSerializer extends JsonSerializer<List> {

    @Override
    public void serialize(List list, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException {
        boolean done = false;
        for (Object obj : list) {
            if (jsonGenerator instanceof ToXmlGenerator) {
                ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
                String className = obj.getClass().getSimpleName();
                // weird switch
                if (!done) xmlGenerator.setNextName(new QName(className));
                else jsonGenerator.writeFieldName(className);
                done = true;
            }
            jsonGenerator.writeObject(obj);
        }
    }

    @Override
    public Class<List> handledType() {
        return List.class;
    }
}

private class MyListDeserializer extends JsonDeserializer<List> {

    @Override
    public List deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        List<Object> items = new ArrayList<>();
        JsonToken nextToken;
        while ((nextToken = p.nextToken()) != JsonToken.END_OBJECT) {
            String currentName = p.currentName();
            try {
                String className = "my.test.project.JacksonCustomSerializer$" + currentName;
                Class<?> loadClass = getClass().getClassLoader().loadClass(className);
                p.nextToken();
                items.add(p.readValueAs(loadClass));
            } catch (ClassNotFoundException e) {
                // some handling
            }
        }
        return items;
    }

    @Override
    public Class<List> handledType() {
        return List.class;
    }
}

暫無
暫無

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

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