FasterXML / jackson-dataformat-xml

Extension for Jackson JSON processor that adds support for serializing POJOs as XML (and deserializing from XML) as an alternative to JSON

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`XmlMapper` serializes `@JsonAppend` property twice

cowtowncoder opened this issue · comments

Discussed in FasterXML/jackson-databind#3806

Originally posted by stepince March 5, 2023
XmlMapper is serializing jsonAppend virtual property twice. ObjectMapper for json works correctly.

jackson version: 2.14.1

public class VirtualBeanPropertyWriterTest {
    @Test
    public void testJsonAppend() throws Exception {
        ObjectMapper mapper = new XmlMapper();
        String xml = mapper.writeValueAsString(new Pojo("foo"));
        assertEquals("<Pojo><name>foo</name><virtual>bar</virtual></Pojo>",xml);
    }

    @JsonAppend(props = @JsonAppend.Prop(name = "virtual", value = MyVirtualPropertyWriter.class))
    public static class Pojo {
        private final String name;

        public Pojo(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    public static class MyVirtualPropertyWriter extends VirtualBeanPropertyWriter {
        public MyVirtualPropertyWriter() {}

        protected MyVirtualPropertyWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations,
                                          JavaType declaredType) {
            super(propDef, contextAnnotations, declaredType);
        }

        @Override
        protected Object value(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception {
            return "bar";
        }

        @Override
        public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass,
                                                    BeanPropertyDefinition propDef, JavaType type) {

            return new MyVirtualPropertyWriter(propDef, declaringClass.getAnnotations(), type);
        }
    }
}

output

org.opentest4j.AssertionFailedError: 
Expected :`<Pojo><name>foo</name><virtual>bar</virtual></Pojo>`
Actual   :`<Pojo><name>foo</name><virtual>bar</virtual><virtual>bar</virtual></Pojo>`
</div>

Sounds like a flaw. Thank you for reporting @stepince

Any workaround for this issue? I am actually using a mixin class for the serialization. Maybe in VirtualBeanPropertyWriter Impl check if the property has been written. Not sure if this is possible?

@stepince Without knowing why it's failing it is hard to suggest any workaround. But no, writer should not really have to check for anything, backend should not write duplicates.

I hope I'll have time to look into this in near future -- existence of unit test should be great help.

Hi @cowtowncoder,

Not sure if this helps, but I was able to track down where the property is getting set twice. It is in this file (AnnotationIntrospectorPair.java) lines 594 and 595. The first virtual prop is getting set when _primary calls findAndAddVirtualProperties and also the second time when _secondary calls findAndAddVirtualProperties. Thanks.

@mukham12 that is indeed helpful! Question then being why do we have 2 JacksonAnnotationIntrospector instances registered (-Pair is used to combine 2 AIs).

Ah. That is because JacksonXmlModule inserts our special JacksonXmlAnnotationIntrospector; it won't (and basically can't) replace plain JacksonAnnotationIntrospector. But what that means, then, is that it doubles up this call.

Hmmh. In a way fix is easy, although I need to think it through -- basically have a switch to prevent some of the calls to super class. The reason for a switch (as opposed to just blocking) is that this implementation may be used directly as well, as a replacement of JacksonAnnotationIntrospector (instead of augmenting) -- if so, calls should be handled by base implementation.

But at least I now know how to implement this.

Happy to help.

I may be able to help with the implementation if you can just nudge me in the right direction and lay out the overall plan. Thanks.