Merkwürdigkeiten von JAXB 2.0

Gegeben sei ein Schema "schema.xsd":
<?xml version="1.0" encoding="ISO-8859-1" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="test">
    <xsd:complexType>
      <xsd:attribute name="value" type="xsd:integer" use="optional"/>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>
Wir generieren nun mit "xjc" (SUN Java 1.6) die passenden JAXB(2.0)-Beans:
xjc -d src -p generated schema.xsd
Die folgende Datei "test.xml" soll eingelesen werden:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<test value=""></test>
Das Attribut "value" besitzt einen Leerstring als Wert. Das ist eigentlich nicht korrekt - aber leider nicht änderbar, da das Backend die Daten so liefert. Die Deklaration 'use="optional"' im Schema bedeutet lediglich, dass das Attribut fehlen darf. Wenn es jedoch vorhanden ist, muss es einen gültigen Wert haben. Wir wollen das Attribut auch nicht als "xsd:string" deklarieren, weil wir sonst ein unschönes "Integer.parseInt(String)" machen müssten. Nützt also nichts. Das müssen wir so hinnehmen.

Wir lesen die Test-Datei ein:
JAXBContext ctx = JAXBContext.newInstance(generated.ObjectFactory.class);
Unmarshaller m  = ctx.createUnmarshaller();
generated.Test t = (generated.Test) m.unmarshal(new File("test.xml"));
System.out.println(t.getValue());
Der Vorgang schlägt fehl mit:
java.lang.NumberFormatException: Zero length BigInteger
Lösungsversuch 1:

Wir registrieren einen ValidationEventHandler, der den Fehler toleriert (mittels "return true"):
m.setEventHandler(new ValidationEventHandler() {
  public boolean handleEvent(ValidationEvent event) {
    System.out.println(event.getMessage());
    return true;
  }
});
Ergebnis unverändert. Der Handler wird gar nicht aufgerufen. Weil die Schema-Validierung nicht explizit aktiviert wurde. Also fügen wir noch folgendes Schnipsel ein:
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("schema.xsd"));
m.setSchema(schema);
Jetzt kommt der Handler zwar zum Zug und schreibt folgenden Text nach STDOUT:
cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.
cvc-attribute.3: The value '' of attribute 'value' on element 'test'
is not valid with respect to its type, 'integer'.
Die NumberFormatException wird dennoch geworfen - die XML-Datei lässt sich immer noch nicht einlesen.

Lösungsversuch 2:

Wir ändern den Typ des Attributes in der Schema-Datei von "xsd:integer" auf "xsd:int" (Typ-Hierarchie) und lassen die Beans von "xjc" neu erzeugen. Der Code läuft durch. Ausgabe:
cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.
cvc-attribute.3: The value '' of attribute 'value' on element 'test'
is not valid with respect to its type, 'int'.
value: 0
OK, wir gehen einen Schritt weiter und entfernen sowohl ValidationEventHandler als auch die Schema-Validierung. Ausgabe:
value: 0

Was lernen wir daraus:
  • xsd:integer und xsd:int verhalten sich - zumindest in der SUN-Implementierung - völlig unterschiedlich. Während ein Leerstring in einem "xsd:integer"-Attribut überhaupt nicht abfangbar ist, wird er in einem "xsd:int"-Attribut grundsätzlich toleriert - auch ohne ValidationEventHandler.

  • Ein ValidationEventHandler kommt nur zum Zug, wenn Schema-Validierung explizit aktiviert wurde. Da das weder in der API, noch in den Beispiel-Code-Schnipseln (die man so im Internet findet) ausdrücklich erwähnt wird, übersieht man das schnell.

  • Die Frage, ob ein fataler Fehler beim Unmarshalling überhaupt von einem ValidationEventHandler toleriert werden darf, ist nicht spezifiert. In der API findet sich hierzu folgender Satz: "Failing to return false from the handleEvent method after encountering a fatal error is undefined by the specification and may result in unexpected behavior."

Faszinierend, dass eine scheinbare Belanglosigkeit zu solchen Problemen führen kann.

Trackbacks

Trackback-URL für diesen Eintrag

Dieser Link ist nicht aktiv. Er enthält die Trackback-URI zu diesem Eintrag. Sie können diese URI benutzen, um Ping- und Trackbacks von Ihrem eigenen Blog zu diesem Eintrag zu schicken. Um den Link zu kopieren, klicken Sie ihn mit der rechten Maustaste an und wählen "Verknüpfung kopieren" im Internet Explorer oder "Linkadresse kopieren" in Mozilla/Firefox.

Keine Trackbacks

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Noch keine Kommentare

Die Kommentarfunktion wurde vom Besitzer dieses Blogs in diesem Eintrag deaktiviert.