1 2 Previous Next 15 Replies Latest reply on Feb 24, 2005 6:50 AM by aloubyansky

    MappingObjectModel and Polymorphism

      I want to be able to configure the MappingObjectModelFactory
      to understand polymorphism.

      e.g. I have the requirement to change the type that is injected into a field
      based on the xml element name.

      public class AttributeMetaData
      {
       public void setValue(ValueMetaData vmd) {}
       // etc...
      }
      
      <attribute name="foo">Some value</attribute> // uses StringValueMetaData
      <attribute name="foo"><depends value="SomeBean"/></attribute> // Uses DependsValueMetaData
      <attribute name="foo">
       <list>
       <value>Another value</value>
       <depends value="AnotherBean"/>
       </list>
      </attribute> // Uses ListValueMetaData
      


      I propose to be able to define something like:
      objectModelFactory.mapElementToField("value", AttributeMetaData.class, null, StringValueMetaData.class); // The default because null
      objectModelFactory.mapElementToField("value", AttributeMetaData.class, "depends", DependsValueMetaData.class);
      objectModelFactory.mapElementToField("value", AttributeMetaData.class, "list", ListValueMetaData.class);
      // etc...
      


      What do you think?
      Is this the correct approach?
      Does this work with marshalling? I'm only interested in parsing.
      Is there another way to achieve the same thing?

        • 1. Re: MappingObjectModel and Polymorphism
          aloubyansky

          First, apologies for not wiki'ing latest changes/features. Working full time on features/fixes required by the WS project.

          So, MappingObjectModelFactory is going to deprecated. (Note: MappingObjectModelFactory is NOT touched by the following changes. I just wrote another ObjectModelFactory impl for this.)

          Recently, I introduced binding metadata which is going to drive unmarshalling process (and already working on marshalling). So, I would encourage you to look at it when discussing ways to customize bindings.

          Before, binding was based on XSD, DTD, default XML name to Java identifier mapping algorithms and, in case of MappingObjectModelFactory, user API. Now, binding is going to be based on metadata. This metadata can be built from XSD, DTD, jaxrpc-mapping, XML-name-to-Java-id algs, user API, etc and organized into a stack. If binding not found on the highest level, the resolution is delegated to lower levels. This already works.

          Metadata API is here http://cvs.sourceforge.net/viewcvs.py/jboss/jboss-common/src/main/org/jboss/xml/binding/metadata/.
          It's still incomplete. I would welcome your feedback.
          You can find examples in the testsuite in org.jboss.test.xml.

          About your specific case.
          Internally, (fortunately) there is a difference in handling element's text value and child elements. Since, depends and list are children, we could just use metadata API to customize their bindings.

           factory.bindElement(attrBinding, "depends", "value", DependsValueMetaData.class);
           factory.bindElement(attrBinding, "list", "value", ListValueMetaData.class);
          


          But customization of text value binding like this
          <attribute name="foo">Some value</attribute> // uses StringValueMetaData
          

          with attribute being bound to AttributeMetaData class is not supported right now. Missed this case. Need to think about it.

          Does this work with marshalling? I'm only interested in parsing.

          Let's talk about what you are interested in :) I'll take care of marshalling later.

          Is there another way to achieve the same thing?

          Unfortunately, only to write your own ObjectModelFactory. What might be easier to do right now to support this case is to add support for ObjectModelFactory per element (attribute in your case). I actually planned to do this but there were things with higher priority.

          • 2. Re: MappingObjectModel and Polymorphism

            I'll investigate the link and get back to you.

            Marshalling will be needed for these classes,
            e.g. JBossIDE or the admin console will likely want to use my MetaData classes
            then marshall it out as an xml file that can be deployed.

            • 3. Re: MappingObjectModel and Polymorphism
              aloubyansky

              I committed a testcase that shows how you could do what you want with the metadata approach.

              Please, have a look at

              package org.jboss.test.xml;
              public class MiscUnitTestCase
               public void testValueBinding() throws Exception
              


              The XML fragment in testsuite/src/resources/xml/valuebinding.xml

              The object model classes are implemented as inner classes in the MiscUnitTestCase and also demonstrate support for immutables in JBossXB.

              What do you think?

              • 4. Re: MappingObjectModel and Polymorphism
                aloubyansky

                PS: it's not yet supported for attributes.

                • 5. Re: MappingObjectModel and Polymorphism

                  That looks like it should work.

                  I have some observations about the new implementation.

                  1) There is no logging so I can't see what is happening. I started adding some.
                  This was present in the old implementation, including being able to see
                  what rules where defined.

                  2) There are a number of places that assume that all collections are lists,
                  I have some sets.

                  3) I also need support for Maps.

                  4) I don't see how I define that a type should be a collection and the exact implementation
                  of that collection, like i did before:

                  <deployment> <!-- AbstractDeploymentMetaData.setBeans(List)
                   <beans> <!-- ArrayList -->
                   <bean>
                  
                  objectModelFactory.mapElementToClass("deployment", AbstractKernelDeployment.class);
                  objectModelFactory.mapElementToClass("beans", ArrayList.class);
                  objectModelFactory.mapElementToClass("bean", AbstractBeanMetaData.class);
                  


                  Although the need to have
                  <beans/>
                  is removed in the new implementation
                  which makes the xml less verbose. :-)
                  I still think it would be good to be able to define the implementation class.
                  NOTE: I don't want to construct the collection in my javabean because I want
                  null when there is none.

                  5) The ability to define the value as something other than string is good:
                   XmlValueBinding stringValue = factory.bindValue(attribute, "value", StringValueMetaData.class);
                   factory.bindValue(stringValue, "value", String.class);
                  
                  This has got rid of my need to write the longwinded
                  <attribute name="blah"><value>foo</value></attribute>
                  


                  6) When you say it does not work for attributes, do you mean
                  attributes don't work at all? Or maybe I'm just not using it correctly?
                   factory.bindAttribute(bean, "", "name", "name", String.class);
                  


                  7) Should I even have to define String attributes that map directly onto the javabean?

                  • 6. Re: MappingObjectModel and Polymorphism
                    aloubyansky

                     


                    1) There is no logging so I can't see what is happening. I started adding some.
                    This was present in the old implementation, including being able to see
                    what rules where defined.

                    2) There are a number of places that assume that all collections are lists,
                    I have some sets.


                    That's right. The code has just been written and not used/tested much yet. Sorry.


                    3) I also need support for Maps.


                    Accepted.

                    4) Currently, unless you keep beans element, you can't do it. Also accepted.

                    6) Attribute bindings do work. XmlValueBinding is not yet supported for them.


                    7) Should I even have to define String attributes that map directly onto the javabean?


                    Do you mean that I could figure bindings out by using introspection? If so, you should create a DocumentBindingStack and add RuntimeDocumentBinding to it. Then, customize the bindings that can't be done with introspection.

                    For an example have a look at

                    package org.jboss.test.xml;
                    public class UnmarshallingMetaDataTestCase
                     public void testRuntimeBookMetadata() throws Exception
                    ...
                    
                     DocumentBindingFactory factory = DocumentBindingFactory.newInstance();
                     DocumentBinding doc = factory.
                     newDocumentBindingStack().
                     push(RuntimeDocumentBinding.class);
                    
                     NamespaceBinding ns = factory.bindNamespace(doc, nsUri, pkg);
                     TopElementBinding book = ns.getTopElement(bookQName.getLocalPart());
                     factory.bindElement(book,
                     characterQName.getNamespaceURI(),
                     characterQName.getLocalPart(),
                     "characters",
                     BookCharacter.class
                     );
                    


                    Thanks for the feedback.

                    • 7. Re: MappingObjectModel and Polymorphism

                      4) That didn't work for me. I couldn't see how to define it:

                       ElementBinding beans = factory.bindElement(deployment, "", "beans", "beans", ArrayList.class);
                       ElementBinding bean = factory.bindElement(beans, "", ??, ??, AbstractBeanMetaData.class);
                      


                      I also have the requirement to do polymorphism on collections,
                      something like:
                      <attribute name="blah">
                       <list>
                       <value type="some.type">foo</value> // uses StringValueMetaData
                       <depends value="SomeBean"/> // uses DependsValueMetaData
                       <list> // recursion :-)
                       ...
                       </list>
                       </list>
                      </attribute>
                       ElementBinding listValue = factory.bindElement(attribute, "", "list", "value", AbstractListMetaData.class); // implements java.util.List
                      //What comes here???
                      


                      and arrays
                      <attribute name="blah">
                       <array type="someClass"> // AbstractArrayValueMetaData
                       <value type="some.type">foo</value> // uses StringValueMetaData
                       <depends value="SomeBean"/> // uses DependsValueMetaData
                       </array>
                      </attribute>
                      


                      • 8. Re: MappingObjectModel and Polymorphism

                        4 continued)

                        Rather than having to define

                        <beans/>

                        would it be possible to specify the type (or maybe even a factory?)

                        e.g.
                        TypeBinding beans = factory.bindType(deployment, "", "beans", ArrayList.class);
                        ElementBinding bean = factory.bindElement(beans, "", "bean", ??, AbstractBeanMetaData.class);
                        


                        • 9. Re: MappingObjectModel and Polymorphism
                          aloubyansky

                           

                          "adrian@jboss.org" wrote:
                          4) That didn't work for me. I couldn't see how to define it:

                           ElementBinding beans = factory.bindElement(deployment, "", "beans", "beans", ArrayList.class);
                           ElementBinding bean = factory.bindElement(beans, "", ??, ??, AbstractBeanMetaData.class);
                          


                          I also have the requirement to do polymorphism on collections,
                          something like:
                          <attribute name="blah">
                           <list>
                           <value type="some.type">foo</value> // uses StringValueMetaData
                           <depends value="SomeBean"/> // uses DependsValueMetaData
                           <list> // recursion :-)
                           ...
                           </list>
                           </list>
                          </attribute>
                           ElementBinding listValue = factory.bindElement(attribute, "", "list", "value", AbstractListMetaData.class); // implements java.util.List
                          //What comes here???
                          



                          Please, check out the value-binding testcase. It's been updated to include what you are asking for except for recursion. In other words, it's global element binding. Not yet supported.

                          "adrian@jboss.org" wrote:

                          and arrays
                          <attribute name="blah">
                           <array type="someClass"> // AbstractArrayValueMetaData
                           <value type="some.type">foo</value> // uses StringValueMetaData
                           <depends value="SomeBean"/> // uses DependsValueMetaData
                           </array>
                          </attribute>
                          


                          And arrays... (not supported yet). It's not hard to add this but I would like to think more about the issues you raised and see how significant the changes I need to make in the API are.

                          Thank you for choosing JBossXB ;)

                          • 10. Re: MappingObjectModel and Polymorphism
                            aloubyansky

                            4 continued) Yes, sure.

                            • 11. Re: MappingObjectModel and Polymorphism

                              I don't actually need support for Arrays, I construct the real arrays myself.
                              I am dealing with metadata that describes an array and how to construct it.

                              Array is just another (specialized) form of collection for me, in fact I use a list.

                              public class AbstractArrayMetaData extends AbstractListMetaData
                              public class AbstractListMetaData extends AbstractCollectionMetaData implements List
                              


                              • 12. Re: MappingObjectModel and Polymorphism
                                aloubyansky

                                I am working on the new metadata API and will post the progress here.

                                An example of using the new prototype of metadata api that is going to cover all the features requested can be found in

                                package org.jboss.test.xml;
                                public class MiscUnitTestCase
                                 public void testNewMetadata() throws Exception
                                


                                The xml file is newmetadata.xml.

                                Currently it supports everything that was supported in the previous version plus collections as collection items (recursion). Maps are still not supported.

                                The API becomes much more verbose. I think, a common case would be to read a file defining the schema (XSD, DTD, etc) and adjust some elements/types to Java bindings if defaults were not sufficient.

                                • 13. Re: MappingObjectModel and Polymorphism

                                  If necessary, I can workaround the map problem with a wrapper that does Set processing.

                                  A map is really just a Set with one attribute identifying the key, e.g.

                                  <map>
                                   <entry key="xxx">xxx</element>
                                   <entry key="yyy">yyy</element>
                                  </map>
                                  


                                  • 14. Re: MappingObjectModel and Polymorphism
                                    aloubyansky

                                    I need to support maps anyway. So, the api and design should allow to add this later if not now.

                                    1 2 Previous Next