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

Add support for JAXB's @XmlSeeAlso (maybe similar to @JsonSubTypes) to improve JAXB compatibility #195

Open
raphw opened this issue Jan 26, 2023 · 5 comments

Comments

@raphw
Copy link

raphw commented Jan 26, 2023

Problem description

Jackson's XML annotation handler does not currently process the XmlSeeAlso of the JAXB specification. As a result, it is always possible to serialize objects based on JAXB, but it is not possible to deserialize them in all cases. This problem occurs for example if JAXB objects are created by the XJC tool from XSD files that include subtyping.

For example, the following class structure represents a valid JAXB object representation:

class Root {
  Base element;
}

@XmlSeeAlso({First.class, Second.class})
abstract class Base { }

@XmlType(name = "FirstType")
class First extends Base { }

@XmlType(name = "SecondType")
class Second extends Base { }

If base is set to First, JAXB will declare a property in the XML-instance namespace which allows to serialize and to deserialize any input as the type information is retained.

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <element xsi:type="FirstType"/>
</root>

Currently, Jackson discards the type information and neither processes it by resolving against XmlSeeAlso if it was available. If the same object was marshalled to JSON, it would result in the following JSON:

{"element": {}}

which cannot be marshalled to an object and where the necessary information to unmarshall this object is neither retained.

Suggested solution

Jackson should introduce a pseudo-attribute to retain type information to support the same form of type discovery. The created JSON should add the JAXB-type within an annotation as in:

{"element": {"@type": "FirstType"}}

where the client should process this information when unmarshalling to recover the instance type.

I tried an implementation of such support, without knowing if this is the most efficient implementation. Also, I discovered that my solution created a null instance for an empty element object as in the example what I worked around. If there is a better solution to that corner-case, I'd appreciate any feedback. I am happy to offer my time to integrate this into the official JAXB support if this is a desired extension.

@wanjidong
Copy link

This is indeed necessary, and what can be supported will be more convenient!

@cowtowncoder cowtowncoder changed the title Add support for JAXB's XmlSeeAlso to improve JAXB-specification-compliance Add support for JAXB's @XmlSeeAlso (maybe similar to @JsonSubTypes) to improve JAXB compatibility Nov 30, 2023
@cowtowncoder
Copy link
Member

@wanjidong This is one of things where contributions (PR) would be most welcome. I will add a note on how this might be supportable relatively easily.

@cowtowncoder
Copy link
Member

cowtowncoder commented Nov 30, 2023

@raphw I may be overlooking something, but would this work if @XmlSeeAlso was used to provide information similar to what Jackson's own @JsonSubTypes does? That is, something accessed via AnnotationIntrospector method:

    public List<NamedType> findSubtypes(Annotated a)

and so making JAXBAnnotationIntrospector implement that method, using @XmlSeeAlso as source.

This alone would not work without base type having necessary annotation to induce @JsonTypeInfo; although an optional setting could make @XmlSeeAlso also infer equivalent of @JsonTypeInfo (one of JAXB annotations already produces that).

One thing that JAXB annotations module does not and cannot do is add actual handling of annotations; the general limitation is that functionality of AnnotationIntrospector is bound by what Jackson's own annotations provide -- but not further.

@raphw
Copy link
Author

raphw commented Dec 3, 2023

I did not manage to make that work as I needed to add XML xsi info. I ended up implementing a custom module, but it feels rather hacky: https://github.com/raphw/jackson-jaxb-extension

@cowtowncoder
Copy link
Member

Ok looks like basic support for @XmlSeeAlso exists, to find subtypes (which I thought did not exist). If combined with Jackson @JsonTypeInfo, it can be useful and does allow reading back type.
But @XmlSeeAlso does not indicate polymorphic handled with Jackson, and I don't think I'd want to add automatic support for that, at least here -- JAXB annotation introspection is focused on translation and cannot really (or, maybe, shouldn't) add functionality beyond that.

But Jackson 2.17 will actually add support for handling xsi:type as expected (that is, you can use "xsi:type" as Type Id, and with suitable Features enabled, namespace will be automatically deducted), so use of something like:

   @JsonTypeInfo(include = As.PROPERTY, use = Id.SIMPLE_NAME, property="xsi:type")
    @XmlSeeAlso({Sub195A.class, Sub195B.class})
    abstract static class Base195 { }

will work somewhat as expected (with XML module).

cowtowncoder added a commit that referenced this issue Feb 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants