Article: The State of JAXB

Discussions

News: Article: The State of JAXB

  1. Article: The State of JAXB (10 messages)

    Yesterday we saw a bunch of articles from BEA on XMLBeans. Today we see an article on the state of JAXB. Satya Komatineni discusses working with JAXB, the class generation process, programming examples using JAXB, and a comparison to how .NET handles the same issues.

    Read The State of JAXB: Availability, Suitability, Analysis, and Architecture
  2. Object Factory of JAXB[ Go to top ]

    'Due to the nature of the interfaces, one cannot new content objects: you have to use a factory. This can be very tedious, as your content hierarchy involves getting new objects all the time. For every object creation you have to go to the factory.'


    If you open the object factory and look at the code what it doesn't do anything more than creating a new instance. You can instantiate new object if you prefer that way..
  3. 'Due to the nature of the interfaces, one cannot new content objects: you have to use a factory. This can be very tedious, as your content hierarchy involves getting new objects all the time. For every object creation you have to go to the factory.'If you open the object factory and look at the code what it doesn't do anything more than creating a new instance. You can instantiate new object if you prefer that way..
    Not sure if that is recommended, since you're suppose to lookup the context and use the context to serializ/deserialize. When jaxb1.0 came it there was problems doing the context lookup depending on the libraries were being loaded and when you do the lookup. to get around that with jaxb1.0, I just used ObjectFactory directly. I'm sure the RI team will say "bad boy", since it's not really a good idea to do that.
  4. Ofcourse you can use the object factory directly and it's not given anywhere in JAXB documentation to do without object factory.

    If you actually look at the code what it does is nothing more that maintaing a has map for interface to implementation and instantiate accordingly. And you will not have any issues in serializing/deserializing the jaxb classes.

    In fact the point I am trying to make is that Object factory is making the job easy by maintining the map and what it does is to create new instances. I don't understand why using the object factory is tedious and why is it not good to have interfaces for hiding the implementation. If I have the interfaces through out the code I can switch to any other implementation of interfaces rather than locking up with vendors like MS
  5. Ofcourse you can use the object factory directly and it's not given anywhere in JAXB documentation to do without object factory. If you actually look at the code what it does is nothing more that maintaing a has map for interface to implementation and instantiate accordingly. And you will not have any issues in serializing/deserializing the jaxb classes.In fact the point I am trying to make is that Object factory is making the job easy by maintining the map and what it does is to create new instances. I don't understand why using the object factory is tedious and why is it not good to have interfaces for hiding the implementation. If I have the interfaces through out the code I can switch to any other implementation of interfaces rather than locking up with vendors like MS
    There are many cases where I want different types of classes implementing the same interface. Say I want to use the same model in a GUI, Webserver and Middle tier. In the gui I want the classes to implement propertyChangeListener and other more specific listeners. On the webserver tier, I might want to have it implement lazy loading. On the middle tier, I may want it to fit into an EJB. Having interfaces in my mind makes it cleaner and allows the implementation to change. But I guess if you only need to use the model in one big monolithic application, you can just have concrete classes. I prefer interfaces myself.
  6. Trouble With Anonymous Types[ Go to top ]

    I've used JAXB fairly successfully, and do like quite a bit about it. But I find that it's best when I have complete control over the schema.

    When using externally defined schemas, I've run into some problems. The most tedious being how JAXB creates inner classes for anonymous complex types. Given a schema with multiple levels of anonymous types and fairly long element names, the code gets very messy.

    Look to see what JAXB generates from this schema:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema
      targetNamespace="http://myns"
      xmlns="http://myns"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      elementFormDefault="qualified"
      version="1.0">

      <xsd:complexType name="MyFirstLevelComplex">
        <xsd:sequence>
          <xsd:element name="MySecondLevelComplex">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="MyEnumerated" type="xsd:string"/>
              </xsd:sequence>
            </xsd:complexType>
          </xsd:element>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>

    Code gets messy calling object factory methods like this:

    import myns.MyFirstLevelComplex;
    import myns.ObjectFactory;
    class foo {

      void foo() {
        ObjectFactory of = new ObjectFactory();
        MyFirstLevelComplex.MySecondLevelComplexType myObj =
            of.createMyFirstLevelComplexMySecondLevelComplexType();
        ...
      }

    }
  7. Schema has serious limitations[ Go to top ]

    I've used JAXB fairly successfully, and do like quite a bit about it. But I find that it's best when I have complete control over the schema.When using externally defined schemas, I've run into some problems. The most tedious being how JAXB creates inner classes for anonymous complex types. Given a schema with multiple levels of anonymous types and fairly long element names, the code gets very messy.Look to see what JAXB generates from this schema:<?xml version="1.0" encoding="UTF-8"?><xsd:schema   targetNamespace="http://myns"  xmlns="http://myns"  xmlns:xsd="http://www.w3.org/2001/XMLSchema"   elementFormDefault="qualified"   version="1.0">  <xsd:complexType name="MyFirstLevelComplex">    <xsd:sequence>      <xsd:element name="MySecondLevelComplex">        <xsd:complexType>          <xsd:sequence>            <xsd:element name="MyEnumerated" type="xsd:string"/>          </xsd:sequence>        </xsd:complexType>      </xsd:element>    </xsd:sequence>  </xsd:complexType></xsd:schema>Code gets messy calling object factory methods like this:import myns.MyFirstLevelComplex;import myns.ObjectFactory;class foo {  void foo() {    ObjectFactory of = new ObjectFactory();    MyFirstLevelComplex.MySecondLevelComplexType myObj =        of.createMyFirstLevelComplexMySecondLevelComplexType();    ...  }}
    I wouldn't consider that a limitation of JAXB personally. I consider it an aweful result of schema specification. One of the many limitations of schema is that you can't define interfaces and have objects implement them or have a complexType extend a type which is outside of the schema. Obviously, that makes it hard to validate the schema, but it can be an optional feature so that by default implement/extend is ignored. Using the previous example, say I have a base class for my GUI application and I want my schema classes to extend the base class. When the schema is used on the server, it can choose to ignore the extension. The schema group has acknowledged that limitation isn't easily solved, but when they will solve it is anyone's guess.
  8. Trouble With Anonymous Types[ Go to top ]

    This is the code, (1 of 5) java files we generate from your example, I've cut off the header and JavaDoc to save space.

    I could have generated a dozen different versions, including with interfaces, without getters and setters, no custom serialization, any package names you like, any header, custom extention, schema versioning (so that version n+1 extends version n etc.). If you're interested I'll send you the tar of the deployed code, you can test it out. You even get ANT tasks to deploy this from ANT without having to use the GUI.


    package myns;

    public class MyFirstLevelComplex extends biz.c24.io.api.data.ComplexDataObject
    {
        private myns.MyFirstLevelComplex.MySecondLevelComplex mySecondLevelComplex;

        public MyFirstLevelComplex(biz.c24.io.api.data.Element definingElementDecl)
        {
            super(definingElementDecl);
        }

        public MyFirstLevelComplex(biz.c24.io.api.data.Element definingElementDecl, biz.c24.io.api.data.ComplexDataType type)
        {
            super(definingElementDecl, type);
        }

        public MyFirstLevelComplex(myns.MyFirstLevelComplex clone)
        {
            super(clone);
        }

        public void addElement(java.lang.String name, java.lang.Object value)
        {
            name = makeSubstitution(name, -1);
            if (name.equals("MySecondLevelComplex"))
                setMySecondLevelComplex((myns.MyFirstLevelComplex.MySecondLevelComplex) value);
            else
                super.addElement(name, value);
        }

        public java.lang.Object clone()
        {
            return new myns.MyFirstLevelComplex(this);
        }

        public myns.MyFirstLevelComplex.MySecondLevelComplex createMySecondLevelComplex()
        {
            myns.MyFirstLevelComplex.MySecondLevelComplex obj = (myns.MyFirstLevelComplex.MySecondLevelComplex) getElementDecl("MySecondLevelComplex").createObject();
            setMySecondLevelComplex(obj);
            return obj;
        }

        public boolean equals(java.lang.Object obj)
        {
            return super.equals(obj);
        }

        public java.lang.Object getElement(java.lang.String name, int index)
        {
            name = getSubstitute(name);
            if (name.equals("MySecondLevelComplex"))
                return this.mySecondLevelComplex;
            else
                return super.getElement(name, index);
        }

        public int getElementCount(java.lang.String name)
        {
            name = getSubstitute(name);
            if (name.equals("MySecondLevelComplex"))
                return this.mySecondLevelComplex == null ? 0 : 1;
            else
                return super.getElementCount(name);
        }

        public int getElementIndex(java.lang.String name, java.lang.Object element)
        {
            name = getSubstitute(name);
            if (name.equals("MySecondLevelComplex"))
                return this.mySecondLevelComplex != null && this.mySecondLevelComplex.equals(element) ? 0 : -1;
            else
                return super.getElementIndex(name, element);
        }

        public myns.MyFirstLevelComplex.MySecondLevelComplex getMySecondLevelComplex()
        {
            return this.mySecondLevelComplex;
        }

        public int hashCode()
        {
            return super.hashCode();
        }

        public void removeElement(java.lang.String name, int index)
        {
            name = unmakeSubstitution(name, index);
            if (name.equals("MySecondLevelComplex"))
            {
                ((biz.c24.io.api.data.ComplexDataObject) this.mySecondLevelComplex).setParent(null);
                this.mySecondLevelComplex = null;
            }
            else
                super.removeElement(name, index);
        }

        public void setElement(java.lang.String name, int index, java.lang.Object value)
        {
            name = makeSubstitution(name, index);
            if (name.equals("MySecondLevelComplex"))
                setMySecondLevelComplex((myns.MyFirstLevelComplex.MySecondLevelComplex) value);
            else
                super.setElement(name, index, value);
        }

        public void setMySecondLevelComplex(myns.MyFirstLevelComplex.MySecondLevelComplex value)
        {
            this.mySecondLevelComplex = value;
            ((biz.c24.io.api.data.ComplexDataObject) this.mySecondLevelComplex).setParent(this);
        }

        private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException
        {
            out.writeObject(this.mySecondLevelComplex);
        }

        private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException
        {
            this.mySecondLevelComplex = (myns.MyFirstLevelComplex.MySecondLevelComplex) in.readObject();
        }

        public static class MySecondLevelComplex extends biz.c24.io.api.data.ComplexDataObject
        {
            private java.lang.String myEnumerated;

            public MySecondLevelComplex(biz.c24.io.api.data.Element definingElementDecl)
            {
                super(definingElementDecl);
            }

            public MySecondLevelComplex(biz.c24.io.api.data.Element definingElementDecl, biz.c24.io.api.data.ComplexDataType type)
            {
                super(definingElementDecl, type);
            }

            public MySecondLevelComplex(MySecondLevelComplex clone)
            {
                super(clone);
            }

            public void addElement(java.lang.String name, java.lang.Object value)
            {
                name = makeSubstitution(name, -1);
                if (name.equals("MyEnumerated"))
                    setMyEnumerated((java.lang.String) value);
                else
                    super.addElement(name, value);
            }

            public java.lang.Object clone()
            {
                return new myns.MyFirstLevelComplex.MySecondLevelComplex(this);
            }

            public boolean equals(java.lang.Object obj)
            {
                return super.equals(obj);
            }

            public java.lang.Object getElement(java.lang.String name, int index)
            {
                name = getSubstitute(name);
                if (name.equals("MyEnumerated"))
                    return this.myEnumerated;
                else
                    return super.getElement(name, index);
            }

            public int getElementCount(java.lang.String name)
            {
                name = getSubstitute(name);
                if (name.equals("MyEnumerated"))
                    return this.myEnumerated == null ? 0 : 1;
                else
                    return super.getElementCount(name);
            }

            public int getElementIndex(java.lang.String name, java.lang.Object element)
            {
                name = getSubstitute(name);
                if (name.equals("MyEnumerated"))
                    return this.myEnumerated != null && this.myEnumerated.equals(element) ? 0 : -1;
                else
                    return super.getElementIndex(name, element);
            }

            public java.lang.String getMyEnumerated()
            {
                return this.myEnumerated;
            }

            public int hashCode()
            {
                return super.hashCode();
            }

            public void removeElement(java.lang.String name, int index)
            {
                name = unmakeSubstitution(name, index);
                if (name.equals("MyEnumerated"))
                    this.myEnumerated = null;
                else
                    super.removeElement(name, index);
            }

            public void setElement(java.lang.String name, int index, java.lang.Object value)
            {
                name = makeSubstitution(name, index);
                if (name.equals("MyEnumerated"))
                    setMyEnumerated((java.lang.String) value);
                else
                    super.setElement(name, index, value);
            }

            public void setMyEnumerated(java.lang.String value)
            {
                this.myEnumerated = value;
            }

            private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException
            {
                out.writeObject(this.myEnumerated);
            }

            private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException
            {
                this.myEnumerated = (java.lang.String) in.readObject();
            }

        }

    }
  9. Object Factory of JAXB[ Go to top ]

    'Due to the nature of the interfaces, one cannot new content objects: you have to use a factory. This can be very tedious, as your content hierarchy involves getting new objects all the time. For every object creation you have to go to the factory.'If you open the object factory and look at the code what it doesn't do anything more than creating a new instance. You can instantiate new object if you prefer that way..
    new Blah()

    vs.

    factory.createBlah()

    rsi here i come.

    and to avoid the "mark as noisy": using factory methods instead of constructors offers significant opportunities to substitute implementations. if jaxb turns out not to be the implementation that is suitable for you, at least with a factory method, they've left opportunity to back out.
  10. Article: The State of JAXB[ Go to top ]

    JAXB has it's limits, it's great for small schemas but try something like FpML and it just simple won't cut it. Nor for that matter will Castor.

    The code generated is also of limitted use, Castor for example creates object bloat to the stage where it will actually slow things down over raw XML.

    We (C24) have taken both of these products and taken them to their ultimate conclusion, we not only generate JavaDoc'd, Externalizable Java with corresponding customized ANT build files but we guarantee support for ANY XML Schema.

    Although this is free to charities and non-profit JSR-like bodies however it is sadly not free. :-(

    For anyone interested we have just released version 3 in beta so there is little on our web site on the new IntelliJ-like GUI or code but we can send you a fully working eval if you are interested. At the time of writing the web site refers to version 2.1.

    Our customers include several of the world's largest banks in New York, London and Frankfurt.

    Marketting? Yes sorry, but if you've got stuck with JAXB, we're got a solution.

    -John Davies-
    CTO, C24
    (Currently at TSS Java Symposium in Vegas)
  11. (he is architect of XMLBeans)
    http://davidbau.com/archives/2003/11/25/jaxb_problems.html
    http://davidbau.com/archives/2003/11/19/the_design_of_xmlbeans_part_2.html