Jaxb2Marshaller schema-Validierung scheint nicht zu funktionieren
Erfuhr ich, dass Jaxb2Marshaller Fehler beim validieren meiner ungültige XML gegen XSD, während Sie das unmarshalling.
Ich bin mit Spring 4.0.0.RELEASE und Java 7.
Hier ist ein Beispiel:
Die XSD-Datei: Obst.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:attribute name="quantity" type="xs:string" />
<xs:element name="fruit">
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:element ref="banana" />
<xs:element ref="apple" />
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="banana">
<xs:complexType>
<xs:attribute ref="quantity" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="apple">
<xs:complexType>
<xs:attribute ref="quantity" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
Ich die generierten JAXB POJOs aus dieser XSD-mit der Spring Tool Suite com.testraptor.xml.jaxb
Paket.
Meine ungültige XML Datei: invalid.xml
<?xml version="1.0" encoding="UTF-8"?>
<fruit>
<banana quantity="5" />
<apple quantity="3" />
</fruit>
Wie Sie sehen können, brach ich das schema, denn es ist eine Wahl, die in der Obst-tag und ich Banane und Apfel in der gleichen Zeit.
Mein Spring-Konfigurationsdatei: app-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd">
<oxm:jaxb2-marshaller id="marshaller" context-path="com.fruit.xml.jaxb" />
</beans>
Main-Klasse zu testen: Main.java
package com.fruit.test;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.xml.sax.SAXException;
import com.fruit.xml.jaxb.Fruit;
public class Main {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"app-context.xml");
//--------------------------------SCHEMA VALIDATION IS OMITTED
Jaxb2Marshaller jaxb2Unmarshaller = (Jaxb2Marshaller) appContext
.getBean("marshaller");
Resource schemaResource = appContext
.getResource("classpath:fruit.xsd");
jaxb2Unmarshaller.setSchema(schemaResource);
Resource xml = appContext.getResource("classpath:invalid.xml");
try {
Fruit fruit = (Fruit) jaxb2Unmarshaller.unmarshal(new StreamSource(xml.getInputStream()));
System.out.println("SCHEMA VALIDATION IS OMITTED:");
System.out.println("Apple quantity is " + fruit.getApple().getQuantity());
System.out.println("Banana quantity is " + fruit.getBanana().getQuantity());
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
//--------------------------------SCHEMA VALIDATION IS PASSED
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema;
try {
schema = sf.newSchema(schemaResource.getURL());
JAXBContext context = JAXBContext.newInstance(Fruit.class);
Unmarshaller unmarshaller = (Unmarshaller) context.createUnmarshaller();
unmarshaller.setSchema(schema);
Fruit fruit2 = (Fruit) unmarshaller.unmarshal(xml.getInputStream());
System.out.println("SCHEMA VALIDATION IS PASSED:");
System.out.println("Apple quantity is " + fruit2.getApple().getQuantity());
System.out.println("Banana quantity is " + fruit2.getBanana().getQuantity());
} catch (SAXException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (JAXBException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Wenn ich den code bekomme ich Folgendes Ergebnis:
INFO: Loading XML bean definitions from class path resource [app-context.xml]
dec. 26, 2013 9:33:22 DE org.springframework.oxm.jaxb.Jaxb2Marshaller createJaxbContextFromContextPath
INFO: Creating JAXBContext with context path [com.fruit.xml.jaxb]
SCHEMA VALIDATION IS OMITTED:
Apple quantity is 3
Banana quantity is 5
javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 24; cvc-complex-type.2.4.d: Invalid content was found starting with element 'apple'. No child element is expected at this point.]
at ...
Wie Sie sehen können die Jaxb2Marshaller vergessen zu bestätigen auf die ungültige XML-Datei während der Unmarshaller könnte es prüfen.
Kann mir jemand einen Anhaltspunkt was falsch sein könnte mit meinem code?
- Tobias' Antwort für mich gearbeitet. Wenn es funktioniert für Sie auch, können Sie markieren Sie es als die richtige Lösung?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich hatte das gleiche problem bei der Konfiguration
Jaxb2Marshaller
zur Laufzeit. Die vorgeschlagene Lösung zu setzen, das schema per Spring-XML-brachte mich zum nachdenken: Was ist der Unterschied zwischen meinem code durch setzen der Eigenschaft und der Frühling?Die Antwort ist einfach:
Jaxb2Marshaller
implementiertorg.springframework.beans.factory.InitializingBean
definiert der lifecycle-MethodeafterPropertiesSet()
- und diese Methode wird aufgerufen, durch FedernBeanFactory
nachdem die Eigenschaften festgelegt wurden.So ist die Lösung zu nennen
afterPropertiesSet()
nachsetSchema()
wurde verwendet, um die schema-Eigenschaft. Da die in dieser Methode der schema-Eigenschaft (das ist einorg.springframework.core.io.Resource
array) ist eigentlich verwendet, um das interne schema-Feldjavax.xml.validation.Schema
die später für die schema-Validierung.Beispiel:
Versuchen Sie, ein validationEventHandler durch den Aufruf setValidationEventHandler() und sehen, wenn sein genannt worden ?