All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * 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.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.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.CompositeCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping;
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.CompositeCollectionMappingContentHandler;
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

/**
 * INTERNAL:
 * 

Purpose: This is how the XML Composite Collection Mapping is handled when used with the TreeObjectBuilder. *

*/ public class XMLCompositeCollectionMappingNodeValue extends XMLRelationshipMappingNodeValue implements ContainerValue { private CompositeCollectionMapping xmlCompositeCollectionMapping; private int index = -1; private boolean isInverseReference; public XMLCompositeCollectionMappingNodeValue(CompositeCollectionMapping xmlCompositeCollectionMapping) { super(); this.xmlCompositeCollectionMapping = xmlCompositeCollectionMapping; } public XMLCompositeCollectionMappingNodeValue(CompositeCollectionMapping xmlCompositeCollectionMapping, boolean isInverse) { this(xmlCompositeCollectionMapping); this.isInverseReference = isInverse; } @Override public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { if (xmlCompositeCollectionMapping.isReadOnly()) { return false; } Object collection = xmlCompositeCollectionMapping.getAttributeAccessor().getAttributeValueFromObject(object); if (null == collection) { AbstractNullPolicy wrapperNP = xmlCompositeCollectionMapping.getWrapperNullPolicy(); if (wrapperNP != null && wrapperNP.getMarshalNullRepresentation() == XMLNullRepresentationType.XSI_NIL) { marshalRecord.nilSimple(namespaceResolver); return true; } else { return false; } } CoreContainerPolicy cp = getContainerPolicy(); int size = marshalRecord.getCycleDetectionStack().size(); // when writing the collection need to see if any of the objects we are // writing are in the parent collection inverse ref if ((isInverseReference || xmlCompositeCollectionMapping.getInverseReferenceMapping() != null) && size >= 2) { Object owner = marshalRecord.getCycleDetectionStack().get(size - 2); try { if (cp.contains(owner, collection, session)) { return false; } } catch (ClassCastException e) { // For Bug #416875 } } Object iterator = cp.iteratorFor(collection); if (null != iterator && cp.hasNext(iterator)) { XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); marshalRecord.closeStartGroupingElements(groupingFragment); int valueSize = cp.sizeFor(collection); if(marshalRecord.getMarshaller().isApplicationJSON() && (valueSize > 1 || !marshalRecord.getMarshaller().isReduceAnyArrays())) { marshalRecord.startCollection(); } do { Object objectValue = cp.next(iterator, session); marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, ObjectMarshalContext.getInstance()); } while (cp.hasNext(iterator)); if(marshalRecord.getMarshaller().isApplicationJSON() && (valueSize > 1 || !marshalRecord.getMarshaller().isReduceAnyArrays())) { marshalRecord.endCollection(); } return true; } return marshalRecord.emptyCollection(xPathFragment, namespaceResolver, xmlCompositeCollectionMapping.getWrapperNullPolicy() != null); } @Override public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { try { Descriptor xmlDescriptor = (Descriptor) xmlCompositeCollectionMapping.getReferenceDescriptor(); if (xmlDescriptor == null) { xmlDescriptor = findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, xmlCompositeCollectionMapping, xmlCompositeCollectionMapping.getKeepAsElementPolicy()); if (xmlDescriptor == null) { if (unmarshalRecord.getXMLReader().isNullRepresentedByXsiNil(xmlCompositeCollectionMapping.getNullPolicy())) { if (unmarshalRecord.isNil()) { return true; } } else if (xmlCompositeCollectionMapping.getNullPolicy().valueIsNull(atts)) { getContainerPolicy().addInto(null, unmarshalRecord.getContainerInstance(this), unmarshalRecord.getSession()); return true; } if (xmlCompositeCollectionMapping.getField() != null) { //try leaf element type QName leafType = ((Field) xmlCompositeCollectionMapping.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) xmlCompositeCollectionMapping.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 = xmlCompositeCollectionMapping.getKeepAsElementPolicy(); if (policy != null && ((xmlDescriptor == null && policy.isKeepUnknownAsElement()) || policy.isKeepAllAsElement())) { if (unmarshalRecord.getTypeQName() != null) { Class theClass = unmarshalRecord.getConversionManager().javaType(unmarshalRecord.getTypeQName()); if (theClass == null) { setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); return true; } } else { setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); return true; } } } AbstractNullPolicy nullPolicy = xmlCompositeCollectionMapping.getNullPolicy(); if (nullPolicy.isNullRepresentedByEmptyNode()) { String qnameString = xPathFragment.getLocalName(); if (xPathFragment.getPrefix() != null) { qnameString = xPathFragment.getPrefix() + Constants.COLON + qnameString; } if (null != xmlDescriptor) { // Process null capable value CompositeCollectionMappingContentHandler aHandler = new CompositeCollectionMappingContentHandler(// unmarshalRecord, this, xmlCompositeCollectionMapping, atts, xPathFragment, xmlDescriptor); // Send control to the handler aHandler.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), qnameString, atts); XMLReader xmlReader = unmarshalRecord.getXMLReader(); xmlReader.setContentHandler(aHandler); xmlReader.setLexicalHandler(aHandler); } } else if (!(unmarshalRecord.getXMLReader().isNullRecord(nullPolicy, atts, unmarshalRecord))) { Field xmlFld = (Field) this.xmlCompositeCollectionMapping.getField(); if (xmlFld.hasLastXPathFragment()) { unmarshalRecord.setLeafElementType(xmlFld.getLastXPathFragment().getLeafElementType()); } processChild(xPathFragment, unmarshalRecord, atts, xmlDescriptor, xmlCompositeCollectionMapping); } } catch (SAXException e) { throw XMLMarshalException.unmarshalException(e); } return true; } @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { Object collection = unmarshalRecord.getContainerInstance(this); endElement(xPathFragment, unmarshalRecord, collection); } @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Object collection) { if(unmarshalRecord.isNil() && unmarshalRecord.getXMLReader().isNullRepresentedByXsiNil(xmlCompositeCollectionMapping.getNullPolicy()) && (unmarshalRecord.getChildRecord() == null)){ if(unmarshalRecord.getXMLReader().isInCollection()){ unmarshalRecord.addAttributeValue(this, null); }else{ unmarshalRecord.setAttributeValueNull(this); } unmarshalRecord.resetStringBuffer(); return; } if (null == unmarshalRecord.getChildRecord()) { SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeCollectionMapping.getKeepAsElementPolicy(); if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && builder.getNodes().size() > 1) { if(unmarshalRecord.getTypeQName() != null){ Class theClass = unmarshalRecord.getConversionManager().javaType(unmarshalRecord.getTypeQName()); if(theClass != null){ //handle simple text endElementProcessText(unmarshalRecord, xmlCompositeCollectionMapping, xPathFragment, collection); return; } } if(builder.getNodes().size() > 1) { setOrAddAttributeValueForKeepAsElement(builder, xmlCompositeCollectionMapping, xmlCompositeCollectionMapping, unmarshalRecord, true, collection); return; } }else{ //handle simple text endElementProcessText(unmarshalRecord, xmlCompositeCollectionMapping, xPathFragment, collection); return; } return; } Object objectValue = unmarshalRecord.getChildRecord().getCurrentObject(); InverseReferenceMapping inverseReferenceMapping = xmlCompositeCollectionMapping.getInverseReferenceMapping(); if(null != inverseReferenceMapping) { if(inverseReferenceMapping.getContainerPolicy() == null) { Object currentValue = inverseReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(objectValue); if( !isInverseReference || (currentValue == null && isInverseReference)) { inverseReferenceMapping.getAttributeAccessor().setAttributeValueInObject(objectValue, unmarshalRecord.getCurrentObject()); } } else { Object backpointerContainer = inverseReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(objectValue); if(backpointerContainer == null) { backpointerContainer = inverseReferenceMapping.getContainerPolicy().containerInstance(); inverseReferenceMapping.getAttributeAccessor().setAttributeValueInObject(objectValue, backpointerContainer); } inverseReferenceMapping.getContainerPolicy().addInto(unmarshalRecord.getCurrentObject(), backpointerContainer, unmarshalRecord.getSession()); } } // convert the value - if necessary objectValue = xmlCompositeCollectionMapping.convertDataValueToObjectValue(objectValue, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); unmarshalRecord.addAttributeValue(this, objectValue, collection); unmarshalRecord.setChildRecord(null); } @Override public Object getContainerInstance() { return getContainerPolicy().containerInstance(); } @Override public void setContainerInstance(Object object, Object containerInstance) { xmlCompositeCollectionMapping.setAttributeValueInObject(object, containerInstance); } @Override public CoreContainerPolicy getContainerPolicy() { return xmlCompositeCollectionMapping.getContainerPolicy(); } @Override public boolean isContainerValue() { return true; } @Override public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { Marshaller marshaller = marshalRecord.getMarshaller(); // convert the value - if necessary boolean isNil = false; if (value instanceof Root) { isNil = ((Root) value).nil; value = ((Root) value).getObject(); } value = xmlCompositeCollectionMapping.convertObjectValueToDataValue(value, session, marshaller); if (null == value) { return xmlCompositeCollectionMapping.getNullPolicy().compositeObjectMarshal(xPathFragment, marshalRecord, object, session, namespaceResolver); } Descriptor descriptor = (Descriptor)xmlCompositeCollectionMapping.getReferenceDescriptor(); if(descriptor == null){ descriptor = (Descriptor) session.getDescriptor(value.getClass()); }else if(descriptor.hasInheritance()){ Class objectValueClass = value.getClass(); if(!(objectValueClass == descriptor.getJavaClass())){ descriptor = (Descriptor) session.getDescriptor(objectValueClass); } } UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeCollectionMapping.getKeepAsElementPolicy(); if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && value instanceof org.w3c.dom.Node) { marshalRecord.node((org.w3c.dom.Node) value, marshalRecord.getNamespaceResolver()); return true; } if(descriptor != null){ marshalRecord.beforeContainmentMarshal(value); ObjectBuilder objectBuilder = (ObjectBuilder)descriptor.getObjectBuilder(); CoreAttributeGroup group = marshalRecord.getCurrentAttributeGroup(); CoreAttributeGroup nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP; CoreAttributeItem item = group.getItem(getMapping().getAttributeName()); 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); xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, objectBuilder, value); if (isNil) { marshalRecord.nilSimple(namespaceResolver); } List extraNamespaces = objectBuilder.addExtraNamespacesToNamespaceResolver(descriptor, marshalRecord, session,true, false); writeExtraNamespaces(extraNamespaces, marshalRecord, session); marshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, (Descriptor) xmlCompositeCollectionMapping.getReferenceDescriptor(), (Field)xmlCompositeCollectionMapping.getField(), false); objectBuilder.buildRow(marshalRecord, value, session, marshaller, xPathFragment); marshalRecord.afterContainmentMarshal(object, value); marshalRecord.popAttributeGroup(); marshalRecord.endElement(xPathFragment, namespaceResolver); marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); } else { if(Constants.UNKNOWN_OR_TRANSIENT_CLASS.equals(xmlCompositeCollectionMapping.getReferenceClassName())){ throw XMLMarshalException.descriptorNotFoundInProject(value.getClass().getName()); } xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, null, value); QName schemaType = ((Field) xmlCompositeCollectionMapping.getField()).getSchemaTypeForValue(value, session); updateNamespaces(schemaType, marshalRecord,((Field)xmlCompositeCollectionMapping.getField())); marshalRecord.characters(schemaType, value, null, false); marshalRecord.endElement(xPathFragment, namespaceResolver); } return true; } @Override public CompositeCollectionMapping getMapping() { return xmlCompositeCollectionMapping; } @Override protected void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection){ unmarshalRecord.addAttributeValue(this, value, collection); } @Override public boolean getReuseContainer() { return xmlCompositeCollectionMapping.getReuseContainer(); } /** * INTERNAL: * Used to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord */ @Override public void setIndex(int index){ this.index = index; } /** * INTERNAL: * Set to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord * Set during TreeObjectBuilder initialization */ @Override public int getIndex(){ return index; } /** * INTERNAL * Return true if an empty container should be set on the object if there * is no presence of the collection in the XML document. * @since EclipseLink 2.3.3 */ @Override public boolean isDefaultEmptyContainer() { return xmlCompositeCollectionMapping.isDefaultEmptyContainer(); } @Override public boolean isWrapperAllowedAsCollectionName() { return true; } }