users@jaxb.java.net

Re: Polymorphism problems

From: Ryan Shoemaker - JavaSoft East <Ryan.Shoemaker_at_Sun.COM>
Date: Tue, 29 Jun 2004 16:48:51 -0400

Matt Munz wrote:

> Hi all,
>
> I'm new to this list and JAXB, so please bear with me. I searched the archives, but didn't see a clear answer to this question. The following was also posted to the Java Technology & XML web forum.
>
> I am finding little use in JAXB's polymorphism. As such, I think I'm going to need to switch to another framework that has a more useful polymorphism feature (or else none at all).
>
> As indicated below, I have a schema that includes a "Person" complex type, and an "Employee" complex type that extends it. There is also an element "people" that is a sequence of "Person" elements. I have used JAXB-generated classes to add instances of Person and Employee (generated classes) to an instance of the People class. The marshaller then erroneously outputs the extensions to Person found in Employee (see below).
>
> Having seen this, I wonder what use polymorphism (in the classes generated by JAXB) has, if it is not acceptable to use a subclass wherever its superclass is allowed. Perhaps there is some other way to do polymorphism that I'm missing?
>

We really aren't talking about OO design and polymorphism here - we are talking
about the way that the JAXB marshaller handles instances of the derived types.
You expect an "employee" element to be marshalled as a "person" element because
the Employee java class extends the Person java class. However, this isn't what
your schema expects and therefore people.getPerson().add(employee) causes
validation errors. Your schema mandates that <people> elements contain only
<person> elements (assuming no type-substitution is involved), but you are passing
in an Employee type. If you look at the generated javadoc for getPeople(), it
clearly restricts the content of the List to contain instances of the Person type.
The reason that the marshaller is wrapping your instance of Employee in a <person>
element in your output below is because types don't know know their element names
- that's determined by the context they are used in. Since Employee is-a Person,
the JAXB RI marshaller marshals <person> and then tells each child element to
marshal its content. In the case of the Employee, it marshals <name> and <title>.

Your agument is that Employee types ARE Person types and therefore you should be
able to use them wherever Person types are expected. Again, although this is
common practice for OO & Java developers, it doesn't exactly map to the way that
schema handles inheritance. AFAIK, you can't pass an Employee to the marshaller
and have it marshal as a <person> element (ignoring the extended content model
for <title>).

What you can do is modify your schema to use type or element substitution so that
the marshalled XML is valid. For example, if you turn on type substitution
(see attachement), you can generate the following XML without modifying your
client code below at all:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people>
   <person>
     <name>Joe Sample</name>
   </person>
   <person xsi:type="employee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <name>Jane Sample Employee</name>
     <title>Engineer</title>
   </person>
</people>

For more info on type substitution, see [1].

Another option would be to modify the schema to accept a choice of <person> or
<employee>, something like:

   <xs:element name="people">
     <xs:complexType>
       <xs:choice maxOccurs="unbounded">
         <xs:element name="person" type="person" maxOccurs="unbounded"/>
         <xs:element name="employee" type="employee" maxOccurs="unbounded"/>
       </xs:choice>
     </xs:complexType>
   </xs:element>

Then you can build-up your content tree and marshal valid xml like this:

<people>
   <person>
     <name>Joe Sample</name>
   </person>
   <employee>
     <name>Jane Sample Employee</name>
     <title>Engineer</title>
   </employee>
</people>

Neither of these give you the specific result you were expecting, but
they all produce valid xml wrt their schemas.

--Ryan

[1] $JAXB_HOME/docs/vendorSchemaLangs.html#xschema

> I really want to have a functionality such as the code example below implies. Does JAXB have the feature I'm looking for, or do I need to switch to another framework? If I need to switch, which one should I use?
>
> Thanks for any help that can be offered.
>
> schema:
>
> <xs:schema xmlns:xs=ttp://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
> <xs:element name=eople">
> <xs:annotation>
> <xs:documentation>Comment describing your root element</xs:documentation>
> </xs:annotation>
> <xs:complexType>
> <xs:sequence>
> <xs:element name=erson" type="Person" maxOccurs="unbounded"/>
> </xs:sequence>
> </xs:complexType>
> </xs:element>
> <xs:complexType name=erson">
> <xs:sequence>
> <xs:element name=ame" type="xs:string"/>
> </xs:sequence>
> </xs:complexType>
> <xs:complexType name=mployee">
> <xs:complexContent>
> <xs:extension base=erson">
> <xs:sequence>
> <xs:element name=itle" type="xs:string"/>
> </xs:sequence>
> </xs:extension>
> </xs:complexContent>
> </xs:complexType>
> </xs:schema>
>
> expected JAXB output:
>
> <people>
> <person>
> <name>Joe Sample</name>
> </person>
> <person>
> <name>Jane Sample Employee</name>
> </person>
> </people>
>
> actual JAXB output (invalid):
>
> <people>
> <person>
> <name>Joe Sample</name>
> </person>
> <person>
> <name>Jane Sample Employee</name>
> <title>Engineer</title>
> </person>
> </people>
>
> Java code:
>
> Person person =actory.createPerson();
> person.setName("Joe Sample");
> Employee employee =actory.createEmployee();
> employee.setName("Jane Sample Employee");
> employee.setTitle("Engineer");
> People people =actory.createPeople();
> people.getPerson().add(person);
> people.getPerson().add(employee);
>
> - Matt Munz
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> For additional commands, e-mail: users-help_at_jaxb.dev.java.net
>
> .
>



<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:xjc ="http://java.sun.com/xml/ns/jaxb/xjc"
           jaxb:extensionBindingPrefixes="xjc"
           jaxb:version="1.0">

  <xs:annotation>
    <xs:appinfo>
      <jaxb:globalBindings>
       <xjc:typeSubstitution type="complex"/>
      </jaxb:globalBindings>
    </xs:appinfo>
  </xs:annotation>

  <xs:element name="people">
    <xs:annotation>
      <xs:documentation>Comment describing your root element</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="person" type="person" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="person">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="employee">
    <xs:complexContent>
      <xs:extension base="person">
        <xs:sequence>
          <xs:element name="title" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
For additional commands, e-mail: users-help_at_jaxb.dev.java.net