问题描述
我正在尝试处理调用 jaxb 生成的 getter(对于 xs:list 类型的属性值)导致创建空 ArrayList,然后将其编组到输出 XML 时为空字符串。空字符串属性值输出破坏了其他生产代码,因此我希望不要输出这些(如果它们不存在于输入 XML 中)。
我尝试使用自定义 XmlAdapter marshall 方法,但是当我配置它时,jaxb 生成的 getter 实现已更改,它不再创建一个空的 ArrayList,它会使用 NullPointerExceptions 破坏现有代码。
这里是更详细的背景信息。 我正在使用 jaxb 从 XML 模式生成 Java 类。 这是通过 ANT 目标完成的:
<java classname="com.sun.tools.internal.xjc.XJCFacade" failonerror="true">
<arg value="-d"/>
<arg value="${generated.dir}"/>
<arg value="-p" />
<arg value="com.myorg.model"/>
<arg value="-b" />
<arg value="${basedir}/bindings.xjb"/>
<arg value="${schema.dir}/Test.xsd" />
</java>
架构 Test.xsd 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.opentravel.org/OTA/2003/05" targetNamespace="http://www.opentravel.org/OTA/2003/05" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:simpleType name="Ref_Type">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{1,8}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="listofRefs">
<xs:list itemType="Ref_Type"/>
</xs:simpleType>
<xs:element name="RootElement">
<xs:complexType>
<xs:sequence>
<xs:element name="ChildElement" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="MyRefs" type="listofRefs"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
jaxb 生成的类 RootElement.java:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation,v2.2.4-2
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2021.04.28 at 05:17:16 PM BST
//
package com.myorg.model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccesstype;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "",propOrder = {
"childElement"
})
@XmlRootElement(name = "RootElement")
public class RootElement {
@XmlElement(name = "ChildElement")
protected List<RootElement.ChildElement> childElement;
public List<RootElement.ChildElement> getChildElement() {
if (childElement == null) {
childElement = new ArrayList<RootElement.ChildElement>();
}
return this.childElement;
}
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "")
public static class ChildElement {
@XmlAttribute(name = "MyRefs")
protected List<String> myRefs;
public List<String> getMyRefs() {
if (myRefs == null) {
myRefs = new ArrayList<String>();
}
return this.myRefs;
}
}
}
注意 getMyRefs() 将创建一个新的空 ArrayList 如果 myRefs == null
我遇到的问题是,在将一些输入 XML 解组到 RootElement 对象之后,然后调用 getMyRefs() 将导致一个空的 MyRefs=" " 将其编组为字符串时要输出的属性。
例如,如果我输入以下内容:
<RootElement>
<ChildElement/>
<ChildElement MyRefs="1 2 3 4"/>
<ChildElement/>
</RootElement>
如果我将其解组到 RootElement 对象并调用 getter:
List<String> myRefs = rootElement.getChildElement().get(0).getMyRefs();
然后我将 rootElement 编组回字符串,它将是:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RootElement xmlns="http://www.opentravel.org/OTA/2003/05">
<ChildElement MyRefs=""/>
<ChildElement MyRefs="1 2 3 4"/>
<ChildElement/>
</RootElement>
你可以看到第一个 ChildElement 现在有一个空的 MyRefs 属性,第三个 ChildElement 没有,因为我没有调用:rootElement.getChildElement().get(2).getMyRefs()
我的要求是第一个 ChildElement 不会输出任何 MyRefs 属性。
我尝试的解决方案是修改我的 bindings.xjb 文件:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ota="http://www.opentravel.org/OTA/2003/05"
version="2.1">
<!-- This file handles exceptions in the JAXB source code generation-->
<!-- Global type bindings -->
<globalBindings typesafeEnumMaxMembers="380">
<javaType name="java.util.List<String>" xmlType="ota:listofRefs" parseMethod="com.myorg.model.utils.AttributeListConverter.unmarshal" printMethod="com.myorg.model.utils.AttributeListConverter.marshal"/>
</globalBindings>
</bindings>
我的 AttributeListConverter 类:
package com.myorg.model.utils;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
public class AttributeListConverter {
private static final Splitter SPACE_SPLITTER = Splitter.on(' ').trimResults().omitEmptyStrings();
public static List<String> unmarshal(String spaceSeparatedList) {
return StringUtils.isEmpty(spaceSeparatedList) ? new ArrayList<String>() : SPACE_SPLITTER.splitToList(spaceSeparatedList);
}
public static String marshal(List<String> attributeList) {
return (attributeList == null || attributeList.isEmpty()) ? null : Joiner.on(" ").join(attributeList);
}
}
在 marshal() 方法中,当 List 为 null 或为空时返回 null,MyRefs 属性不会输出。 >
但是,自动生成的 RootElement.java 类现在已更改:
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "")
public static class ChildElement {
@XmlAttribute(name = "MyRefs")
@XmlJavaTypeAdapter(Adapter28 .class)
protected List<String> myRefs;
/**
* Gets the value of the myRefs property.
*
* @return
* possible object is
* {@link java.lang.String }
*
*/
public List<String> getMyRefs() {
return myRefs;
}
/**
* Sets the value of the myRefs property.
*
* @param value
* allowed object is
* {@link java.lang.String }
*
*/
public void setMyRefs(List<String> value) {
this.myRefs = value;
}
}
getMyRefs() 方法不再检查 null,并返回一个空的 ArrayList,它只是直接返回 myRefs 值。
这会破坏其他始终假定 getMyRefs() 永远不会为 null 的代码(它们现在抛出 NullPointerExceptions)的副作用。
使用自定义 marsall() 方法确实解决了输出空 MyRefs 属性的问题,但是它破坏了依赖于 getMyRefs() 不返回 null 的其他功能。
有什么方法可以获得我需要的行为吗?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)