/******************************************************************************* * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * 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; } public Object getContainerInstance() { return getContainerPolicy().containerInstance(); } public CoreContainerPolicy getContainerPolicy() { return xmlCollectionReferenceMapping.getContainerPolicy(); } @Override public CollectionReferenceMapping getMapping() { return xmlCollectionReferenceMapping; } public boolean getReuseContainer() { return xmlCollectionReferenceMapping.getReuseContainer(); } 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 */ 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 */ 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 */ public boolean isDefaultEmptyContainer() { return getMapping().isDefaultEmptyContainer(); } }