2016-08-05 5 views
0

Мне действительно нужно уметь различать «missing» и «null» при развязывании XML в POJO. У меня есть Optional<BigInteger> поля и адаптер для Optional типов:Moxy JAXB и разделение между «недостающими» и явными нулями

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; 
    } 
} 

То, что я хочу для XML который отсутствует узел для этого Optional<BigInteger> поля НЕ вызывать сеттер, но и для любого XML, который действительно есть узел, пусто (я выбрал это для представления явного null), чтобы вызвать setter, который установит поле в Optional.empty().

Если я сделаю это, в случае явного нуль не работает:

@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE, 
     isSetPerformedForAbsentNode =false) 
private Optional<BigInteger> field; 

поле не установлен и остается null. Если я установил isSetPerformedForAbsentNode в true, тогда случай для отсутствующего узла не работает. Setter вызывается с номером null и поле установлено равным Optional.empty(). Есть ли способ, я могу настроить некоторую реализацию JAXB на то, что я хочу? Absent и null означают совсем другие вещи, и я должен уметь отличать друг от друга.

ответ

1

Мне пришлось использовать ссылку на элемент и реализацию Moxy JaxB.

Я поместил в jaxb.properties файл в пакете для моего POJO с этим свойством определенным:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

Тогда я объявил два поля, в Optional<BigInteger> поле, которое является фактическим значением свойства на POJO и которое я использую, чтобы определить, является ли значение явно нулевым или отсутствующим в источнике 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; 
} 

Теперь все мой блок испытания проходят. Непустые, нулевые и отсутствующие все обрабатываются надлежащим образом.

 Смежные вопросы

  • Нет связанных вопросов^_^