/******************************************************************************* * Copyright (c) 2013, 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: * 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.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.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.security.PrivilegedAccessHelper; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.oxm.XMLContext; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.oxm.sequenced.SequencedObject; public class XPathObjectBuilder extends CoreObjectBuilder<CoreAbstractRecord, CoreAbstractSession, CoreField, CoreMapping> implements ObjectBuilder { public static final String CYCLE_RECOVERABLE = "com.sun.xml.bind.CycleRecoverable"; public static final String CYCLE_RECOVERABLE_CONTEXT = "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, new Class[] { 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 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(); } public List<ContainerValue> getContainerValues() { return this.containerValues; } public List<ContainerValue> getDefaultEmptyContainerValues() { return this.defaultEmptyContainerValues; } @Override public CoreDescriptor getDescriptor() { return descriptor; } @Override public CoreMapping getMappingForField(CoreField field) { throw new UnsupportedOperationException(); } public List<NullCapableValue> getNullCapableValues() { return this.nullCapableValues; } @Override public XPathNode getRootXPathNode() { lazyInitialize(); return this.rootXPathNode; } 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 (Exception e) { } } @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<Field, NodeValue>(); 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()); } }