2

在 JAXB 解组期间看到以下堆栈跟踪,我感到很惊讶:

[#|2013-02-05T18:59:27.551-0500|SEVERE|glassfish3.1.2|ConfigurationService|_ThreadID=82;_ThreadName=Thread-2;|Exception processing C:\glassfish3\glassfish\domains\domain1\config\myConfig.xml : @NotNull method com/foo/services/config/Config.getBars must not return null
java.lang.IllegalStateException: @NotNull method com.foo.services.config.Config.getBars must not return null
    at com.foo.services.Config.getBars(Config.java:222)
    at com.foo.services.Config$JaxbAccessorM_getBars_setBars_java_util_List.get(MethodAccessor_Ref.java:56)
    at com.sun.xml.bind.v2.runtime.reflect.Lister$CollectionLister.startPacking(Lister.java:294)
    at com.sun.xml.bind.v2.runtime.reflect.Lister$CollectionLister.startPacking(Lister.java:269)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Scope.start(Scope.java:142)
    at com.sun.xml.bind.v2.runtime.property.ArrayERProperty$ItemsLoader.startElement(ArrayERProperty.java:119)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:501)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:480)
    at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:102)
    at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:150)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:506)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:376)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2715)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:488)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:218)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:190)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:172)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:177)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:186)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)

getter 使用 org.jetbrains.annotation.NotNull 进行注释,目的是应将其标记为不返回 NULL,因为 getter 也使用 @XmlElementRef(required = true) 进行注释。所以基本上,@NotNull 被放在那里是为了告诉客户,这永远不应该为空,因为它是 XML 文件中的必需元素被解组,因此解析将失败,因为它丢失或将在那里。可以在此处找到有关 @NotNull 的更多信息。

在这种情况下,与 getter 关联的属性是 a List<Bar>,它没有被类初始化为任何东西,因为它期望解组过程会这样做。

在任何情况下,我都看到如果在解组 JAXB 调用 getter 期间解析失败,这会触发生成上述异常的 @NotNull。

任何人都可以阐明这种行为吗?谢谢,

-诺亚

4

1 回答 1

2

默认情况下,JAXB (JSR-222)实现将公共属性视为已映射。它调用 get on your Listproperty 的原因是查看您的值是否已预先初始化。

情景#1

JAXB 将调用getBars()以查看是否已创建集合,这将返回null. 由于null返回 JAXB 将创建一个实例,java.util.ArrayList该实例将通过setBars.

public class Foo {

    private List<Bar> bars;

    public List<Bar> getBars() {
        return bars;
    }

    public void setBars(List<Bar> bars) {
        this.bars = bars;
    }

}

情景#2

JAXB 将调用getBars()以查看是否已经创建了一个集合,这将返回一个LinkList. 由于null没有返回 JAXB 将使用List从 get 方法返回的实例。

public class Foo {

    private List<Bar> bars = new LinkedList<Bar>();

    public List<Bar> getBars() {
        return bars;
    }

    public void setBars(List<Bar> bars) {
        this.bars = bars;
    }

}

场景#3

如果您希望 JAXB 使用字段而不是属性,那么您可以@XmlAccessorType(XmlAccessType.FIELD)在类或包上指定(请参阅:http ://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html ) .

@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    private List<Bar> bars;

    public List<Bar> getBars() {
        return bars;
    }

    public void setBars(List<Bar> bars) {
        this.bars = bars;
    }

}
于 2013-02-06T00:45:33.837 回答