tags:

views:

495

answers:

2

When unmarshalling using jaxb, I have in class A something along:

public class A {
    @XmlElements( { //
    @XmlElement(name = "g", type = A.class),
        @XmlElement(name = "x", type = X.class), 
        @XmlElement(name = "y", type = Y.class),        
    })
    List<XXX> children;
}

That is, I have a list, children, consisting of X:s and Y:s

Now for my question: I would like to subclass A, and I would like to redefine the 'XmlElements' list and bind it to the same variable, 'children', like:

public class B extends A {
    @XmlElements( { //
    @XmlElement(name = "g", type = B.class),
        @XmlElement(name = "x", type = X.class), 
        @XmlElement(name = "y", type = Y.class), 
        @XmlElement(name = "z", type = Z.class),        
    })
    List<XXX> children;
}

The issues with the above are twofold:

  1. I create a new variable children, I would like to refer to the variable in class A.

  2. I would like to avoid respecifying the 'x' and 'y' since they are already specified in 'A'.

Is there some good pattern to achieve this?

Or some pointers/articles or other info for how to build something like this?

+1  A: 

There's no avoiding the re-declaration of the annotation, but you can move the annotation from the field on to the getter method, as long as you use the @XmlAccessorType annotation to tell JAXB to look for public getter methods rather than fields.

So you could override getChildren() in class B wit the new annotation set:

@XmlAccessorType(PROPERTY)
public class A {
    private List<XXX> children;

    @XmlElements( { //
    @XmlElement(name = "g", type = A.class),
        @XmlElement(name = "x", type = X.class), 
        @XmlElement(name = "y", type = Y.class),        
    })
    public List<XXX> getChildren() {
       return children;
    }

    public void setChildren(List<XXX> children) {
       this.children = children;
    }
}

@XmlAccessorType(PROPERTY)
public class B extends A {
    @XmlElements( { //
    @XmlElement(name = "g", type = B.class),
        @XmlElement(name = "x", type = X.class), 
        @XmlElement(name = "y", type = Y.class), 
        @XmlElement(name = "z", type = Z.class),        
    })
    public List<XXX> getChildren() {
       return super.getChildren();
    }
}

What I'm not sure about is how JAXB will handle the overriden getChildren() method. Hopefully it'll take the annotations from B, but it's possible it'll get confused.

Try it and see.

skaffman
Ah, quite cool, I did not know I could move the annotation to the getter field!I'll try that immediately, if it works it isabsolutely good enough for my current problem.Many thanks, skaffman, for taking your time to explain this to me!
Bjorn J
A: 

JAXB will actually handle the overriden method, when PROPERTY @XmlAccessorType is used in parent, but as a result in output xml data JAXB probably will also generate additionally in the root tag attributes such as: xsi:type="B" and xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance", because we defined a new type B inherited from A. So xml produced from class A won't be identical to that produced from class B because of those two attributes correctly added by JAXB to inform that we defined additional type B.

I would like to see a way to avoid this xsi and xmlns information in output xml. This behavior of JAXB is perfectly fine but for me it would be great to not inform receiver in my xml output that I've made class extending original class that I took possibly from client xsd schema.

To produce xml from derived subclass but w/o the xsi and xmlns attributes added by JAXB I used temporary trick which I am trying to exchange for something nicer: I did override of method in child, in parent overriden method I had to use @XmlElement but I did not added inherited class type to the JAXB.newinstance call.

KonradM