/******************************************************************************* * Copyright (c) 1998, 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: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.oxm; import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.namespace.QName; import org.eclipse.persistence.exceptions.DescriptorException; import org.eclipse.persistence.exceptions.XMLMarshalException; import org.eclipse.persistence.internal.core.helper.CoreField; import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; import org.eclipse.persistence.internal.oxm.mappings.Descriptor; import org.eclipse.persistence.internal.oxm.mappings.Field; import org.eclipse.persistence.internal.oxm.mappings.Mapping; import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy; import org.eclipse.persistence.internal.oxm.mappings.XMLConverterMapping; import org.eclipse.persistence.internal.oxm.record.MarshalRecord; 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.DescriptorNotFoundContentHandler; import org.eclipse.persistence.core.queries.CoreAttributeGroup; import org.eclipse.persistence.core.queries.CoreAttributeItem; import org.xml.sax.Attributes; import org.xml.sax.SAXException; public abstract class XMLRelationshipMappingNodeValue extends MappingNodeValue { // Protected to public public void processChild(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts, Descriptor xmlDescriptor, Mapping mapping) throws SAXException { if(xmlDescriptor == null){ //Use the DescriptorNotFoundContentHandler to "look ahead" and determine if this is a simple or complex element //if it is complex the exception should be thrown DescriptorNotFoundContentHandler handler = new DescriptorNotFoundContentHandler(unmarshalRecord, mapping); 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; } if (xmlDescriptor.hasInheritance()) { unmarshalRecord.setAttributes(atts); CoreAbstractSession session = unmarshalRecord.getSession(); Class classValue = ((ObjectBuilder)xmlDescriptor.getObjectBuilder()).classFromRow(unmarshalRecord, session); if (classValue == 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) { classValue = (Class)indicator; } } } if (classValue != null) { xmlDescriptor = (Descriptor)session.getDescriptor(classValue); } 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()); } } } ObjectBuilder targetObjectBuilder = (ObjectBuilder)xmlDescriptor.getObjectBuilder(); CoreAttributeGroup group = unmarshalRecord.getUnmarshalAttributeGroup(); CoreAttributeGroup nestedGroup = null; if(group == XMLRecord.DEFAULT_ATTRIBUTE_GROUP) { nestedGroup = group; } if(nestedGroup == null) { CoreAttributeItem item = group.getItem(getMapping().getAttributeName()); nestedGroup = item.getGroup(xmlDescriptor.getJavaClass()); if(nestedGroup == null) { if(item.getGroup() == null) { nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP; } else { nestedGroup = item.getGroup(); } } } UnmarshalRecord childRecord = unmarshalRecord.getChildUnmarshalRecord(targetObjectBuilder); childRecord.setAttributes(atts); childRecord.startDocument(); childRecord.initializeRecord((Mapping) null); childRecord.setUnmarshalAttributeGroup(nestedGroup); childRecord.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), xPathFragment.getShortName(), atts); XMLReader xmlReader = unmarshalRecord.getXMLReader(); xmlReader.setContentHandler(childRecord); xmlReader.setLexicalHandler(childRecord); } protected Descriptor findReferenceDescriptor(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts, Mapping mapping, UnmarshalKeepAsElementPolicy policy) { Descriptor returnDescriptor = null; //try xsi:type if(atts != null){ Context xmlContext = unmarshalRecord.getUnmarshaller().getContext(); String schemaType = null; if(unmarshalRecord.isNamespaceAware()){ schemaType = atts.getValue(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_TYPE_ATTRIBUTE); }else{ schemaType = atts.getValue(Constants.EMPTY_STRING, Constants.SCHEMA_TYPE_ATTRIBUTE); } if(schemaType != null){ schemaType = schemaType.trim(); if(schemaType.length() > 0) { XPathFragment frag = new XPathFragment(schemaType, unmarshalRecord.getNamespaceSeparator(), unmarshalRecord.isNamespaceAware()); QName qname = null; if (frag.hasNamespace()) { String prefix = frag.getPrefix(); String url = unmarshalRecord.resolveNamespacePrefix(prefix); frag.setNamespaceURI(url); qname = new QName(url, frag.getLocalName()); unmarshalRecord.setTypeQName(qname); } else { String url = unmarshalRecord.resolveNamespacePrefix(Constants.EMPTY_STRING); if(null != url) { frag.setNamespaceURI(url); qname = new QName(url, frag.getLocalName()); unmarshalRecord.setTypeQName(qname); } if(!unmarshalRecord.isNamespaceAware() || !unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().useXsdTypesWithPrefix()){ qname = new QName(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI ,frag.getLocalName()); unmarshalRecord.setTypeQName(qname); } } returnDescriptor = xmlContext.getDescriptorByGlobalType(frag); if(returnDescriptor == null){ if(policy == null || (!policy.isKeepUnknownAsElement() && !policy.isKeepAllAsElement())){ Class theClass = unmarshalRecord.getConversionManager().javaType(qname); if(theClass == null){ throw XMLMarshalException.unknownXsiTypeValue(schemaType, mapping); } } } } } } return returnDescriptor; } protected void addTypeAttribute(Descriptor descriptor, MarshalRecord marshalRecord, String schemaContext) { String typeValue = schemaContext.substring(1); String xsiPrefix = null; if (descriptor.getNamespaceResolver() != null) { xsiPrefix = descriptor.getNamespaceResolver().resolveNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); } else { xsiPrefix = Constants.SCHEMA_INSTANCE_PREFIX; marshalRecord.namespaceDeclaration(xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); } if (xsiPrefix == null) { xsiPrefix = descriptor.getNamespaceResolver().generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX); marshalRecord.namespaceDeclaration(xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); } marshalRecord.attribute(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_TYPE_ATTRIBUTE, xsiPrefix + Constants.COLON + Constants.SCHEMA_TYPE_ATTRIBUTE, typeValue); } protected void writeExtraNamespaces(List extraNamespaces, XMLRecord xmlRecord, CoreAbstractSession session) { if (extraNamespaces == null) { return; } for (int i = 0, extraNamespacesSize=extraNamespaces.size(); i < extraNamespacesSize; i++) { Namespace next = (Namespace)extraNamespaces.get(i); String prefix = next.getPrefix(); if(((MarshalRecord)xmlRecord).hasCustomNamespaceMapper()) { prefix = ((MarshalRecord)xmlRecord).getNamespaceResolver().resolveNamespaceURI(next.getNamespaceURI()); } ((MarshalRecord)xmlRecord).namespaceDeclaration(prefix, next.getNamespaceURI()); } } protected void setupHandlerForKeepAsElementPolicy(UnmarshalRecord unmarshalRecord, XPathFragment xPathFragment, Attributes atts) { SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); builder.setOwningRecord(unmarshalRecord); builder.setMixedContent(xPathNode.getUnmarshalNodeValue().isMixedContentNodeValue()); try { String namespaceURI = Constants.EMPTY_STRING; if (xPathFragment.getNamespaceURI() != null) { namespaceURI = xPathFragment.getNamespaceURI(); } String qName = xPathFragment.getLocalName(); if (xPathFragment.getPrefix() != null) { qName = xPathFragment.getPrefix() + unmarshalRecord.getNamespaceSeparator() + qName; } if(!(unmarshalRecord.getPrefixesForFragment().isEmpty())) { for(Entry<String, String> next:((Map<String, String>) unmarshalRecord.getPrefixesForFragment()).entrySet()) { builder.startPrefixMapping(next.getKey(), next.getValue()); } } builder.startElement(namespaceURI, xPathFragment.getLocalName(), qName, atts); XMLReader xmlReader = unmarshalRecord.getXMLReader(); xmlReader.setContentHandler(builder); xmlReader.setLexicalHandler(null); } catch (SAXException ex) { } } protected void setOrAddAttributeValueForKeepAsElement(SAXFragmentBuilder builder, Mapping mapping, XMLConverterMapping converter, UnmarshalRecord unmarshalRecord, boolean isCollection, Object collection) { Object node = builder.getNodes().remove(builder.getNodes().size() -1); if (converter != null) { node = converter.convertDataValueToObjectValue(node, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); } if (isCollection) { if(collection != null){ unmarshalRecord.addAttributeValue((ContainerValue) this, node, collection); }else{ unmarshalRecord.addAttributeValue((ContainerValue) this, node); } } else { unmarshalRecord.setAttributeValue(node, mapping); } } protected void endElementProcessText(UnmarshalRecord unmarshalRecord, XMLConverterMapping converter, XPathFragment xPathFragment, Object collection) { Object value = unmarshalRecord.getCharacters().toString(); unmarshalRecord.resetStringBuffer(); if(!unmarshalRecord.isNil()) { QName qname = unmarshalRecord.getTypeQName(); if (qname == null) { if(Constants.EMPTY_STRING.equals(value)) { value = null; } } else { ConversionManager conversionManager = unmarshalRecord.getConversionManager(); if(qname.equals(Constants.QNAME_QNAME)) { value = conversionManager.buildQNameFromString((String)value, unmarshalRecord); } else { Class theClass = getClassForQName(qname, conversionManager); if (theClass != null) { value = conversionManager.convertObject(value, theClass, qname); } } } value = converter.convertDataValueToObjectValue(value, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); setOrAddAttributeValue(unmarshalRecord, value, xPathFragment, collection); } } protected Class getClassForQName(QName qname, ConversionManager conversionManager){ CoreField field = getMapping().getField(); if(field != null){ return ((Field)field).getJavaClass(qname, conversionManager); } return conversionManager.javaType(qname); } protected abstract void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection); }