org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.oxm.mappings.nullpolicy;
import org.eclipse.persistence.core.sessions.CoreSession;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.NamespaceResolver;
import org.eclipse.persistence.internal.oxm.NullCapableValue;
import org.eclipse.persistence.internal.oxm.XPathEngine;
import org.eclipse.persistence.internal.oxm.XPathFragment;
import org.eclipse.persistence.internal.oxm.XPathNode;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecord;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
/**
* PUBLIC: Description: This node null policy allows for the handling of
* various representations of null in XML documents.
*
* Null policies have 2 concrete implementations:
*
* - NullPolicy (default implementation)
* - IsSetNullPolicy (keyed off isSet() state of the node)
*
*
*
* Unmarshalling
*
* Unmarshal Flag
* Description
*
*
* isSetPerformedForAbsentNode
* This umarshal flag represents whether a set is done for
* absent nodes only.
*
*
* isNullRepresentedByEmptyNode
* If this unmarshal flag is false for empty nodes we set an
* empty Object for composite mappings, otherwise we set to null.
*
*
* isNullRepresentedByXsiNil
* If this unmarshal flag is false for xsi:nil nodes we ignore
* the xsi:nil attribute and treat as an empty node.
* Otherwise we set to null.
*
*
*
*
* Marshalling
*
* Marshal Enum
* XMLNullRepresentationType Description
*
*
* XSI_NIL
* Nillable: Write out an xsi:nil="true" attribute.
*
*
* ABSENT_NODE(default)
* Optional: Write out no node.
*
*
* EMPTY_NODE
* Required: Write out an empty {@literal } or node="" node.
*
*
Usage:
*
* @see org.eclipse.persistence.internal.oxm.NullCapableValue
* @since Oracle TopLink 11g Release 1 (11.1.1)
*/
public abstract class AbstractNullPolicy {
protected static final String TRUE = "true";
protected static final String COLON_W_SCHEMA_NIL_ATTRIBUTE = Constants.COLON + Constants.SCHEMA_NIL_ATTRIBUTE;
protected static final String XSI_NIL_ATTRIBUTE = Constants.SCHEMA_INSTANCE_PREFIX + COLON_W_SCHEMA_NIL_ATTRIBUTE;
/**
* This state flag determines how we unmarshal absent nodes. true =
* (default) Perform a set(null). false = Do not perform a set(null).
*/
protected boolean isSetPerformedForAbsentNode = true;
/**
* This state flag determines how we unmarshal empty nodes. true = Perform a
* set(null) or primitive type equivalent. false = (default) Perform a
* set(new Object()).
*/
protected boolean isNullRepresentedByEmptyNode = false;
/**
* This state flag determines how we unmarshal xsi:nil nodes. A set is
* performed in both cases. true = Perform a set(null) or primitive type
* equivalent.. false = (default) do nothing and treat as an empty node.
*/
protected boolean isNullRepresentedByXsiNil = false;
/**
* This state flag determines how we unmarshal xsi:nil nodes when there
* are other attributes (other than xsi:nil) present. If false, we ignore
* any attributes and treat the element as nil. If true, we inspect if
* some attributes are present and if yes, we process them.
*/
protected boolean ignoreAttributesForNil = true;
/**
* This enum instance determines what to write out during a marshal
* operation. We are defaulting to ABSENT_NODE
*/
protected XMLNullRepresentationType marshalNullRepresentation = XMLNullRepresentationType.ABSENT_NODE;
/**
* Get the enum that determines what XML to write when a null value is encountered.
*/
public XMLNullRepresentationType getMarshalNullRepresentation() {
return marshalNullRepresentation;
}
/**
* Set the enum that determines what XML to write when a null value is encountered.
*/
public void setMarshalNullRepresentation(XMLNullRepresentationType anEnumInstance) {
marshalNullRepresentation = anEnumInstance;
}
/**
* INTERNAL:
* When using the SAX or DOM Platform, this method is responsible for
* marshalling null values for the XML Direct Mapping.
*
* @param xPathFragment
* @param marshalRecord
* @param object
* @param session
* @param namespaceResolver
* @return true if this method caused any nodes to be marshaled, else false.
*/
public boolean directMarshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, //
Object object, CoreSession session, NamespaceResolver namespaceResolver) {
// Handle attributes - XSI_NIL, ABSENT_NODE have the same behavior
if (xPathFragment.isAttribute()) {
// Write out an empty attribute
if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
marshalRecord.emptyAttribute(xPathFragment, namespaceResolver);
return true;
} else {
// XSI_NIL attributes are invalid - and are ignored
// ABSENT_NODE - Write out nothing
return false;
}
} else {
// Nillable: write out xsi:nil="true" attribute in empty element
if (marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
marshalRecord.nilSimple(namespaceResolver);
return true;
} else {
// EMPTY_NODE - Write out empty element
if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
marshalRecord.emptySimple(namespaceResolver);
return true;
} else {
// ABSENT_NODE - Write out nothing
return false;
}
}
}
}
/**
* INTERNAL: When using the SAX Platform, this method is responsible for
* marshalling null values for the XML Composite Object Mapping.
*
* @param xPathFragment
* @param marshalRecord
* @param object
* @param session
* @param namespaceResolver
* @return true if this method caused any nodes to be marshaled, else false.
*/
public boolean compositeObjectMarshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, //
Object object, CoreSession session, NamespaceResolver namespaceResolver) {
if (marshalNullRepresentation == XMLNullRepresentationType.ABSENT_NODE){
return false;
}
// Nillable
else if (marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
marshalRecord.nilComplex(xPathFragment, namespaceResolver);
return true;
} else if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
// Optional and Required
// This call is really only valid when using DOM - TBD false
// Write out empty element - we need to differentiate between
// object=null and object=new Object() with null fields and 0-numeric primitive values
// EMPTY_NODE - Write out empty element - Required
marshalRecord.emptyComplex(xPathFragment, namespaceResolver);
return true;
}
return false;
}
/**
* INTERNAL: When using the DOM Platform, this method is responsible for
* marshalling null values for the XML Composite Object Mapping.
*
* @param record
* @param object
* @param field
* @return true if this method caused any objects to be marshaled, else false.
*/
public boolean compositeObjectMarshal(AbstractMarshalRecord record, Object object, Field field, CoreAbstractSession session) {
if (marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
record.put(field, XMLRecord.NIL);
return true;
} else {
// EMPTY_NODE - Write out empty element - Required
if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
Node element = XPathEngine.getInstance().createUnownedElement(record.getDOM(), field);
record.put(field, element);
return true;
} else {
// ABSENT_NODE - Write out nothing - Optional
return false;
}
}
}
/**
* INTERNAL: When using the SAX or DOM Platform during unmarshal operations.
* Use the attributes to determine if the element represents a null value.
*
* @param attributes
* @return true if based on the attributes the corresponding element
* represents a null value, else false.
*/
public boolean valueIsNull(Attributes attributes) {
// Nillable
if (isNullRepresentedByXsiNil()) {
// Ignore any other attributes that are in addition to xsi:nil
if(null == attributes) {
return false;
}
return attributes.getValue(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_NIL_ATTRIBUTE) != null;
} else {
// EMPTY_NODE - Required
if (isNullRepresentedByEmptyNode() && (null == attributes || attributes.getLength() == 0)) {
return true;
}
}
return false;
}
/**
* INTERNAL: When using the DOM Platform during unmarshal operations.
* Use the element to determine if the element represents a null value.
*
* @param element
* @return true if based on the element it represents a null value, else false.
*/
public boolean valueIsNull(Element element) {
// Check Nillable: Ignore any other attributes that are in addition to xsi:nil
if (null == element) {
return true;
} else {
if (isNullRepresentedByXsiNil() && element.hasAttributeNS(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_NIL_ATTRIBUTE)) {
return true;
} else {
// EMPTY_NODE - Required
// Verify no attributes and no child nodes on the DOM element
if (isNullRepresentedByEmptyNode() && !element.hasAttributes() && (element.getChildNodes().getLength() == 0)) {
return true;
} else {
return false;
}
}
}
}
/**
* INTERNAL: When using the SAX Platform this allows a NodeValue to be
* registered to receive events from the TreeObjectBuilder.
* @param xPathNode
* @param nullCapableValue
*/
public abstract void xPathNode(XPathNode xPathNode, NullCapableValue nullCapableValue);
/**
* @return the isSetPerformedForAbsentNode flag
*/
public boolean getIsSetPerformedForAbsentNode() {
return isSetPerformedForAbsentNode;
}
/**
*
* @return
*/
public boolean isNullRepresentedByEmptyNode() {
return isNullRepresentedByEmptyNode;
}
/**
*
* @param bIsNullRepresentedByEmptyNode
*/
public void setNullRepresentedByEmptyNode(boolean bIsNullRepresentedByEmptyNode) {
isNullRepresentedByEmptyNode = bIsNullRepresentedByEmptyNode;
}
/**
*
* @return
*/
public boolean isNullRepresentedByXsiNil() {
return isNullRepresentedByXsiNil;
}
/**
*
* @param bIsNullRepresentedByXsiNil
*/
public void setNullRepresentedByXsiNil(boolean bIsNullRepresentedByXsiNil) {
isNullRepresentedByXsiNil = bIsNullRepresentedByXsiNil;
}
/**
*
* @return
*/
public boolean ignoreAttributesForNil() {
return ignoreAttributesForNil;
}
/**
*
* @param ignoreAttributesForNil
*/
public void setIgnoreAttributesForNil(boolean ignoreAttributesForNil) {
this.ignoreAttributesForNil = ignoreAttributesForNil;
}
/**
* INTERNAL:
* Private function to process or create an entry in the NamespaceResolver for the xsi prefix.
* @param namespaceResolver
* @return xsi prefix
*/
protected String processNamespaceResolverForXSIPrefix(NamespaceResolver namespaceResolver, MarshalRecord marshalRecord) {
String xsiPrefix;
if (null == namespaceResolver) {
// add new xsi entry into the properties map
xsiPrefix = Constants.SCHEMA_INSTANCE_PREFIX;
marshalRecord.namespaceDeclaration(xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
} else {
// find an existing xsi entry in the map
xsiPrefix = namespaceResolver.resolveNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
if (null == xsiPrefix) {
xsiPrefix = namespaceResolver.generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX);
marshalRecord.namespaceDeclaration(xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
}
}
return xsiPrefix;
}
/**
* INTERNAL
*/
public void directMarshal(Field field, AbstractMarshalRecord record, Object object) {
Object fieldValue = null;
if(marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
fieldValue = Constants.EMPTY_STRING;
} else {
if(!field.getLastXPathFragment().isAttribute()) {
if(marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
fieldValue = XMLRecord.NIL;
}
}
}
record.put(field, fieldValue);
}
}