blob: 487197f5a7904b94518423c0ad94defaec747e63 [file] [log] [blame]
/*
* Copyright (c) 2013, 2021 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:
// Blaise Doughan - 2.5 - initial implementation
package org.eclipse.persistence.internal.oxm;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import javax.xml.namespace.QName;
import org.eclipse.persistence.core.descriptors.CoreDescriptor;
import org.eclipse.persistence.core.mappings.CoreMapping;
import org.eclipse.persistence.core.mappings.transformers.CoreFieldTransformer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.descriptors.CoreObjectBuilder;
import org.eclipse.persistence.internal.core.helper.CoreField;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractRecord;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.oxm.mappings.AnyAttributeMapping;
import org.eclipse.persistence.internal.oxm.mappings.AnyCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.AnyObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.BinaryDataCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.BinaryDataMapping;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.CollectionReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.CompositeCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.CompositeObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.DirectCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.DirectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.FragmentCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.FragmentMapping;
import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.mappings.ObjectReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.TransformationMapping;
import org.eclipse.persistence.internal.oxm.mappings.VariableXPathCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.VariableXPathObjectMapping;
import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecord;
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.SequencedMarshalContext;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.mappings.AttributeAccessor;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.oxm.XMLContext;
import org.eclipse.persistence.oxm.XMLMarshaller;
import org.eclipse.persistence.oxm.XMLUnmarshaller;
import org.eclipse.persistence.oxm.mappings.UnmarshalKeepAsElementPolicy;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.sequenced.SequencedObject;
import org.eclipse.persistence.sessions.Session;
public class XPathObjectBuilder extends CoreObjectBuilder<CoreAbstractRecord, CoreAbstractSession, CoreField, CoreMapping> implements ObjectBuilder {
public static final String CYCLE_RECOVERABLE = "org.glassfish.jaxb.runtime.CycleRecoverable";
public static final String CYCLE_RECOVERABLE_CONTEXT = "org.glassfish.jaxb.runtime.CycleRecoverable$Context";
private static final String CYCLE_RECOVERABLE_OLD = "com.sun.xml.bind.CycleRecoverable";
private static final String CYCLE_RECOVERABLE_CONTEXT_OLD = "com.sun.xml.bind.CycleRecoverable$Context";
public static final String ON_CYCLE_DETECTED = "onCycleDetected";
private List<ContainerValue> containerValues;
private int counter = 0;
private Class cycleRecoverableClass = null;
private Class cycleRecoverableContextClass = null;
private List<ContainerValue> defaultEmptyContainerValues; //a list of container values that have isDefaultEmptyContainer() set to true
private CoreDescriptor descriptor;
private volatile boolean initialized = false;
private List<NullCapableValue> nullCapableValues;
private XPathNode rootXPathNode;
private List<TransformationMapping> transformationMappings;
private boolean xsiTypeIndicatorField;
public XPathObjectBuilder(CoreDescriptor descriptor) {
this.descriptor = descriptor;
this.rootXPathNode = new XPathNode();
}
private XPathNode addChild(XPathFragment xPathFragment, NodeValue nodeValue, NamespaceResolver namespaceResolver) {
return rootXPathNode.addChild(xPathFragment, nodeValue, namespaceResolver);
}
@Override
public boolean addClassIndicatorFieldToRow(AbstractMarshalRecord abstractMarshalRecord) {
if (descriptor.hasInheritance() && !xsiTypeIndicatorField) {
descriptor.getInheritancePolicy().addClassIndicatorFieldToRow((CoreAbstractRecord) abstractMarshalRecord);
return true;
}
return false;
}
private void addContainerValue(ContainerValue containerValue) {
if (null == this.containerValues) {
this.containerValues = new ArrayList();
}
containerValue.setIndex(counter++);
this.containerValues.add(containerValue);
if(containerValue.isDefaultEmptyContainer()){
addDefaultEmptyContainerValue(containerValue);
}
}
private void addDefaultEmptyContainerValue(ContainerValue containerValue){
if (null == this.defaultEmptyContainerValues) {
this.defaultEmptyContainerValues = new ArrayList();
}
this.defaultEmptyContainerValues.add(containerValue);
}
@Override
public List<Namespace> addExtraNamespacesToNamespaceResolver(Descriptor desc, AbstractMarshalRecord marshalRecord, CoreAbstractSession session, boolean allowOverride, boolean ignoreEqualResolvers) {
if (rootXPathNode.getNonAttributeChildren() == null) {
return null;
} else {
return marshalRecord.addExtraNamespacesToNamespaceResolver(desc, session, allowOverride, ignoreEqualResolvers);
}
}
private void addNullCapableValue(NullCapableValue nullCapableValue) {
if (null == this.nullCapableValues) {
this.nullCapableValues = new ArrayList();
}
this.nullCapableValues.add(nullCapableValue);
}
public void addTransformationMapping(TransformationMapping transformationMapping) {
if (null == this.transformationMappings) {
this.transformationMappings = new ArrayList();
}
transformationMappings.add(transformationMapping);
}
/**
* Return a new instance of the receiver's javaClass.
*/
@Override
public Object buildNewInstance() {
return this.descriptor.getInstantiationPolicy().buildNewInstance();
}
@Override
public XMLRecord buildRow(XMLRecord record, Object object,
CoreAbstractSession session, Marshaller marshaller,
XPathFragment rootFragment) {
lazyInitialize();
XPathNode textNode = rootXPathNode.getTextNode();
List<XPathNode> nonAttributeChildren = rootXPathNode.getNonAttributeChildren();
if (null == textNode && null == nonAttributeChildren) {
return record;
}
Descriptor xmlDescriptor = (Descriptor) descriptor;
XPathNode node = rootXPathNode;
MarshalRecord marshalRecord = (MarshalRecord) record;
QName schemaType = null;
if (marshalRecord.getCycleDetectionStack().contains(object, marshaller.isEqualUsingIdenity())) {
if (cycleRecoverableClass == null) {
initCycleRecoverableClasses();
}
if (cycleRecoverableClass != null && cycleRecoverableClass.isAssignableFrom(object.getClass())) {
try {
Object jaxbMarshaller = marshaller.getProperty(Constants.JAXB_MARSHALLER);
// Create a proxy instance of CycleRecoverable$Context, a parameter to
// the onCycleDetected method
Object contextProxy = CycleRecoverableContextProxy.getProxy(cycleRecoverableContextClass, jaxbMarshaller);
// Invoke onCycleDetected method, passing in proxy, and reset
// 'object' to the returned value
Method onCycleDetectedMethod = object.getClass().getMethod(ON_CYCLE_DETECTED, cycleRecoverableContextClass);
object = PrivilegedAccessHelper.invokeMethod(onCycleDetectedMethod, object, new Object[] { contextProxy });
} catch (Exception e) {
throw XMLMarshalException.marshalException(e);
}
// Returned object might have a different descriptor
xmlDescriptor = (Descriptor) session.getDescriptor(object.getClass());
if (xmlDescriptor != null) {
node = ((ObjectBuilder) xmlDescriptor.getObjectBuilder()).getRootXPathNode();
} else {
node = null;
}
// Push new object
marshalRecord.getCycleDetectionStack().push(object);
// Write xsi:type if onCycleDetected returned an object of a type different than the one mapped
if (xmlDescriptor != descriptor) {
if (xmlDescriptor == null) {
schemaType = record.getConversionManager().schemaType(object.getClass());
} else {
schemaType = xmlDescriptor.getSchemaReference().getSchemaContextAsQName();
}
marshalRecord.writeXsiTypeAttribute(xmlDescriptor, schemaType.getNamespaceURI(), schemaType.getLocalPart(), schemaType.getPrefix(), false);
}
} else {
// Push the duplicate object anyway, so that we can get the complete cycle string
marshalRecord.getCycleDetectionStack().push(object);
throw XMLMarshalException.objectCycleDetected(marshalRecord.getCycleDetectionStack().getCycleString());
}
} else {
marshalRecord.getCycleDetectionStack().push(object);
}
NamespaceResolver namespaceResolver = null;
if (xmlDescriptor != null) {
namespaceResolver = xmlDescriptor.getNamespaceResolver();
}
MarshalContext marshalContext = null;
if (xmlDescriptor != null && xmlDescriptor.isSequencedObject()) {
SequencedObject sequencedObject = (SequencedObject) object;
marshalContext = new SequencedMarshalContext(sequencedObject.getSettings());
} else {
marshalContext = ObjectMarshalContext.getInstance();
}
if (null == nonAttributeChildren) {
textNode.marshal((MarshalRecord) record, object, session, namespaceResolver, marshaller, marshalContext, rootFragment);
} else {
if (node == null) {
// No descriptor for this object, so manually create a MappingNodeValue and marshal it
XPathNode n = new XPathNode();
CompositeObjectMapping<AbstractSession, AttributeAccessor, ContainerPolicy, Converter, ClassDescriptor, DatabaseField, XMLMarshaller, Session, UnmarshalKeepAsElementPolicy, XMLUnmarshaller, org.eclipse.persistence.oxm.record.XMLRecord> m = new XMLCompositeObjectMapping();
m.setXPath(".");
XMLCompositeObjectMappingNodeValue nv = new XMLCompositeObjectMappingNodeValue(m);
n.setMarshalNodeValue(nv);
nv.marshalSingleValue(new XPathFragment("."), marshalRecord, null, object, session, namespaceResolver, marshalContext);
} else {
for (int x = 0, size = marshalContext.getNonAttributeChildrenSize(node); x < size; x++) {
XPathNode xPathNode = (XPathNode) marshalContext.getNonAttributeChild(x, node);
xPathNode.marshal((MarshalRecord) record, object, session, namespaceResolver, marshaller, marshalContext.getMarshalContext(x), rootFragment);
}
}
}
marshalRecord.getCycleDetectionStack().pop();
return record;
}
@Override
public Class classFromRow(UnmarshalRecord record, CoreAbstractSession session) {
return descriptor.getInheritancePolicy().classFromRow((CoreAbstractRecord) record, session);
}
/**
* Create a new row/record for the object builder.
* This allows subclasses to define different record types.
*/
@Override
public CoreAbstractRecord createRecord(CoreAbstractSession session) {
UnmarshalRecordImpl record = new UnmarshalRecordImpl(this);
record.setSession(session);
return record;
}
@Override
public Object extractPrimaryKeyFromObject(Object object, CoreAbstractSession session) {
throw new UnsupportedOperationException();
}
@Override
public List<ContainerValue> getContainerValues() {
return this.containerValues;
}
@Override
public List<ContainerValue> getDefaultEmptyContainerValues() {
return this.defaultEmptyContainerValues;
}
@Override
public CoreDescriptor getDescriptor() {
return descriptor;
}
@Override
public CoreMapping getMappingForField(CoreField field) {
throw new UnsupportedOperationException();
}
@Override
public List<NullCapableValue> getNullCapableValues() {
return this.nullCapableValues;
}
@Override
public XPathNode getRootXPathNode() {
lazyInitialize();
return this.rootXPathNode;
}
@Override
public List<TransformationMapping> getTransformationMappings() {
return this.transformationMappings;
}
private void initCycleRecoverableClasses() {
try {
this.cycleRecoverableClass = PrivilegedAccessHelper.getClassForName(CYCLE_RECOVERABLE);
this.cycleRecoverableContextClass = PrivilegedAccessHelper.getClassForName(CYCLE_RECOVERABLE_CONTEXT);
} catch (Throwable e) {
//try old one
try {
this.cycleRecoverableClass = PrivilegedAccessHelper.getClassForName(CYCLE_RECOVERABLE_OLD);
this.cycleRecoverableContextClass = PrivilegedAccessHelper.getClassForName(CYCLE_RECOVERABLE_CONTEXT_OLD);
} catch (Throwable e2) {
//ignore
}
}
}
@Override
public boolean isXsiTypeIndicatorField() {
return xsiTypeIndicatorField;
}
void lazyInitialize() {
if(initialized) {
return;
}
synchronized(this) {
if(initialized) {
return;
}
Descriptor xmlDescriptor = (Descriptor) descriptor;
// MAPPINGS
Iterator mappingIterator = xmlDescriptor.getMappings().iterator();
Iterator fieldTransformerIterator;
Mapping xmlMapping;
// Transformation Mapping
TransformationMapping transformationMapping;
FieldTransformerNodeValue fieldTransformerNodeValue;
Object[] nextFieldToTransformer;
// Simple Type Translator
TypeNodeValue typeNodeValue;
NodeValue mappingNodeValue = null;
Field xmlField;
while (mappingIterator.hasNext()) {
xmlMapping = (Mapping)mappingIterator.next();
xmlField = (Field)xmlMapping.getField();
if (xmlMapping.isTransformationMapping()) {
transformationMapping = (TransformationMapping)xmlMapping;
addTransformationMapping(transformationMapping);
fieldTransformerIterator = transformationMapping.getFieldToTransformers().iterator();
while (fieldTransformerIterator.hasNext()) {
fieldTransformerNodeValue = new FieldTransformerNodeValue(transformationMapping);
nextFieldToTransformer = (Object[])fieldTransformerIterator.next();
xmlField = (Field)nextFieldToTransformer[0];
fieldTransformerNodeValue.setXMLField(xmlField);
fieldTransformerNodeValue.setFieldTransformer((CoreFieldTransformer)nextFieldToTransformer[1]);
addChild(xmlField.getXPathFragment(), fieldTransformerNodeValue, xmlDescriptor.getNamespaceResolver());
}
} else {
if (xmlMapping.isAbstractDirectMapping()) {
mappingNodeValue = new XMLDirectMappingNodeValue((DirectMapping)xmlMapping);
} else if (xmlMapping.isAbstractCompositeObjectMapping()) {
mappingNodeValue = new XMLCompositeObjectMappingNodeValue((CompositeObjectMapping)xmlMapping);
} else if (xmlMapping.isAbstractCompositeCollectionMapping()) {
CompositeCollectionMapping collectionMapping = (CompositeCollectionMapping) xmlMapping;
mappingNodeValue = new XMLCompositeCollectionMappingNodeValue(collectionMapping);
if (collectionMapping.getWrapperNullPolicy() != null) {
addChild(xmlField.getXPathFragment(), new CollectionGroupingElementNodeValue((ContainerValue) mappingNodeValue), xmlDescriptor.getNamespaceResolver());
}
} else if (xmlMapping.isAbstractCompositeDirectCollectionMapping()) {
DirectCollectionMapping collectionMapping = (DirectCollectionMapping) xmlMapping;
mappingNodeValue = new XMLCompositeDirectCollectionMappingNodeValue(collectionMapping);
if (collectionMapping.getWrapperNullPolicy() != null) {
addChild(xmlField.getXPathFragment(), new CollectionGroupingElementNodeValue((ContainerValue) mappingNodeValue), xmlDescriptor.getNamespaceResolver());
}
} else if (xmlMapping instanceof InverseReferenceMapping) {
xmlMapping = (Mapping)((InverseReferenceMapping)xmlMapping).getInlineMapping();
if(xmlMapping == null){
continue;
}
xmlField = (Field)xmlMapping.getField();
if(xmlMapping.isAbstractCompositeCollectionMapping()){
mappingNodeValue=new XMLCompositeCollectionMappingNodeValue((CompositeCollectionMapping)xmlMapping, true);
}
if(xmlMapping.isAbstractCompositeObjectMapping()){
mappingNodeValue=new XMLCompositeObjectMappingNodeValue((CompositeObjectMapping)xmlMapping, true);
}
} else if (xmlMapping instanceof VariableXPathCollectionMapping) {
mappingNodeValue = new XMLVariableXPathCollectionMappingNodeValue((VariableXPathCollectionMapping)xmlMapping);
} else if (xmlMapping instanceof VariableXPathObjectMapping){
mappingNodeValue = new XMLVariableXPathObjectMappingNodeValue((VariableXPathObjectMapping)xmlMapping);
} else if (xmlMapping instanceof AnyObjectMapping) {
mappingNodeValue = new XMLAnyObjectMappingNodeValue((AnyObjectMapping)xmlMapping);
} else if (xmlMapping instanceof AnyCollectionMapping) {
mappingNodeValue = new XMLAnyCollectionMappingNodeValue((AnyCollectionMapping)xmlMapping);
} else if (xmlMapping instanceof AnyAttributeMapping) {
mappingNodeValue = new XMLAnyAttributeMappingNodeValue((AnyAttributeMapping)xmlMapping);
} else if (xmlMapping instanceof BinaryDataMapping) {
mappingNodeValue = new XMLBinaryDataMappingNodeValue((BinaryDataMapping)xmlMapping);
} else if (xmlMapping instanceof BinaryDataCollectionMapping) {
mappingNodeValue = new XMLBinaryDataCollectionMappingNodeValue((BinaryDataCollectionMapping)xmlMapping);
} else if (xmlMapping instanceof FragmentMapping) {
mappingNodeValue = new XMLFragmentMappingNodeValue((FragmentMapping)xmlMapping);
} else if (xmlMapping instanceof FragmentCollectionMapping) {
mappingNodeValue = new XMLFragmentCollectionMappingNodeValue((FragmentCollectionMapping)xmlMapping);
} else if (xmlMapping instanceof CollectionReferenceMapping) {
CollectionReferenceMapping xmlColMapping = (CollectionReferenceMapping)xmlMapping;
List fields = xmlColMapping.getFields();
Field xmlColMappingField = (Field) xmlColMapping.getField();
XPathNode branchNode;
if(null == xmlColMappingField) {
if(fields.size() > 1 && !xmlColMapping.usesSingleNode()) {
addChild(XPathFragment.SELF_FRAGMENT, new XMLCollectionReferenceMappingMarshalNodeValue(xmlColMapping), xmlDescriptor.getNamespaceResolver());
}
branchNode = rootXPathNode;
} else {
branchNode = addChild(((Field) xmlColMapping.getField()).getXPathFragment(), new XMLCollectionReferenceMappingMarshalNodeValue(xmlColMapping), xmlDescriptor.getNamespaceResolver());
}
int containerIndex = -1;
for (int i = 0, size = fields.size(); i < size; i++) {
Field xmlFld = (Field)fields.get(i);
mappingNodeValue = new XMLCollectionReferenceMappingNodeValue(xmlColMapping, xmlFld);
if(i == 0){
addContainerValue((ContainerValue)mappingNodeValue);
containerIndex = ((ContainerValue)mappingNodeValue).getIndex();
}else{
((ContainerValue)mappingNodeValue).setIndex(containerIndex);
}
branchNode.addChild(xmlFld.getXPathFragment(), mappingNodeValue, xmlDescriptor.getNamespaceResolver());
}
continue;
} else if (xmlMapping instanceof ObjectReferenceMapping) {
ObjectReferenceMapping xmlORMapping = (ObjectReferenceMapping)xmlMapping;
Iterator fieldIt = xmlORMapping.getFields().iterator();
while (fieldIt.hasNext()) {
Field xmlFld = (Field)fieldIt.next();
mappingNodeValue = new XMLObjectReferenceMappingNodeValue(xmlORMapping, xmlFld);
addChild(xmlFld.getXPathFragment(), mappingNodeValue, xmlDescriptor.getNamespaceResolver());
}
continue;
} else if (xmlMapping instanceof ChoiceObjectMapping) {
ChoiceObjectMapping xmlChoiceMapping = (ChoiceObjectMapping)xmlMapping;
Iterator fields = xmlChoiceMapping.getChoiceElementMappings().keySet().iterator();
Field firstField = (Field)fields.next();
XMLChoiceObjectMappingNodeValue firstNodeValue = new XMLChoiceObjectMappingNodeValue(xmlChoiceMapping, firstField);
firstNodeValue.setNullCapableNodeValue(firstNodeValue);
addChild(firstField.getXPathFragment(), firstNodeValue, xmlDescriptor.getNamespaceResolver());
while(fields.hasNext()) {
Field next = (Field)fields.next();
XMLChoiceObjectMappingNodeValue nodeValue = new XMLChoiceObjectMappingNodeValue(xmlChoiceMapping, next);
nodeValue.setNullCapableNodeValue(firstNodeValue);
addChild(next.getXPathFragment(), nodeValue, xmlDescriptor.getNamespaceResolver());
}
continue;
} else if(xmlMapping instanceof ChoiceCollectionMapping) {
ChoiceCollectionMapping xmlChoiceMapping = (ChoiceCollectionMapping)xmlMapping;
Iterator<Entry<Field, Mapping>> fields = xmlChoiceMapping.getChoiceElementMappings().entrySet().iterator();
Entry<Field, Mapping> firstEntry = fields.next();
Field firstField = firstEntry.getKey();
XMLChoiceCollectionMappingUnmarshalNodeValue unmarshalValue = new XMLChoiceCollectionMappingUnmarshalNodeValue(xmlChoiceMapping, firstField);
XMLChoiceCollectionMappingMarshalNodeValue marshalValue = new XMLChoiceCollectionMappingMarshalNodeValue(xmlChoiceMapping, firstField);
//The reason behind LinkedHashMap is the order of items when for-cycling HashMap.getEntrySet() or HashMap.getKeySet().
//This change fixes non-determinism (implementation in JDK8 has changed so the order is different (sometimes) than in JDK6 and JDK7).
HashMap<Field, NodeValue> fieldToNodeValues = new LinkedHashMap<>();
unmarshalValue.setContainerNodeValue(unmarshalValue);
unmarshalValue.setFieldToNodeValues(fieldToNodeValues);
if(xmlChoiceMapping.isMixedContent() && (xmlChoiceMapping.getMixedContentMapping() == firstEntry.getValue())) {
unmarshalValue.setIsMixedNodeValue(true);
marshalValue.setIsMixedNodeValue(true);
}
this.addContainerValue(unmarshalValue);
((ContainerValue)unmarshalValue.getChoiceElementNodeValue()).setIndex(unmarshalValue.getIndex());
fieldToNodeValues.put(firstField, unmarshalValue);
addChild(firstField.getXPathFragment(), unmarshalValue, xmlDescriptor.getNamespaceResolver());
addChild(firstField.getXPathFragment(), marshalValue, xmlDescriptor.getNamespaceResolver());
while(fields.hasNext()) {
Entry<Field, Mapping> nextEntry = fields.next();
Field nextField = nextEntry.getKey();
XMLChoiceCollectionMappingUnmarshalNodeValue nodeValue = new XMLChoiceCollectionMappingUnmarshalNodeValue(xmlChoiceMapping, nextField);
nodeValue.setContainerNodeValue(unmarshalValue);
nodeValue.setIndex(unmarshalValue.getIndex());
((ContainerValue)nodeValue.getChoiceElementNodeValue()).setIndex(unmarshalValue.getIndex());
addChild(nextField.getXPathFragment(), nodeValue, xmlDescriptor.getNamespaceResolver());
fieldToNodeValues.put(nextField, nodeValue);
if(xmlChoiceMapping.isMixedContent() && (xmlChoiceMapping.getMixedContentMapping() == nextEntry.getValue())) {
nodeValue.setIsMixedNodeValue(true);
}
}
if(xmlChoiceMapping.isAny()) {
XMLChoiceCollectionMappingUnmarshalNodeValue nodeValue = new XMLChoiceCollectionMappingUnmarshalNodeValue(xmlChoiceMapping, null, xmlChoiceMapping.getAnyMapping());
nodeValue.setContainerNodeValue(unmarshalValue);
nodeValue.setIndex(unmarshalValue.getIndex());
((ContainerValue)nodeValue.getChoiceElementNodeValue()).setIndex(unmarshalValue.getIndex());
addChild(null, nodeValue, xmlDescriptor.getNamespaceResolver());
fieldToNodeValues.put(null, nodeValue);
if(xmlChoiceMapping.isMixedContent()) {
nodeValue.setIsMixedNodeValue(true);
}
}
marshalValue.setFieldToNodeValues(fieldToNodeValues);
continue;
}
if (mappingNodeValue.isContainerValue()) {
addContainerValue((ContainerValue)mappingNodeValue);
}
if (mappingNodeValue.isNullCapableValue()) {
addNullCapableValue((NullCapableValue)mappingNodeValue);
}
if (xmlField != null) {
addChild(xmlField.getXPathFragment(), mappingNodeValue, xmlDescriptor.getNamespaceResolver());
} else {
addChild(null, mappingNodeValue, xmlDescriptor.getNamespaceResolver());
}
}
}
if (descriptor.hasInheritance()) {
Field indicatorField = (Field) descriptor
.getInheritancePolicy().getClassIndicatorField();
if (indicatorField != null) {
if (indicatorField.getLastXPathFragment().getNamespaceURI() != null
&& indicatorField
.getLastXPathFragment()
.getNamespaceURI()
.equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
&& indicatorField.getLastXPathFragment()
.getLocalName()
.equals(Constants.SCHEMA_TYPE_ATTRIBUTE)) {
xsiTypeIndicatorField = true;
}
}
}
initialized = true;
}
}
@Override
public boolean marshalAttributes(MarshalRecord marshalRecord, Object object, CoreAbstractSession session) {
lazyInitialize();
boolean hasValue = false;
NamespaceResolver namespaceResolver = ((Descriptor)descriptor).getNamespaceResolver();
List<XPathNode> attributeChildren = rootXPathNode.getAttributeChildren();
if (null != attributeChildren) {
ObjectMarshalContext objectMarshalContext = ObjectMarshalContext.getInstance();
for (XPathNode anAttributeChildren : attributeChildren) {
hasValue = anAttributeChildren.marshal(marshalRecord, object, session, namespaceResolver, null, objectMarshalContext, null) || hasValue;
}
}
if (rootXPathNode.getAnyAttributeNode() != null) {
hasValue = rootXPathNode.getAnyAttributeNode().marshal(marshalRecord, object, session, namespaceResolver, null, ObjectMarshalContext.getInstance(), null) || hasValue;
}
List<XPathNode> selfChildren = rootXPathNode.getSelfChildren();
if (null != selfChildren) {
for (XPathNode selfXPathNode : selfChildren) {
NodeValue marshalNodeValue = selfXPathNode.getMarshalNodeValue();
if(marshalNodeValue instanceof MappingNodeValue) {
Mapping selfMapping = ((MappingNodeValue) marshalNodeValue).getMapping();
Object value = selfMapping.getAttributeValueFromObject(object);
Descriptor referenceDescriptor = (Descriptor)selfMapping.getReferenceDescriptor();
Descriptor valueDescriptor;
if(value != null && (referenceDescriptor == null || referenceDescriptor.hasInheritance())){
valueDescriptor = (Descriptor)session.getDescriptor(value.getClass());
} else {
valueDescriptor = referenceDescriptor;
}
if(null != valueDescriptor) {
marshalRecord.addXsiTypeAndClassIndicatorIfRequired(valueDescriptor, referenceDescriptor, (Field) selfMapping.getField(), false);
}
}
selfXPathNode.marshalSelfAttributes(marshalRecord, object, session, namespaceResolver, marshalRecord.getMarshaller());
}
}
return hasValue;
}
@Override
public CoreAbstractRecord createRecordFromXMLContext(XMLContext context) {
return createRecord((AbstractSession)context.getSession());
}
}