【问题标题】:JAXB fails to marshal null value when using XMLAdapter使用 XMLAdapter 时 JAXB 无法编组空值
【发布时间】:2014-09-19 11:24:07
【问题描述】:

我在我的源代码中使用 Guava 可选字段,并且我想将一个使用 Optional 的对象编组为 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。我没有得到的是,如果我不使用可选类型而只使用装箱整数并且值为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)

【问题讨论】:

    标签: java xml jaxb


    【解决方案1】:

    这是要怪的代码:

            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&lt;Integer&gt; 调整为 String 而不是 Integer

    【讨论】:

      猜你喜欢
      • 2012-10-21
      • 1970-01-01
      • 2021-07-21
      • 2017-06-05
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 2012-06-22
      • 1970-01-01
      相关资源
      最近更新 更多