本文介绍了多个Jackson XML自定义(XMLStreamWriter)序列化程序引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果一个类中有多个自定义XML序列化器(XMLStreamWriter),则序列化失败.

If there are multiple custom XML Serializers (XMLStreamWriter) in a class, serialization fails.

我有两个班级:CustomClass1CustomClass2.有一个包装类TestJacksonXml1.当我尝试序列化TestJacksonXml1时,它将引发异常.

I have two classes: CustomClass1, CustomClass2. There is a wrapping class TestJacksonXml1. When I am trying to serialize TestJacksonXml1, it throws an exception.

CustomClass1

CustomClass1

class CustomClass1 {
    int prop1;

    public CustomClass1(int prop1) {
        this.prop1 = prop1;
    }

    public int getProp1() {
        return prop1;
    }

    static class CustomClass1Serializer extends StdSerializer<CustomClass1> {
        public CustomClass1Serializer() { this(null); }

        public CustomClass1Serializer(Class<CustomClass1> t) {
            super(t);
        }

        @Override
        public void serialize(CustomClass1 customClass1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            final ToXmlGenerator toXmlGenerator = (ToXmlGenerator) jsonGenerator;
            final XMLStreamWriter staxWriter = (toXmlGenerator).getStaxWriter();
            try {
                staxWriter.writeStartElement("class1");
                staxWriter.writeCharacters(String.valueOf(customClass1.prop1));
                staxWriter.writeEndElement();
            } catch (XMLStreamException e){
                e.printStackTrace();
            }
        }
    }
}

CustomClass2

CustomClass2

class CustomClass2 {
        int prop2;

        public CustomClass2(int prop2) {
            this.prop2 = prop2;
        }

        public int getProp2() {
            return prop2;
        }

        static class CustomClass2Serializer extends StdSerializer<CustomClass2> {
            public CustomClass2Serializer() { this(null); }

            public CustomClass2Serializer(Class<CustomClass2> t) {
                super(t);
            }

            @Override
            public void serialize(CustomClass2 customClass2, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                final ToXmlGenerator toXmlGenerator = (ToXmlGenerator) jsonGenerator;
                final XMLStreamWriter staxWriter = (toXmlGenerator).getStaxWriter();
                try {
                    staxWriter.writeStartElement("class2");
                    staxWriter.writeCharacters(String.valueOf(customClass2.prop2));
                    staxWriter.writeEndElement();
                } catch (XMLStreamException e){
                    e.printStackTrace();
                }
            }
        }
    }

封闭类

public class TestJacksonXml1 {
    @JsonSerialize(using = CustomClass1.CustomClass1Serializer.class)
    CustomClass1 obj1;

    @JsonSerialize(using = CustomClass2.CustomClass2Serializer.class)
    CustomClass2 obj2;

    public TestJacksonXml1(CustomClass1 obj1, CustomClass2 obj2) {
        this.obj1 = obj1;
        this.obj2 = obj2;
    }

    public CustomClass1 getObj1() {
        return obj1;
    }

    public CustomClass2 getObj2() {
        return obj2;
    }

    public static void main(String[] args) throws JsonProcessingException {
        XmlMapper xmlMapper = new XmlMapper();
        System.out.println(xmlMapper.writeValueAsString(new TestJacksonXml1(new CustomClass1(10), new CustomClass2(20))));
    }
}

我得到的例外是

Exception in thread "main" com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value
    at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1961)
    at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeFieldName(ToXmlGenerator.java:435)
    at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeFieldName(ToXmlGenerator.java:577)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:725)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerBase.serializeFields(XmlBeanSerializerBase.java:202)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serialize(XmlBeanSerializer.java:117)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider.serializeValue(XmlSerializerProvider.java:107)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219)
    at fk.reportsvc.common.TestJacksonXml1.main(TestJacksonXml1.java:39)

当我注释掉其中一个自定义序列化程序时,另一个工作.为什么会这样呢?

When I comment out one of the custom serializers, the other one works. Why is it so?

我们不是应该一次使用两个/多个自定义序列化程序(与XMLStreamWriter一起使用)吗?

Shouldn't we use two/multiple custom serializers (with XMLStreamWriter) at once?

如果我直接使用JsonGenerator而不是XMLStreamWriter,则可以一次使用两个自定义序列化程序.

If I use JsonGenerator directly instead of XMLStreamWriter, then I am able to use both custom serializers at once.

PS:我的实际业务类别包含许多字段,这些字段将转换为嵌套的XML元素和属性.因此,更喜欢直接使用XMLStreamWriter.

PS: My actual business classes contain many fields that are to be converted into nested XML elements and attributes. Hence preferring XMLStreamWriter directly over others.

推荐答案

更简单的方法是使用ToXmlGenerator类中的方法.看一下: setNextName writeRaw writeRepeatedFieldName 方法.在您的情况下,实现可能如下所示:

Much simpler would be to use methods from ToXmlGenerator class. Take a look at: setNextName, writeRaw and writeRepeatedFieldName methods. In your case, implementation could look like below:

class CustomClass2Serializer extends StdSerializer<CustomClass2> {

    private final QName name = new QName("class2");

    public CustomClass2Serializer() {
        super(CustomClass2.class);
    }

    @Override
    public void serialize(CustomClass2 customClass2, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        final ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
        xmlGenerator.setNextName(name);
        xmlGenerator.writeStartObject();
        xmlGenerator.writeRaw(String.valueOf(customClass2.prop2));
        xmlGenerator.writeRepeatedFieldName();
        xmlGenerator.writeEndObject();
    }
}

和:

class CustomClass1Serializer extends StdSerializer<CustomClass1> {

    private final QName name = new QName("class1");

    public CustomClass1Serializer() {
        super(CustomClass1.class);
    }

    @Override
    public void serialize(CustomClass1 customClass1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        final ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
        xmlGenerator.setNextName(name);
        xmlGenerator.writeStartObject();
        xmlGenerator.writeRaw(String.valueOf(customClass1.prop1));
        xmlGenerator.writeRepeatedFieldName();
        xmlGenerator.writeEndObject();
    }
}

生成的XML应该如下所示:

<TestJacksonXml1>
  <class1>10</class1>
  <class2>20</class2>
</TestJacksonXml1>

您遇到的主要问题是要跳过CustomClass1CustomClass1类的object节点.为TestJacksonXml1类实现序列化器会更简单:

Main problem in your case is you want to skip object node for CustomClass1 and CustomClass1 classes. Much simpler would be implementing serialiser for TestJacksonXml1 class:

class TestJacksonXml1JsonSerializer extends JsonSerializer<TestJacksonXml1> {
    @Override
    public void serialize(TestJacksonXml1 value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("class1", String.valueOf(value.obj1.prop1));
        gen.writeStringField("class2", String.valueOf(value.obj2.prop2));
        gen.writeEndObject();
    }
}

现在,TestJacksonXml1类应如下所示:

Now, TestJacksonXml1 class should look like below:

@JsonSerialize(using = TestJacksonXml1JsonSerializer.class)
class TestJacksonXml1 {

    CustomClass1 obj1;
    CustomClass2 obj2;
    // getters, setters, etc
}

它应该生成相同的输出,但是易于实现.

It should generate the same output but is much easier to implement.

这篇关于多个Jackson XML自定义(XMLStreamWriter)序列化程序引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-03 04:13