The Great JAXB API Blunder

September 15, 2006

You've got to hand it to Sun for screwing this one up. It's one thing to write software that doesn't adhere to a specification when the documentation is as thick as a textbook. Take, for example, just about anything created by the W3C. However, it's really bad when it is your own spec that you can't follow, especially when it is the most well known part of it. That's right, Sun missed by a mile on their own spec when they created the JAXB 2.0 API. The JAXB 2.0 compiler (XJC) incorrectly uses the prefix "is" rather than "get" when generating the getter method for a java.lang.Boolean property. While the JavaBean spec states that read methods for primitive booleans can use the alternate "is" prefix, this flexibility does not extend to its boolean wrapper counterpart.

8.3.2 Boolean Properties

In addition, for boolean properties, we allow a getter method to match the pattern:

public boolean is();

This "is" method may be provided instead of a "get" method, or it may be provided in addition to a "get" method. In either case, if the "is" method is present for a boolean property then we will use the "is" method to read the property value.

An example boolean property might be:

public boolean isMarsupial();
public void setMarsupial(boolean m);

Given that JAXB is a code generation framework, and the idea behind code generation frameworks is that the code is to be used "as is" and not modified thereafter, this is a pretty big "oops". While this issue has been reported, the response from Sun is "sorry, its too late".

This behavior is governed by the spec, and unfortunately it's just too late for the spec to change now.

In terms of the user experience, thanks to auto-boxing, I don't think this will be a real issue for people. Is the problem that you are using Introspector and it's missing the property?

Too late? Not a real issue? It's BROKEN. FIX IT! I also don't like the naive statement that it probably won't affect frameworks. Um, yes it will, considering other projects did happen to adhere to the spec (hibernate, spring, myfaces, etc.)

UPDATE: Stevo Slavic informed me that this has been fixed in JAXB 2.1.13. See JAXB-131 for details. Yeah!

Of course, this blunder brings several issues to the table. For one, it proves the evilness of getter/setter methods and for so called "convenience" naming prefixes that, in the end, just create more work for framework builders. When the "generate getters/setters" option showed up in Java IDEs, it should have been a rather obvious indication that it was time to rethink the problem. It also shows, once again, what a dangerous idea it was to separate primitives from objects in the language. More importantly, however, it emphasizes how counterproductive specs can be and why frameworks such as Spring come to life. If a spec is broken, the response should not be "oh well, too late". Rather, it should be treated as the vermin it is, and eradicated immediately.

I do want to end on a positive note, given that this entry has been a tad negative. JAXB 2.0 is a great framework and makes working with XML data structures a very restful process. I especially like the use of annotations to offer POJO simplicity to the generated classes. I previously wrote about how I loath code generation frameworks, but this is definitely one I can handle...even if I am having to deal with a rather annoying bug at the current moment.

Posted at 11:26 PM in Java | Permalink Icon Permalink

8 Comments from the Peanut Gallery

1 | Posted by Erik on October 04, 2007 at 03:11 AM EST

You say "I am having to deal with a rather annoying bug at the current moment", can i ask you how you managed to deal with it? :)

I'm using Spring BeanWrapper and JAXB 2 generated classes and it just don't work for Boolean properties :( Is there any quick workaround for the problem?

2 | Posted by akoskiss on February 13, 2008 at 04:49 AM EST

You should create FooBeanInfo class extending SimpleBeanInfo for your Foo class (which has the Boolean proprety) and you should override the getPropertyDescriptors() method. This new class must be in the same package as your Foo class.

If you have JAXB generated inner classes (i.e. Bar) you shoud change your schema files, because this solution is not working for inner classes unless you put the customized BarBeanInfo class into your Foo class. But this is not working in case of using generated classes.

I hope this information is usefull for you.

3 | Posted by Torsten Reinhard on November 05, 2008 at 03:59 AM EST

I have the same (showstopper) issue using JXPath from Apache - and I could not write BeanInfo classes, because I have a lot of JAXB generated classes from many (unchangeable) *.xsd files - all using inner classes...

IsnĀ“t there an xjc plugin available that generates the missing "Boolean get.....()" methods in addition to the already existing Boolean is....() methods?

4 | Posted by Alan Greasley on June 17, 2009 at 07:56 AM EST

There is a plugin here: http://fisheye5.cenqua.com/browse/~raw,r=1.1/jaxb2-commons/www/boolean-getter/index.html

This looks just the ticket - it is meant to work with JAXB 2.1.2, but I cannot get it to work as yet in std JDK 6 (u13) which is meant to contain JAXB 2.1.3

5 | Posted by John Newman on June 30, 2009 at 02:02 PM EST

Alan -

Thanks for posting that, it did the trick. I did not have any issues at all using it with jaxb 2.1.3, not sure what problem you are running into. Initially I had some version conflict issues with the maven plugin, but with

jaxb-xjc 2.1.6 javax.xml.bind 2.1 jaxb-impl 2.1.3

it works fine...

I'm going through my xsd and removing use="required" from all Boolean types. Now I've got getBoolean() again instead of isBoolean(). So my xml doesn't have boolean="false" all through it now. whoo hoo...

The only thing is a few spots in the app are creating NPEs since it would always assume non null, have to add the null check first. I'm debating on whether I could/should add this to the getter methods or test and put the check where needed..

thanks

6 | Posted by BobFields on November 20, 2009 at 12:28 PM EST

What would work best is if Jaxb generated a @deprecated getBoolean method for primitive booleans, and a @deprecated isBoolean method for wrapped Booleans, so that any framework that uses either will still work. The plugin merely replaces isBoolean with getBoolean method declarations, meaning it still doesn't work with other frameworks that follow the spec.

7 | Posted by Stevo Slavic on February 14, 2012 at 05:41 AM EST

This has been fixed in jaxb 2.1.13 (see http://java.net/jira/browse/JAXB-131 ) so just upgrade your jaxb dependencies e.g. for org.codehause.mojo:jaxb2-maven-plugin:1.3.1 as described in following JIRA ticket comment:

http://jira.codehaus.org/browse/MJAXB-37?focusedCommentId=291602&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-291602

8 | Posted by Dan Allen on February 14, 2012 at 10:10 AM EST

Thanks for the update Stevo! I've added an update to the entry.