Showing posts with label JAXB. Show all posts
Showing posts with label JAXB. Show all posts

Wednesday, October 31, 2007

Generate is property set methods in JAXB objects

Keywords:
JAXB "is property set" method object

Problem:
Defining a default value in the schema does not come through as a default value in the generated objects. This could be worked around if you could check for when a field has been explicitly set in the XML (as opposed the value being returned by the get or is) method being the default).

Solution:
Along the lines of past post - Getting xs:any as DOM object

You simply add another custom binding property:
<xs:appinfo>
    <jaxb:property generateIsSetMethod="true"/>
</xs:appinfo> 

This post has the snippet: How do you pick up default values from XSD/JAXB
Reasonable summary of Customizing JAXB Bindings (though not that easy to read): Customizing JAXB Bindings.

Friday, July 20, 2007

JAXB xs:any xml content missing from marshalled output

Keywords:
JAXB xs:any xml content missing from marshalled output processContents="lax"

Problem:
I'm defining an XML schema that needs to be able to include any XML - "xs:any" seems perfect for the job. Also need to generate JAXB objects from this schema ... everything seems fine on compilation and in constructing the JAXB objects. The problem is at runtime, it appears that the "any" content is missing from the JAXB objects.

example schema

<xs:schema
    targetNamespace="http://example.com/xml"
    xmlns="http://example.com/xml"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">
    <xs:element name="MyXmlObject">
        <xs:complexType mixed="true">
            <xs:sequence minOccurs="0">
                <xs:any namespace="##any" processContents="lax" minOccurs="0"/>
            </xs:sequence>
            <xs:attribute name="firstName" type="xs:string" use="required"/>
            <xs:attribute name="lastName" type="xs:string" use="required"/>
            <xs:attribute name="happy" type="xs:boolean" use="optional"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

example JAXB object usage

String xmlContent = "<foo>misc. text</foo>";

InputSource source = new InputSource(new StringReader(xmlContent));
Element domElem = (Element)NodeUtils.parseStream(source, true);
myXmlObject.getContent().add(domElem);

JAXBContext jc = JAXBContext.newInstance("com.example.xml");
// marshal to System.out
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( response, System.out);

example XML output (missing my any content)

<MyXmlObject xmlns="http://example.com/xml" firstName="bar" lastName="bar" happy="true">
</MyXmlObject>

Solution:
The JAXB 1.0.x FAQ had the answer - Can I access <xs:any> as a DOM node?. There's detailed notes here with links to example schema and the Bug report, but basically "the spec doesn't support the mapping to DOM, so the RI is not allowed to do this" ... but it will if you put it in "extension mode".

This involves adding some extra elements to your schema and compiling with the "-extension" switch (or extension="true" attribute if using the XJC ant task).

new example schema (with JAXB customisation)

<xs:schema
    targetNamespace="http://example.com/xml"
    xmlns="http://example.com/xml"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    jaxb:extensionBindingPrefixes="xjc"
    jaxb:version="1.0">
    <xs:element name="MyXmlObject">
        <xs:complexType mixed="true">
            <xs:sequence minOccurs="0">
                <xs:any namespace="##any" processContents="lax" minOccurs="0">
                    <xs:annotation>
                        <xs:appinfo>
                            <xjc:dom/>
                        </xs:appinfo>
                    </xs:annotation>
                </xs:any>
            </xs:sequence>
            <xs:attribute name="firstName" type="xs:string" use="required"/>
            <xs:attribute name="lastName" type="xs:string" use="required"/>
            <xs:attribute name="happy" type="xs:boolean" use="optional"/>
        </xs:complexType>
    </xs:element>
</xs:schema>