【问题标题】:Serialize List to xml with Jackson without Annotation?使用没有注释的杰克逊将列表序列化为xml?
【发布时间】:2018-12-06 08:29:28
【问题描述】:

我正在寻找一种方法来(反)序列化 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>"
    }

}

所以,结果是&lt;List&gt;&lt;item&gt;&lt;value&gt;true&lt;/value&gt;&lt;/item&gt;&lt;/List&gt;,而我希望将&lt;item&gt;-tag 替换为(合格的)类名或提供type-attribute。 当然,如果 Jackson 无法处理此类名称,即使这样也无济于事。

我是走到了死胡同还是有路要走?​​p>

【问题讨论】:

    标签: java xml generics collections jackson


    【解决方案1】:

    您可以定义自己的 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>"
    }
    

    【讨论】:

    • 嗯,这看起来是一种可行的方法!谢谢你!但是一旦第二次调用writeObject(obj),它就不适用于具有多个元素的List,因为JsonGenerationException - Can not start an object, expecting field name
    【解决方案2】:

    好的,在对 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-13
      • 2017-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多