java解组 - NULL值或缺少标签?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18440987/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java unmarshalling - NULL value or missing tag?
提问by user1414745
I have a nillable field in a class that is being set by the unmarshaller:
我在解组器设置的类中有一个可空字段:
@XmlElement(name = "value", nillable = true)
private BigDecimal valueVariable;
My problem is that I can't tell if the xml element has been omitted or set to nil:
我的问题是我无法判断 xml 元素是否已被省略或设置为 nil:
A. element <value/>
is missing from the XML file, it is not required.
=> (valueVariable == null) is true
A. <value/>
XML 文件中缺少元素,它不是必需的。
=> (valueVariable == null) 为真
B. XML file contains <value xsi:nil="true"/>
=> (valueVariable == null) is true
B. XML 文件包含<value xsi:nil="true"/>
=> (valueVariable == null) 为真
How can I tell for a non-String variable if the value is xsi:nil
or the tag is missing?
我如何判断一个非字符串变量是值存在xsi:nil
还是标签丢失?
UPDATEYou can see 2 good solutions, I preferred one of them, but the other would also be fine!
更新您可以看到 2 个很好的解决方案,我更喜欢其中一个,但另一个也可以!
采纳答案by bdoughan
JAXB (JSR-222) implementations can represent null
as either an absent node or a nillable element based on the nillable
setting on @XmlElement
. When you need to support both, or differentiate between the two then you can leverage JAXBElement
.
JAXB (JSR-222) 实现可以null
根据 上的nillable
设置表示为缺失节点或可空元素@XmlElement
。当您需要同时支持两者或区分两者时,您可以利用JAXBElement
.
Java Model
Java模型
Root
根
Fields/properties of type JAXBElement
are mapped with the @XmlElementRef
annotation. This corresponds to @XmlElementDecl
annotations on a class annotated with @XmlRegistry
.
类型的字段/属性JAXBElement
与@XmlElementRef
注释映射。这对应于用@XmlElementDecl
注释的类上的注释@XmlRegistry
。
import java.math.BigDecimal;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElementRef(name="foo")
JAXBElement<BigDecimal> foo;
@XmlElementRef(name="bar")
JAXBElement<BigDecimal> bar;
@XmlElementRef(name="baz")
JAXBElement<BigDecimal> baz;
}
ObjectFactory
对象工厂
import java.math.BigDecimal;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name = "foo")
public JAXBElement<BigDecimal> createFoo(BigDecimal value) {
return new JAXBElement<BigDecimal>(new QName("foo"), BigDecimal.class, value);
}
@XmlElementDecl(name = "bar")
public JAXBElement<BigDecimal> createBar(BigDecimal value) {
return new JAXBElement<BigDecimal>(new QName("bar"), BigDecimal.class, value);
}
@XmlElementDecl(name = "baz")
public JAXBElement<BigDecimal> createBaz(BigDecimal value) {
return new JAXBElement<BigDecimal>(new QName("baz"), BigDecimal.class, value);
}
}
Demo Code
演示代码
input.xml
输入文件
<?xml version="1.0" encoding="UTF-8"?>
<root>
<bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<baz>123.456</baz>
</root>
Demo
演示
Below is some demo code you can run to show that everything works. Note how the JAXBIntrospector
can be used to get the real value unwrapping the JAXBElement
if necessary.
下面是一些演示代码,您可以运行以显示一切正常。请注意如何在JAXBIntrospector
必要时使用 来解开 来获得实际值JAXBElement
。
import java.io.File;
import java.math.BigDecimal;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum18440987/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
nullOrAbsent("foo", root.foo);
nullOrAbsent("bar", root.bar);
nullOrAbsent("baz", root.baz);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
private static void nullOrAbsent(String property, JAXBElement<BigDecimal> value) {
System.out.print(property);
if(null == value) {
System.out.print(": ABSENT - ");
} else if(value.isNil()) {
System.out.print(": NIL - ");
} else {
System.out.print(": VALUE - ");
}
System.out.println(JAXBIntrospector.getValue(value));
}
}
Output
输出
foo: ABSENT - null
bar: NIL - null
baz: VALUE - 123.456
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<baz>123.456</baz>
</root>
UPDATE
更新
If you wanted to maintain your existing get/set methods, then you could keep field access as I have in this answer and change your accessor methods to look like the following:
如果您想维护现有的 get/set 方法,那么您可以像我在此答案中那样保留字段访问权限,并将访问器方法更改为如下所示:
public BigDecimal getBar() {
if(null == bar) {
return null;
}
return bar.getValue();
}
public void setBar(BigDecimal bar) {
if(null == this.bar) {
this.bar = new JAXBElement<BigDecimal>(new QName("bar"), BigDecimal.class, bar);
} else {
this.bar.setValue(bar);
}
}
Additionally you could add an isSet
method to see if the value had been set.
此外,您可以添加一个isSet
方法来查看是否已设置该值。
public boolean isSetBar() {
return null != bar;
}
This approach does not require that you have access to the Unmarshaller
. To make sure that the ObjectFactory
is picked up you can use the @XmlSeeAlso
annotation to reference it from one of your domain classes.
这种方法不需要您有权访问Unmarshaller
. 为了确保ObjectFactory
被拾取,您可以使用@XmlSeeAlso
注释从您的域类之一中引用它。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(ObjectFactory.class)
public class Root {
回答by Xavi López
There's a similar question here: Handling missing nodes with JAXB. It seems that if the element is missing, the setter method won't be called. So you could put some logic in the method to determine if the node is missing or has an empty value.
这里有一个类似的问题:用 JAXB 处理丢失的节点。似乎如果缺少元素,则不会调用 setter 方法。所以你可以在方法中加入一些逻辑来确定节点是否丢失或具有空值。
@XmlElement(name = "value", nillable = true)
private BigDecimal valueVariable;
private boolean valueVariableMissing = true;
public void setValueVariable(BigDecimal valueVariable){
this.valueVariable = valueVariable;
this.valueVariableMissing = false;
}
回答by Dimitris
I was dealing with the same issue,
In order to fix it i created a new file in the package were I was marshaling the object:
"package-info.java"
There I added:
我正在处理同样的问题,为了解决它,我在包中创建了一个新文件,我正在封送对象:
“package-info.java”在那里我添加了:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://the.correct.namespace.com/gateway/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.the.package.name;
Now everything is ok
现在一切正常