Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

@XmlType(propOrder=) overrides propOrder of super classes; should merge #66

Closed
ajdergute opened this issue Aug 1, 2017 · 4 comments
Closed

Comments

@ajdergute
Copy link

Consider the following setup:

// getter and setter omitted in this example

@XmlType(namespace = "http://test/", propOrder = { "prop4", "prop1" })
public abstract class Base {
    private String prop1;
    private int prop4;
}

@XmlType(namespace = "http://test/", propOrder = { "prop3", "prop2" })
public class Child extends Base {
    private String prop3;
    private String prop2;
}

Property order with Jackson now is:
prop3, prop2, prop1, prop4
Expected serializaton:
prop4, prop1, prop2, prop3

It isn't possible to mention prop1 or prop4 in propOrder of class Child, because this class has no getter or setter for this property. I know that there exist more than one assumption how properties are ordered, but to ignore propOrder of super class seems not the desired behaviour.

I tracked down this issue and strongly assume that it's because JaxbAnnotationIntrospector#findSerializationPropertyOrder(AnnotatedClass) doesn't traverse super classes. Thus I changed this method as follows:

    @Override
    public String[] findSerializationPropertyOrder(AnnotatedClass ac) {
        // @XmlType.propOrder fits the bill here:
        AnnotatedClass annotatedClass = ac;

        Deque<XmlType> types = new LinkedList<>();
        // find annotations on class
        types.add(findAnnotation(XmlType.class, annotatedClass, false, false, false));

        // find annotations on super classes
        Class<?> superClass = annotatedClass.getAnnotated().getSuperclass();
        while (null != superClass && !superClass.equals(Object.class)) {
            annotatedClass = AnnotatedClass.construct(superClass, this, null);
            types.add(findAnnotation(XmlType.class, annotatedClass, false, false, false));
            superClass = annotatedClass.getAnnotated().getSuperclass();
        }

        if (types.isEmpty()) {
            return null;
        }

        // merge them in reverse order
        List<String> orderList = new ArrayList<>();
        Iterator<XmlType> reverseIterator = types.descendingIterator();
        while (reverseIterator.hasNext()) {
            XmlType type = reverseIterator.next();
            if (type != null) {
                orderList.addAll(Arrays.asList(type.propOrder()));
            }
        }

        if (orderList.isEmpty()) {
            return null;
        }
        return orderList.toArray(new String[orderList.size()]);
    }

Please change the code like above.
This fixed the issue for us. If one can tell me what's needed (tests?) for a successful pull request I'm willing to create one.

@cowtowncoder
Copy link
Member

I appreciate your suggestion, but the way generic annotation handling works there is no way to merge annotations this way. Perhaps with Jackson 3.x we can try to tackle this, since it would ultimately make sense for many annotations (but not all): but it has to be done in a way that does not require annotation handler to be aware of specific semantics of all annotations.

@cowtowncoder
Copy link
Member

Forgot to add: there is actually issue filed for this, at:

FasterXML/jackson-annotations#82

so not closing as invalid or anything, but simply as duplicate

@cowtowncoder cowtowncoder changed the title @XmlType(propOrder=) doesn't respect propOrder of super classes @XmlType(propOrder=) overrides propOrder of super classes; should merge Aug 1, 2017
@ajdergute
Copy link
Author

Thank you very much for your quick answer. Since it's simply working for us we will wait (maybe for Jackson 3.x). Your proposal sounds interesting, im tense how this will be implemented.

@cowtowncoder
Copy link
Member

@ajdergute yes, I think your local fix makes sense for your usage. The problem from jackson perspective is that in general similar fix is impractical based on division of responsibilities between different parts:

  1. Handling of hierarchic nature of annotations is by jackson-databind, and it simple flattens class, field and method annotations (i.e. does support inheritance via all paths, including interfaces, as well as mix-in annotations). It does not know anything about semantics of specific annotations -- and even if it did, there wouldn't be any way to create merged instances of Annotation types (since this is what it exposes)
  2. AnnotationIntrospector implementations are based on flattened set of Annotations from (1), and should not (have to) traverse hierarchy -- plus, since there may be multiple introspectors (Jackson's own and JAXB at least) there's questions of how to combine inputs (may or may not be problem: can just use simple preference)

There are also practical concerns of AnnotationIntrospector implementation getting complicated if they had to handle full (1) (including mix-ins).

But none of these is necessary by application code that can omit/skip parts that are not necessary, or are known to follow specific patterns.

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

No branches or pull requests

2 participants