Ryan,
Thanks. "Turning on" type substitution is a good idea, and I may use
that technique. I'm not psyched, however, since this technique results
in rather verbose XML.
I understand now that the JAXB RI doesn't have the "smarts" that I
want it to have -- but is the functionality that I desire unattainable?
I don't think it is. All the marshaller needs to know is that it is
writing into the "Person" slot, and so, when encountering a subtype of
person, marshals only the fields of Person, and not the (extra) fields
of the subtype.
Given the current behavior of JAXB, I am at a loss to understand what
the generation of an inheritance tree is good for? If I can't exchange
Employee for Person in my object graph, then why have an inheritance
relation between them at all? I mean, I know it looks good to have an
inheritance tree instead of a flat list of classes, but I think this
only leads to "mistakes" like the one I made, since java inheritance
implies certain functionality that JAXB RI does not provide.
BTW, the whole notion that the JAXB-generated Data Objects marshal
themselves to XML seems like poor OO design to me. Where's the
separation of concerns (model and view)? How is this not a weakness in
the design?
- Matt
-----Original Message-----
From: Ryan Shoemaker - JavaSoft East [mailto:Ryan.Shoemaker_at_Sun.COM]
Sent: Tuesday, June 29, 2004 4:49 PM
To: users_at_jaxb.dev.java.net
Subject: Re: Polymorphism problems
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
>
> .
>
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
For additional commands, e-mail: users-help_at_jaxb.dev.java.net