Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » JAXB: Represent nested Model Group Schema Components with a java object hierarchy
JAXB: Represent nested Model Group Schema Components with a java object hierarchy [message #1711160] Tue, 13 October 2015 15:38 Go to next message
J F is currently offline J FFriend
Messages: 256
Registered: July 2009
Senior Member
Schema allows a designer to specify optional sequences of child elements as follows;

 <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Schema1" xmlns:tns="http://www.example.org/Schema1" elementFormDefault="qualified">
    
        <complexType name="RootType">
        	<sequence>
        		<choice>
        			<sequence minOccurs="1" maxOccurs="1">
        				<element name="A" type="tns:A"></element>
        				<element name="B" type="tns:B"></element>
        				<element name="C" type="tns:C"></element>
        			</sequence>
        			<element name="P" type="tns:P" minOccurs="1" maxOccurs="1"></element>
        			<element name="Q" type="tns:Q" minOccurs="1" maxOccurs="1"></element>
        		</choice>
        	</sequence>
        </complexType>
        
        <complexType name="A">
        	<sequence>
        		<element name="one" type="string"/>
        		<element name="two" type="string"/>
        		<element name="three" type="string"/>
        	</sequence>
        </complexType>
        
        <complexType name="B">
        	<sequence>
        		<element name="one" type="string"/>
        		<element name="two" type="string"/>
        		<element name="three" type="string"/>
        	</sequence>
        </complexType>
        
        <complexType name="C">
        	<sequence>
        		<element name="one" type="string"/>
        		<element name="two" type="string"/>
        		<element name="three" type="string"/>
        	</sequence>
        </complexType>
        
        <complexType name="P">
        	<sequence>
        		<element name="one" type="string"/>
        		<element name="two" type="string"/>
        		<element name="three" type="string"/>
        	</sequence>
        </complexType>
        
        <complexType name="Q">
        	<sequence>
        		<element name="one" type="string"/>
        		<element name="two" type="string"/>
        		<element name="three" type="string"/>
        	</sequence>
        </complexType>
    
        <element name="TopLevel" type="tns:RootType"></element>
    </schema>



This validates

 <?xml version="1.0" encoding="UTF-8"?>
    <tns:TopLevel xmlns:tns="http://www.example.org/Schema1">
    	<tns:A>
    		<tns:one>tns:one</tns:one>
    		<tns:two>tns:two</tns:two>
    		<tns:three>tns:three</tns:three>
    	</tns:A>
    	<tns:B>
    		<tns:one>tns:one</tns:one>
    		<tns:two>tns:two</tns:two>
    		<tns:three>tns:three</tns:three>
    	</tns:B>
    	<tns:C>
    		<tns:one>tns:one</tns:one>
    		<tns:two>tns:two</tns:two>
    		<tns:three>tns:three</tns:three>
    	</tns:C>
    </tns:TopLevel>



and rejects

 <?xml version="1.0" encoding="UTF-8"?>
    <tns:TopLevel xmlns:tns="http://www.example.org/Schema1">
    	<tns:A>
    		<tns:one>tns:one</tns:one>
    		<tns:two>tns:two</tns:two>
    		<tns:three>tns:three</tns:three>
    	</tns:A>
    	<tns:B>
    		<tns:one>tns:one</tns:one>
    		<tns:two>tns:two</tns:two>
    		<tns:three>tns:three</tns:three>
    	</tns:B>
    </tns:TopLevel>

or


       <?xml version="1.0" encoding="UTF-8"?>
        <tns:TopLevel xmlns:tns="http://www.example.org/Schema1">
        	<tns:A>
        		<tns:one>tns:one</tns:one>
        		<tns:two>tns:two</tns:two>
        		<tns:three>tns:three</tns:three>
        	</tns:A>
        	<tns:B>
        		<tns:one>tns:one</tns:one>
        		<tns:two>tns:two</tns:two>
        		<tns:three>tns:three</tns:three>
        	</tns:B>
        	<tns:C>
        		<tns:one>tns:one</tns:one>
        		<tns:two>tns:two</tns:two>
        		<tns:three>tns:three</tns:three>
        	</tns:C>
        	<tns:P>
        		<tns:one>tns:one</tns:one>
        		<tns:two>tns:two</tns:two>
        		<tns:three>tns:three</tns:three>
        	</tns:P>
        </tns:TopLevel>


Ofcourse if I generate a JAXB class from this I get
    ...
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "RootType", propOrder = {
        "a",
        "b",
        "c",
        "p",
        "q"
    })
    //Manually added for testing 
    @XmlRootElement(name="TopLevel")
    public class RootType {
    
        @XmlElement(name = "A")
        protected A a;
        @XmlElement(name = "B")
        protected B b;
        @XmlElement(name = "C")
        protected C c;
        @XmlElement(name = "P")
        protected P p;
        @XmlElement(name = "Q")
        protected Q q;
    
        /**
         * Gets the value of the a property.
         * 
         * @return
         *     possible object is
         *     {@link A }
         *     
         */
        public A getA() {
            return a;
        }
    
        /**
         * Sets the value of the a property.
         * 
         * @param value
         *     allowed object is
         *     {@link A }
         *     
         */
        public void setA(A value) {
            this.a = value;
        }
        
        ....
        
        etc.


which will load all 3 instances without complaining provided I don't set up the Schema validation on the Unmarshaller.

The java instance is then contrary to the Schema, and the following will fail. Even if it is valid I must do extra work to determine what state the RootType instance is in.

    private static void validate(uk.co.his.test.complexSequenceAndChoice.generated.nact1moxy.RootType root)
    {
    	if(root.getA()!=null)
    	{
    		Assert.assertTrue("RootType should either be a sequence of A, B, C or a sinle P or a single Q", root.getB()!=null&&root.getC()!=null&&root.getP()==null&&root.getQ()==null);
    	}
    	else
    	{
    		Assert.assertTrue("RootType should either be a sequence of A, B, C or a sinle P or a single Q", root.getB()==null&&root.getC()==null
    				&&((root.getP()!=null&&root.getQ()==null)
    				|| (root.getP()==null&&root.getQ()!=null)));
    	}
    }

The question is;

- Is there anyway to represent this more accurately in a Java class hierachy?
Generally Model Group Schema Components specify the ordering of child elements, but Java can only capture the 'bucket of all children' in cases where more complex orderings are specified by nested Model Group Schema components?

The difficulty is we would like to represent these groupings by java classes that do not bind to Element parsing events in a one to one way;

Imagine a @XmlElementSequence annotation existed that allowed a sequence of children to be specified;

    package uk.co.his.test.complexSequenceAndChoice.manual5;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlElements;
    import javax.xml.bind.annotation.XmlType;
    
    @XmlType(name = "RootType")
    @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
    public class RootType {
    
    	@XmlElements({
    		@XmlElementSequence(Sequencepart.class), 
    		@XmlElement(name="P", type=P.class), 
    		@XmlElement(name="Q", type=Q.class)
    		})
    	public Object partA;
    
    }



   package uk.co.his.test.complexSequenceAndChoice.manual5;
    
    import javax.xml.bind.annotation.XmlElement;
    
    import uk.co.his.test.complexSequenceAndChoice.generated.nact1.A;
    import uk.co.his.test.complexSequenceAndChoice.generated.nact1.B;
    
    @XmlElementSequenceDef(propOrder = {
        "a",
        "b",
        "c"
    })
    public class Sequencepart {
    
        @XmlElement(name = "A")
        protected A a;
        @XmlElement(name = "B")
        protected B b;
        @XmlElement(name = "C")
    
    }




The marshaller would be relatively simple. The Unmarshaller would have to know to create a Sequencepart when it saw the start of an "A" element tag, and to insert the A values inside that Sequencepart instance.

This is the same question I posted on StackOverflow . This version has a simple Maven project source in case my question needs clarification.
Re: JAXB: Represent nested Model Group Schema Components with a java object hierarchy [message #1712347 is a reply to message #1711160] Fri, 23 October 2015 08:59 Go to previous messageGo to next message
J F is currently offline J FFriend
Messages: 256
Registered: July 2009
Senior Member
Reply to wrong message, please delete

[Updated on: Fri, 23 October 2015 09:03]

Report message to a moderator

Re: JAXB: Represent nested Model Group Schema Components with a java object hierarchy [message #1714542 is a reply to message #1711160] Fri, 13 November 2015 13:25 Go to previous message
J F is currently offline J FFriend
Messages: 256
Registered: July 2009
Senior Member
This can be done using MOXy specific annotations.

See the section "Creating "Self" Mappings"
here for more detail.

If I annotate my JAXB class as follows;

import java.util.Optional;

import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.eclipse.persistence.oxm.annotations.XmlPath;



@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name = "RootType", propOrder = {
    "seq1",
    "p",
    "q"
})
@XmlRootElement(name="TopLevel")
public class RootType {


    [b]@XmlPath(".")[/b]
    private InnerSequence seq1;
    @XmlElement(name = "P")
    private P p;
    @XmlElement(name = "Q")
    private Q q;
    
    public static class InnerSequence 
    {
    	@XmlElement(name = "A")
        public A a;
        @XmlElement(name = "B")
        public B b;
        @XmlElement(name = "C")
        public C c;
        
        public boolean isEmpty() {
        	return c==null&&b==null&&a==null;
        }
        ...
    }


I can now create XML that validates against the schema;

<?xml version="1.0" encoding="UTF-8"?>
<TopLevel xmlns="http://www.example.org/Schema1">
   <A>
      <one>Hello One A</one>
   </A>
   <B>
      <one>Hello One B</one>
   </B>
   <C>
      <one>Hello One C</one>
   </C>
</TopLevel>


Note that MOXy will populate seq1 with an instance of InnerSequence during Unmarshalling regardless of whether the file contains any A, B or Cs.

The file;

<?xml version="1.0" encoding="UTF-8"?>
<TopLevel xmlns="http://www.example.org/Schema1">
   <P>
      <one>Hello One A</one>
   </P>
</TopLevel>


still populates se1 with an InnerSequence.

The attached example is a Maven project that tests this out.

[Updated on: Fri, 13 November 2015 15:12]

Report message to a moderator

Previous Topic:EclipseLink ignores GeneratedValue(strategy=GenerationType.IDENTITY)
Next Topic:Possible BUG: @XmlPaths and 'Self Mappings'
Goto Forum:
  


Current Time: Thu Apr 25 08:25:44 GMT 2024

Powered by FUDForum. Page generated in 0.03366 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top