当前位置: 首页 > 知识库问答 >
问题:

JavaJAXB马歇尔/unmarshal使用Java选项

狄玉书
2023-03-14

我的应用程序需要在Java和XML之间转换数据。

在转换数据时,我需要区分该值是否存在,该值是否显式设置为null,或者该值是否有值。

XML示例:

<person><name>Bob</name></person>     <-- element 'name' contains value "Bob"

<person><name nil="true"/></person>   <-- element 'name' was set explicitly to 'nil'/null

<person></person>                     <-- element 'name' is missing

由于像“String”这样的Java类型只知道两种状态(null或notnull),所以我尝试使用Java选项来解决这个问题。

XML和Java选项之间的映射可以如下所示:

<person></person>                   <=> Optional<String> name = null;

<person><name>Bob</name></person>   <=> Optional<String> name = Optional.of("Bob");

<person><name nil="true"/></person> <=> Optional<String> name = Optional.empty();

我尝试使用JAXB进行编组和解组。其思想是,只有当一个值需要显式地设置为一个值时,才会调用字段的setter。这意味着隐式缺少一个值。

我查看了其他stackoverflow问题,如以下问题,但所有这些问题都没有完全解决我需要实现的行为:

如何用java生成JaxB类。util。可选择的

使用通用@XmlJavaTypeAdapter散集包装在Guava的可选

将番石榴汁与@XmlAttribute一起使用

我已经在这个问题上挣扎了两天。我尝试使用XMLAdapter和GenericAdapter,尝试了几种如何使用@XmlElement注释字段和getter/setter的方法,尝试使用@XmlAnyElment有和没有lax,但所有这些都只导致了部分成功。要么nil值处理不正确,列表打印不正确,...

我认为每一个具有正确实现的补丁操作的Java Web服务都应该有这个问题。(不是说“json补丁方法”(RFC 6902))

有没有通用的方法来解决我的问题?

共有3个答案

何雅惠
2023-03-14

您可以在java类中使用一些验证,比如@NotNull、@Size等等。或者你可以设置默认值,确保它不为空。之后,您可以使用推荐的Xml注释创建DTO(数据传输对象),并使用ModelMapper对其进行映射。

邹锦
2023-03-14

由于我不能完全通过正确使用和配置JAXB来解决这个问题,我决定按如下方式解决它:

(主要目标是编写一个子系统,以便与基于XML的外部系统通信)

作为起点,我使用目标系统提供的XSD模式与JAXB和XSD文件进行通信,并生成相应的(XML)Java类。这些生成的类中的所有字段都是JAXBELENT类型

在业务模型方面,我使用了带有可选属性的Java类

对于映射,我编写了一个映射器,它使用反射递归地从JAXB映射到Java,反之亦然。当从Java映射到JAXB时,映射程序使用ObjectFactory创建JAXBElement对象。(Mapper本身只有大约300行代码)。根据匹配的字段名称映射字段。

最难看和最具挑战性的部分是,需要修改XSD模式文件,以使JAXB生成的类使用JAXBElement字段类型。因此,如果尚未设置属性minOccurs=“0”nillable=“true”,我必须手动将其添加到XML元素中。

有了上面的解决方案,考虑到所需的3种状态,我最终成功地将XML映射到Java,反之亦然。

当然,这种解决方案有其缺点。一是手动修改XSD文件。通常不好的做法是更改外部系统提供的XSD文件,它充当html" target="_blank">接口契约。

按照我当时的要求,这个解决方案非常有效。即使是对外部系统接口合同的更改也可以非常容易地实现。

段干跃
2023-03-14

下面的代码能够区分空名称和空名称。为了使解决方案有效,我创建了一个PersonList元素来包含所有person元素。如果XML将元素显式设置为null,则每个人都包含一个名称,该名称将使isNil()返回true:

Person.java:

import java.util.Optional;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(propOrder = {"name"})
@XmlRootElement(name = "person")
public class Person {

    private Optional<Name> optionalName;

    public Person() {
        optionalName = Optional.<Name>empty();
    }

    public Optional<Name> getOptionalName() {
        return optionalName;
    }

    public Name getName() {
        return (optionalName.isPresent()) ? (optionalName.get()) : (null);
    }

    @XmlElement(name = "name", required = false)
    public void setName(Name name) {
        optionalName = Optional.ofNullable(name);
    }

    @Override
    public String toString() {
        return String.format("Person(optionalName.isPresent() = %s, name = %s)",
                             Boolean.toString(optionalName.isPresent()),
                             ((getName() == null) ? ("null") : (getName().toString())));
    }
}

Name.java:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "name")
public class Name {

    @XmlAttribute(name = "nil")
    private boolean nil;

    @XmlValue
    private String value;

    public Name() {
        nil = false;
        value = null;
    }

    public boolean isNil() {
        return nil;
    }

    public void setNil(boolean torf) {
        this.nil = torf;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return String.format("Name(nil = %s, value = %s)",
                             Boolean.toString(nil),
                             (value == null) ? ("null"):("\""+getValue()+"\""));
    }
}

个人主义者。爪哇:

import java.util.Iterator;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "PersonList")
public class PersonList {

    private List<Person> persons;

    public PersonList() {
        persons = null;
    }

    @XmlElement(name = "person")
    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("PersonList(persons = ");
        if(persons == null) {
            sb.append("null");
        }
        else {
            sb.append("[");
            Iterator<Person> iterator = persons.iterator();
            while(iterator.hasNext()) {
                sb.append(iterator.next().toString());
                if(iterator.hasNext()) {
                    sb.append(", ");
                }
            }
            sb.append("]");
        }
        sb.append(")");
        return sb.toString();
    }
}

主类演示解决方案:

import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

public class XmlOptional {
    public static final int STATUS_OKAY = 0;
    public static final int STATUS_ERROR = -1;

    public static final String XML_DATA = "<PersonList>" +
                                          "<person><name>Bob</name></person>" +
                                          "<person><name nil=\"true\" /></person>" +
                                          "<person></person>" +
                                          "</PersonList>";

    private XmlOptional() {
    }

    private static PersonList loadXml() {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(XML_DATA.getBytes());
            JAXBContext context = JAXBContext.newInstance(PersonList.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            PersonList personList = (PersonList)unmarshaller.unmarshal(bais);
            return personList;
        }
        catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        int status = STATUS_OKAY;

        try {
            PersonList personList = loadXml();
            System.out.format("Xml contained: %s%n", personList);
        }
        catch (Throwable thrown) {
            status = STATUS_ERROR;
            thrown.printStackTrace();
        }
        finally {
            System.exit(status);
        }
    }
}

样本输出:

包含的Xml:PersonList(Person=[Person(optionalName.isPresent()=true,name=name(nil=false,value=“Bob”))、Person(optionalName.isPresent()=true,name=name(nil=true,value=“”))、Person(optionalName.isPresent()=false,name=null)])

 类似资料:
  • 问题内容: 我正在使用JAXB marshaller创建和格式化我的.xml文件。除了一个地方,它运作良好。缩进缺少两个地方: .xml文件的其余部分看起来不错。我正在使用这种方法来美化整个代码: 不幸的是,它不适用于这两个元素。有任何想法吗? 问题答案: 可以通过将javax Transformer应用于输出来解决此烦人的问题。

  • 我使用JAXB(MoXY)对XML和JSON中的数据进行编组/解编。 我有一个

  • 我有一个从org.springframework.security.core.userdetails.user扩展而来的bean,并将这个bean与openid一起使用。bean看起来像: 控制器将Employee的实例接受为: @RequestMapping(值=“/addemp.do”,方法=RequestMethod.Post)public@ResponseBody String addEm

  • 问题内容: 我有看起来像下面的XML: 我有一个如下的ObjectList类: 还有一个对象类,如下所示: 当我尝试使用以下代码将xml解组为和对象时: 我收到以下错误: javax.xml.bind.UnmarshalException:意外元素(uri:“”,本地:“ ObjectList”)。期望的元素是<{} Object>,<{} objectList> 编辑: 我只是注意到几个问题,我

  • 1. 马尔科夫链概述 马尔科夫链定义本身比较简单,它假设某一时刻状态转移的概率只依赖于它的前一个状态。举个形象的比喻,假如每天的天气是一个状态的话,那个今天是不是晴天只依赖于昨天的天气,而和前天的天气没有任何关系。当然这么说可能有些武断,但是这样做可以大大简化模型的复杂度,因此马尔科夫链在很多时间序列模型中得到广泛的应用,比如循环神经网络RNN,隐式马尔科夫模型HMM等,当然MCMC也需要它。 如

  • 我有一个SpringBoot应用程序和一组应用程序。不同配置文件的yaml文件。 这些文件位于类路径中,没有额外的配置来切换它们,只需在intellij的配置“活动配置文件”部分更改配置文件。 我的一个Spring豆子依赖财产 它有一个如下所示的构造函数 如果appUrl在属性文件中不存在,这一点的全部意义就是使bean构造失败(从而导致应用程序无法启动)。 在application.yamlap