The Source for Java Technology Collaboration
User: Password:



Kohsuke Kawaguchi

Kohsuke Kawaguchi's Blog

Simpler and better binding mode for JAXB 2.0

Posted by kohsuke on March 15, 2006 at 03:17 PM | Comments (5)

One of the common issues that JAXB 2.0 users face is this. When they compile their favorite schema, XJC reports back the following scary-looking errors and refuses to compile it:

parsing a schema...
[ERROR] Property "MiOrMoOrMn" is already defined.
  line 132 of file:/C:/kohsuke/Sun/JAXB/jaxb-unit/schemas/individual/MathML2/presentation/scripts.xsd

[ERROR] The following location is relevant to the above error
  line 138 of file:/C:/kohsuke/Sun/JAXB/jaxb-unit/schemas/individual/MathML2/presentation/scripts.xsd

A year ago, I explained why this is not a bug in JAXB but it's something users need to fix by themselves, but the truth is, this just reduces the ease of use of JAXB. I mean, users are always lazy and in a hurry, and so they just want their schema to compile. If anyone is interested, I can probably spend a good hour explaining why it was difficult and not desirable to handle this out of the box, but at the end of the day, who cares? I know you just want your schema to compile.

I take pride in JAXB, so I didn't like the idea that it slows down the productivty of some people by issueing errors. Therefore, I've been thinking about doing a better job on this since then. I wanted to improve XJC so that it works like a magic, so that you can get your job done quickly. And to this end, I was able to implement a new algorithm that hopefully does a better job on schemas like this.

Since this change was made after EA3, to try this out today you need to download a JAXB RI nightly (but it will be a part of the upcoming JAXB RI 2.0 release.)

Once you download the RI, also download this "schemalet", then compile your favorite schema like this (the additional option and the file is to give you a mentral barrier to cross, because this is still an experimental stuff and subject to change.):

$ xjc -extension simpleBinding.schemalet abc.xsd def.xsd ...

That's it. This puts XJC into a new binding mode, where it has less compilation errors. It works more magically.

Now, let me brag a bit more about how I did this.

The way the JAXB 2.0 spec binds XML content models is to do it inductively on the structure of the content model definition, which makes it sensitive to the way the content model definition is written. For example, A,A* and A+ represent the same content model, but just because they are written differently, JAXB spec binds them to different things (the former fails with an error, the latter works just fine.)

More common occurence of this problem is that when a schema author wants to define a content model that can't be naturally captured by W3C XML Schema, he often ends up writing a convoluted content model. Here are a few simple real-world examples:

  1. You want to say "a sequence of length > 1 where A and B can only appear as the head", and you end up writing (A|B,C*)|C+
  2. You want to say "there has to be at least A, B, or C, but it can also have any number of Xs in between", and you end up writing X*, ((A|B|C), X*)+

When the binding algorithm is defined based on the structure of the content model, it really breaks down quickly when it faces these convoluted content models. What that means is that it was not a good idea to do a binding based on the structure. That eventually led me to a new algorithm that borrows a few concepts from the graph theory --- like strongly connected components, cut set, and so on. The new algorithm focuses on the (possibly infinite) set of sequence of elements that are allowed by the content model, which more closely reflect the schema author's intention. It builds an acceptor graph where elements are nodes, then de-compose it to a set of strongly-connected components. Then check if each one of them form a cut set of the original graph. This result is then turned into a set of Java properties in an obvious way :-)

I don't expect you to care about those theories and details, but as a result, when it sees a content model ike (A,B)|(B,C), it can bind this to the following Java class (it's smart enough to figure out that B is effectively mandatory):

class Foo {
  @XmlElement
  String a;
  @XmlElement(required=true)
  String b;
  @XmlElement
  String c;
}

I'm confident that this greatly reduces the likelihood of our users hit any schema compilation issue.

This new binding algorithm is a part of my bigger "simple and better binding mode" effort. I briefly talked about one aspect of this mode a week ago. I plan to talk about other improvements in this mode in a near future.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first)

  • Hi -

    I downloaded the latest release canidate and the schemalet, but I'm still getting "element is already defined" error. Any suggestions?

    XJC VERSION
    ================================
    $ xjc.sh -version
    xjc version "hudson-jaxb-3268"
    JavaTM Architecture for XML Binding(JAXB) Reference Implementation, (build hudson-jaxb-3268)

    simpleBinding.schemalet
    ================================



    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
    xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">









    My XML Schema (snippet of base2003-money.xsd)
    ===============================================\


    The ISO standard ISO 4217 contains codes for the representation of currencies and funds. Each currency code is a three letter ID. Every position in the ID is from the A-Z character set. In most cases, the currency code is composed of the country's two-character internet country code plus an extra character to denote the currency unit.







    Money




    An amount in US dollars or other specifed currency.




    If omitted assume "USD".




    ]]>

    ERROR:
    ========================================
    $ xjc.sh -extension "$JAXB_HOME/bin/simpleBinding.schemalet" -verbose -p cv.profile.domain.jaxb "d:/projects/cv2/dev/profil
    e/src/main/resources/xmlschema/profileL3.xsd"

    parsing a schema...
    [ERROR] 'CurrencyCode_Type' is already defined
    line 31 of http://orbworld.wellsfargo.com:8080/base/base2003-money.xsd

    [ERROR] (related to above error) the first definition appears here
    line 23 of http://orbworld.wellsfargo.com:8080/base/base2003-money.xsd

    Posted by: julio_mistral on April 01, 2006 at 08:54 AM

  • I get NPE instead.

    ========================
    xjc version "2.0-20060424-fcs"
    JavaTM Architecture for XML Binding(JAXB) Reference Implementation, (build 2.0-2
    0060424-fcs)


    C:\jaxb>C:\jaxb\bin\xjc.bat -extension simpleBinding.schemalet -verbose SoapEnvelope.xsd SOAPRoutingProtocol.xsd
    parsing a schema...
    Exception in thread "main" java.lang.NullPointerException
    at com.sun.tools.xjc.reader.xmlschema.BGMBuilder._getBindInfoReadOnly(BG
    MBuilder.java:383)
    at com.sun.tools.xjc.reader.xmlschema.BGMBuilder.getBindInfo(BGMBuilder.
    java:367)
    at com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty.getCustomizati
    ons(BIProperty.java:469)
    at com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty.createReferenc
    eProperty(BIProperty.java:368)
    at com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty.createElementO
    rReferenceProperty(BIProperty.java:405)
    at com.sun.tools.xjc.reader.xmlschema.ExpressionParticleBinder.buildProp
    erty(ExpressionParticleBinder.java:78)
    at com.sun.tools.xjc.reader.xmlschema.ExpressionParticleBinder.build(Exp
    ressionParticleBinder.java:33)
    at com.sun.tools.xjc.reader.xmlschema.ParticleBinder.build(ParticleBinde
    r.java:61)
    at com.sun.tools.xjc.reader.xmlschema.ct.FreshComplexTypeBuilder$1.parti
    cle(FreshComplexTypeBuilder.java:70)
    at com.sun.xml.xsom.impl.ParticleImpl.visit(ParticleImpl.java:90)
    at com.sun.tools.xjc.reader.xmlschema.ct.FreshComplexTypeBuilder.build(F
    reshComplexTypeBuilder.java:51)
    at com.sun.tools.xjc.reader.xmlschema.ct.ComplexTypeFieldBuilder.build(C
    omplexTypeFieldBuilder.java:64)
    at com.sun.tools.xjc.reader.xmlschema.BindRed.complexType(BindRed.java:3
    7)
    at com.sun.xml.xsom.impl.ComplexTypeImpl.visit(ComplexTypeImpl.java:236)

    at com.sun.tools.xjc.reader.xmlschema.ClassSelector$Binding.build(ClassS
    elector.java:181)
    at com.sun.tools.xjc.reader.xmlschema.ClassSelector.executeTasks(ClassSe
    lector.java:348)
    at com.sun.tools.xjc.reader.xmlschema.BGMBuilder._build(BGMBuilder.java:
    139)
    at com.sun.tools.xjc.reader.xmlschema.BGMBuilder.build(BGMBuilder.java:7
    7)
    at com.sun.tools.xjc.ModelLoader.annotateXMLSchema(ModelLoader.java:388)

    at com.sun.tools.xjc.ModelLoader.load(ModelLoader.java:145)
    at com.sun.tools.xjc.ModelLoader.load(ModelLoader.java:91)
    at com.sun.tools.xjc.Driver.run(Driver.java:287)
    at com.sun.tools.xjc.Driver.run(Driver.java:173)
    at com.sun.tools.xjc.Driver._main(Driver.java:98)
    at com.sun.tools.xjc.Driver.access$000(Driver.java:56)
    at com.sun.tools.xjc.Driver$1.run(Driver.java:78)

    C:\jaxb>


    Posted by: alanyu on April 24, 2006 at 01:00 PM

  • This isn't a very good place for a support question. Please post them to users@jaxb.dev.java.net

    Posted by: kohsuke on May 15, 2006 at 03:23 PM

  • Good work, that saved me having to learn how to write property customizations! (Not that it looked difficult to write property customizations, but why do it when I can have it done for me?)

    I think you've got a mismatch between the filename that's at the "this schemalet" link (simpleMode.xsd) and the filename used in your example xjc.sh line (simpleBinding.schemalet); at least I had to change them to match to get xjc to run.

    Finally, might you use a similar "acceptor graph" built from required elements to generate constructors? I've raised the issue of constructors before (Using JAXB 2.0's XmlJavaTypeAdapter) and realise it's not a universally applicable approach, but it seems like you're pretty close with this acceptor graph thing.

    Posted by: johnbchicago on July 07, 2006 at 10:39 AM

  • I am trying to run a simple jaxb example. I am encountering numerous errors when I try to generate teh classes using xjc compiler.

    For some odd reason each class seems to import itself and there are a lot of '@XmlAccessorType' references which are generating 'Syntax error on token "Invalid Character", "interface", "class" expected' kind of errors.

    Probably I am missing some jar file. I am using jaxb 2.0 and trying to invoke it from WSAD 5.1.

    Kindly advise, any help would be greatly appreciated.

    Posted by: priyat on April 24, 2007 at 10:55 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds