org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue 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, 2021 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.internal.oxm;
import java.lang.reflect.Modifier;
import java.util.List;
import javax.xml.namespace.QName;
import org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.core.queries.CoreAttributeItem;
import org.eclipse.persistence.core.sessions.CoreSession;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.CompositeObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.DirectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy;
import org.eclipse.persistence.internal.oxm.record.MarshalContext;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
import org.eclipse.persistence.internal.oxm.record.XMLReader;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.eclipse.persistence.internal.oxm.record.deferred.CompositeObjectMappingContentHandler;
import org.eclipse.persistence.oxm.XMLRoot;
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy;
import org.eclipse.persistence.platform.xml.XMLPlatformFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* INTERNAL:
* Purpose: This is how the XML Composite Object Mapping is handled
* when used with the TreeObjectBuilder.
*/
public class XMLCompositeObjectMappingNodeValue extends XMLRelationshipMappingNodeValue implements NullCapableValue {
private CompositeObjectMapping xmlCompositeObjectMapping;
private boolean isInverseReference;
public XMLCompositeObjectMappingNodeValue(CompositeObjectMapping xmlCompositeObjectMapping) {
this.xmlCompositeObjectMapping = xmlCompositeObjectMapping;
}
public XMLCompositeObjectMappingNodeValue(CompositeObjectMapping xmlCompositeObjectMapping, boolean isInverse) {
this(xmlCompositeObjectMapping);
isInverseReference = isInverse;
}
@Override
public void attribute(UnmarshalRecord unmarshalRecord, String namespaceURI, String localName, String value) {
unmarshalRecord.removeNullCapableValue(this);
Descriptor referenceDescriptor = (Descriptor) getMapping().getReferenceDescriptor();
ObjectBuilder treeObjectBuilder = (ObjectBuilder) referenceDescriptor.getObjectBuilder();
MappingNodeValue textMappingNodeValue = (MappingNodeValue) treeObjectBuilder.getRootXPathNode().getTextNode().getNodeValue();
Mapping textMapping = textMappingNodeValue.getMapping();
Object childObject = referenceDescriptor.getInstantiationPolicy().buildNewInstance();
if(textMapping.isAbstractDirectMapping()) {
DirectMapping xmlDirectMapping = (DirectMapping) textMappingNodeValue.getMapping();
Field xmlField = (Field) xmlDirectMapping.getField();
Object realValue = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, (ConversionManager) unmarshalRecord.getSession().getDatasourcePlatform().getConversionManager(), unmarshalRecord);
Object convertedValue = xmlDirectMapping.getAttributeValue(realValue, unmarshalRecord.getSession(), unmarshalRecord);
xmlDirectMapping.setAttributeValueInObject(childObject, convertedValue);
} else {
Object oldChildObject = unmarshalRecord.getCurrentObject();
CompositeObjectMapping nestedXMLCompositeObjectMapping = (CompositeObjectMapping) textMappingNodeValue.getMapping();
unmarshalRecord.setCurrentObject(childObject);
textMappingNodeValue.attribute(unmarshalRecord, namespaceURI, localName, value);
unmarshalRecord.setCurrentObject(oldChildObject);
}
setAttributeValue(childObject, unmarshalRecord);
}
/**
* Marshal any 'self' mapped attributes.
*
*/
@Override
public boolean marshalSelfAttributes(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, Marshaller marshaller) {
Object objectValue = xmlCompositeObjectMapping.getAttributeValueFromObject(object);
objectValue = xmlCompositeObjectMapping.convertObjectValueToDataValue(objectValue, session, marshaller);
Descriptor descriptor = (Descriptor)session.getDescriptor(objectValue);
if(descriptor != null){
ObjectBuilder objectBuilder = (ObjectBuilder)descriptor.getObjectBuilder();
return objectBuilder.marshalAttributes(marshalRecord, objectValue, session);
} else {
UnmarshalKeepAsElementPolicy keepAsElementPolicy = getMapping().getKeepAsElementPolicy();
if(null != keepAsElementPolicy && (keepAsElementPolicy.isKeepAllAsElement() || keepAsElementPolicy.isKeepUnknownAsElement())) {
if(objectValue instanceof Node) {
Node rootNode = (Node)objectValue;
NamedNodeMap attributes = rootNode.getAttributes();
for(int i = 0; i < attributes.getLength(); i++) {
Attr next = (Attr)attributes.item(i);
if(!(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(next.getNamespaceURI()))) {
marshalRecord.node(next, namespaceResolver);
}
}
}
}
}
return false;
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) {
return marshal(xPathFragment, marshalRecord, object, session, namespaceResolver, ObjectMarshalContext.getInstance());
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) {
if (xmlCompositeObjectMapping.isReadOnly()) {
return false;
}
int size =marshalRecord.getCycleDetectionStack().size();
Object objectValue = marshalContext.getAttributeValue(object, xmlCompositeObjectMapping);
if ((isInverseReference || xmlCompositeObjectMapping.getInverseReferenceMapping() != null) && objectValue != null && size >= 2) {
Object owner = marshalRecord.getCycleDetectionStack().get(size - 2);
if (objectValue.equals(owner)) {
return false;
}
}
return this.marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext);
}
private boolean isNil(Object value) {
if (value instanceof XMLRoot) {
return ((XMLRoot)value).isNil();
}
return false;
}
@Override
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) {
boolean isNilFlag = isNil(objectValue);
objectValue = xmlCompositeObjectMapping.convertObjectValueToDataValue(objectValue, session, marshalRecord.getMarshaller());
if (null == objectValue) {
return xmlCompositeObjectMapping.getNullPolicy().compositeObjectMarshal(xPathFragment, marshalRecord, object, session, namespaceResolver);
}
XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver);
if(xPathFragment.hasAttribute) {
ObjectBuilder tob = (ObjectBuilder) xmlCompositeObjectMapping.getReferenceDescriptor().getObjectBuilder();
MappingNodeValue textMappingNodeValue = (MappingNodeValue) tob.getRootXPathNode().getTextNode().getMarshalNodeValue();
Mapping textMapping = textMappingNodeValue.getMapping();
if(textMapping.isAbstractDirectMapping()) {
DirectMapping xmlDirectMapping = (DirectMapping) textMapping;
Object fieldValue = xmlDirectMapping.getFieldValue(xmlDirectMapping.valueFromObject(objectValue, xmlDirectMapping.getField(), session), session, marshalRecord);
QName schemaType = ((Field) xmlDirectMapping.getField()).getSchemaTypeForValue(fieldValue, session);
if(fieldValue != null) {
marshalRecord.attribute(xPathFragment, namespaceResolver, fieldValue, schemaType);
} else {
XMLMarshalException ex = XMLMarshalException.nullValueNotAllowed(this.xmlCompositeObjectMapping.getAttributeName(), this.xmlCompositeObjectMapping.getDescriptor().getJavaClass().getName());
try {
marshalRecord.getMarshaller().getErrorHandler().warning(new SAXParseException(null, null, ex));
} catch(Exception saxException) {
throw ex;
}
}
marshalRecord.closeStartGroupingElements(groupingFragment);
return true;
} else {
return textMappingNodeValue.marshalSingleValue(xPathFragment, marshalRecord, objectValue, textMapping.getAttributeValueFromObject(objectValue), session, namespaceResolver, marshalContext);
}
}
boolean isSelfFragment = xPathFragment.isSelfFragment;
marshalRecord.closeStartGroupingElements(groupingFragment);
UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeObjectMapping.getKeepAsElementPolicy();
if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && objectValue instanceof Node) {
if (isSelfFragment) {
NodeList children = ((org.w3c.dom.Element) objectValue).getChildNodes();
for (int i = 0, childrenLength = children.getLength(); i < childrenLength ; i++) {
Node next = children.item(i);
short nodeType = next.getNodeType();
if (nodeType == Node.ELEMENT_NODE) {
marshalRecord.node(next, marshalRecord.getNamespaceResolver());
return true;
} else if (nodeType == Node.TEXT_NODE) {
marshalRecord.characters(next.getNodeValue());
return true;
}
}
return false;
} else {
marshalRecord.node((Node) objectValue, marshalRecord.getNamespaceResolver());
return true;
}
}
Descriptor descriptor = (Descriptor)xmlCompositeObjectMapping.getReferenceDescriptor();
if(descriptor == null){
descriptor = (Descriptor) session.getDescriptor(objectValue.getClass());
}else if(descriptor.hasInheritance()){
Class> objectValueClass = objectValue.getClass();
if(!(objectValueClass == descriptor.getJavaClass())){
descriptor = (Descriptor) session.getDescriptor(objectValueClass);
}
}
if(descriptor != null){
marshalRecord.beforeContainmentMarshal(objectValue);
ObjectBuilder objectBuilder = (ObjectBuilder)descriptor.getObjectBuilder();
CoreAttributeGroup group = marshalRecord.getCurrentAttributeGroup();
CoreAttributeItem item = group.getItem(getMapping().getAttributeName());
CoreAttributeGroup nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP;
if(item != null) {
if(item.getGroups() != null) {
nestedGroup = item.getGroup(descriptor.getJavaClass());
}
if(nestedGroup == null) {
nestedGroup = item.getGroup() == null?XMLRecord.DEFAULT_ATTRIBUTE_GROUP:item.getGroup();
}
}
marshalRecord.pushAttributeGroup(nestedGroup);
if (!(isSelfFragment || xPathFragment.nameIsText)) {
xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, objectBuilder, objectValue);
if (isNilFlag) {
marshalRecord.nilSimple(namespaceResolver);
}
}
List extraNamespaces = null;
if (marshalRecord.getNamespaceResolver() != null && descriptor.getNamespaceResolver() != null) {
for (String prefix: descriptor.getNamespaceResolver().getPrefixesToNamespaces().keySet()) {
if (!marshalRecord.getNamespaceResolver().hasPrefix(prefix)) {
marshalRecord.setEqualNamespaceResolvers(false);
break;
}
}
}
if (!marshalRecord.hasEqualNamespaceResolvers()) {
extraNamespaces = objectBuilder.addExtraNamespacesToNamespaceResolver(descriptor, marshalRecord, session, true, false);
writeExtraNamespaces(extraNamespaces, marshalRecord, session);
}
if(!isSelfFragment) {
marshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, (Descriptor) xmlCompositeObjectMapping.getReferenceDescriptor(), (Field)xmlCompositeObjectMapping.getField(), false);
}
objectBuilder.buildRow(marshalRecord, objectValue, session, marshalRecord.getMarshaller(), xPathFragment);
marshalRecord.afterContainmentMarshal(object, objectValue);
marshalRecord.popAttributeGroup();
if (!(isSelfFragment || xPathFragment.nameIsText())) {
marshalRecord.endElement(xPathFragment, namespaceResolver);
}
marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session);
} else {
if(Constants.UNKNOWN_OR_TRANSIENT_CLASS.equals(xmlCompositeObjectMapping.getReferenceClassName())){
throw XMLMarshalException.descriptorNotFoundInProject(objectValue.getClass().getName());
}
if (!(isSelfFragment || xPathFragment.nameIsText())) {
xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, null, objectValue);
}
QName schemaType = ((Field) xmlCompositeObjectMapping.getField()).getSchemaTypeForValue(objectValue,session);
updateNamespaces(schemaType, marshalRecord,((Field)xmlCompositeObjectMapping.getField()));
marshalRecord.characters(schemaType, objectValue, null, false);
if (!(isSelfFragment || xPathFragment.nameIsText())) {
marshalRecord.endElement(xPathFragment, namespaceResolver);
}
}
return true;
}
@Override
public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) {
try {
unmarshalRecord.removeNullCapableValue(this);
Descriptor xmlDescriptor = (Descriptor)xmlCompositeObjectMapping.getReferenceDescriptor();
if (null == xmlDescriptor) {
xmlDescriptor = findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, xmlCompositeObjectMapping,xmlCompositeObjectMapping.getKeepAsElementPolicy());
if(xmlDescriptor == null){
if(xmlCompositeObjectMapping.getField() != null){
//try leaf element type
QName leafType = ((Field)xmlCompositeObjectMapping.getField()).getLastXPathFragment().getLeafElementType();
if (leafType != null) {
XPathFragment frag = new XPathFragment();
frag.setNamespaceAware(unmarshalRecord.isNamespaceAware());
String xpath = leafType.getLocalPart();
String uri = leafType.getNamespaceURI();
if (uri != null && uri.length() > 0) {
frag.setNamespaceURI(uri);
String prefix = ((Descriptor)xmlCompositeObjectMapping.getDescriptor()).getNonNullNamespaceResolver().resolveNamespaceURI(uri);
if (prefix != null && prefix.length() > 0) {
xpath = prefix + Constants.COLON + xpath;
}
}
frag.setXPath(xpath);
Context xmlContext = unmarshalRecord.getUnmarshaller().getContext();
xmlDescriptor = xmlContext.getDescriptorByGlobalType(frag);
}
}
}
UnmarshalKeepAsElementPolicy policy = xmlCompositeObjectMapping.getKeepAsElementPolicy();
if (null != policy && ((xmlDescriptor == null && policy.isKeepUnknownAsElement()) || policy.isKeepAllAsElement())) {
QName schemaType = unmarshalRecord.getTypeQName();
if(schemaType == null){
schemaType = ((Field)xmlCompositeObjectMapping.getField()).getSchemaType();
unmarshalRecord.setTypeQName(schemaType);
}
if(schemaType != null){
Class