| /* |
| * Copyright (c) 1998, 2020 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: |
| // bdoughan - October 21/2009 - 2.0 - Initial implementation |
| package org.eclipse.persistence.internal.oxm; |
| |
| import java.util.List; |
| 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.Descriptor; |
| 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; |
| |
| public class XMLCollectionReferenceMappingMarshalNodeValue extends MappingNodeValue implements ContainerValue { |
| |
| private CollectionReferenceMapping xmlCollectionReferenceMapping; |
| private XPathNode branchNode; |
| private int index = -1; |
| |
| public XMLCollectionReferenceMappingMarshalNodeValue(CollectionReferenceMapping xmlCollectionReferenceMapping) { |
| this.xmlCollectionReferenceMapping = xmlCollectionReferenceMapping; |
| branchNode = new XPathNode(); |
| NamespaceResolver namespaceResolver = ((Descriptor) xmlCollectionReferenceMapping.getDescriptor()).getNamespaceResolver(); |
| List fkFields = xmlCollectionReferenceMapping.getFields(); |
| for(int x=0, fkFieldsSize=fkFields.size(); x<fkFieldsSize; x++) { |
| Field fkField = (Field) fkFields.get(x); |
| branchNode.addChild(fkField.getXPathFragment(), new XMLCollectionReferenceMappingFKMarshalNodeValue(xmlCollectionReferenceMapping, fkField), namespaceResolver); |
| } |
| } |
| |
| @Override |
| public boolean isOwningNode(XPathFragment fragment) { |
| return true; |
| } |
| |
| @Override |
| public Object getContainerInstance() { |
| return getContainerPolicy().containerInstance(); |
| } |
| |
| @Override |
| public CoreContainerPolicy getContainerPolicy() { |
| return xmlCollectionReferenceMapping.getContainerPolicy(); |
| } |
| |
| @Override |
| public CollectionReferenceMapping getMapping() { |
| return xmlCollectionReferenceMapping; |
| } |
| |
| @Override |
| public boolean getReuseContainer() { |
| return xmlCollectionReferenceMapping.getReuseContainer(); |
| } |
| |
| @Override |
| public void setContainerInstance(Object object, Object containerInstance) { |
| xmlCollectionReferenceMapping.setAttributeValueInObject(object, containerInstance); |
| } |
| |
| @Override |
| public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { |
| if (xmlCollectionReferenceMapping.isReadOnly()) { |
| return false; |
| } |
| |
| Object collection = xmlCollectionReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(object); |
| if (null == collection) { |
| return false; |
| } |
| CoreContainerPolicy cp = getContainerPolicy(); |
| Object iterator = cp.iteratorFor(collection); |
| if (cp.hasNext(iterator)) { |
| XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| } else { |
| return marshalRecord.emptyCollection(xPathFragment, namespaceResolver, false); |
| } |
| marshalRecord.startCollection(); |
| |
| if(xPathFragment != XPathFragment.SELF_FRAGMENT) { |
| marshalRecord.openStartElement(xPathFragment, namespaceResolver); |
| } |
| while (cp.hasNext(iterator)) { |
| Object objectValue = cp.next(iterator, session); |
| marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, ObjectMarshalContext.getInstance()); |
| } |
| if(xPathFragment != XPathFragment.SELF_FRAGMENT) { |
| marshalRecord.endElement(xPathFragment, namespaceResolver); |
| } |
| marshalRecord.endCollection(); |
| |
| 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, (String) value); |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| } else { |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| marshalRecord.characters((String) value); |
| } |
| } else { |
| for (int x = 0, size = marshalContext.getNonAttributeChildrenSize(branchNode); x < size; x++) { |
| XPathNode xPathNode = (XPathNode)marshalContext.getNonAttributeChild(x, branchNode); |
| xPathNode.marshal(marshalRecord, value, session, namespaceResolver, marshalRecord.getMarshaller(), marshalContext.getMarshalContext(x), null); |
| } |
| |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean isMarshalNodeValue() { |
| return !xmlCollectionReferenceMapping.usesSingleNode(); |
| } |
| |
| @Override |
| public boolean isUnmarshalNodeValue() { |
| return false; |
| } |
| |
| @Override |
| public boolean isWrapperAllowedAsCollectionName() { |
| return true; |
| } |
| |
| private static class XMLCollectionReferenceMappingFKMarshalNodeValue extends MappingNodeValue { |
| |
| private CollectionReferenceMapping xmlCollectionReferenceMapping; |
| private Field xmlField; |
| |
| public XMLCollectionReferenceMappingFKMarshalNodeValue(CollectionReferenceMapping xmlCollectionReferenceMapping, Field xmlField) { |
| this.xmlCollectionReferenceMapping = xmlCollectionReferenceMapping; |
| this.xmlField = xmlField; |
| } |
| |
| @Override |
| public boolean isUnmarshalNodeValue() { |
| return false; |
| } |
| |
| @Override |
| public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { |
| XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| return marshalSingleValue(xPathFragment, marshalRecord, null, object, session, namespaceResolver, ObjectMarshalContext.getInstance()); |
| } |
| |
| @Override |
| public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { |
| Object fieldValue = xmlCollectionReferenceMapping.buildFieldValue(value, xmlField, session); |
| if (fieldValue == null) { |
| if(null != value) { |
| Field f2 = (Field) xmlCollectionReferenceMapping.getSourceToTargetKeyFieldAssociations().get(xmlField); |
| fieldValue = marshalRecord.getMarshaller().getContext().getValueByXPath(value, f2.getXPath(), f2.getNamespaceResolver(), Object.class); |
| } |
| if(null == fieldValue) { |
| return false; |
| } |
| } |
| QName schemaType = xmlField.getSchemaTypeForValue(fieldValue, session); |
| if (xPathFragment.isAttribute()) { |
| marshalRecord.attribute(xPathFragment, namespaceResolver, fieldValue, schemaType); |
| marshalRecord.closeStartElement(); |
| } else { |
| marshalRecord.closeStartElement(); |
| marshalRecord.characters(schemaType, fieldValue, null, false); |
| } |
| return true; |
| |
| } |
| |
| @Override |
| public CollectionReferenceMapping getMapping() { |
| return xmlCollectionReferenceMapping; |
| } |
| |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| } |