JAXB und Java Type Mapping

saftmeister

Nutze den Saft!
Hallo,

da ich nach Google- und Forensuche noch nicht weiß, wie ich das machen kann, stelle ich hier meine Frage:

Ich habe verschiedene XSD-Files, die mit jeweils unterschiedlichen Binding-XML-Files Klassen generieren. Die Packages sind teilweise sehr unterschiedlich. Daran kann auch nichts geändert werden. In ein oder zwei von diesen Binding-Files werden javatype-Mappings von bspw. xmlType="dateTime" auf name="java.util.Calendar" (und andere) gemappt. Dies natürlich in Kombination mit der entsprechenden parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" sowie das printMethod-Äquivalent.

Also quasi wie hier beschrieben: https://jaxb.dev.java.net/guide/Using_different_datatypes.html

Dabei wird jeweils eine Adapter-Klasse erstellt. Leider nicht wie auf obiger Seite beschrieben sondern mit dem Namen

org.w3._2001.xmlschema.Adapter[n].class

Wobei [n] bei drei Java-Type-Mappings natürlich 1 bis 3 lautet. Ich hätte es gern so, das der Package-Pfad dieser Adapter-Klasse definierbar ist oder das der Name der Klasse frei wählbar ist. Durch das Generieren aller XSDs erhalte ich nämlich zwei Klassen mit dem gleichen Namen und gleichem Pfad aber in unterschiedlichen Pfaden innerhalb meiner Build-Umgebung. Das Resultat ist jedenfalls, das der Compile mittels ant abbricht, weil diese zwei Klassen gefunden und deshalb einer von beiden als Duplikat gekennzeichnet wird.

Leider kann ich an der Strukur überhaupt nichts ändern. Lediglich das Binding kann ich anpassen.

Verwendet wird JAXB 2.0.

Außerdem möchte ich noch anmerken, das die Target-Namespaces zwischen den XSDs durchaus auch komplett unterschiedlich sind. Die generierten Adapter-Klassen lauten allerdings immer gleich und verwenden das gleiche Package "org.w3._2001.xmlschema". Ich wäre schon sehr froh, wenn ich diesen ändern könnte.

Kann mir jemand einen Tipp geben, wie das Binding dazu aussehen muss?
 
Hallo,

kannst du mal ein Beispiel-Schema angeben?

Bei mir klappts scheinbar wie gewünscht (zumindest das Package kann ich beeinflussen):

test.xsd:
XML:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:simpleType name="stringtype">
  <xs:restriction base="xs:string"/>
</xs:simpleType>

<xs:simpleType name="inttype">
  <xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>

<xs:simpleType name="dectype">
  <xs:restriction base="xs:decimal"/>
</xs:simpleType>

<xs:simpleType name="orderidtype">
  <xs:restriction base="xs:string">
    <xs:pattern value="[0-9]{6}"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="shiptotype">
  <xs:sequence>
    <xs:element name="name" type="stringtype"/>
    <xs:element name="address" type="stringtype"/>
    <xs:element name="city" type="stringtype"/>
    <xs:element name="country" type="stringtype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="itemtype">
  <xs:sequence>
    <xs:element name="title" type="stringtype"/>
    <xs:element name="note" type="stringtype" minOccurs="0"/>
    <xs:element name="quantity" type="inttype"/>
    <xs:element name="price" type="dectype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="shipordertype">
  <xs:sequence>
    <xs:element name="orderperson" type="stringtype"/>
    <xs:element name="shipto" type="shiptotype"/>
    <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
  </xs:sequence>
  <xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>

<xs:element name="shiporder" type="shipordertype"/>

</xs:schema>

Die Bindings:
bindings.xml
XML:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <globalBindings>
    <javaType name="java.util.Date" xmlType="xs:date"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseDate"
      printMethod="de.tutorials.jaxb.DataAdapter.printDate"
    />

    <javaType name="java.lang.Integer" xmlType="xs:integer"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseInt"
      printMethod="de.tutorials.jaxb.DataAadpter.printInt"
    />

    <javaType name="java.lang.String" xmlType="xs:string"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseString"
      printMethod="de.tutorials.jaxb.DataAadpter.printString"
    />
  </globalBindings>
</bindings>

Der Aufruf:
Code:
tom@halu:~/Desktop/jaxb$ java -version
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.6.1) (6b16-1.6.1-3ubuntu1)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)


tom@halu:~/Desktop/jaxb$ xjc -target 2.0 -p de.tutorials.jaxb -d gen test.xsd -b bindings.xml

Ausgabe:
Code:
parsing a schema...
compiling a schema...
de/tutorials/jaxb/Adapter1.java
de/tutorials/jaxb/Adapter2.java
de/tutorials/jaxb/Adapter3.java
de/tutorials/jaxb/Itemtype.java
de/tutorials/jaxb/ObjectFactory.java
de/tutorials/jaxb/Shipordertype.java
de/tutorials/jaxb/Shiptotype.java

Die generierten Adapter-Klassen sind dann schon im passenden package:
Beispielsweise:
Java:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2010.02.25 at 09:21:44 PM MEZ 
//


package de.tutorials.jaxb;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class Adapter1
    extends XmlAdapter<String, Integer>
{


    public Integer unmarshal(String value) {
        return (de.tutorials.jaxb.DataAadpter.parseInt(value));
    }

    public String marshal(Integer value) {
        return (de.tutorials.jaxb.DataAadpter.printInt(value));
    }

}

Die Adapter werden dann auch entsprechend verwendet:
Java:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2010.02.25 at 09:21:44 PM MEZ 
//


package de.tutorials.jaxb;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


/**
 * <p>Java class for shipordertype complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="shipordertype">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="orderperson" type="{}stringtype"/>
 *         &lt;element name="shipto" type="{}shiptotype"/>
 *         &lt;element name="item" type="{}itemtype" maxOccurs="unbounded"/>
 *       &lt;/sequence>
 *       &lt;attribute name="orderid" use="required" type="{}orderidtype" />
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "shipordertype", propOrder = {
    "orderperson",
    "shipto",
    "item"
})
public class Shipordertype {

    @XmlElement(required = true)
    @XmlJavaTypeAdapter(Adapter3 .class)
    protected String orderperson;
    @XmlElement(required = true)
    protected Shiptotype shipto;
    @XmlElement(required = true)
    protected List<Itemtype> item;
    @XmlAttribute(required = true)
    @XmlJavaTypeAdapter(Adapter3 .class)
    protected String orderid;

    /**
     * Gets the value of the orderperson property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getOrderperson() {
        return orderperson;
    }

    /**
     * Sets the value of the orderperson property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setOrderperson(String value) {
        this.orderperson = value;
    }

    /**
     * Gets the value of the shipto property.
     * 
     * @return
     *     possible object is
     *     {@link Shiptotype }
     *     
     */
    public Shiptotype getShipto() {
        return shipto;
    }

    /**
     * Sets the value of the shipto property.
     * 
     * @param value
     *     allowed object is
     *     {@link Shiptotype }
     *     
     */
    public void setShipto(Shiptotype value) {
        this.shipto = value;
    }

    /**
     * Gets the value of the item property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the item property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getItem().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Itemtype }
     * 
     * 
     */
    public List<Itemtype> getItem() {
        if (item == null) {
            item = new ArrayList<Itemtype>();
        }
        return this.item;
    }

    /**
     * Gets the value of the orderid property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getOrderid() {
        return orderid;
    }

    /**
     * Sets the value of the orderid property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setOrderid(String value) {
        this.orderid = value;
    }

}

Ansosnten hilft vielleicht auch folgender Blog-Eintrag weiter:
http://blogs.sun.com/CoreJavaTechTips/entry/exchanging_data_with_xml_and1

Gruß Tom
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

so gings auch:

bindings.xml
XML:
<bindings 
xmlns="http://java.sun.com/xml/ns/jaxb" 
version="2.0" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
>
  <globalBindings>

    <javaType name="java.util.Date" xmlType="xs:date"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseDate"
      printMethod="de.tutorials.jaxb.DataAdapter.printDate"
    />



    <javaType name="java.lang.Integer" xmlType="xs:integer"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseInt"
      printMethod="de.tutorials.jaxb.DataAadpter.printInt"
    />

    <xjc:javaType name="java.lang.String" xmlType="xs:string" adapter="com.foo.bar.DataAdapter"/>
<!--
    <javaType name="java.lang.String" xmlType="xs:string"
      parseMethod="de.tutorials.jaxb.DataAadpter.parseString"
      printMethod="de.tutorials.jaxb.DataAadpter.printString"
    />-->
  </globalBindings>
</bindings>

Aufruf / Ausgabe:
(Wir müssen hier mit -extension die Erweiterungen anschalten damit der xjc-Namespace ausgewertet wird.
Code:
tom@halu:~/Desktop/jaxb$ xjc -extension -target 2.0 -p de.tutorials.jaxb -d gen test.xsd -b bindings.xml
parsing a schema...
compiling a schema...
de/tutorials/jaxb/Adapter1.java
de/tutorials/jaxb/Adapter2.java
de/tutorials/jaxb/Itemtype.java
de/tutorials/jaxb/ObjectFactory.java
de/tutorials/jaxb/Shipordertype.java
de/tutorials/jaxb/Shiptotype.java

Jetzt wird auch die Klasse com.foo.bar.DataAdapter für das Unmarshalling verwendet (die wird aber nicht generiert
und muss zusätzlich angelegt werden -> von javax.xml.bind.annotation.adapters.XmlAdapter ableiten und mit
<Input,Output> parameterisieren).

Beispielsweise ItemType:
Java:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2010.02.25 at 09:41:21 PM MEZ 
//


package de.tutorials.jaxb;

import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.foo.bar.DataAdapter;


/**
 * <p>Java class for itemtype complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="itemtype">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="title" type="{}stringtype"/>
 *         &lt;element name="note" type="{}stringtype" minOccurs="0"/>
 *         &lt;element name="quantity" type="{}inttype"/>
 *         &lt;element name="price" type="{}dectype"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "itemtype", propOrder = {
    "title",
    "note",
    "quantity",
    "price"
})
public class Itemtype {

    @XmlElement(required = true)
    @XmlJavaTypeAdapter(DataAdapter.class)
    protected String title;
    @XmlJavaTypeAdapter(DataAdapter.class)
    protected String note;
    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    protected Integer quantity;
    @XmlElement(required = true)
    protected BigDecimal price;

    /**
     * Gets the value of the title property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTitle() {
        return title;
    }

    /**
     * Sets the value of the title property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setTitle(String value) {
        this.title = value;
    }

    /**
     * Gets the value of the note property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getNote() {
        return note;
    }

    /**
     * Sets the value of the note property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setNote(String value) {
        this.note = value;
    }

    /**
     * Gets the value of the quantity property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public Integer getQuantity() {
        return quantity;
    }

    /**
     * Sets the value of the quantity property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setQuantity(Integer value) {
        this.quantity = value;
    }

    /**
     * Gets the value of the price property.
     * 
     * @return
     *     possible object is
     *     {@link BigDecimal }
     *     
     */
    public BigDecimal getPrice() {
        return price;
    }

    /**
     * Sets the value of the price property.
     * 
     * @param value
     *     allowed object is
     *     {@link BigDecimal }
     *     
     */
    public void setPrice(BigDecimal value) {
        this.price = value;
    }

}



Gruß Tom
 
Zuletzt bearbeitet von einem Moderator:
Vielen herzlichen Dank! Deine Ausführungen haben mich weiter gebracht. Letztendlich habe ich den Weg mit der Adapter-Definition im Java-Type-Mapping gewählt. Funktioniert echt Klasse.

Also danke noch mal.
 
Nur weil ich hier gerade drüber stolper - ist zwar nen alter Beitrag, aber man braucht für Integer keine Adapter-Methoden schreiben, wenn man minOccures="0" setzt. Dann macht der automatisch nen Integer draus:

Code:
<xs:element name="id" type="xs:int" minOccurs="0"/>

Grüße
 
Ja, das liegt daran, das der primitive Datentyp int nicht null werden kann. Er kann höchstens 0 werden. Manchmal wird das aber so gewünscht. Bei minOccurs=0 wird also definiert, dass das Feld null sein darf. Dann muss man aber beim Zugriff auf das Feld darauf achten, das nicht evtl. eine NullPointer geworfen wird.
 

Neue Beiträge

Zurück