使用XMLAdapter时,JAXB无法编组空值

时间:2014-09-19 11:24:08

标签: java xml jaxb

我在源代码中使用了Guava可选字段,我想编组一个使用Optional to xml的对象,所以我使用了JAXB。

我为此创建了XMLAdapter

public abstract class OptionalAdpater<T> extends XmlAdapter<T, Optional<T>> {

    @Override
    public Optional<T> unmarshal(T v) throws Exception {
        return Optional.of(v);
    }

    @Override
    public T marshal(Optional<T> v) throws Exception {
        if (v == null) { 
            return null;
        }

        return v.isPresent() ? v.get() : null;
    }
}

但是当我在课堂上使用它时

@XmlRootElement(name = "test")
public class Test {

    private Optional<Integer> optionalValue = Optional.absent();

    @XmlElement(name = "optional-value", type = Integer.class)
    @XmlJavaTypeAdapter(type = Integer.class, value = OptionalIntegerAdapter.class)
    public Optional<Integer> getOptionalValue() {
        return optionalValue;
    }

    public void setOptionalValue(Optional<Integer> optionalValue) {
        this.optionalValue = optionalValue;
    }
}

JAXB失败并显示NullPointerException。我没有得到的是,如果我不使用可选类型并且只使用盒装的Integer并且值为null那么JAXB会跳过编组该字段,但是当我使用可选的适配器时它不起作用类型。

跟踪:

Exception in thread "main" java.lang.NullPointerException
    at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$17.print(RuntimeBuiltinLeafInfoImpl.java:717)
    at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$17.print(RuntimeBuiltinLeafInfoImpl.java:711)
    at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$StringImpl.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:149)
    at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:241)
    at com.sun.xml.internal.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:114)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:341)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:582)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:483)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:103)

1 个答案:

答案 0 :(得分:0)

这是责任的代码:

        primaryList.add(new StringImpl<Integer>(Integer.class,
            createXS("int"),
            createXS("unsignedShort")
            ) {
            public Integer parse(CharSequence text) {
                return DatatypeConverterImpl._parseInt(text);
            }

            public String print(Integer v) {
                return DatatypeConverterImpl._printInt(v);
            }
        });

_printInt接受int因此,如果您返回一个空整数,则会隐式取消装箱。

为什么没有适配器/可选的工作可能是因为可选。某些地方可能会检查null的属性。您没有null,而是Optional

从我的角度来看,这是JAXB中的一个错误。运行时应在适配器转换后检查null,而不是之前。

如何解决它 - 我认为目前唯一的方法是将Optional<Integer>调整为字符串而不是Integer