Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization of a polymorphic class As.Property with Identity information doesn't work #81

Closed
pgelinas opened this issue Dec 4, 2013 · 4 comments

Comments

@pgelinas
Copy link
Member

pgelinas commented Dec 4, 2013

Basically, XmlBeanSerializer#serializeWithType doesn't take into account Object Id when it sets "NextIsAttribute". I'll try to attach a unit test, probably tomorrow.


Exception in thread "main" java.io.IOException: javax.xml.stream.XMLStreamException: Trying to write an attribute when there is no open start element.
    at com.fasterxml.jackson.dataformat.xml.util.StaxUtil.throwXmlAsIOException(StaxUtil.java:24)
    at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeString(ToXmlGenerator.java:498)
    at com.fasterxml.jackson.databind.ser.std.StringSerializer.serialize(StringSerializer.java:39)
    at com.fasterxml.jackson.databind.ser.std.StringSerializer.serialize(StringSerializer.java:21)
    at com.fasterxml.jackson.databind.ser.impl.WritableObjectId.writeAsId(WritableObjectId.java:36)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:575)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeWithType(BeanSerializerBase.java:514)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serializeWithType(XmlBeanSerializer.java:253)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:543)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serializeFields(XmlBeanSerializer.java:161)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:560)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:145)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanPropertyWriter.serializeAsField(XmlBeanPropertyWriter.java:127)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serializeFields(XmlBeanSerializer.java:161)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider.serializeValue(XmlSerializerProvider.java:92)
    at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:809)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:633)
    at com.nuecho.desjardins.CsvConfigLoader.main(CsvConfigLoader.java:355)
Caused by: javax.xml.stream.XMLStreamException: Trying to write an attribute when there is no open start element.
    at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1522)
    at com.ctc.wstx.sw.RepairingNsStreamWriter.writeAttribute(RepairingNsStreamWriter.java:110)
    at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeString(ToXmlGenerator.java:482)
    ... 20 more
@pgelinas
Copy link
Member Author

pgelinas commented Dec 5, 2013

As a note, this happens when trying to write an object as a reference, only the id and not the full object.

@pgelinas
Copy link
Member Author

pgelinas commented Dec 5, 2013

I found two ways to fix this issue:

  • the assumption to generate the "type" property as an xml attribute is removed. This is the easiest code modification, but it changes how the Xml is serialized. Not a big deal, IMHO.
  • Change BeanSerializerBase to enable sub-class to modify the object id serialization processing flow. Basically, this require either removing the "final" modifier on _serializeWithObjectId or extracting the bottom part of that method (starting at String typeStr = (_typeId == null) ? null :_customTypeId(bean);) into a new method, which isn't final. This is still relatively simple to do, but it changes a little bit the API so dataformat-xml 2.3.1 would require databind 2.3.1 and not 2.3.0 anymore, so I don't know if this is possible for a patch version.

Currently, I've built locally a SNAPSHOT version of databind and dataformat xml with the second solution and using that in the project, and it works pretty well.

pgelinas pushed a commit to pgelinas/jackson-databind that referenced this issue Jan 28, 2014
pgelinas pushed a commit to pgelinas/jackson-dataformat-xml that referenced this issue Jan 28, 2014
pgelinas pushed a commit to pgelinas/jackson-dataformat-xml that referenced this issue Jan 28, 2014
pgelinas pushed a commit to pgelinas/jackson-dataformat-xml that referenced this issue Jan 28, 2014
pgelinas pushed a commit to pgelinas/jackson-dataformat-xml that referenced this issue Jan 28, 2014
pgelinas pushed a commit to pgelinas/jackson-dataformat-xml that referenced this issue Jan 28, 2014
cowtowncoder added a commit that referenced this issue Jan 28, 2014
@lightbringer
Copy link

This seems to be a pretty old issue, but I've just encountered it in 2.8.9:

@JsonIdentityInfo( generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id" )
@JacksonXmlRootElement( localName = "a" )
public class A {
    public static void main( String[] args ) throws IOException {
        final A a = new A();
        a.b = new B(); //B has a reference back to A
        a.b.setA( a );
        
        final XmlMapper mapper = new XmlMapper();
        final String json = mapper.writeValueAsString( a );
        System.out.println( json );
    }

    private B b;

    private String name = "test";

    
    @JacksonXmlProperty( isAttribute = true ) //test runs with isAttribute set to false (but serializes name as an elment
    public String getName() {
        return name;
    }
 //other getter/setter omitted for brevity    

Expected output:

<a name="test">
<id>1</id>
<b>
<a>1</a>
</b>
</a>

Instead the exception:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Unexpected IOException (of type java.io.IOException): javax.xml.stream.XMLStreamException: Trying to write an attribute when there is no open start element.
at com.fasterxml.jackson.databind.JsonMappingException.fromUnexpectedIOE(JsonMappingException.java:333)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3077)
at test.A.main(A.java:20)

is thrown. Removing the JsonIdentityInfo annotation solves the issue as well, i.e. name is serialized as an attribute, but then the circular reference causes a stack overflow.

@cowtowncoder
Copy link
Member

@lightbringer Please file a new issue -- I try not open closed issues since this makes it difficult to track where fixes go. This may or may not be same or related issue; it makes sense to add a reference this as possibly related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants