为什么JAXB在解组期间调用getter

为什么JAXB在解组期间调用getter,jaxb,Jaxb,在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/

在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还使用@xmlementref(required=true)进行注释。因此,基本上,@NotNull放在那里是为了告诉客户端,这永远不应该是null,因为它是XML文件中被取消组分的必需元素,因此解析将失败,因为它丢失了,或者它将在那里。可以找到有关@NotNull的更多信息

在本例中,与getter关联的属性是一个
列表
,该列表未被类初始化为解组过程预期的任何内容

在任何情况下,我都可以看到,如果解析在解组过程中失败,JAXB调用getter并触发@NotNull,它将生成上述异常

有人能解释这种行为吗?谢谢

-Noah

默认情况下,实现将公共属性视为映射。它在
列表
属性上调用get的原因是为了查看您的值是否已预初始化

情景#1

JAXB将调用
getBars()
,查看是否已经创建了一个集合,这将返回
null
。由于返回了
null
,JAXB将创建
java.util.ArrayList
的实例,该实例将通过
setbar
进行设置

公共类Foo{
私人酒吧名单;
公共列表getbar(){
返回杆;
}
公共空心立杆(列表栏){
这个。巴=巴;
}
}
场景#2

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

公共类Foo{
私有列表栏=新的LinkedList();
公共列表getbar(){
返回杆;
}
公共空心立杆(列表栏){
这个。巴=巴;
}
}
场景#3

如果希望JAXB使用字段而不是属性,那么可以在类或包上指定
@xmlacessortype(xmlacesstype.FIELD)
(请参阅:)

@xmlacessortype(xmlacesstype.FIELD)
公开课Foo{
私人酒吧名单;
公共列表getbar(){
返回杆;
}
公共空心立杆(列表栏){
这个。巴=巴;
}
}

很有趣。我的JAXB注释类看起来像您的第一个尚未初始化“List”的示例。但是,根据“@NotNull”触发的IllegalStateException,getter似乎返回NULL vs.和ArrayList实例。也许注释与JAXB?@NBW之间存在问题-默认情况下,JAXB使用getter在解组过程中检查属性的值。在您的情况下,它将是
null
。然后,当JAXB看到该值为null时,它将创建
ArrayList
的一个新实例。我更新了我的答案,试图让这更清楚。是的,现在清楚了。谢谢你的见解!我还有另一个关于解组器文件锁定的问题,我将很快发布。@NBW-我已经为您的新问题添加了一个答案(请参阅:),这是否意味着在场景2中,永远不会调用setter?如果setter执行的操作不同于只设置
this.bar=bar
那么如果它想在设置之前调用addbar()方法来执行某种验证呢?