我真的需要能够区分&#39;缺少&#39;和&#39; null&#39;将XML解组为POJO时。我有一个Optional<BigInteger>
字段和Optional
类型的适配器:
public abstract class OptionalAdapter<T> extends XmlAdapter<T, Optional<T>> {
@Override
public Optional<T> unmarshal(T value) throws Exception {
log.debug("Unmarshalling value: {}", value);
if(value == null) {
log.debug("Value is null, returning Optional.empty()");
return Optional.empty();
} else {
log.debug("Value is not null, returning an optional holding the value");
return Optional.of(value);
}
}
@Override
public T marshal(Optional<T> value) throws Exception {
if (value == null) {
return null;
}
return value.isPresent() ? value.get() : null;
}
}
我想要的是缺少这个Optional<BigInteger>
字段的节点的XML没有调用setter,但是对于任何有空节点的XML(我选择它来表示显式null)调用将字段设置为Optional.empty()
的setter。
如果我这样做,显式null的情况不起作用:
@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE,
isSetPerformedForAbsentNode =false)
private Optional<BigInteger> field;
该字段未设置且仍为null
。如果我将isSetPerformedForAbsentNode
设置为true
,则缺少节点的情况不起作用。使用null
调用setter,并将字段设置为Optional.empty()
。有什么办法,我可以配置一些JAXB实现到我想要的东西?缺席和null
意味着非常不同的事情,我需要能够分辨出来。
答案 0 :(得分:2)
我必须使用元素引用和JaxB的Moxy实现。
我将一个jaxb.properties
文件放在我的POJO的包中并定义了这个属性:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
然后我声明了两个字段,Optional<BigInteger>
字段,它是POJO上属性的实际值,以及一个元素引用字段,用于确定该值是否显式为null或从XML源中丢失。
private Optional<BigInteger> parentGroupId;
private JAXBElement<BigInteger> parentGroupIdElementRef;
我的Optional
适配器类:
public abstract class OptionalAdapter<T> extends XmlAdapter<T, Optional<T>> {
@Override
public Optional<T> unmarshal(T value) throws Exception {
return Optional.of(value);
}
@Override
public T marshal(Optional<T> value) throws Exception {
return value.isPresent() ? value.get() : null;
}
}
元素参考的处理程序:
@XmlRegistry
public class ParentGroupIdXmlElementRef {
@XmlElementDecl(name="parentGroupId")
public JAXBElement<BigInteger> createFooJAXBElement(final BigInteger value) {
return new JAXBElement<>(new QName("parentGroupId"), BigInteger.class, value);
}
}
我在POJO中的吸尘器和制定者:
@XmlElement(required = false, nillable = true)
@XmlJavaTypeAdapter(OptionalBigIntegerAdapter.class)
@XmlNullPolicy(isSetPerformedForAbsentNode = false, nullRepresentationForXml = XmlMarshalNullRepresentation.XSI_NIL)
@Override
public void setParentGroupId(final Optional<BigInteger> parent) {
log.debug("Parent setter called: {}", parent);
if (parent != null && parent.isPresent() && parent.get().signum() == -1) {
throw log.throwing(new IllegalArgumentException("Cannot specify a parent group ID less than 0"));
}
this.parentGroupId = parent;
//this.isParentIdMissing = false;
if (parent == null) {
parentGroupIdElementRef = null;
} else if (parent.isPresent() && parentGroupIdElementRef == null) {
parentGroupIdElementRef = new ParentGroupIdXmlElementRef().createFooJAXBElement(parent.get());
} else if(parentGroupIdElementRef == null) {
parentGroupIdElementRef = new ParentGroupIdXmlElementRef().createFooJAXBElement(null);
parentGroupIdElementRef.setNil(true);
}
}
@XmlElement(required = false, nillable = true)
@XmlJavaTypeAdapter(OptionalBigIntegerAdapter.class)
@XmlNullPolicy(isSetPerformedForAbsentNode = false, nullRepresentationForXml = XmlMarshalNullRepresentation.XSI_NIL)
@Override
public @Nullable @Nonnegative Optional<BigInteger> getParentGroupId() {
return parentGroupId;
}
@XmlElementRef(name="parentGroupId", required=false)
public void setParentGroupIdElementRef(final JAXBElement<BigInteger> elementRef) {
log.debug("Setting element reference for parent ID: {}", elementRef);
this.parentGroupIdElementRef = elementRef;
if(parentGroupIdElementRef == null) {
setParentGroupId(null);
} else if(parentGroupIdElementRef.isNil()) {
setParentGroupId(Optional.empty());
} else {
setParentGroupId(Optional.of(elementRef.getValue()));
}
}
@XmlElementRef(name="parentGroupId", required=false)
public JAXBElement<BigInteger> getParentGroupIdElementRef() {
log.debug("Getting Element reference: {}", parentGroupIdElementRef);
return this.parentGroupIdElementRef;
}
现在我所有的单元测试都通过了。非null,null和缺失都得到了妥善处理。