1 2 Previous Next 23 Replies Latest reply on May 12, 2005 5:25 PM by adrian.brock Go to original post
      • 15. Re: POJO Schema parsing
        aloubyansky

         

        "adrian@jboss.org" wrote:
        It looks like the new parsing is going to cope with everything I throw at it
        for the pojo parsing. Well done Alex.


        Glad to hear it works for you :)
        I am still not satisfied with the API though. And, frankly, am still also experimenting with other prototypes of the same style trying to come up with a more elegant programming model.
        Sorry, got hooked and just can't stop now :)

        "adrian@jboss.org" wrote:
        The outstanding issues are:
        1) Using schema annotations to define the parsing
        2) The ANY parsing
        3) Making the map definition less verbose.


        1) I think, annotations will be the next step (will need to patch xerces.2.6 for this, 2.7 is going to be released about June 24).
        2) I'll probably write some kind of spec for this before coding so we can discuss it in details.
        3) is being discussed in this thread.

        • 16. Re: POJO Schema parsing
          aloubyansky

           

          "adrian@jboss.org" wrote:
          Is it possible for the parser to understand this or is this just something that
          isn't guaranteed to work with xml?
          <map>
           <key/><value/>
           <key/><value/>
           <key/><value/>
          </map>
          


          So, there are several issues with maps:
          1) representation of entries in XML
          2) unmarshalling entries (representation of entries in Java)
          3) configuration, e.g. with xsd annotations, etc

          1) Representation in XML
          Probably, the most natural one is to have an element that wraps key/value pair, e.g. that represents the entry. This is what you currently do.
          I don't see a problem with having "complex" keys and values. A key element is unmarshalled (be it of a complex or a simple type) and used as the key, the same for the value element.

          Another representation is actually your question. I don't have tests for this but it's possible as long as you can rely on the order of the elements in the sequence, i.e. after the key element we always have the corresponding value element. In XSD, when you define the type of the map, you have to use sequence compositor (other kinds of compositors are 'choice' and 'all'). If the compositor is 'all', the order of the elements in XML content is not guaranteed (SAX parser of course will still report elements in the order they appear in the XML content). This is important if we want to make sure that if an XML content is valid we can guarantee the unmarshalling result.
          How to unmarshal this? Create an entry object when the key element starts, complete and add the entry to the map when the value element is parsed.

          I was thinking about adding a convenient API for unmarshalling a sequence of elements (w/o a wrapper element) into one object but didn't want to complicate the API too early. I think, it'll be added in the future.

          2) Unmarshalling of and Java representation of entries
          In the approach we use currently, we create objects ahead, i.e. when an element starts we create an object and then add data to it when we parse the content of the element.
          The disadvantage of this approach is that sometimes we have to create temporary container objects, like a map entry object (as you do) which we actually don't need or a container for constructor arguments for classes that don't have default no-arg constructors.
          In general, there is no way you can avoid an 'entry' object in this approach.

          A bit of theory... another approach would be to expose the stack of objects (which is present anyway) to unmarshalling handlers. And instead of requering an element handler to return an object from startElement (or whatever it's called), let the handler to push an object (or maybe even several objects into the stack). Attribute values, text content and child elements would also be pushed into the stack. In the endElement, the element handler would pop objects from the stack and do whatever is needed, i.e. pop key and value from the stack and add them to the map, pop ctor arguments and create an instance, etc.
          I had one prototype of this approach but the API was a bit complex and error-prone. Though, maybe it was just a bad try.

          3) configuration, xsd annotation or something else
          I am also actually not sure atm how it would translate into xsd annotations. But I believe it's possible :)

          • 17. Re: POJO Schema parsing
            starksm64

            I don't see a problem with needing to create holder objects. The main advantage is that they give you a type explicit representation of the stack as opposed to having to know the types and order of the stack. An example I have that has a clean ObjectModelFactory view is the org.jboss.security.auth.login.LoginConfigObjectModelFactory.

            Here the javax.security.auth.login.AppConfigurationEntry that is represented in the xml config cannot be constructed incrementally as a java bean because it has no setters. All data must be passed in via the ctor. There is an example of such a document with the associated xsds in jboss-head/testsuite/src/resources/xml/mbeanserver:

            [starksm@banshee9100 jboss-4.0]$ ls -l jboss-head/testsuite/src/resources/xml/mbeanserver/
            total 10
            drwxrwxrwx+ 2 starksm None 0 May 3 18:12 CVS/
            -rwxrwxrwx 1 starksm None 1879 May 3 18:14 login-config2.xsd*
            -rwxrwxrwx 1 starksm None 1599 May 3 18:14 mbean-service_1_0.xsd*
            -rwxrwxrwx 1 starksm None 3370 May 3 18:14 testObjFactory.xml*
            -rwxrwxrwx 1 starksm None 1040 May 3 18:14 user-roles.xsd*
            


            I think the general extension to jaxb that we need is the notion of a holder object that is a java bean which can be constructed via standard jaxb rules or customizations + a mapping of that holder into the actual object. The mapping could be specified via simple transform/factory interface. The authentication type in the login-config2.xsd could be customized using something like:

            <xs:complexType name="authentication">
             <xs:annotation>
             <xs:appinfo>
             <jbossxb:factory
             name="org.jboss.security.auth.login.LoginConfigFactory"
             holderClass="org.jboss.security.auth.login.AppConfigurationEntryHolder"
             />
             </xs:appinfo>
             </xs:annotation>
            ...
            



            • 18. Re: POJO Schema parsing

              I've figured out what the problem is with the expression of the Map and Key/Value.
              The issue is with the polymorphism, my attempts to reduce the
              verbosity of the xml and the parsing API.

              Essentially, the problem is that to get the polymorphism to work,
              I have to introduce a type binding, in this case
              key -> valueType
              value -> valueType
              where valueType can be collection/array/list/ANY/etc.

              But this then requires an extra object to be constructed to model the polymorphic behaviour:

               // value binding
               TypeBinding valueType = schemaBinding.getType(valueTypeQName);
              
               configureValueBindings(valueType); // <------ subelements
              
               valueType.setHandler(new DefaultElementHandler()
               {
               public Object startElement(Object parent, QName name, TypeBinding type)
               {
               return new AbstractValueMetaData(new StringValueMetaData());
               }
              etc.
              


              Then later I have to unwrap the extra AbstractValueMetaData
               AbstractMapMetaData map = (AbstractMapMetaData) parent;
               MapEntry entry = (MapEntry) child;
               AbstractValueMetaData entryKey = (AbstractValueMetaData) entry.key;
               if (entryKey == null)
               throw new IllegalArgumentException("No key in map entry");
               AbstractValueMetaData entryValue = (AbstractValueMetaData) entry.value;
               if (entryValue == null)
               throw new IllegalArgumentException("No value in map entry");
               map.put(entryKey.getValue(), entryValue.getValue());
              


              • 19. Re: POJO Schema parsing

                So the problem is two fold:

                1) The need to specify a concrete type in startElement

                2) My desire to have a less verbose API in the common case

                <entry><key class="java.lang.Integer>1</key><value>x</value></entry>
                

                instead of
                <entry><key><value class="java.lang.Integer">1</value></key><value>x</value></entry>
                

                The later is closer to the underlying object model, but obviously more tedious.

                • 20. Re: POJO Schema parsing

                  In case it isn't clear from the above posts.

                  The Map stuff is working now, but I'd appreciate it if you know a better way to
                  handle what I'm trying to do.

                  • 21. Re: POJO Schema parsing
                    aloubyansky

                     

                    "scott.stark@jboss.org" wrote:
                    I don't see a problem with needing to create holder objects. The main advantage is that they give you a type explicit representation of the stack as opposed to having to know the types and order of the stack.


                    Ok, thanks for feedback.

                    "scott.stark@jboss.org" wrote:
                    I think the general extension to jaxb that we need is the notion of a holder object that is a java bean which can be constructed via standard jaxb rules or customizations + a mapping of that holder into the actual object. The mapping could be specified via simple transform/factory interface.


                    I actually have this general holder. There are some tests for classes that don't have no-arg ctors. I find out that at runtime and collect children. When element is parsed I am trying to find a constructor that would take all the children (the order is the order of the elements in the XML content).

                    • 22. Re: POJO Schema parsing
                      aloubyansky

                       

                      "adrian@jboss.org" wrote:
                      Essentially, the problem is that to get the polymorphism to work,
                      I have to introduce a type binding, in this case
                      key -> valueType
                      value -> valueType
                      where valueType can be collection/array/list/ANY/etc.

                      But this then requires an extra object to be constructed to model the polymorphic behaviour:

                       // value binding
                       TypeBinding valueType = schemaBinding.getType(valueTypeQName);
                      
                       configureValueBindings(valueType); // <------ subelements
                      
                       valueType.setHandler(new DefaultElementHandler()
                       {
                       public Object startElement(Object parent, QName name, TypeBinding type)
                       {
                       return new AbstractValueMetaData(new StringValueMetaData());
                       }
                      etc.
                      


                      Then later I have to unwrap the extra AbstractValueMetaData
                       AbstractMapMetaData map = (AbstractMapMetaData) parent;
                       MapEntry entry = (MapEntry) child;
                       AbstractValueMetaData entryKey = (AbstractValueMetaData) entry.key;
                       if (entryKey == null)
                       throw new IllegalArgumentException("No key in map entry");
                       AbstractValueMetaData entryValue = (AbstractValueMetaData) entry.value;
                       if (entryValue == null)
                       throw new IllegalArgumentException("No value in map entry");
                       map.put(entryKey.getValue(), entryValue.getValue());
                      


                      You want to get rid of constructing an instance of AbstractValueMetaData, right?
                      I think, you could just use the DefaultElementHandler as is, w/o overwritting the startElement. Which will just propagate the MapEntry further and you will be able to add the actual key and value to it.

                      • 23. Re: POJO Schema parsing

                        Yes, but the problem is also with processing the attributes.

                        <key class="java.lang.Integer">7</key>

                        will eventually lead to
                        map.put(new StringValueMetaData("java.lang.Integer", "7"), ...)

                        whereas
                        <key><collection/></key>

                        leads to
                        map.put(new CollectionValueMetaData(), ...)


                        The
                        new AbstractValueMetaData(new StringValueMetaData()))

                        serves two purposes
                        1) The AbstractValueMetaData is really just a holder for the polymorphic object
                        2) I have somewhere to store the attributes if they are present, although
                        they only apply if there is a direct xsd:string element.

                        The problem I think is the ordering, which means I have to put something
                        in place to meet all possible later outcomes:

                        key -> AbstractValueMetaData
                        attributes -> StringValueMetaData
                        valueGroup -> It is only here that I know what is really going on

                        This also repeats for the "value" part of the map element.

                        Maybe I should be looking at richer holder object that does things a bit
                        more lazily?

                        1 2 Previous Next