All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.oxm.XMLAnyCollectionMappingNodeValue Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 1998, 2024 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 org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.core.queries.CoreAttributeItem;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.AnyCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
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.AnyMappingContentHandler;
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;

/**
 * INTERNAL:
 * 

Purpose: This is how the XML Any Collection Mapping is handled when * used with the TreeObjectBuilder.

*/ public class XMLAnyCollectionMappingNodeValue extends XMLRelationshipMappingNodeValue implements ContainerValue { private AnyCollectionMapping xmlAnyCollectionMapping; private int index = -1; private static XPathFragment SIMPLE_FRAGMENT = new XPathFragment(); public XMLAnyCollectionMappingNodeValue(AnyCollectionMapping xmlAnyCollectionMapping) { super(); this.xmlAnyCollectionMapping = xmlAnyCollectionMapping; } @Override public boolean isOwningNode(XPathFragment xPathFragment) { return null == xPathFragment; } @Override public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { if (xmlAnyCollectionMapping.isReadOnly()) { return false; } CoreContainerPolicy cp = xmlAnyCollectionMapping.getContainerPolicy(); Object collection = xmlAnyCollectionMapping.getAttributeAccessor().getAttributeValueFromObject(object); if (null == collection) { AbstractNullPolicy wrapperNP = xmlAnyCollectionMapping.getWrapperNullPolicy(); if (wrapperNP != null && wrapperNP.getMarshalNullRepresentation().equals(XMLNullRepresentationType.XSI_NIL)) { marshalRecord.nilSimple(namespaceResolver); return true; } else { return false; } } Object iterator = cp.iteratorFor(collection); if (null != iterator && cp.hasNext(iterator)) { XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); marshalRecord.closeStartGroupingElements(groupingFragment); } else { return marshalRecord.emptyCollection(xPathFragment, namespaceResolver, xmlAnyCollectionMapping.getWrapperNullPolicy() != null); } if(marshalRecord.getMarshaller().isApplicationJSON()){ List frags = new ArrayList(); List values = new ArrayList<>(); List mixedValues = new ArrayList(); //sort the elements. Results will be a list of xpathfragments and a corresponding list of //collections associated with those xpathfragments XPathFragment xmlRootFragment; while(cp.hasNext(iterator)) { Object nextValue = cp.next(iterator, session); nextValue = xmlAnyCollectionMapping.convertObjectValueToDataValue(nextValue, session, marshalRecord.getMarshaller()); XPathFragment frag = getXPathFragmentForValue(nextValue, marshalRecord,marshalRecord.getMarshaller() ); if(frag != null){ if(frag == SIMPLE_FRAGMENT){ mixedValues.add(nextValue); }else{ int index = frags.indexOf(frag); if(index > -1){ values.get(index).add(nextValue); }else{ frags.add(frag); List valuesList = new ArrayList(); valuesList.add(nextValue); values.add(valuesList); } } } } if(!mixedValues.isEmpty()){ frags.add(SIMPLE_FRAGMENT); values.add(mixedValues); } for(int i =0;i < frags.size(); i++){ XPathFragment nextFragment = frags.get(i); List listValue = values.get(i); if(nextFragment != null){ int valueSize = listValue.size(); if(valueSize > 1 || !marshalRecord.getMarshaller().isReduceAnyArrays()){ marshalRecord.startCollection(); } for(int j=0;j 1 || !marshalRecord.getMarshaller().isReduceAnyArrays()){ marshalRecord.endCollection(); } } } return true; }else{ Object objectValue; marshalRecord.startCollection(); while (cp.hasNext(iterator)) { objectValue = cp.next(iterator, session); objectValue = xmlAnyCollectionMapping.convertObjectValueToDataValue(objectValue, session, marshalRecord.getMarshaller()); marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, ObjectMarshalContext.getInstance()); } marshalRecord.endCollection(); return true; } } private XPathFragment getXPathFragmentForValue(Object value, MarshalRecord marshalRecord, Marshaller marshaller){ if (xmlAnyCollectionMapping.usesXMLRoot() && (value instanceof Root xmlRootValue)) { XPathFragment xmlRootFragment = new XPathFragment(xmlRootValue.getLocalName(), marshalRecord.getNamespaceSeparator(), marshalRecord.isNamespaceAware()); xmlRootFragment.setNamespaceURI(xmlRootValue.getNamespaceURI()); return xmlRootFragment; } if(value instanceof Node n){ XPathFragment frag = null; if(n.getNodeType() == Node.ELEMENT_NODE){ Element elem = (Element)n; String local = elem.getLocalName(); if(local == null){ local = elem.getNodeName(); } String prefix = elem.getPrefix(); if(prefix != null && !prefix.equals(Constants.EMPTY_STRING)){ frag = new XPathFragment(prefix + marshalRecord.getNamespaceSeparator() + elem.getLocalName(), marshalRecord.getNamespaceSeparator(), marshalRecord.isNamespaceAware()); }else{ frag = new XPathFragment(local, marshalRecord.getNamespaceSeparator(), marshalRecord.isNamespaceAware()); } }else if(n.getNodeType() == Node.ATTRIBUTE_NODE){ Attr attr = (Attr)n; attr.getLocalName(); String prefix = attr.getPrefix(); if(prefix != null && prefix.equals(Constants.EMPTY_STRING)){ frag = new XPathFragment(prefix + marshalRecord.getNamespaceSeparator() + attr.getLocalName(), marshalRecord.getNamespaceSeparator(), marshalRecord.isNamespaceAware()); }else{ frag = new XPathFragment(attr.getLocalName(), marshalRecord.getNamespaceSeparator(), marshalRecord.isNamespaceAware()); } }else if(n.getNodeType() == Node.TEXT_NODE){ return SIMPLE_FRAGMENT; } return frag; } CoreAbstractSession childSession = null; try { childSession= marshaller.getContext().getSession(value); } catch (XMLMarshalException e) { return SIMPLE_FRAGMENT; } if(childSession != null){ Descriptor descriptor = (Descriptor) childSession.getDescriptor(value); String defaultRootElementString = descriptor.getDefaultRootElement(); if(defaultRootElementString != null){ return new XPathFragment(defaultRootElementString); } } return null; } @Override public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { try { // Mixed Content Object collection = unmarshalRecord.getContainerInstance(this); startElementProcessText(unmarshalRecord, collection); Context xmlContext = unmarshalRecord.getUnmarshaller().getContext(); //used to only check xsitype when usesXMLRoot was true??? Descriptor workingDescriptor = findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, xmlAnyCollectionMapping, xmlAnyCollectionMapping.getKeepAsElementPolicy()); if (workingDescriptor == null) { XPathQName qname = new XPathQName(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), unmarshalRecord.isNamespaceAware()); workingDescriptor = xmlContext.getDescriptor(qname); // Check if descriptor is for a wrapper, if it is null it out and let continue if (workingDescriptor != null && workingDescriptor.isWrapper()) { workingDescriptor = null; } } UnmarshalKeepAsElementPolicy policy = xmlAnyCollectionMapping.getKeepAsElementPolicy(); if (null != policy && (workingDescriptor == null && policy.isKeepUnknownAsElement()) || policy.isKeepAllAsElement()) { if(!(xmlAnyCollectionMapping.isMixedContent() && unmarshalRecord.getTextWrapperFragment() != null && unmarshalRecord.getTextWrapperFragment().equals(xPathFragment))){ setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); } } else if (workingDescriptor != null) { processChild(xPathFragment, unmarshalRecord, atts, workingDescriptor, xmlAnyCollectionMapping); } else { //need to give to special handler, let it find out what to do depending on if this is simple or complex content AnyMappingContentHandler handler = new AnyMappingContentHandler(unmarshalRecord, xmlAnyCollectionMapping.usesXMLRoot()); String qnameString = xPathFragment.getLocalName(); if (xPathFragment.getPrefix() != null) { qnameString = xPathFragment.getPrefix() + Constants.COLON + qnameString; } handler.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), qnameString, atts); XMLReader xmlReader = unmarshalRecord.getXMLReader(); xmlReader.setContentHandler(handler); xmlReader.setLexicalHandler(handler); return true; } } catch (SAXException e) { throw XMLMarshalException.unmarshalException(e); } return true; } @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { endElement(xPathFragment, unmarshalRecord, null); } @Override public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Object collection) { UnmarshalRecord childRecord = unmarshalRecord.getChildRecord(); if (null != childRecord) { // OBJECT VALUE if (!xmlAnyCollectionMapping.usesXMLRoot()) { Object objectValue = childRecord.getCurrentObject(); objectValue = xmlAnyCollectionMapping.convertDataValueToObjectValue(objectValue, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); unmarshalRecord.addAttributeValue(this, objectValue); } else { Object childObject = childRecord.getCurrentObject(); Descriptor workingDescriptor = childRecord.getDescriptor(); if (workingDescriptor != null) { String prefix = xPathFragment.getPrefix(); if ((prefix == null) && (xPathFragment.getNamespaceURI() != null)) { prefix = unmarshalRecord.resolveNamespaceUri(xPathFragment.getNamespaceURI()); } childObject = workingDescriptor.wrapObjectInXMLRoot(childObject, xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), prefix, false, unmarshalRecord.isNamespaceAware(), unmarshalRecord.getUnmarshaller()); childObject = xmlAnyCollectionMapping.convertDataValueToObjectValue(childObject, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); unmarshalRecord.addAttributeValue(this, childObject); } } unmarshalRecord.setChildRecord(null); } else { SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); if(xmlAnyCollectionMapping.isMixedContent() && unmarshalRecord.getTextWrapperFragment() != null && unmarshalRecord.getTextWrapperFragment().equals(xPathFragment)){ endElementProcessText(unmarshalRecord, xmlAnyCollectionMapping, xPathFragment, null); return; } UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlAnyCollectionMapping.getKeepAsElementPolicy(); if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && builder.getNodes().size() > 1) { setOrAddAttributeValueForKeepAsElement(builder, xmlAnyCollectionMapping, xmlAnyCollectionMapping, unmarshalRecord, true, collection); } else { //TEXT VALUE if(xmlAnyCollectionMapping.isMixedContent()) { endElementProcessText(unmarshalRecord, xmlAnyCollectionMapping, xPathFragment, null); } else { unmarshalRecord.resetStringBuffer(); } } } } private void startElementProcessText(UnmarshalRecord unmarshalRecord, Object collection) { String value = unmarshalRecord.getCharacters().toString(); unmarshalRecord.resetStringBuffer(); if (!value.isEmpty() && xmlAnyCollectionMapping.isMixedContent()) { unmarshalRecord.addAttributeValue(this, value); } } @Override protected void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection){ if (!xmlAnyCollectionMapping.usesXMLRoot() || xPathFragment.getLocalName() == null || (xmlAnyCollectionMapping.isMixedContent() && unmarshalRecord.getTextWrapperFragment() != null && unmarshalRecord.getTextWrapperFragment().equals(xPathFragment))) { unmarshalRecord.addAttributeValue(this, value); } else { Root xmlRoot = unmarshalRecord.createRoot(); xmlRoot.setNamespaceURI(xPathFragment.getNamespaceURI()); xmlRoot.setSchemaType(unmarshalRecord.getTypeQName()); xmlRoot.setLocalName(xPathFragment.getLocalName()); xmlRoot.setObject(value); unmarshalRecord.addAttributeValue(this, xmlRoot); } } @Override public Object getContainerInstance() { return getContainerPolicy().containerInstance(); } @Override public void setContainerInstance(Object object, Object containerInstance) { xmlAnyCollectionMapping.setAttributeValueInObject(object, containerInstance); } @Override public CoreContainerPolicy getContainerPolicy() { return xmlAnyCollectionMapping.getContainerPolicy(); } @Override public boolean isContainerValue() { return true; } private Namespace setupFragment(Root originalValue, XPathFragment xmlRootFragment, MarshalRecord marshalRecord) { Namespace generatedNamespace = null; String xpath = originalValue.getLocalName(); if (originalValue.getNamespaceURI() != null) { xmlRootFragment.setNamespaceURI((originalValue).getNamespaceURI()); String prefix = marshalRecord.getNamespaceResolver().resolveNamespaceURI((originalValue).getNamespaceURI()); if (prefix == null || prefix.isEmpty()) { prefix = marshalRecord.getNamespaceResolver().generatePrefix(); generatedNamespace = new Namespace(prefix, xmlRootFragment.getNamespaceURI()); xmlRootFragment.setGeneratedPrefix(true); } xpath = prefix + Constants.COLON + xpath; } xmlRootFragment.setXPath(xpath); return generatedNamespace; } @Override public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { if (null == value) { return false; } boolean wasXMLRoot = false; XPathFragment xmlRootFragment = null; Object originalValue = value; Descriptor descriptor; ObjectBuilder objectBuilder; CoreAbstractSession childSession; Marshaller marshaller = marshalRecord.getMarshaller(); XPathFragment rootFragment; if (xmlAnyCollectionMapping.usesXMLRoot() && (value instanceof Root)) { xmlRootFragment = new XPathFragment(); xmlRootFragment.setNamespaceAware(marshalRecord.isNamespaceAware()); wasXMLRoot = true; value = ((Root) value).getObject(); if(null == value){ setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); marshalRecord.nilComplex(xmlRootFragment, namespaceResolver); return true; } } UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlAnyCollectionMapping.getKeepAsElementPolicy(); if (value instanceof String) { marshalSimpleValue(xmlRootFragment, marshalRecord, originalValue, object, value, session, namespaceResolver); } else if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && value instanceof org.w3c.dom.Node) { marshalRecord.node((org.w3c.dom.Node) value, marshalRecord.getNamespaceResolver()); } else { try { childSession = marshaller.getContext().getSession(value); } catch (XMLMarshalException e) { marshalSimpleValue(xmlRootFragment, marshalRecord, originalValue, object, value, session, namespaceResolver); return true; } descriptor = (Descriptor) childSession.getDescriptor(value); pushAttributeGroup(marshalRecord, descriptor, getMapping().getAttributeName()); objectBuilder = (ObjectBuilder) descriptor.getObjectBuilder(); List extraNamespaces = objectBuilder.addExtraNamespacesToNamespaceResolver(descriptor, marshalRecord, session, true, true); if(wasXMLRoot){ setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); } /* * B5112171: 25 Apr 2006 * During marshalling - XML AnyObject and AnyCollection * mappings throw a NullPointerException when the * "document root element" on child object descriptors are not * all defined. These nodes will be ignored with a warning. */ String defaultRootElementString = descriptor.getDefaultRootElement(); if (!wasXMLRoot && (defaultRootElementString == null)) { throw XMLMarshalException.defaultRootElementNotSpecified(descriptor); } else { marshalRecord.beforeContainmentMarshal(value); if (xmlRootFragment != null) { rootFragment = xmlRootFragment; } else { rootFragment = new XPathFragment(defaultRootElementString); //resolve URI if (rootFragment.getNamespaceURI() == null) { String uri = descriptor.getNonNullNamespaceResolver().resolveNamespacePrefix(rootFragment.getPrefix()); rootFragment.setNamespaceURI(uri); } } if (!wasXMLRoot) { marshalRecord.setLeafElementType(descriptor.getDefaultRootElementType()); } getXPathNode().startElement(marshalRecord, rootFragment, object, childSession, marshalRecord.getNamespaceResolver(), objectBuilder, value); writeExtraNamespaces(extraNamespaces, marshalRecord, session); pushAttributeGroup(marshalRecord, descriptor, rootFragment.getLocalName()); marshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, descriptor, (Field)xmlAnyCollectionMapping.getField(), originalValue, value, wasXMLRoot, false); objectBuilder.buildRow(marshalRecord, value, session, marshaller, null); marshalRecord.afterContainmentMarshal(object, value); marshalRecord.endElement(rootFragment, namespaceResolver); marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); marshalRecord.popAttributeGroup(); } marshalRecord.popAttributeGroup(); } return true; } private void pushAttributeGroup(MarshalRecord marshalRecord, Descriptor descriptor, String attributeName) { CoreAttributeGroup group = marshalRecord.getCurrentAttributeGroup(); CoreAttributeItem item = group.getItem(attributeName); 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); } private void marshalSimpleValue(XPathFragment xmlRootFragment, MarshalRecord marshalRecord, Object originalValue, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver) { QName qname = null; if (xmlRootFragment != null) { qname = ((Root) originalValue).getSchemaType(); setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); CoreAttributeGroup group = marshalRecord.getCurrentAttributeGroup(); CoreAttributeItem item = group.getItem(getMapping().getAttributeName()); CoreAttributeGroup nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP; if(item != null) { if (item.getGroup() != null && null != xmlRootFragment.getLocalName()) { CoreAttributeItem nestedItem = item.getGroup().getItem(xmlRootFragment.getLocalName()); if (null != nestedItem) { nestedGroup = item.getGroup(); } else { return; } } } getXPathNode().startElement(marshalRecord, xmlRootFragment, object, session, namespaceResolver, null, null); updateNamespaces(qname, marshalRecord, null); } marshalRecord.characters(qname, value, null, false); if (xmlRootFragment != null) { marshalRecord.endElement(xmlRootFragment, namespaceResolver); } } @Override public AnyCollectionMapping getMapping() { return xmlAnyCollectionMapping; } @Override public boolean isWhitespaceAware() { return this.xmlAnyCollectionMapping.isMixedContent() && this.xmlAnyCollectionMapping.isWhitespacePreservedForMixedContent(); } @Override public boolean isWrapperAllowedAsCollectionName() { return false; } @Override public boolean isAnyMappingNodeValue() { return true; } @Override public boolean getReuseContainer() { return getMapping().getReuseContainer(); } /** * INTERNAL: * Return true if this is the node value representing mixed content. */ @Override public boolean isMixedContentNodeValue() { return this.xmlAnyCollectionMapping.isMixedContent(); } /** * INTERNAL: * Used to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord */ @Override public void setIndex(int index){ this.index = index; } /** * INTERNAL: * Set to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord * Set during TreeObjectBuilder initialization */ @Override public int getIndex(){ return index; } /** * INTERNAL * Return true if an empty container should be set on the object if there * is no presence of the collection in the XML document. * @since EclipseLink 2.3.3 */ @Override public boolean isDefaultEmptyContainer() { return getMapping().isDefaultEmptyContainer(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy