我的应用程序需要在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))
有没有通用的方法来解决我的问题?
您可以在java类中使用一些验证,比如@NotNull、@Size等等。或者你可以设置默认值,确保它不为空。之后,您可以使用推荐的Xml注释创建DTO(数据传输对象),并使用ModelMapper对其进行映射。
由于我不能完全通过正确使用和配置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">接口契约。
按照我当时的要求,这个解决方案非常有效。即使是对外部系统接口合同的更改也可以非常容易地实现。
下面的代码能够区分空名称和空名称。为了使解决方案有效,我创建了一个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