org.eclipse.persistence.internal.oxm.XMLChoiceObjectMappingNodeValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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 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:
* Purpose: This is how the XML Choice Collection Mapping is
* handled when used with the TreeObjectBuilder.
* @author mmacivor
*/
public class XMLChoiceObjectMappingNodeValue extends MappingNodeValue {
private NodeValue choiceElementNodeValue;
private Map 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();
}
@Override
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 entry: ((Map)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<>();
}
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;
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) {
return this.marshal(xPathFragment, marshalRecord, object, session, namespaceResolver, ObjectMarshalContext.getInstance());
}
@Override
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);
}
@Override
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) 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 sourceFields = null;
theClass = valueClass;
while(theClass != null) {
sourceFields = (List) 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;
}
@Override
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);
}
}
@Override
public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) {
return this.choiceElementNodeValue.startElement(xPathFragment, unmarshalRecord, atts);
}
@Override
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.
*
*/
@Override
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();
}
}