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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:39:00  来源:igfitidea点击:

java unmarshalling - NULL value or missing tag?

javajaxbxml-nil

提问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:nilor 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 nullas either an absent node or a nillable element based on the nillablesetting 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 JAXBElementare mapped with the @XmlElementRefannotation. This corresponds to @XmlElementDeclannotations 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 JAXBIntrospectorcan be used to get the real value unwrapping the JAXBElementif 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 isSetmethod 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 ObjectFactoryis picked up you can use the @XmlSeeAlsoannotation 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

现在一切正常