prev | table of contents | next |
Most of the time JAXB's mapping of XML Schema types to Java datatypes
will meet your expectations, and the standard conversion of values between
binary and string is just what you need. In those rare cases where this
is not adequate, it is possible to customize the datatype binding. We'll
illustrate this by a simple example where a xsd:simpleType
for roman numbers is defined like this:
<xsd:simpleType name="RomanNumberType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="M*D?C{,4}L?X{,4}V?I{,4}"/> <xsd:minLength value="1"/> </xsd:restriction> </xsd:simpleType>(The pattern does not cover the subtractive notation which wasn't used in ancient times anyway.) Although the XML type is
xsd:string
,
we'd like to have these values represented by Java's int
. This
means that we'll also have to supply the conversions between the Roman number
as a string of letters and as an integer value. For this, we have to write a
simple class like the one given below.
package util.roman; import java.util.HashMap; import java.util.Map; public class RomanNumberConverter { private static Map<Character,Integer> rom2int = new HashMap<Character,Integer>(); private static Map<Integer,Character> int2rom = new HashMap<Integer,Character>(); private static int[] digits = new int[]{ 1000, 500, 100, 50, 10, 5, 1 }; static { rom2int.put( 'I', 1 ); rom2int.put( 'V', 5 ); rom2int.put( 'X', 10 ); rom2int.put( 'L', 50 ); rom2int.put( 'C', 100 ); rom2int.put( 'D', 500 ); rom2int.put( 'M', 1000 ); for( Map.Entry<Character,Integer> entry: rom2int.entrySet() ){ int2rom.put( entry.getValue(), entry.getKey() ); } } public static int parseStringToInt( String value ){ int result = 0; for( int i = 0; i < value.length(); i++ ){ result += rom2int.get( value.charAt( i ) ); } return result; } public static String printIntToString( int value ){ StringBuilder sb = new StringBuilder(); for( int d: digits ){ while( value > d ){ value -= d; sb.append( int2rom.get( d ) ); } } return sb.toString(); } }There is a useful class that supports the writing of convertes such as this one:
javax.xml.bind.DatatypeConverter
provides a rich set
of methods that come in handy whenever the XML representation must follow
the specifications in
XML Schema Part 2: Datatypes.
The essential methods are the ones we'll have to announce to JAXB,
so that it will call our methods for the to and fro between the
representations. You may choose any names you like, but the methods
must be static. The customizing entry supplied in a bindings file
should then look like the one given below, with a threefold nesting of
<jaxb:bindings>
providing the level where you define
the schema position with an XPATH expression.
<?xml version="1.0" encoding="UTF-8"?> <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="1.0"> <jaxb:bindings schemaLocation="roman.xsd" node="/xsd:schema"> <jaxb:bindings node="//xsd:simpleType[@name='RomanNumberType']"> <jaxb:javaType name="int" parseMethod="util.roman.RomanNumberConverter.parseStringToInt" printMethod="util.roman.RomanNumberConverter.printIntToString"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
prev | table of contents | next |