简体   繁体   English

Jaxb2Marshaller模式验证似乎不起作用

[英]Jaxb2Marshaller schema validation doesn't seem to be working

I experienced that Jaxb2Marshaller failed to validate my invalid XML against the XSD while doing the unmarshalling. 我经历过Jaxb2Marshaller在进行解组时无法验证我对XSD的无效XML。 I'm using Spring 4.0.0.RELEASE and Java 7. 我正在使用Spring 4.0.0.RELEASE和Java 7。

Here is an example: 这是一个例子:

The XSD file: fruit.xsd XSD文件: fruit.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>

I generated the JAXB POJOs from this XSD with Spring Tool Suite to com.testraptor.xml.jaxb package. 我使用Spring Tool Suite从这个XSD生成了JAXB POJO到com.testraptor.xml.jaxb包。

My invalid XML file: invalid.xml 我的XML文件无效invalid.xml

<?xml version="1.0" encoding="UTF-8"?>
<fruit>
    <banana quantity="5" />
    <apple quantity="3" />
</fruit>

As you can see I broke the schema because there is a choice in the fruit tag and I used banana and apple at the same time. 如你所见,我打破了架构,因为在水果标签中有一个选择,我同时使用了香蕉和苹果。

My Spring configuration file: app-config.xml 我的Spring配置文件: 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>

The main class to test: Main.java 要测试的主要类: 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();
        } 
    }

}

When I run the code I get the following result: 当我运行代码时,我得到以下结果:

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 ...

As you can see the Jaxb2Marshaller forgot to validate my invalid XML file while the Unmarshaller could validate it. 正如您所看到的,当Unmarshaller可以验证时,Jaxb2Marshaller忘记验证我的无效XML文件。

Can anyone give me a clue what could be wrong with my code? 任何人都可以告诉我我的代码可能有什么问题吗?

I had the same problem when configuring Jaxb2Marshaller at runtime. 在运行时配置Jaxb2Marshaller时遇到了同样的问题。 The proposed solution to set the schema via Spring XML got me thinking: What's the difference between my code setting the property and Spring? 通过Spring XML设置模式的建议解决方案让我想到:我的代码设置属性和Spring之间的区别是什么?

The answer is simple: Jaxb2Marshaller implements org.springframework.beans.factory.InitializingBean which defines the lifecycle method afterPropertiesSet() and this method is called by Springs BeanFactory after the properties have been set. 答案很简单: Jaxb2Marshaller实现了org.springframework.beans.factory.InitializingBean ,它定义了生命周期方法afterPropertiesSet()并且在设置了属性后,Springs BeanFactory调用了此方法。

So the Solution is to call afterPropertiesSet() after setSchema() has been used to set the schema property. 因此,解决方案是在使用setSchema()设置架构属性之后调用afterPropertiesSet() Because in that method the schema property (which is a org.springframework.core.io.Resource array) is actually used to set the internal schema field of type javax.xml.validation.Schema which is later used for schema validation. 因为在该方法中,schema属性( org.springframework.core.io.Resource数组)实际上用于设置javax.xml.validation.Schema类型的内部模式字段,该字段稍后用于模式验证。

Example: 例:

Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
Resource schema = new ClassPathResource("fruit.xsd");
marshaller.setSchema(schema);
marshaller.setContextPath("com.fruit.xml.jaxb");
// manually call Spring lifecycle method which actually loads the schema resource
marshaller.afterPropertiesSet();
// use marshaller...

Try setting a validationEventHandler by calling setValidationEventHandler() and see if its been called ? 尝试通过调用setValidationEventHandler()来设置validationEventHandler并查看它是否已被调用?

setValidationEventHandler(new ValidationEventHandler() {
                @Override
                public boolean handleEvent(ValidationEvent event) {
                     System.out.println(event.getLinkedException().getMessage());
                    return false;
                }
            });)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM