1 2 Previous Next 18 Replies Latest reply on Oct 12, 2007 5:48 PM by starksm64

    @XmlElementWrapper/@XmlElements

    starksm64

      I'm trying to use @XmlElementWrapper/@XmlElements to create the ear modules, but its not parsing as expected. I created a simple test in jbossxb that is also failing to parse. See the org.jboss.test.xb.builder.object.element.wrapper.test.WrapperUnitTestCase

      testFooWrapper fails with:


      Caused by: org.jboss.xb.binding.JBossXBRuntimeException: float not found as a child of bar
      at org.jboss.xb.binding.sunday.unmarshalling.SundayContentHandler.startElement(SundayContentHandler.java:370)
      at org.jboss.xb.binding.parser.sax.SaxJBossXBParser$DelegatingContentHandler.startElement(SaxJBossXBParser.java:402)
      at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
      at org.apache.xerces.xinclude.XIncludeHandler.startElement(Unknown Source)
      at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
      at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
      at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
      at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
      at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
      at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
      at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
      at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
      at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.parse(SaxJBossXBParser.java:180)
      ... 22 more


      testFoo2Wrapper is essentially the same, but Foo2 has a parameterized items property. This fails with:

      Caused by: java.lang.InstantiationException
      at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
      at org.jboss.reflect.plugins.introspection.ReflectionUtils.newInstance(ReflectionUtils.java:136)
      at org.jboss.reflect.plugins.introspection.ReflectConstructorInfoImpl.newInstance(ReflectConstructorInfoImpl.java:104)
      at org.jboss.joinpoint.plugins.BasicConstructorJoinPoint.dispatch(BasicConstructorJoinPoint.java:80)
      at org.jboss.beans.info.plugins.AbstractBeanInfo.newInstance(AbstractBeanInfo.java:222)
      at org.jboss.beans.info.plugins.AbstractBeanInfo.newInstance(AbstractBeanInfo.java:216)
      at org.jboss.xb.spi.AbstractBeanAdapter.construct(AbstractBeanAdapter.java:115)
      ... 41 more



        • 1. Re: @XmlElementWrapper/@XmlElements
          starksm64

          I worked around this by adding support for using JBossXmlChildren with a non-collection type:

          @XmlType
          @JBossXmlChildren
          ({
           @JBossXmlChild(name="int", type=Integer.class),
           @JBossXmlChild(name="float", type=Float.class),
          })
          public class Bar
          {
           private Number value;
          
           public Number getValue()
           {
           return value;
           }
          
           public void setValue(Number value)
           {
           this.value = value;
           }
          }
          


          There was a TODO for this in JBossXBNoSchemaBuilder. The restriction is that the type must have a value property to accept the child value.

          The logic for the XmlElementWrapper seems incorrect for a property with XmlElements. The XmlElementWrapper Sequence should wrap the XmlElements Choice I believe?


          • 2. Re: @XmlElementWrapper/@XmlElements
            aloubyansky

            This is how it is supposed to work
            http://java.sun.com/javaee/5/docs/api/javax/xml/bind/annotation/XmlElements.html

            There supposed to be only one bar element wrapping the XmlElements.

            • 3. Re: @XmlElementWrapper/@XmlElements
              starksm64

              I don't see that you can make a meanignful distinction between these two fragments:

               <!-- XML Schema fragment -->
               <xs:complexType name="Foo">
               <xs:sequence>
               <xs:element name="bar" minOccurs="1" maxOccurs="unbounded">
               <xs:complexType>
               <xs:choice minOccurs="0" maxOccurs="unbounded">
               <xs:element name="A" type="xs:string"/>
               <xs:element name="B" type="xs:string"/>
               </xs:choice>
               </xs:complexType>
               </xs:element>
               </xs:sequence>
               </xs:complexType>
              


               <!-- XML Schema fragment -->
               <xs:complexType name="Foo">
               <xs:sequence>
               <xs:element name="bar" minOccurs="1" maxOccurs="unbounded">
               <xs:complexType>
               <xs:choice minOccurs="0" maxOccurs="1">
               <xs:element name="A" type="xs:string"/>
               <xs:element name="B" type="xs:string"/>
               </xs:choice>
               </xs:complexType>
               </xs:element>
               </xs:sequence>
               </xs:complexType>
              


              both accept:

              <foo>
               <bar>
               <A />
               </bar>
               <bar>
               <B />
               </bar>
               <bar>
               <A />
               </bar>
              </foo>
              


              and since the @XmlElementWrapper should be flattening out the bar elements to its children, both end up with a List of the choice elements.


              • 4. Re: @XmlElementWrapper/@XmlElements
                aloubyansky

                The XmlElementWrapper should have maxOccurs=1 according to the javadoc examples.

                • 5. Re: @XmlElementWrapper/@XmlElements
                  starksm64

                  Ok, but the javadoc is not authoritative. In reading the jaxb 2.1 spec I can't make out what the behavior should be. Have you looked at that?

                  • 6. Re: @XmlElementWrapper/@XmlElements
                    aloubyansky

                    Yes, maxOccurs=1 for XmlElementWrapper according to the spec.

                    • 7. Re: @XmlElementWrapper/@XmlElements
                      starksm64

                      So how would an application.xml module element have to be handled? It should be something like this, but the schema for the wrapping module element has an unbounded max:

                      class Application
                      {
                       @XmlElementWrapper(name="module")
                       @XmlElements(
                       @XmlElement(name="connector", type=ConnectorModule.class),
                       @XmlElement(name="java", type=JavaModule.class),
                      ...
                       )
                       private List<Module> modules;
                      }
                      



                      • 8. Re: @XmlElementWrapper/@XmlElements
                        aloubyansky

                        I am looking into this.

                        • 9. Re: @XmlElementWrapper/@XmlElements
                          aloubyansky

                          I see two ways to workaround this.

                          In both cases the Module class should be bound to choice with @JBossXmlModelGroup.

                          First is to create a ModuleHolder that would be bound to the module element. And then add JavaXmlTypeAdapter that would take ModuleHandler and return the module it holds.

                          Second is to introduce an XB annotation equivalent to TermBinding.setSkip(trueOrFalse) and set it on the module element.

                          • 10. Re: @XmlElementWrapper/@XmlElements
                            jason.greene

                             

                            "scott.stark@jboss.org" wrote:
                            So how would an application.xml module element have to be handled? It should be something like this, but the schema for the wrapping module element has an unbounded max:



                            You need to introduce another type in JAXB to get both nesting levels to be unbounded. Like this (public fields used for simplicity):

                            XmlAccessorType(XmlAccessType.FIELD)
                            @XmlType(name = "Foo")
                            public class Foo {
                             @XmlElement(required = true)
                             public List<Foo.Bar> bar;
                            
                             @XmlAccessorType(XmlAccessType.FIELD)
                             @XmlType(name = "")
                             public static class Bar {
                             @XmlElements({
                             @XmlElement(name="A", type=Integer.class),
                             @XmlElement(name="B", type=Float.class)
                             })
                             public List items;
                             }
                            }
                            


                            • 11. Re: @XmlElementWrapper/@XmlElements
                              aloubyansky

                              This should be closer to what we would like to have

                              @XmlRootElement
                               public static class Application
                               {
                               private List<Module> modules;
                              
                               public void setModules(List<Module> modules)
                               {
                               this.modules = modules;
                               }
                              
                               @XmlElement(name="module", type=ModuleHolder.class)
                               public List<Module> getModules()
                               {
                               return modules;
                               }
                               }
                              
                               public static class ModuleAdapter extends XmlAdapter<ModuleHolder, Module>
                               {
                               @Override
                               public ModuleHolder marshal(Module arg0) throws Exception
                               {
                               // TODO Auto-generated method stub
                               return null;
                               }
                              
                               @Override
                               public Module unmarshal(ModuleHolder arg0) throws Exception
                               {
                               return arg0.getModule();
                               }
                               }
                              
                               @XmlJavaTypeAdapter(value = ModuleAdapter.class)
                               public static class ModuleHolder
                               {
                               private Module module;
                              
                               public void setModule(Module module)
                               {
                               this.module = module;
                               }
                              
                               @XmlTransient
                               public Module getModule()
                               {
                               return module;
                               }
                              
                               public void setConnector(ConnectorModule module)
                               {
                               this.module = module;
                               }
                              
                               public ConnectorModule getConnector()
                               {
                               return (ConnectorModule) module;
                               }
                              
                              
                               public void setEjb(EjbModule module)
                               {
                               this.module = module;
                               }
                              
                               public EjbModule getEjb()
                               {
                               return (EjbModule) module;
                               }
                              
                               public void setJava(JavaModule module)
                               {
                               this.module = module;
                               }
                              
                               public JavaModule getJava()
                               {
                               return (JavaModule) module;
                               }
                               }
                              
                               public static abstract class Module
                               {
                               private String value;
                              
                               public void setValue(String value)
                               {
                               this.value = value;
                               }
                              
                               @XmlValue
                               public String getValue()
                               {
                               return value;
                               }
                               }
                              
                               public static class ConnectorModule extends Module
                               {
                               }
                              
                               public static class EjbModule extends Module
                               {
                               }
                              
                               public static class JavaModule extends Module
                               {
                               }


                              But there is an issue... currently it applies the adapter to the collection of modules as well as to the each module separately. I am looking into it.

                              • 12. Re: @XmlElementWrapper/@XmlElements
                                aloubyansky

                                Actually the last approach is wrong. The adapter on ModuleHolder will make Module dictate the schema structure. That's pointless.

                                • 13. Re: @XmlElementWrapper/@XmlElements
                                  jason.greene

                                  Ah, I see you dont want a nested maxOccurs="unbounded".

                                  So is this what you want?

                                  @XmlAccessorType(XmlAccessType.FIELD)
                                  @XmlType(name = "application")
                                  public class Foo {
                                   @XmlElement(required = true)
                                   public List<Module> module;
                                  
                                   @XmlAccessorType(XmlAccessType.FIELD)
                                   @XmlType(name = "")
                                   public static class Module {
                                   @XmlElements({
                                   @XmlElement(name="connector", type=Connector.class),
                                   @XmlElement(name="java", type=Java.class)
                                   })
                                   public Component component;
                                  
                                   @XmlElement(name="alt-dd")
                                   public String altDD;
                                   }
                                  
                                   public static interface Component {}
                                   public static class Connector implements Component
                                   {
                                   }
                                  
                                   public static class Java implements Component
                                   {
                                   }
                                  }
                                  


                                  Or you could also do this:
                                  XmlAccessorType(XmlAccessType.FIELD)
                                  @XmlType(name = "application")
                                  public class Foo {
                                   @XmlElement(required = true)
                                   public List<Module> module;
                                  
                                   @XmlAccessorType(XmlAccessType.FIELD)
                                   @XmlType(name = "")
                                   public static class Module {
                                   @XmlElement(name="java")
                                   public Java java;
                                  
                                   @XmlElement(name="connector")
                                   public Connector connector;
                                  
                                   @XmlElement(name="alt-dd")
                                   public String altDD;
                                   }
                                  
                                   public static class Connector
                                   {
                                   }
                                  
                                   public static class Java
                                   {
                                   }
                                  }
                                  


                                  Also, why not just use xjc generated model?

                                  -Jason

                                  • 14. Re: @XmlElementWrapper/@XmlElements
                                    aloubyansky

                                    Yes, that would work. I was trying to avoid Module as a wrapping class since this is what I think Scott wanted to have at the end.

                                    1 2 Previous Next