| /* |
| * Copyright (c) 1998, 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: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.internal.oxm; |
| |
| import java.lang.reflect.Modifier; |
| import java.util.List; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.core.queries.CoreAttributeGroup; |
| import org.eclipse.persistence.core.queries.CoreAttributeItem; |
| import org.eclipse.persistence.core.sessions.CoreSession; |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.exceptions.XMLMarshalException; |
| import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; |
| import org.eclipse.persistence.internal.oxm.mappings.CompositeObjectMapping; |
| import org.eclipse.persistence.internal.oxm.mappings.Descriptor; |
| import org.eclipse.persistence.internal.oxm.mappings.DirectMapping; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping; |
| import org.eclipse.persistence.internal.oxm.mappings.Mapping; |
| import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy; |
| 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.UnmarshalRecord; |
| import org.eclipse.persistence.internal.oxm.record.XMLReader; |
| import org.eclipse.persistence.internal.oxm.record.XMLRecord; |
| import org.eclipse.persistence.internal.oxm.record.deferred.CompositeObjectMappingContentHandler; |
| import org.eclipse.persistence.oxm.XMLRoot; |
| import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy; |
| import org.eclipse.persistence.platform.xml.XMLPlatformFactory; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| /** |
| * INTERNAL: |
| * <p><b>Purpose</b>: This is how the XML Composite Object Mapping is handled |
| * when used with the TreeObjectBuilder.</p> |
| */ |
| public class XMLCompositeObjectMappingNodeValue extends XMLRelationshipMappingNodeValue implements NullCapableValue { |
| private CompositeObjectMapping xmlCompositeObjectMapping; |
| private boolean isInverseReference; |
| |
| public XMLCompositeObjectMappingNodeValue(CompositeObjectMapping xmlCompositeObjectMapping) { |
| this.xmlCompositeObjectMapping = xmlCompositeObjectMapping; |
| } |
| |
| public XMLCompositeObjectMappingNodeValue(CompositeObjectMapping xmlCompositeObjectMapping, boolean isInverse) { |
| this(xmlCompositeObjectMapping); |
| isInverseReference = isInverse; |
| } |
| |
| @Override |
| public void attribute(UnmarshalRecord unmarshalRecord, String namespaceURI, String localName, String value) { |
| unmarshalRecord.removeNullCapableValue(this); |
| |
| Descriptor referenceDescriptor = (Descriptor) getMapping().getReferenceDescriptor(); |
| ObjectBuilder treeObjectBuilder = (ObjectBuilder) referenceDescriptor.getObjectBuilder(); |
| MappingNodeValue textMappingNodeValue = (MappingNodeValue) treeObjectBuilder.getRootXPathNode().getTextNode().getNodeValue(); |
| Mapping textMapping = textMappingNodeValue.getMapping(); |
| Object childObject = referenceDescriptor.getInstantiationPolicy().buildNewInstance(); |
| if(textMapping.isAbstractDirectMapping()) { |
| DirectMapping xmlDirectMapping = (DirectMapping) textMappingNodeValue.getMapping(); |
| Field xmlField = (Field) xmlDirectMapping.getField(); |
| Object realValue = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, (ConversionManager) unmarshalRecord.getSession().getDatasourcePlatform().getConversionManager(), unmarshalRecord); |
| Object convertedValue = xmlDirectMapping.getAttributeValue(realValue, unmarshalRecord.getSession(), unmarshalRecord); |
| xmlDirectMapping.setAttributeValueInObject(childObject, convertedValue); |
| } else { |
| Object oldChildObject = unmarshalRecord.getCurrentObject(); |
| CompositeObjectMapping nestedXMLCompositeObjectMapping = (CompositeObjectMapping) textMappingNodeValue.getMapping(); |
| unmarshalRecord.setCurrentObject(childObject); |
| textMappingNodeValue.attribute(unmarshalRecord, namespaceURI, localName, value); |
| unmarshalRecord.setCurrentObject(oldChildObject); |
| } |
| setAttributeValue(childObject, unmarshalRecord); |
| } |
| |
| /** |
| * Marshal any 'self' mapped attributes. |
| * |
| */ |
| @Override |
| public boolean marshalSelfAttributes(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, Marshaller marshaller) { |
| Object objectValue = xmlCompositeObjectMapping.getAttributeValueFromObject(object); |
| objectValue = xmlCompositeObjectMapping.convertObjectValueToDataValue(objectValue, session, marshaller); |
| Descriptor descriptor = (Descriptor)session.getDescriptor(objectValue); |
| if(descriptor != null){ |
| ObjectBuilder objectBuilder = (ObjectBuilder)descriptor.getObjectBuilder(); |
| return objectBuilder.marshalAttributes(marshalRecord, objectValue, session); |
| } else { |
| UnmarshalKeepAsElementPolicy keepAsElementPolicy = getMapping().getKeepAsElementPolicy(); |
| if(null != keepAsElementPolicy && (keepAsElementPolicy.isKeepAllAsElement() || keepAsElementPolicy.isKeepUnknownAsElement())) { |
| if(objectValue instanceof Node) { |
| Node rootNode = (Node)objectValue; |
| NamedNodeMap attributes = rootNode.getAttributes(); |
| for(int i = 0; i < attributes.getLength(); i++) { |
| Attr next = (Attr)attributes.item(i); |
| if(!(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(next.getNamespaceURI()))) { |
| marshalRecord.node(next, namespaceResolver); |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { |
| return 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 (xmlCompositeObjectMapping.isReadOnly()) { |
| return false; |
| } |
| int size =marshalRecord.getCycleDetectionStack().size(); |
| Object objectValue = marshalContext.getAttributeValue(object, xmlCompositeObjectMapping); |
| |
| if ((isInverseReference || xmlCompositeObjectMapping.getInverseReferenceMapping() != null) && objectValue != null && size >= 2) { |
| Object owner = marshalRecord.getCycleDetectionStack().get(size - 2); |
| if (objectValue.equals(owner)) { |
| return false; |
| } |
| } |
| |
| return this.marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext); |
| } |
| |
| |
| private boolean isNil(Object value) { |
| if (value instanceof XMLRoot) { |
| return ((XMLRoot)value).isNil(); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { |
| boolean isNilFlag = isNil(objectValue); |
| objectValue = xmlCompositeObjectMapping.convertObjectValueToDataValue(objectValue, session, marshalRecord.getMarshaller()); |
| if (null == objectValue) { |
| return xmlCompositeObjectMapping.getNullPolicy().compositeObjectMarshal(xPathFragment, marshalRecord, object, session, namespaceResolver); |
| } |
| XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); |
| if(xPathFragment.hasAttribute) { |
| ObjectBuilder tob = (ObjectBuilder) xmlCompositeObjectMapping.getReferenceDescriptor().getObjectBuilder(); |
| MappingNodeValue textMappingNodeValue = (MappingNodeValue) tob.getRootXPathNode().getTextNode().getMarshalNodeValue(); |
| Mapping textMapping = textMappingNodeValue.getMapping(); |
| if(textMapping.isAbstractDirectMapping()) { |
| DirectMapping xmlDirectMapping = (DirectMapping) textMapping; |
| Object fieldValue = xmlDirectMapping.getFieldValue(xmlDirectMapping.valueFromObject(objectValue, xmlDirectMapping.getField(), session), session, marshalRecord); |
| QName schemaType = ((Field) xmlDirectMapping.getField()).getSchemaTypeForValue(fieldValue, session); |
| if(fieldValue != null) { |
| marshalRecord.attribute(xPathFragment, namespaceResolver, fieldValue, schemaType); |
| } else { |
| XMLMarshalException ex = XMLMarshalException.nullValueNotAllowed(this.xmlCompositeObjectMapping.getAttributeName(), this.xmlCompositeObjectMapping.getDescriptor().getJavaClass().getName()); |
| try { |
| marshalRecord.getMarshaller().getErrorHandler().warning(new SAXParseException(null, null, ex)); |
| } catch(Exception saxException) { |
| throw ex; |
| } |
| } |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| return true; |
| } else { |
| return textMappingNodeValue.marshalSingleValue(xPathFragment, marshalRecord, objectValue, textMapping.getAttributeValueFromObject(objectValue), session, namespaceResolver, marshalContext); |
| } |
| } |
| boolean isSelfFragment = xPathFragment.isSelfFragment; |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| |
| UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeObjectMapping.getKeepAsElementPolicy(); |
| if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && objectValue instanceof Node) { |
| if (isSelfFragment) { |
| NodeList children = ((org.w3c.dom.Element) objectValue).getChildNodes(); |
| for (int i = 0, childrenLength = children.getLength(); i < childrenLength ; i++) { |
| Node next = children.item(i); |
| short nodeType = next.getNodeType(); |
| if (nodeType == Node.ELEMENT_NODE) { |
| marshalRecord.node(next, marshalRecord.getNamespaceResolver()); |
| return true; |
| } else if (nodeType == Node.TEXT_NODE) { |
| marshalRecord.characters(next.getNodeValue()); |
| return true; |
| } |
| } |
| return false; |
| } else { |
| marshalRecord.node((Node) objectValue, marshalRecord.getNamespaceResolver()); |
| return true; |
| } |
| } |
| Descriptor descriptor = (Descriptor)xmlCompositeObjectMapping.getReferenceDescriptor(); |
| if(descriptor == null){ |
| descriptor = (Descriptor) session.getDescriptor(objectValue.getClass()); |
| }else if(descriptor.hasInheritance()){ |
| Class<? extends Object> objectValueClass = objectValue.getClass(); |
| if(!(objectValueClass == descriptor.getJavaClass())){ |
| descriptor = (Descriptor) session.getDescriptor(objectValueClass); |
| } |
| } |
| |
| if(descriptor != null){ |
| marshalRecord.beforeContainmentMarshal(objectValue); |
| ObjectBuilder objectBuilder = (ObjectBuilder)descriptor.getObjectBuilder(); |
| |
| CoreAttributeGroup group = marshalRecord.getCurrentAttributeGroup(); |
| CoreAttributeItem item = group.getItem(getMapping().getAttributeName()); |
| CoreAttributeGroup nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP; |
| if(item != null) { |
| if(item.getGroups() != null) { |
| nestedGroup = item.getGroup(descriptor.getJavaClass()); |
| } |
| if(nestedGroup == null) { |
| nestedGroup = item.getGroup() == null?XMLRecord.DEFAULT_ATTRIBUTE_GROUP:item.getGroup(); |
| } |
| } |
| |
| marshalRecord.pushAttributeGroup(nestedGroup); |
| if (!(isSelfFragment || xPathFragment.nameIsText)) { |
| xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, objectBuilder, objectValue); |
| if (isNilFlag) { |
| marshalRecord.nilSimple(namespaceResolver); |
| } |
| } |
| |
| List extraNamespaces = null; |
| if (marshalRecord.getNamespaceResolver() != null && descriptor.getNamespaceResolver() != null) { |
| for (String prefix: descriptor.getNamespaceResolver().getPrefixesToNamespaces().keySet()) { |
| if (!marshalRecord.getNamespaceResolver().hasPrefix(prefix)) { |
| marshalRecord.setEqualNamespaceResolvers(false); |
| break; |
| } |
| } |
| } |
| if (!marshalRecord.hasEqualNamespaceResolvers()) { |
| extraNamespaces = objectBuilder.addExtraNamespacesToNamespaceResolver(descriptor, marshalRecord, session, true, false); |
| writeExtraNamespaces(extraNamespaces, marshalRecord, session); |
| } |
| if(!isSelfFragment) { |
| marshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, (Descriptor) xmlCompositeObjectMapping.getReferenceDescriptor(), (Field)xmlCompositeObjectMapping.getField(), false); |
| } |
| |
| objectBuilder.buildRow(marshalRecord, objectValue, session, marshalRecord.getMarshaller(), xPathFragment); |
| marshalRecord.afterContainmentMarshal(object, objectValue); |
| marshalRecord.popAttributeGroup(); |
| |
| if (!(isSelfFragment || xPathFragment.nameIsText())) { |
| marshalRecord.endElement(xPathFragment, namespaceResolver); |
| } |
| marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); |
| } else { |
| if(Constants.UNKNOWN_OR_TRANSIENT_CLASS.equals(xmlCompositeObjectMapping.getReferenceClassName())){ |
| throw XMLMarshalException.descriptorNotFoundInProject(objectValue.getClass().getName()); |
| } |
| |
| if (!(isSelfFragment || xPathFragment.nameIsText())) { |
| xPathNode.startElement(marshalRecord, xPathFragment, object, session, namespaceResolver, null, objectValue); |
| } |
| QName schemaType = ((Field) xmlCompositeObjectMapping.getField()).getSchemaTypeForValue(objectValue,session); |
| |
| updateNamespaces(schemaType, marshalRecord,((Field)xmlCompositeObjectMapping.getField())); |
| marshalRecord.characters(schemaType, objectValue, null, false); |
| |
| if (!(isSelfFragment || xPathFragment.nameIsText())) { |
| marshalRecord.endElement(xPathFragment, namespaceResolver); |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { |
| try { |
| unmarshalRecord.removeNullCapableValue(this); |
| |
| Descriptor xmlDescriptor = (Descriptor)xmlCompositeObjectMapping.getReferenceDescriptor(); |
| if (null == xmlDescriptor) { |
| xmlDescriptor = findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, xmlCompositeObjectMapping,xmlCompositeObjectMapping.getKeepAsElementPolicy()); |
| |
| if(xmlDescriptor == null){ |
| if(xmlCompositeObjectMapping.getField() != null){ |
| //try leaf element type |
| QName leafType = ((Field)xmlCompositeObjectMapping.getField()).getLastXPathFragment().getLeafElementType(); |
| if (leafType != null) { |
| XPathFragment frag = new XPathFragment(); |
| frag.setNamespaceAware(unmarshalRecord.isNamespaceAware()); |
| String xpath = leafType.getLocalPart(); |
| String uri = leafType.getNamespaceURI(); |
| if (uri != null && uri.length() > 0) { |
| frag.setNamespaceURI(uri); |
| String prefix = ((Descriptor)xmlCompositeObjectMapping.getDescriptor()).getNonNullNamespaceResolver().resolveNamespaceURI(uri); |
| if (prefix != null && prefix.length() > 0) { |
| xpath = prefix + Constants.COLON + xpath; |
| } |
| } |
| frag.setXPath(xpath); |
| Context xmlContext = unmarshalRecord.getUnmarshaller().getContext(); |
| xmlDescriptor = xmlContext.getDescriptorByGlobalType(frag); |
| } |
| } |
| } |
| |
| UnmarshalKeepAsElementPolicy policy = xmlCompositeObjectMapping.getKeepAsElementPolicy(); |
| if (null != policy && ((xmlDescriptor == null && policy.isKeepUnknownAsElement()) || policy.isKeepAllAsElement())) { |
| QName schemaType = unmarshalRecord.getTypeQName(); |
| if(schemaType == null){ |
| schemaType = ((Field)xmlCompositeObjectMapping.getField()).getSchemaType(); |
| unmarshalRecord.setTypeQName(schemaType); |
| } |
| if(schemaType != null){ |
| Class<Object> theClass = unmarshalRecord.getConversionManager().javaType(schemaType); |
| if(theClass == null){ |
| setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); |
| return true; |
| } |
| }else{ |
| setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); |
| return true; |
| } |
| } |
| } |
| |
| // |
| // Null Composite Objects are marshalled in 2 ways when the input XML node is empty. |
| // (1) as null |
| // - isNullRepresentedByEmptyNode = true |
| // (2) as empty object |
| // - isNullRepresentedByEmptyNode = false |
| // A deferred contentHandler is used to queue events until we are able to determine |
| // whether we are in one of empty/simple/complex state. |
| // Control is returned to the UnmarshalHandler after creation of (1) or (2) above is started. |
| // Object creation was deferred to the DeferredContentHandler |
| // |
| // Check if we need to create the DeferredContentHandler based on policy state |
| AbstractNullPolicy nullPolicy = xmlCompositeObjectMapping.getNullPolicy(); |
| if(nullPolicy.isNullRepresentedByEmptyNode()) { |
| String qnameString = xPathFragment.getLocalName(); |
| if(xPathFragment.getPrefix() != null) { |
| qnameString = xPathFragment.getPrefix() + Constants.COLON + qnameString; |
| } |
| if(null != xmlDescriptor) { |
| // Process null capable value |
| CompositeObjectMappingContentHandler aHandler = new CompositeObjectMappingContentHandler(// |
| unmarshalRecord, this, xmlCompositeObjectMapping, atts, xPathFragment, xmlDescriptor); |
| // Send control to the handler |
| aHandler.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), qnameString, atts); |
| XMLReader xmlReader = unmarshalRecord.getXMLReader(); |
| xmlReader.setContentHandler(aHandler); |
| xmlReader.setLexicalHandler(aHandler); |
| } |
| } else { |
| if(unmarshalRecord.getXMLReader().isNullRecord(nullPolicy, atts, unmarshalRecord) && nullPolicy.ignoreAttributesForNil()){ |
| xmlCompositeObjectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), null); |
| } else { |
| Field xmlFld = (Field)this.xmlCompositeObjectMapping.getField(); |
| if (xmlFld.hasLastXPathFragment()) { |
| unmarshalRecord.setLeafElementType(xmlFld.getLastXPathFragment().getLeafElementType()); |
| } |
| processChild(xPathFragment, unmarshalRecord, atts, xmlDescriptor, xmlCompositeObjectMapping); |
| } |
| } |
| |
| } catch (SAXException e) { |
| throw XMLMarshalException.unmarshalException(e); |
| } |
| return true; |
| } |
| |
| @Override |
| public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { |
| if(unmarshalRecord.isNil() && xmlCompositeObjectMapping.getNullPolicy().isNullRepresentedByXsiNil() && (unmarshalRecord.getChildRecord() == null)){ |
| unmarshalRecord.resetStringBuffer(); |
| return; |
| } |
| |
| if (null == unmarshalRecord.getChildRecord()) { |
| SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); |
| UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeObjectMapping.getKeepAsElementPolicy(); |
| |
| if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && builder.getNodes().size() != 0) { |
| |
| if(unmarshalRecord.getTypeQName() != null){ |
| Class<Object> theClass = unmarshalRecord.getConversionManager().javaType(unmarshalRecord.getTypeQName()); |
| if(theClass != null){ |
| //handle simple text |
| endElementProcessText(unmarshalRecord, xmlCompositeObjectMapping, xPathFragment, null); |
| return; |
| } |
| } |
| |
| if (builder.getDocument() != null) { |
| setOrAddAttributeValueForKeepAsElement(builder, xmlCompositeObjectMapping, xmlCompositeObjectMapping, unmarshalRecord, false, null); |
| return; |
| } |
| }else{ |
| //handle simple text |
| endElementProcessText(unmarshalRecord, xmlCompositeObjectMapping, xPathFragment, null); |
| return; |
| } |
| |
| } else { |
| Object object = unmarshalRecord.getChildRecord().getCurrentObject(); |
| setAttributeValue(object, unmarshalRecord); |
| unmarshalRecord.setChildRecord(null); |
| } |
| } |
| |
| private void setAttributeValue(Object object, UnmarshalRecord unmarshalRecord) { |
| InverseReferenceMapping inverseReferenceMapping = xmlCompositeObjectMapping.getInverseReferenceMapping(); |
| |
| //If isInverseReference then this mapping is an inlineMapping of an InverseReference |
| if(null != inverseReferenceMapping){ |
| if(inverseReferenceMapping.getContainerPolicy() == null) { |
| Object currentValue = inverseReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(object); |
| if( !isInverseReference || (currentValue == null && isInverseReference)) { |
| inverseReferenceMapping.getAttributeAccessor().setAttributeValueInObject(object, unmarshalRecord.getCurrentObject()); |
| } |
| } else { |
| Object backpointerContainer = inverseReferenceMapping.getAttributeAccessor().getAttributeValueFromObject(object); |
| if(backpointerContainer == null) { |
| backpointerContainer = inverseReferenceMapping.getContainerPolicy().containerInstance(); |
| inverseReferenceMapping.getAttributeAccessor().setAttributeValueInObject(object, backpointerContainer); |
| } |
| inverseReferenceMapping.getContainerPolicy().addInto(unmarshalRecord.getCurrentObject(), backpointerContainer, unmarshalRecord.getSession()); |
| } |
| } |
| |
| object = xmlCompositeObjectMapping.convertDataValueToObjectValue(object, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); |
| // Set the child object on the parent |
| unmarshalRecord.setAttributeValue(object, xmlCompositeObjectMapping); |
| |
| } |
| |
| @Override |
| public void endSelfNodeValue(UnmarshalRecord unmarshalRecord, UnmarshalRecord selfRecord, Attributes attributes) { |
| if(xmlCompositeObjectMapping.getNullPolicy().valueIsNull(attributes)){ |
| xmlCompositeObjectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), null); |
| return; |
| } |
| unmarshalRecord.removeNullCapableValue(this); |
| if (unmarshalRecord.getFragmentBuilder().getDocument() != null) { |
| UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlCompositeObjectMapping.getKeepAsElementPolicy(); |
| |
| SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); |
| if ((((keepAsElementPolicy.isKeepUnknownAsElement()) || (keepAsElementPolicy.isKeepAllAsElement())))&& (builder.getNodes().size() != 0) ) { |
| if(unmarshalRecord.getTypeQName() != null){ |
| Class<Object> theClass = unmarshalRecord.getConversionManager().javaType(unmarshalRecord.getTypeQName()); |
| if(theClass != null){ |
| //handle simple text |
| endElementProcessText(unmarshalRecord, xmlCompositeObjectMapping, null, null); |
| return; |
| } |
| } |
| Element element = (Element) builder.getNodes().remove(builder.getNodes().size() -1); |
| |
| String xsiType = null; |
| if(null != element) { |
| if(unmarshalRecord.isNamespaceAware()){ |
| xsiType = element.getAttributeNS(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_TYPE_ATTRIBUTE); |
| }else{ |
| xsiType = element.getAttribute(Constants.SCHEMA_TYPE_ATTRIBUTE); |
| } |
| } |
| if(null != xsiType) { |
| xsiType = xsiType.trim(); |
| Object value = element; |
| String namespace = null; |
| int colonIndex = xsiType.indexOf(unmarshalRecord.getNamespaceSeparator()); |
| if (colonIndex > -1) { |
| String prefix = xsiType.substring(0, colonIndex); |
| namespace = unmarshalRecord.resolveNamespacePrefix(prefix); |
| if(null == namespace) { |
| namespace = XMLPlatformFactory.getInstance().getXMLPlatform().resolveNamespacePrefix(element, prefix); |
| } |
| QName qName = new QName(namespace, xsiType.substring(colonIndex + 1)); |
| ConversionManager conversionManager = unmarshalRecord.getConversionManager(); |
| Class<Object> theClass = conversionManager.javaType(qName); |
| if (theClass != null) { |
| value = conversionManager.convertObject(element.getTextContent(), theClass, qName); |
| } |
| }else{ |
| if(!unmarshalRecord.isNamespaceAware() || !unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().useXsdTypesWithPrefix()){ |
| QName qName = new QName(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI, xsiType); |
| |
| ConversionManager conversionManager = unmarshalRecord.getConversionManager(); |
| Class<Object> theClass = conversionManager.javaType(qName); |
| if (theClass != null) { |
| value = conversionManager.convertObject(element.getTextContent(), theClass, qName); |
| } |
| } |
| } |
| xmlCompositeObjectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), value); |
| } else { |
| xmlCompositeObjectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), element); |
| } |
| } |
| } else { |
| Object valueToSet = selfRecord.getCurrentObject(); |
| valueToSet = xmlCompositeObjectMapping.convertDataValueToObjectValue(valueToSet, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); |
| xmlCompositeObjectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), valueToSet); |
| InverseReferenceMapping inverseReferenceMapping = xmlCompositeObjectMapping.getInverseReferenceMapping(); |
| if (null != inverseReferenceMapping) { |
| inverseReferenceMapping.getAttributeAccessor().setAttributeValueInObject(valueToSet, unmarshalRecord.getCurrentObject()); |
| } |
| } |
| } |
| |
| @Override |
| public UnmarshalRecord buildSelfRecord(UnmarshalRecord unmarshalRecord, Attributes atts) { |
| try { |
| Descriptor xmlDescriptor = (Descriptor)xmlCompositeObjectMapping.getReferenceDescriptor(); |
| if (null == xmlDescriptor) { |
| xmlDescriptor = findReferenceDescriptor(null, unmarshalRecord, atts, xmlCompositeObjectMapping,xmlCompositeObjectMapping.getKeepAsElementPolicy()); |
| } |
| |
| if(xmlDescriptor != null){ |
| if (xmlDescriptor.hasInheritance()) { |
| unmarshalRecord.setAttributes(atts); |
| Class clazz = ((ObjectBuilder)xmlDescriptor.getObjectBuilder()).classFromRow(unmarshalRecord, unmarshalRecord.getSession()); |
| if (clazz == null) { |
| // no xsi:type attribute - look for type indicator on the default root element |
| XPathQName leafElementType = unmarshalRecord.getLeafElementType(); |
| |
| // if we have a user-set type, try to get the class from the inheritance policy |
| if (leafElementType != null) { |
| Object indicator = xmlDescriptor.getInheritancePolicy().getClassIndicatorMapping().get(leafElementType); |
| if(indicator != null) { |
| clazz = (Class)indicator; |
| } |
| } |
| } |
| |
| if (clazz != null) { |
| xmlDescriptor = (Descriptor)unmarshalRecord.getSession().getDescriptor(clazz); |
| } else { |
| // since there is no xsi:type attribute, use the reference descriptor set |
| // on the mapping - make sure it is non-abstract |
| if (Modifier.isAbstract(xmlDescriptor.getJavaClass().getModifiers())) { |
| // need to throw an exception here |
| throw DescriptorException.missingClassIndicatorField(unmarshalRecord, (org.eclipse.persistence.oxm.XMLDescriptor)xmlDescriptor.getInheritancePolicy().getDescriptor()); |
| } |
| } |
| } |
| UnmarshalRecord childRecord = unmarshalRecord.getChildUnmarshalRecord((ObjectBuilder) xmlDescriptor.getObjectBuilder()); |
| childRecord.setSelfRecord(true); |
| unmarshalRecord.setChildRecord(childRecord); |
| childRecord.startDocument(); |
| childRecord.initializeRecord(this.xmlCompositeObjectMapping); |
| |
| return childRecord; |
| } else{ |
| return null; |
| } |
| |
| } catch (SAXException e) { |
| throw XMLMarshalException.unmarshalException(e); |
| } |
| } |
| |
| @Override |
| public void setNullValue(Object object, CoreSession session) { |
| xmlCompositeObjectMapping.setAttributeValueInObject(object, null); |
| } |
| |
| @Override |
| public boolean isNullCapableValue() { |
| if(xmlCompositeObjectMapping.getAttributeAccessor().isInstanceVariableAttributeAccessor() && !xmlCompositeObjectMapping.hasConverter()) { |
| return false; |
| } |
| Field xmlField = (Field)xmlCompositeObjectMapping.getField(); |
| if (xmlField.getLastXPathFragment().isSelfFragment) { |
| return false; |
| } |
| return xmlCompositeObjectMapping.getNullPolicy().getIsSetPerformedForAbsentNode(); |
| } |
| |
| @Override |
| public CompositeObjectMapping getMapping() { |
| return xmlCompositeObjectMapping; |
| } |
| |
| @Override |
| protected void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection){ |
| unmarshalRecord.setAttributeValue(value, xmlCompositeObjectMapping); |
| } |
| |
| } |