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

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

There is a newer version: 5.0.0-B03
Show newest version
/*
 * 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.internal.oxm;


import javax.xml.namespace.QName;

import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.CollectionReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.Field;
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.xml.sax.Attributes;

/**
 * INTERNAL:
 * 

Purpose: Class to handle (un)marshal operations for * XMLCollectionReferenceMappings.

* *

An instance of this class is required for each XMLField set on the * mapping, that is, for each source field in the source-target key field * association list.

* *

When unmarshalling, an instance of org.eclipse.persistence.internal.oxm.Reference is * created on a per mapping basis (keyed on source object instance) and sorted * on the associated session's org.eclipse.persistence.internal.oxm.ReferenceResolver * instance. Each target primary key value is stored in the Reference instance * for use during mapping resolution phase after unmarshalling completes.

* *

When marshalling, the target object's primary key value that is mapped to * this NodeValue's XMLField (in the XMLObjectReferenceMapping's source-target * key field association list) is retrieved and written out.

* * @see org.eclipse.persistence.internal.oxm.Reference * @see org.eclipse.persistence.internal.oxm.ReferenceResolver * @see org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping */ public class XMLCollectionReferenceMappingNodeValue extends MappingNodeValue implements ContainerValue { private CollectionReferenceMapping xmlCollectionReferenceMapping; private Field xmlField; private static final String SPACE = " "; private int index = -1; /** * This constructor sets the XMLCollectionReferenceMapping and XMLField members to * the provided values. * * @param xmlCollectionReferenceMapping */ public XMLCollectionReferenceMappingNodeValue(CollectionReferenceMapping xmlCollectionReferenceMapping, Field xmlField) { super(); this.xmlCollectionReferenceMapping = xmlCollectionReferenceMapping; this.xmlField = xmlField; } /** * Handle attribute operation. Here we will create and populate an * org.eclipse.persistence.internal.oxm.Reference instance to be used during * the mapping resolution stage. In particular, the primary key value * for this element will be added to the Reference object's map of * target primary key values - based on the target key field name. Note * that if a reference already exists for the xmlCollectionReferenceMapping's * source object instance, we will simply add to the target pk value list. * The Reference object is stored on the ReferenceResolver associated with * the UnmarshalRecord's session. */ @Override public void attribute(UnmarshalRecord unmarshalRecord, String namespaceURI, String localName, String value) { if (value != null) { Object realValue = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, (ConversionManager) unmarshalRecord.getSession().getDatasourcePlatform().getConversionManager(), unmarshalRecord); Object container = unmarshalRecord.getContainerInstance(this); // build a reference which will be resolved after unmarshalling is complete xmlCollectionReferenceMapping.buildReference(unmarshalRecord, xmlField, realValue, unmarshalRecord.getSession(), container); } } /** * Handle endElement operation. Here we will create and populate an * org.eclipse.persistence.internal.oxm.Reference instance to be used during * the mapping resolution stage. In particular, the primary key value * for this element will be added to the Reference object's map of * target primary key values - based on the target key field name. Note * that if a reference already exists for the xmlCollectionReferenceMapping's * source object instance, we will simply add to the target pk value list. * The Reference object is stored on the ReferenceResolver associated with * the UnmarshalRecord's session. */ @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { if (!xmlField.getLastXPathFragment().nameIsText()) { return; } Object value = unmarshalRecord.getCharacters().toString(); unmarshalRecord.resetStringBuffer(); ConversionManager conversionManager = unmarshalRecord.getConversionManager(); if (unmarshalRecord.getTypeQName() != null) { Class typeClass = xmlField.getJavaClass(unmarshalRecord.getTypeQName(), conversionManager); value = conversionManager.convertObject(value, typeClass, unmarshalRecord.getTypeQName()); } else { value = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, conversionManager, unmarshalRecord); } Object container = unmarshalRecord.getContainerInstance(this); // build a reference which will be resolved after unmarshalling is complete xmlCollectionReferenceMapping.buildReference(unmarshalRecord, xmlField, value, unmarshalRecord.getSession(), container); } @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Object container) { this.endElement(xPathFragment, unmarshalRecord); } /** * Indicate if the next XPathFragment is an attribute or text() node. */ @Override public boolean isOwningNode(XPathFragment xPathFragment) { if(isMarshalNodeValue()) { if (xmlCollectionReferenceMapping.usesSingleNode()) { return xPathFragment.nameIsText() || xPathFragment.isAttribute(); } XPathFragment nextFragment = xPathFragment.getNextFragment(); return (nextFragment != null) && (nextFragment.nameIsText() || nextFragment.isAttribute()); } return super.isOwningNode(xPathFragment); } @Override public boolean isWrapperAllowedAsCollectionName() { return true; } @Override public boolean isContainerValue() { return true; } @Override public Object getContainerInstance() { return getContainerPolicy().containerInstance(); } @Override public void setContainerInstance(Object object, Object containerInstance) { xmlCollectionReferenceMapping.setAttributeValueInObject(object, containerInstance); } @Override public CoreContainerPolicy getContainerPolicy() { return xmlCollectionReferenceMapping.getContainerPolicy(); } /** * Handle the marshal operation for this NodeValue. Each of the target * object's primary key values that are mapped to the collection mapping's fields * (in the XMLCollectionReferenceMapping's source-target key field association list) * are retrieved and written out. */ @Override public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { if(this.xmlCollectionReferenceMapping.isReadOnly()) { return false; } CoreContainerPolicy cp = xmlCollectionReferenceMapping.getContainerPolicy(); Object collection = xmlCollectionReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(object); if (collection == null) { return false; } Object iterator = cp.iteratorFor(collection); if (cp.hasNext(iterator)) { XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); marshalRecord.closeStartGroupingElements(groupingFragment); } else { return marshalRecord.emptyCollection(xPathFragment, namespaceResolver, false); } Object objectValue; if (xmlCollectionReferenceMapping.usesSingleNode()) { StringBuilder stringValueStringBuilder = new StringBuilder(); String newValue; QName schemaType; while (cp.hasNext(iterator)) { objectValue = cp.next(iterator, session); Object fieldValue = xmlCollectionReferenceMapping.buildFieldValue(objectValue, xmlField, session); if (fieldValue == null) { if(null != objectValue) { Field fkField = (Field) xmlCollectionReferenceMapping.getSourceToTargetKeyFieldAssociations().get(xmlField); fieldValue = marshalRecord.getMarshaller().getContext().getValueByXPath(objectValue, fkField.getXPath(), fkField.getNamespaceResolver(), Object.class); } if(null == fieldValue) { break; } } schemaType = xmlField.getSchemaTypeForValue(fieldValue, session); newValue = marshalRecord.getValueToWrite(schemaType, fieldValue, (ConversionManager) session.getDatasourcePlatform().getConversionManager()); if (newValue != null) { stringValueStringBuilder.append(newValue); if (cp.hasNext(iterator)) { stringValueStringBuilder.append(SPACE); } } } marshalSingleValue(xPathFragment, marshalRecord, object, stringValueStringBuilder.toString(), session, namespaceResolver, ObjectMarshalContext.getInstance()); } else { marshalRecord.startCollection(); while (cp.hasNext(iterator)) { objectValue = cp.next(iterator, session); marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, ObjectMarshalContext.getInstance()); } marshalRecord.endCollection(); } return true; } /** * @param xPathFragment * @param unmarshalRecord * @param atts */ @Override public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { if (xmlField.getLastXPathFragment().isAttribute()) { if (!this.xmlCollectionReferenceMapping.usesSingleNode()) { String namespaceURI = xmlField.getLastXPathFragment().getNamespaceURI(); String value; if (namespaceURI == null) { value = atts.getValue(xmlField.getLastXPathFragment().getLocalName()); } else { value = atts.getValue(namespaceURI, xmlField.getLastXPathFragment().getLocalName()); } xmlCollectionReferenceMapping.buildReference(unmarshalRecord, xmlField, value, unmarshalRecord.getSession(), unmarshalRecord.getContainerInstance(this)); return true; } } return true; } @Override public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { if (xmlCollectionReferenceMapping.usesSingleNode()) { XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); if (xPathFragment.isAttribute()) { marshalRecord.attribute(xPathFragment, namespaceResolver, value, null); marshalRecord.closeStartGroupingElements(groupingFragment); } else { marshalRecord.closeStartGroupingElements(groupingFragment); marshalRecord.characters(null, value, null, false); } } else { QName schemaType; Object fieldValue = xmlCollectionReferenceMapping.buildFieldValue(value, xmlField, session); if (fieldValue == null) { return false; } schemaType = xmlField.getSchemaTypeForValue(fieldValue, session); marshalRecord.openStartElement(xPathFragment, namespaceResolver); XPathFragment nextFragment = xPathFragment.getNextFragment(); if (nextFragment.isAttribute()) { marshalRecord.attribute(nextFragment, namespaceResolver, fieldValue, schemaType); marshalRecord.closeStartElement(); } else { marshalRecord.predicateAttribute(xPathFragment, namespaceResolver); marshalRecord.closeStartElement(); marshalRecord.characters(schemaType, fieldValue, null, false); } marshalRecord.endElement(xPathFragment, namespaceResolver); } return true; } @Override public CollectionReferenceMapping getMapping() { return xmlCollectionReferenceMapping; } @Override public boolean getReuseContainer() { return getMapping().getReuseContainer(); } @Override public boolean isMarshalNodeValue() { return xmlCollectionReferenceMapping.getFields().size() == 1 || xmlCollectionReferenceMapping.usesSingleNode(); } /** * 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 getMapping().isDefaultEmptyContainer(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy