/******************************************************************************* * 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: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.oxm; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.persistence.internal.core.helper.CoreField; import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; import org.eclipse.persistence.internal.oxm.mappings.BinaryDataMapping; import org.eclipse.persistence.internal.oxm.mappings.ChoiceObjectMapping; import org.eclipse.persistence.internal.oxm.mappings.CompositeObjectMapping; import org.eclipse.persistence.internal.oxm.mappings.DirectMapping; import org.eclipse.persistence.internal.oxm.mappings.Field; import org.eclipse.persistence.internal.oxm.mappings.Mapping; import org.eclipse.persistence.internal.oxm.mappings.ObjectReferenceMapping; 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.UnmarshalContext; import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord; import org.xml.sax.Attributes; /** * INTERNAL: * <p><b>Purpose</b>: This is how the XML Choice Collection Mapping is * handled when used with the TreeObjectBuilder.</p> * @author mmacivor */ public class XMLChoiceObjectMappingNodeValue extends MappingNodeValue { private NodeValue choiceElementNodeValue; private Map<Class, NodeValue> choiceElementNodeValues; private ChoiceObjectMapping xmlChoiceMapping; //The first node value of the choice will be registered as a null capable value. If any //of the choice elements get hit, this needs to be removed as a null value. private XMLChoiceObjectMappingNodeValue nullCapableNodeValue; private Field xmlField; public XMLChoiceObjectMappingNodeValue(ChoiceObjectMapping mapping, Field xmlField) { this.xmlChoiceMapping = mapping; this.xmlField = xmlField; initializeNodeValue(); } public boolean isOwningNode(XPathFragment xPathFragment) { return choiceElementNodeValue.isOwningNode(xPathFragment); } public void initializeNodeValue() { Mapping xmlMapping = (Mapping) xmlChoiceMapping.getChoiceElementMappings().get(xmlField); choiceElementNodeValue = getNodeValueForMapping(xmlMapping); //check for mappings to other classes with the same field for(Entry<Class, Mapping> entry: ((Map<Class, Mapping>)xmlChoiceMapping.getChoiceElementMappingsByClass()).entrySet()) { Field field = (Field) xmlChoiceMapping.getClassToFieldMappings().get(entry.getKey()); if(field != null && field.equals(this.xmlField)) { Mapping mappingForClass = entry.getValue(); if(mappingForClass != xmlMapping) { if(this.choiceElementNodeValues == null) { choiceElementNodeValues = new HashMap<Class, NodeValue>(); } choiceElementNodeValues.put(entry.getKey(), getNodeValueForMapping(mappingForClass)); } } } } private NodeValue getNodeValueForMapping(Mapping xmlMapping) { if(xmlMapping instanceof BinaryDataMapping){ return new XMLBinaryDataMappingNodeValue((BinaryDataMapping)xmlMapping); } else if(xmlMapping instanceof DirectMapping) { return new XMLDirectMappingNodeValue((DirectMapping)xmlMapping); } else if(xmlMapping instanceof ObjectReferenceMapping) { return new XMLObjectReferenceMappingNodeValue((ObjectReferenceMapping)xmlMapping, xmlField); } else { return new XMLCompositeObjectMappingNodeValue((CompositeObjectMapping)xmlMapping); } } public void setNullCapableNodeValue(XMLChoiceObjectMappingNodeValue nodeValue) { this.nullCapableNodeValue = nodeValue; } public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { return this.marshal(xPathFragment, marshalRecord, object, session, namespaceResolver, ObjectMarshalContext.getInstance()); } public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { if(xmlChoiceMapping.isReadOnly()) { return false; } Object value = xmlChoiceMapping.getFieldValue(object, session, marshalRecord); return this.marshalSingleValue(xPathFragment, marshalRecord, object, value, session, namespaceResolver, marshalContext); } public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { Class valueClass = null; if (value instanceof Root) { Root root = (Root)value; for(CoreField next: (List<CoreField>) this.xmlChoiceMapping.getFields()) { XPathFragment fragment = ((Field)next).getXPathFragment(); while(fragment != null && !fragment.nameIsText) { if(fragment.getNextFragment() == null || fragment.getHasText()) { if(fragment.getLocalName().equals(root.getLocalName())) { String fragUri = fragment.getNamespaceURI(); String namespaceUri = root.getNamespaceURI(); if((namespaceUri == null && fragUri == null) || (namespaceUri != null && fragUri != null && namespaceUri.equals(fragUri))) { if(next == this.xmlField) { return this.choiceElementNodeValue.marshalSingleValue(xPathFragment, marshalRecord, object, value, session, namespaceResolver, marshalContext); } else { //If this root is associated with another field, then return and let that NodeValue handle it return false; } } } } fragment = fragment.getNextFragment(); } } valueClass = root.getObject().getClass(); } if (value != null) { if(valueClass == null) { valueClass = value.getClass(); } Field fieldForClass = null; Class theClass = valueClass; while(theClass != null) { fieldForClass = (Field) xmlChoiceMapping.getClassToFieldMappings().get(valueClass); if(fieldForClass != null) { break; } theClass = theClass.getSuperclass(); } if (fieldForClass != null && fieldForClass.equals(this.xmlField)) { if(this.choiceElementNodeValues != null) { NodeValue nodeValue = this.choiceElementNodeValues.get(theClass); if(nodeValue != null) { return nodeValue.marshalSingleValue(xPathFragment, marshalRecord, object, value, session, namespaceResolver, marshalContext); } } return this.choiceElementNodeValue.marshalSingleValue(xPathFragment, marshalRecord, object, value, session, namespaceResolver, marshalContext); } List<Field> sourceFields = null; theClass = valueClass; while(theClass != null) { sourceFields = (List<Field>) xmlChoiceMapping.getClassToSourceFieldsMappings().get(theClass); if(sourceFields != null) { break; } theClass = theClass.getSuperclass(); } if (sourceFields != null && sourceFields.contains(this.xmlField)) { return this.choiceElementNodeValue.marshalSingleValue(xPathFragment, marshalRecord, object, value, session, namespaceResolver, marshalContext); } } return false; } public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { if(null != xmlChoiceMapping.getConverter()) { UnmarshalContext unmarshalContext = unmarshalRecord.getUnmarshalContext(); unmarshalRecord.setUnmarshalContext(new ChoiceUnmarshalContext(unmarshalContext, xmlChoiceMapping)); this.choiceElementNodeValue.endElement(xPathFragment, unmarshalRecord); unmarshalRecord.setUnmarshalContext(unmarshalContext); } else { this.choiceElementNodeValue.endElement(xPathFragment, unmarshalRecord); } } public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { return this.choiceElementNodeValue.startElement(xPathFragment, unmarshalRecord, atts); } public void setXPathNode(XPathNode xPathNode) { super.setXPathNode(xPathNode); this.choiceElementNodeValue.setXPathNode(xPathNode); if(this.choiceElementNodeValues != null) { for(NodeValue next:choiceElementNodeValues.values()) { next.setXPathNode(xPathNode); } } } /** * The underlying choice element node value will handle attributes. * */ public void attribute(UnmarshalRecord unmarshalRecord, String URI, String localName, String value) { this.choiceElementNodeValue.attribute(unmarshalRecord, URI, localName, value); } @Override public Mapping getMapping() { return this.xmlChoiceMapping; } @Override public boolean isWhitespaceAware() { return choiceElementNodeValue.isWhitespaceAware(); } }