JAXB空元素解组

joh*_*ohn 4 java xml exception jaxb

问题在于:

我在内部使用空元素获取soap响应(例如... <someDate /> ...),因此当JAXB想要解析此元素而不是使用null值设置适当的字段时抛出异常.

如何配置JAXB将空元素视为null?我们能否仅使用JAXB执行此操作(不使用某些第三方解决方法)

bdo*_*han 9

基本问题

Empty String不是该xsd:date类型的有效值.要对XML模式有效,可选元素应表示为缺少节点.


为什么基础问题会影响你

所有JAXB实现都会识别出empty String不是有效值xsd:date.他们通过将其报告给一个实例来完成此操作ValidationEventHandler.您可以通过执行以下操作自己查看:

    Unmarshaller unmarshaller = jc.createUnmarshaller();
    unmarshaller.setEventHandler(new ValidationEventHandler() {

        @Override
        public boolean handleEvent(ValidationEvent event) {
            System.out.println(event);
            return true;
        }
    });
Run Code Online (Sandbox Code Playgroud)

您正在使用的JAX-WS的实现利用EclipseLink MOXy作为JAXB提供程序.在使用MOXy的版本中,默认情况下会在遇到ValidationEvent严重性时抛出异常,ERROR而不是FATAL_ERROR像参考实现那样抛出异常.从那以后修复了以下错误:


解决

如果您直接使用JAXB API,则可以简单地覆盖默认值ValidationEventHandler.在JAX-WS环境中,XmlAdapter可以使用a来提供自定义转换逻辑.我们将利用a XmlAdapter覆盖转换/转换的Date处理方式.

XmlAdapter(DateAdapter)

import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date>{

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public Date unmarshal(String v) throws Exception {
        if(v.length() == 0) {
            return null;
        }
        return dateFormat.parse(v);
    }

    @Override
    public String marshal(Date v) throws Exception {
        if(null == v) {
            return null;
        }
        return dateFormat.format(v);
    }

}
Run Code Online (Sandbox Code Playgroud)

Java模型(根)

XmlAdapter使用引用的@XmlJavaTypeAdapter注释.如果您希望这XmlAdapter适用于Date您的所有实例,可以在包级别注册它(请参阅:http: //blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html).

import java.util.Date;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlSchemaType(name = "date")
    @XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
    private Date abc;

    @XmlSchemaType(name="date")
    @XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
    private Date qwe;

}
Run Code Online (Sandbox Code Playgroud)

演示代码

下面是一个独立的示例,您可以运行以查看一切正常.

jaxb.properties

在使用MOXy作为JAXB提供程序的独立示例中,您需要包含jaxb.propeties与域模型在同一程序包中调用的文件,并带有以下条目(请参阅:http: //blog.bdoughan.com/2011/05/specifying-eclipselink -moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

input.xml中

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <abc></abc>
    <qwe>2013-09-05</qwe>
</root>
Run Code Online (Sandbox Code Playgroud)

演示

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum18617998/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}
Run Code Online (Sandbox Code Playgroud)

产量

请注意,在编组的XML中Date,null 的字段被编组为缺少的元素(请参阅:http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <qwe>2013-09-05</qwe>
</root>
Run Code Online (Sandbox Code Playgroud)