JAXB – receptár tipov a trikov

2008/09/04

Pri kompilácii XML schémy pomocou JAXB sú niektoré XML typy namapované na „neštandardné" Java triedy. Napríklad typy pre dátum a čas (xsd:date, xsd:time) nie sú mapované na java.util.Date(), ale na špeciálnu triedu javax.xml.datatype.XMLGregorianCalendar (dôvodom je vraj rozličný rozsah platnosti tried). V JAXB je však možné prispôsobiť mapovania tried pomocou XJB súboru. Na [blogu jedného z autorov](http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html |) JAXB sa udáva možnosť priameho mapovania na java.util.Date.

V jednom z projektov sme potrebovali mapovanie na java.sql.Date. Súbor prispôsobenia binding.xjb vyzerá nasledovne:

<jaxb:bindings version="2.0" 
	xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
	xmlns:xs="http://www.w3.org/2001/XMLSchema" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
	xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
	schemaLocation="studijneProgramy.xsd"
    jaxb:extensionBindingPrefixes="xjc"
>

    <jaxb:globalBindings>
      <jaxb:javaType name="java.sql.Date" xmlType="xs:date"
         parseMethod="ws.util.JavaSqlDateAdapter.parseDate"
         printMethod="ws.util.JavaSqlDateAdapter.printDate"
      />
    </jaxb:globalBindings>
</jaxb:bindings>

Typ xsd:date bude mapovaný na java.sql.Date. Na konverziu sa použije trieda ws.util.JavaSqlDateAdapter a jej metódy parseDate(), resp. printDate(). Tried vyzerá nasledovne:

public class JavaSqlDateAdapter {
  public static Date parseDate(String s) {
    Calendar calendar = DatatypeConverter.parseDate(s);
    Date date = new Date(calendar.getTimeInMillis());
    
    return date;
  }

  public static String printDate(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    return DatatypeConverter.printDate(cal);
  }
}

Pri spúšťaní xjc nesmieme zabudnúť na parameter classpath, ktorému dodáme cestu k binárkam tejto triedy.

xjc -classpath web/WEB-INF/classes [...]

Po vygenerovaní uvidíme, že xjc vytvoril prapodivnú triedu org.w3/_2001.xmlschema.Adapter1.java, ktorá vyzerá nasledovne:

public class Adapter1 extends XmlAdapter<String, Date> {

    public Date unmarshal(String value) {
        return (ais.ws.util.JavaSqlDateAdapter.parseDate(value));
    }

    public String marshal(Date value) {
        return (ais.ws.util.JavaSqlDateAdapter.printDate(value));
    }

}

Ide o implementáciu klasickej JAXB triedy XmlAdapter, ktorá priamo volá našu konverznú triedu. Ak nám tento postup prekáža a nechcem mať jednu zbytočnú triedu (navyše s pochybným názvom), môžeme sa jej zbaviť.

Namiesto prispôsobenia cez jaxb:javaType môžeme použiť rozšírenia od dodávateľov (vendor extensions) režim pri kompilovaní cez xjc.

Namiesto elementu jaxb:javaType uvedieme element xjc:javaType

<jaxb:globalBindings>
  <xjc:javaType name="java.sql.Date" 
                xmlType="xsd:date"
                adapter="ais.ws.util.JavaSqlDateAdapter" />
</jaxb:globalBindings>

(V koreňovom elemente musíme mať deklarovaný menný priestor xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" a jaxb:extensionBindingPrefixes="xjc".) Pri spúšťaní xjc musíme dodať parameter -extension, ktorý zapne používanie rozšírení.

>> Home