Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB treets empty int XML attribute as 0

Tags:

java

jaxb

JAXB treets empty int XML attribute as 0, which is fine with me, but I've got requirement to store it as a null. Seems I can't change DataConverterImpl class to custom implementation. What could be done if at all?

<xs:attribute name="Count" type="Integer0to999" use="optional">

<xs:simpleType name="Integer0to999">
    <xs:annotation>
      <xs:documentation xml:lang="en">Used for Integer values, from 0 to 999 inclusive</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:integer">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="999"/>
    </xs:restriction>
  </xs:simpleType>

After xjc schema compilation I got class with the following:

 @XmlAttribute(name = "Count")
    protected Integer passengerCount;

During XML parse parseInt() get called from DataConverterImpl.class from Sun(Oracle) which code is below, your neve going to get null from this code :

 public static int _parseInt(CharSequence s) {
        int len = s.length();
        int sign = 1;

        int r = 0;

        for( int i=0; i<len; i++ ) {
            char ch = s.charAt(i);
            if(WhiteSpaceProcessor.isWhiteSpace(ch)) {
                // skip whitespace
            } else
            if('0'<=ch && ch<='9') {
                r = r*10 + (ch-'0');
            } else
            if(ch=='-') {
                sign = -1;
            } else
            if(ch=='+') {
                ; // noop
            } else
                throw new NumberFormatException("Not a number: "+s);
        }

        return r*sign;
    }
like image 454
kot Avatar asked May 05 '10 17:05

kot


2 Answers

You could try writing a custom XMLAdaptor that converts your integer to a String (or other object), then converts it back as you see fit. During the unmarshalling, I imagine a quick case-insensitive check for 'null' would be all that you'd need.

Start here: http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html

Attach the adaptor to your int field and write the body.

Your converter would start as follows:

public class MyIntConverter extends XmlAdapter<String,Integer> 
{
    @Override
    public String marshal(Integer value) throws Exception {

        if ( value.intValue() == 0 )
                   return null;  // Or, "null" depending on what you'd like

            return value.toString();
    }

    @Override
    public Integer unmarshal(String storedValue) throws Exception {

        if ( storedValue.equalsIgnoreCase("null") )
                   return 0;

            return Integer.valueOf(storedValue);
    }
}

Then, you could put it to use:

@XmlJavaTypeAdapter(MyIntConverter.class)
int someNumber;

The code is untested, but I think it should solve the issue.

like image 144
NBJack Avatar answered Nov 16 '22 20:11

NBJack


FWIW, I am currently finding that JAXB unmarshals an empty element to zero (if an Integer field) but to null if it's a Long field.

Admittedly that might be some kind of problem with custom data type converters. Or it might be a bug with the JAXB version with JDK 6.0 and you might be using a later version.

like image 1
Iain Avatar answered Nov 16 '22 21:11

Iain