| /* |
| * 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: |
| // rbarkhouse - 2009-04-14 - 2.0 - Initial implementation |
| |
| package org.eclipse.persistence.oxm.mappings; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.exceptions.XMLMarshalException; |
| import org.eclipse.persistence.internal.descriptors.ObjectBuilder; |
| import org.eclipse.persistence.internal.oxm.ConversionManager; |
| import org.eclipse.persistence.internal.queries.ContainerPolicy; |
| import org.eclipse.persistence.internal.queries.JoinedAttributeManager; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.oxm.XMLContext; |
| import org.eclipse.persistence.oxm.XMLDescriptor; |
| import org.eclipse.persistence.oxm.XMLRoot; |
| import org.eclipse.persistence.oxm.mappings.converters.XMLConverter; |
| import org.eclipse.persistence.oxm.record.DOMRecord; |
| import org.eclipse.persistence.oxm.record.XMLRecord; |
| import org.eclipse.persistence.platform.xml.XMLPlatformFactory; |
| import org.eclipse.persistence.queries.ObjectBuildingQuery; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| |
| /** |
| * <p><b>Purpose:</b> An abstract superclass for XMLAnyObjectMapping and XMLAnyCollectionMapping. |
| * Maps an attribute of an object to an xs:any construct in the schema. |
| * |
| * @see XMLAnyObjectMapping |
| * @see XMLAnyCollectionMapping |
| * |
| */ |
| public abstract class XMLAbstractAnyMapping extends DatabaseMapping { |
| |
| private UnmarshalKeepAsElementPolicy keepAsElementPolicy; |
| private boolean isWriteOnly; |
| |
| public UnmarshalKeepAsElementPolicy getKeepAsElementPolicy() { |
| return keepAsElementPolicy; |
| } |
| |
| public void setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy keepAsElementPolicy) { |
| this.keepAsElementPolicy = keepAsElementPolicy; |
| } |
| |
| protected XMLDescriptor getDescriptor(XMLRecord xmlRecord, AbstractSession session, QName rootQName) throws XMLMarshalException { |
| if (rootQName == null) { |
| rootQName = new QName(xmlRecord.getNamespaceURI(), xmlRecord.getLocalName()); |
| } |
| XMLContext xmlContext = xmlRecord.getUnmarshaller().getXMLContext(); |
| XMLDescriptor xmlDescriptor = xmlContext.getDescriptor(rootQName); |
| if (null == xmlDescriptor) { |
| if (!(getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT || getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT)) { |
| throw XMLMarshalException.noDescriptorWithMatchingRootElement(xmlRecord.getLocalName()); |
| } |
| } |
| return xmlDescriptor; |
| } |
| |
| protected Object buildObjectForNonXMLRoot(ClassDescriptor referenceDescriptor, XMLConverter converter, ObjectBuildingQuery query, DOMRecord record, DOMRecord nestedRecord, JoinedAttributeManager joinManager, AbstractSession session, Node next, Object container, ContainerPolicy containerPolicy) { |
| Object objectValue = null; |
| |
| if ((referenceDescriptor != null) && (getKeepAsElementPolicy() != UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT)) { |
| ObjectBuilder builder = referenceDescriptor.getObjectBuilder(); |
| objectValue = builder.buildObject(query, nestedRecord, joinManager); |
| if (converter != null) { |
| objectValue = converter.convertDataValueToObjectValue(objectValue, session, record.getUnmarshaller()); |
| } |
| if (containerPolicy != null) { |
| containerPolicy.addInto(objectValue, container, session); |
| } |
| } else { |
| if ((getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT) || (getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT)) { |
| XMLPlatformFactory.getInstance().getXMLPlatform().namespaceQualifyFragment((Element) next); |
| objectValue = next; |
| if (converter != null) { |
| objectValue = converter.convertDataValueToObjectValue(objectValue, session, record.getUnmarshaller()); |
| } |
| if (containerPolicy != null) { |
| containerPolicy.addInto(objectValue, container, session); |
| } |
| } |
| } |
| |
| return objectValue; |
| } |
| |
| /** |
| * Uses a given reference descriptor to build an object based on a given DOMRecord. |
| * If a converter is provided it is applied to the newly built object. The |
| * reference descriptor will wrap the object in an XMLRoot if required, and the |
| * object will be added to the given Container Policy if it is non-null. |
| */ |
| protected Object buildObjectAndWrapInXMLRoot(ClassDescriptor referenceDescriptor, XMLConverter converter, ObjectBuildingQuery query, DOMRecord record, DOMRecord nestedRecord, JoinedAttributeManager joinManager, AbstractSession session, Node next, Object container, ContainerPolicy containerPolicy) { |
| ObjectBuilder builder = referenceDescriptor.getObjectBuilder(); |
| Object objectValue = builder.buildObject(query, nestedRecord, joinManager); |
| if (converter != null) { |
| objectValue = converter.convertDataValueToObjectValue(objectValue, session, record.getUnmarshaller()); |
| } |
| Object updated = ((XMLDescriptor) referenceDescriptor).wrapObjectInXMLRoot(objectValue, next.getNamespaceURI(), next.getLocalName(), next.getPrefix(), false, record.isNamespaceAware(), record.getUnmarshaller()); |
| if (containerPolicy != null) { |
| containerPolicy.addInto(updated, container, session); |
| } |
| return updated; |
| } |
| |
| /** |
| * Convenience method that takes a given Node and applies namespace |
| * information, converts it if necessary, and adds the resulting |
| * object to the given ContainerPolicy if non-null. |
| */ |
| protected Object buildObjectNoReferenceDescriptor(DOMRecord record, XMLConverter converter, AbstractSession session, Node next, Object container, ContainerPolicy cp) { |
| XMLPlatformFactory.getInstance().getXMLPlatform().namespaceQualifyFragment((Element) next); |
| Object objectValue = next; |
| if (converter != null) { |
| objectValue = converter.convertDataValueToObjectValue(objectValue, session, record.getUnmarshaller()); |
| } |
| if (cp != null) { |
| cp.addInto(objectValue, container, session); |
| } |
| return objectValue; |
| } |
| |
| /** |
| * Convenience method that takes a given node and checks the first child for |
| * TEXT_NODE. If the first child is a text node containing a non-empty |
| * String, the String value will be processed and wrapped in an XMLRoot. |
| * If schemaTypeQName represents a default XML type (boolean, dateTime, etc) |
| * the String value will be converted to that type. If a converter is |
| * provided it will be applied before wrapping in an XMLRoot. |
| */ |
| protected XMLRoot buildXMLRootForText(Node node, QName schemaTypeQName, XMLConverter converter, AbstractSession session, DOMRecord record) { |
| XMLRoot rootValue = null; |
| Node textchild = node.getFirstChild(); |
| if ((textchild != null) && (textchild.getNodeType() == Node.TEXT_NODE)) { |
| String stringValue = textchild.getNodeValue(); |
| if ((stringValue != null) && stringValue.length() > 0) { |
| Object convertedValue = stringValue; |
| if (schemaTypeQName != null) { |
| ConversionManager conversionManager = (ConversionManager) session.getDatasourcePlatform().getConversionManager(); |
| Class<Object> theClass = conversionManager.javaType(schemaTypeQName); |
| if (theClass != null) { |
| convertedValue = conversionManager.convertObject(convertedValue, theClass, schemaTypeQName); |
| } |
| } |
| if (converter != null) { |
| convertedValue = converter.convertDataValueToObjectValue(convertedValue, session, record.getUnmarshaller()); |
| } |
| rootValue = new XMLRoot(); |
| rootValue.setLocalName(node.getLocalName()); |
| rootValue.setSchemaType(schemaTypeQName); |
| rootValue.setNamespaceURI(node.getNamespaceURI()); |
| rootValue.setObject(convertedValue); |
| } |
| } |
| return rootValue; |
| } |
| |
| /** |
| * Convenience method that builds an XMLRoot wrapping a given object. |
| * The local name and uri are set using the given Node. |
| */ |
| protected XMLRoot buildXMLRoot(Node node, Object object) { |
| XMLRoot xmlRoot = new XMLRoot(); |
| xmlRoot.setLocalName(node.getLocalName()); |
| xmlRoot.setNamespaceURI(node.getNamespaceURI()); |
| xmlRoot.setObject(object); |
| return xmlRoot; |
| } |
| |
| @Override |
| public boolean isWriteOnly() { |
| return this.isWriteOnly; |
| } |
| |
| public void setIsWriteOnly(boolean b) { |
| this.isWriteOnly = b; |
| } |
| |
| @Override |
| public void setAttributeValueInObject(Object object, Object value) throws DescriptorException { |
| if(isWriteOnly()) { |
| return; |
| } |
| super.setAttributeValueInObject(object, value); |
| } |
| |
| @Override |
| public void preInitialize(AbstractSession session) throws DescriptorException { |
| getAttributeAccessor().setIsWriteOnly(this.isWriteOnly()); |
| getAttributeAccessor().setIsReadOnly(this.isReadOnly()); |
| super.preInitialize(session); |
| } |
| } |