The Source for Java Technology Collaboration
User: Password:



Kohsuke Kawaguchi

Kohsuke Kawaguchi's Blog

Compiling MathML with JAXB 2.0

Posted by kohsuke on May 16, 2005 at 04:02 PM | Comments (11)

Step 1: Download

The first thing I did was to download the MathML schema into my local disk. You can compile a remote schema by running XJC like:

$ xjc.sh -proxy webcache.sfbay.sun.com:8080 http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd

But when you are going to compile schemas multiple times, it's often easier to first download them locally. Sometimes this ends up in more work as you need to fix inter-schema dependencie, but in this case MathML uses relative URLs for referencing other schemas, and therefore I only needed to download the tgz archive and run it locally.

Step 2: Property name "Class" is reserved

The first thing I did was to run it without any option to see how it goes:

$ xjc.sh mathml2/mathml2.xsd

This gave me a tons of the following errors.:

[ERROR] Property name "Class" is reserved by java.lang.Object.
  line 26 of file:/C:/kohsuke/Sun/JAXB/jaxb-unit/schemas/individual/MathML2/common/common-attribs.xsd

If you go to the line 26 of this file, you'll see that this is the attribute called 'class'

<xs:attributeGroup name="Common.attrib">
  <xs:attribute name="class" type="xs:NMTOKENS"/>
  ...
</xs:attributeGroup>

The problem is that this attribute calls for the "getClass" and "setClass" methods to be generated on the generated class, but "getClass" will collide with the same method on the Object class. To get around this error, we need to rename the methods generated from this attribute.

To do this, you need to write a "binding customization", which change the way XJC behaves. You can do this either inline or externally; I'll show you both in here, but you only need to do either one of them.

Doing it inline means modifying the schema directly. You first put the following declaration on the <schema> element.

<xs:schema 
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns="http://www.w3.org/1998/Math/MathML"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  targetNamespace="http://www.w3.org/1998/Math/MathML"
  elementFormDefault="qualified"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  jaxb:version="2.0"
>

This signals that XJC that you are using 2.0 customizations. Then you add the following declaration:

<xs:attributeGroup name="Common.attrib">
  <xs:attribute name="class" type="xs:NMTOKENS">
    <xs:annotation><xs:appinfo>
      <jaxb:property name="clazz" />
    </xs:appinfo></xs:annotation>
  </xs:attribute>
  ...
</xs:attributeGroup>

This tells XJC to map this attribute to a property named "clazz" (so you'll see getClazz and setClazz.)

Doing it externally means writing it in a separate file, like this:

<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          version="2.0">
   <bindings schemaLocation="common/common-attribs.xsd"
     node="/xsd:schema/xsd:attributeGroup[@name='Common.attrib']/xsd:attribute[@name='class']">
      <property name="clazz" />
   </bindings>
</bindings>

Notice that it contains the same information but in a different way. I needed to use an XPath to point to the place where I want to attach a customization. This is harder to do, but sometimes you can't modify the schema inline.

Now that I see this bug, I think that the JAXB spec should be smart enough to automatically resolve this collision by renaming it to "Clazz" or something. Hopefully the spec team will have time to incorporate this into the spec.

Step 3: Property "MiOrMoOrMn" is already defined

With the new binding file at my hand, I run XJC again, this time like this:

$ xjc.sh mathml2/mathml2.xsd -b binding.xjb

... which gave me this:

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

If you go to line 132 of scripts.xsd, you'll see that it's a somewhat complicated content model definition:

<xs:group name="mmultiscripts.content">
  <xs:sequence>
    <xs:group ref="Presentation-expr.class"/>
    <xs:sequence minOccurs="0" maxOccurs="unbounded">     <!-- line 132 -->
      <xs:group ref="Presentation-expr-or-none.class"/>
      <xs:group ref="Presentation-expr-or-none.class"/>
    </xs:sequence>
    <xs:sequence minOccurs="0">
      <xs:element ref="mprescripts"/>
      <xs:sequence maxOccurs="unbounded">                 <!-- line 138 -->
        <xs:group ref="Presentation-expr-or-none.class"/>
        <xs:group ref="Presentation-expr-or-none.class"/>
      </xs:sequence>
    </xs:sequence>
  </xs:sequence>
</xs:group>

This is a standard technique in designing a schema. When you want to say "in this element, B can occur arbitrary times, but C can occur only up to once", you write this as B*,(C,B*)?. This, however, confuses JAXB, because it tries to bind the first B to its own property, then C to its own property, then the second B to its own property, and we end up having a collision again.

In this particlar case, B isn't a single element but it's a choice of large number of elements abstracted away in <xs:group>s, so they are hard to see. But if you see the same content model refering to the same element/group twice in a different place, you can suspect this.

In this case, you'd probably want the whole thing to map to a single list so that you can retain the order those elements show up in the document. You can do this by putting the same <jaxb:property> customization on the whole "mmultiscripts.content" model group, like this (or you can do it externally with XPath):

<xs:group name="mmultiscripts.content">
  <xs:annotation><xs:appinfo>
    <jaxb:property name="content" />
  </xs:appinfo></xs:annotation>
  <xs:sequence>
    <xs:group ref="Presentation-expr.class"/>

It would be nice if the JAXB spec is (once again) smart enough to detect this and bind it appropriately, but this is harder. I plan to think about this more carefully and see if we can do something about this.

Step 4: Miller Time!

Anyhow, with this change in the customization, I run XJC yet again:

$ xjc.sh mathml2/mathml2.xsd -b binding.xjb

... and this time it worked and generated all the classes. If you've come this far, it calls for a little celebration. With this satisfaction, I'm heading home today!

In case you just want to compile MathML, here's the binding file you can use by cut&paste:

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    version="2.0">

	<bindings schemaLocation="common/common-attribs.xsd"
		node="/xsd:schema/xsd:attributeGroup[@name='Common.attrib']/xsd:attribute[@name='class']">
		<property name="clazz" />
	</bindings>
	
	<bindings schemaLocation="presentation/scripts.xsd"
		node="/xsd:schema/xsd:group[@name='mmultiscripts.content']">
		<property name="content" />
	</bindings>
</bindings>

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) | Post Comment

  • I'm a bit off topic here, but something I'd really like to see in a blog post on JAXB would be a performance comparison of jaxb2 with some other data binding implementations out there. I imagine it's a bit speedier than jaxb1. How would it fit in with the performance numbers at http://www-106.ibm.com/developerworks/library/x-databdopt2/index.html

    Posted by: richunger on May 16, 2005 at 06:28 PM

  • Your wish is my command. I'll try.

    Posted by: kohsuke on May 16, 2005 at 08:02 PM

  • just wanted to say great post, thanks for writing it up

    Posted by: ronaldyang on May 17, 2005 at 05:01 PM

  • For one (thorough) comparison of Java XML binding implementations, see the Bindmark project here on java.net.

    Posted by: johnbchicago on September 28, 2005 at 08:48 AM

  • Hey Kohsuke

    Great website. Couldn't have implemented our serialization stuff w/o help from here. I didn't know how to post the following question to you and just want to do it here. Hope this is Ok.

    Every now and then albiet very rare we get a ConcurrentModificationException when we try to serialize we get a ConcurrentModificationException on the com.xml./bind.v2.runtime.property.ArrayElementProperty.serializeListBody().

    Is this a known bug ? I use a shared JAXBContext across multiple threads. Could this be a problem ?

    Thanks in advance
    A

    Posted by: avinashdha on March 27, 2006 at 10:22 AM

  • I think it's best to talk about those issues at either java.net JAXB forum or users@jaxb.dev.java.net, so that we can have a dialog more efficiently.
    Thanks in advance.

    Posted by: kohsuke on March 27, 2006 at 11:38 AM

  • Great post. Exactly what I was looking for. Thanx a lot.

    Posted by: sesto on April 03, 2006 at 07:12 AM

  • I need an external binding of the MathMl, because I am trying to compile a schema that imports mathml.. .If you have the external binding XML for solve these binding customization problems, please let me know.

    Posted by: felipegaucho on November 13, 2006 at 01:12 AM

  • The external binding file is shown at the end of the post, felipegaucho.

    Posted by: kohsuke on March 21, 2007 at 07:47 PM

  • Hello, I am using a binding.xjb as showen in step 4 in an ant-task. With JAXB 2.0.5 it is OK. But with JAXB 2.1.4, I get the errors as if I have not used binding.xjb. What must I change to use JAXB 2.1.x?

    Posted by: wnast on August 15, 2007 at 02:07 AM

  • It would be the best for questions like that to go to the forum, wnast.

    Posted by: kohsuke on August 16, 2007 at 10:12 AM





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