Skip to main content

Problem with multiple inheritance (Java types to Xml)

5 replies [Last post]
mumu
Offline
Joined: 2005-08-10

I tried to use multiple inheritance with jaxb2.0 on the well known Shape/Circle/Square example... but i failed.

Suppose you have the following code:

<br />
@XmlType<br />
public abstract class Shape {<br />
    private String id;<br />
    ...<br />
}</p>
<p>@XmlType<br />
public class Circle extends Shape {<br />
    private double radius;<br />
    ...<br />
}</p>
<p>@XmlType<br />
public class Square extends Shape {<br />
    private double length;<br />
    ...<br />
}</p>
<p>@XmlType<br />
public class ShapeResult {<br />
    /* Can hold a Square or Circle */<br />
    private Shape result;<br />
    ...<br />
}<br />

The wsdl generation is working quite well with wsgen JAX-WS2.0, but i have one problem with the Shape class.

1st question : Is it normal that the abstract type Shape is not replicated to the xsd? ( like abstract="true" in the xsd Shape definition)

Then i tried to marshall a ShapeResult instance holding a reference to a Circle object :

<br />
ShapeResult shapeResult = new ShapeResult();<br />
shapeResult.setShape( new Circle() );</p>
<p>Marshaller m = context.createMarshaller();<br />
m.marshal(shapeResult, System.out);<br />

But the xml result contains only the "id" attribute of the Shape class, but not the Circle attributes. Then it's impossible to read back the xml to instanciate the ShapeResult.

2nd question : why the marshaller doesn't take into account the class hierarchy? did i miss something?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
sekhar
Offline
Joined: 2003-06-25

With respect to your questions:
1. abstract type (e.g. Shape) should map to an abstract schema type.

2. marshaller should take into account the class hierarchy. An instance of type (Circle in your example) that is a subtype of another type (Shape in your example) should be marshalled with an xsi:type that includes the mapped fields/properties of the subtype(Circle in your example).

I did try out your example with the latest internal version of the JAXB 2.0 RI that I have and got the following:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="circle">
5
0.0

I made the following modifications (and a few others) to your code:

a. annotated ShapeResult with @XmlRootElement:

@XmlRootElement @XmlType ShapeResult {...}

b. assigned value to Shape.id .

I would also like to point out the following. Starting with Public Review version of the JAXB 2.0, if a class has a zero arg constructor, then the default java->schema binding rules associate the class with an @XmlType. So it is not necessary to explicitly annotate such a class with @XmlType.

mumu
Offline
Joined: 2005-08-10

Thanks and sorry! i forgot that i patched a while a go the RuntimeInlineAnnotationReader to force using backport175... and it was not working correctly in this example and with new builds of JAXB.

I tried the non-patched version and it's working now. I changed my patched version too.

Sorry again for this mistake.

jongerrish
Offline
Joined: 2005-11-02

Hi, sorry I know this is a fairly old thread, but I have tried exactly the same thing and cannot get this to work. (POJO -> XML, No xsd) As you can see from the code below, the output XML contains the fields defined in the superclass, but not those defined in either of the two subclasses. I'm right in believing that its possible to map Java inherritance to XML with JAXB2.0? Am I doing anything silly here?

Many thanks in advance, Jonathan

/**
* The holder class
*/
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement @XmlType
public class ShapeHolder {
private Shape firstShape;
private Shape secondShape;
/**
* @param firstShape The firstShape to set.
*/
public void setFirstShape(Shape firstShape) {
this.firstShape = firstShape;
}
/**
* @return Returns the firstShape.
*/
public Shape getFirstShape() {
return firstShape;
}
/**
* @param secondShape The secondShape to set.
*/
public void setSecondShape(Shape secondShape) {
this.secondShape = secondShape;
}
/**
* @return Returns the secondShape.
*/
public Shape getSecondShape() {
return secondShape;
}
}

/**
* The parent class
*/
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

public abstract class Shape {
@XmlElement
private int area;

/**
* @param area The area to set.
*/
void setArea(int area) {
this.area = area;
}

/**
* @return Returns the area.
*/
int getArea() {
return area;
}
}

/**
* First subclass, Circle
*/
import javax.xml.bind.annotation.XmlElement;

public class Circle extends Shape {
@XmlElement
private int radius;

/**
* @param radius The radius to set.
*/
public void setRadius(int r) {
this.radius = r;
}

/**
* @return Returns the radius.
*/
public int getRadius() {
return radius;
}
}

/**
* Second subclass, Square
*/
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlType
public class Square extends Shape {
@XmlElement
private int length;

/**
* @param length The length to set.
*/
public void setLength(int length) {
this.length = length;
}

/**
* @return Returns the length.
*/
public int getLength() {
return length;
}
}

/**
* The object construction + marshalling code
*/
ShapeHolder holder = new ShapeHolder();
Circle circle = new Circle();
circle.setArea(1);
circle.setRadius(3);

Square square = new Square();
square.setArea(3);
square.setLength(4);

holder.setFirstShape(circle);
holder.setSecondShape(square);

JAXBContext context = JAXBContext.newInstance(ShapeHolder.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
marshaller.marshal(holder, System.out);




1


3

kohsuke
Offline
Joined: 2003-06-09

When you do
[code]
JAXBContext.newInstance(ShapeHolder.class)
[/code]
JAXB does a static type analysis and identifies other classes tha are involved. This includes Shape, but notice that Circle and Square are not reachable statically. That's why your Circle and Square are treated as Shape, since JAXB only knows about Shape, not Circle.

You can invoke JAXBContext like this to tell it that you want Square and Circle to be bound:

[code]
JAXBContext.newInstance(ShapeHolder.class,Circle.class,Square.class)
[/code]

jongerrish
Offline
Joined: 2005-11-02

Hi,
Thanks for the prompt reply, that solved my problem. I noticed that by default the parent classes field "area" was not included in the marshalled XML. By adding the @XmlElement annotation to the field of the class, resulted in the field being included. Just because I am curious, is there a reason why parent class fields are not marshalled by default?
Anyway, thanks for the help, I'm really enthusiastic about using JAXB2.0, as you mentioned before, its a lot nicer to use than the previous version. Well done!

Thanks, Jonathan