| /* |
| * Copyright (c) 1998, 2020 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.util.ArrayList; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.core.sessions.CoreSession; |
| import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; |
| import org.eclipse.persistence.internal.oxm.mappings.DirectMapping; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| 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; |
| |
| /** |
| * INTERNAL: |
| * <p><b>Purpose</b>: This is how the XML Direct Mapping is handled when used |
| * with the TreeObjectBuilder.</p> |
| */ |
| public class XMLDirectMappingNodeValue extends MappingNodeValue implements NullCapableValue { |
| private DirectMapping xmlDirectMapping; |
| |
| public XMLDirectMappingNodeValue(DirectMapping xmlDirectMapping) { |
| this.xmlDirectMapping = xmlDirectMapping; |
| } |
| |
| @Override |
| public void setXPathNode(XPathNode xPathNode) { |
| super.setXPathNode(xPathNode); |
| xmlDirectMapping.getNullPolicy().xPathNode(xPathNode, this); |
| if(((Field) xmlDirectMapping.getField()).isTypedTextField()) { |
| XPathFragment typeAttributeXPathFragment = new XPathFragment(); |
| typeAttributeXPathFragment.setAttribute(true); |
| typeAttributeXPathFragment.setLocalName(Constants.SCHEMA_TYPE_ATTRIBUTE); |
| typeAttributeXPathFragment.setNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
| xPathNode.getParent().addChild(typeAttributeXPathFragment, new TypeNodeValue(), null); |
| } |
| } |
| |
| @Override |
| public boolean isOwningNode(XPathFragment xPathFragment) { |
| return xPathFragment.hasAttribute || xPathFragment.nameIsText; |
| } |
| |
| @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 (xmlDirectMapping.isReadOnly()) { |
| return false; |
| } |
| Object objectValue = marshalContext.getAttributeValue(object, xmlDirectMapping); |
| return this.marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext); |
| } |
| |
| @Override |
| public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { |
| Object fieldValue = xmlDirectMapping.getFieldValue(objectValue, session, marshalRecord); |
| |
| // Check for a null value |
| if (null == fieldValue) { |
| // Perform marshal operations based on the null policy |
| return xmlDirectMapping.getNullPolicy().directMarshal(xPathFragment, marshalRecord, object, session, namespaceResolver); |
| } else { |
| QName schemaType = ((Field) xmlDirectMapping.getField()).getSchemaTypeForValue(fieldValue, session); |
| XPathFragment groupingFragment = null; |
| boolean isQName = false; |
| if(Constants.QNAME_QNAME.equals(schemaType)) { |
| //if marshalling a QName, handle grouping elements here in case namespace adjustments need |
| //to happen |
| groupingFragment = openGroupingElementsForQName((QName)fieldValue, marshalRecord); |
| isQName = true; |
| } |
| if(groupingFragment == null) { |
| groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); |
| } |
| if (xPathFragment.hasAttribute) { |
| marshalRecord.attribute(xPathFragment, namespaceResolver, fieldValue, schemaType); |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| } else { |
| if(((Field) xmlDirectMapping.getField()).getXPathFragment().nameIsText ){ |
| XPathNode parentNode = xPathNode.getParent(); |
| if(parentNode.getAttributeChildren() != null){ |
| marshalRecord.forceValueWrapper(); |
| } |
| } |
| Field xmlField = (Field) xmlDirectMapping.getField(); |
| if (xmlField.isTypedTextField()) { |
| updateNamespaces(schemaType, marshalRecord, xmlField); |
| } |
| marshalRecord.closeStartGroupingElements(groupingFragment); |
| marshalRecord.characters(schemaType, fieldValue, null, xmlDirectMapping.isCDATA()); |
| } |
| if(isQName) { |
| //check to see if the last grouping fragment was swapped |
| XPathFragment fragment = getLastGroupingFragment(); |
| if(fragment != groupingFragment) { |
| marshalRecord.endElement(groupingFragment, namespaceResolver); |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| private XPathFragment getLastGroupingFragment() { |
| XPathFragment fragment = ((Field)this.getMapping().getField()).getXPathFragment(); |
| if(fragment.hasAttribute || fragment.nameIsText) { |
| return null; |
| } |
| while(fragment.getNextFragment() != null) { |
| if(fragment.getNextFragment().nameIsText || fragment.getNextFragment().hasAttribute) { |
| return fragment; |
| } |
| fragment = fragment.getNextFragment(); |
| } |
| return fragment; |
| } |
| private XPathFragment openGroupingElementsForQName(QName fieldValue, MarshalRecord marshalRecord) { |
| XPathFragment xPathFragment = null; |
| ArrayList<XPathNode> groupingElements = marshalRecord.getGroupingElements(); |
| NamespaceResolver namespaceResolver = marshalRecord.getNamespaceResolver(); |
| if((fieldValue.getNamespaceURI() == null || fieldValue.getNamespaceURI().equals(Constants.EMPTY_STRING)) && marshalRecord.getNamespaceResolver().getDefaultNamespaceURI() != null) { |
| //In this case, the last grouping element may need to have a new prefix generated. |
| for (int x = 0, groupingElementsSize = groupingElements.size(); x < groupingElementsSize; x++) { |
| XPathNode xPathNode = groupingElements.get(x); |
| xPathFragment = xPathNode.getXPathFragment(); |
| if(x == (groupingElements.size() - 1) && namespaceResolver.getDefaultNamespaceURI().equals(xPathFragment.getNamespaceURI()) && xPathFragment.getPrefix() == null) { |
| String prefix = namespaceResolver.generatePrefix(); |
| String xPath = prefix + Constants.COLON + xPathFragment.getShortName(); |
| XPathFragment newFragment = new XPathFragment(xPath); |
| newFragment.setNamespaceURI(namespaceResolver.getDefaultNamespaceURI()); |
| marshalRecord.openStartElement(newFragment, namespaceResolver); |
| marshalRecord.namespaceDeclaration(prefix, namespaceResolver.getDefaultNamespaceURI()); |
| marshalRecord.predicateAttribute(xPathFragment, namespaceResolver); |
| xPathFragment = newFragment; |
| } else { |
| marshalRecord.openStartElement(xPathFragment, namespaceResolver); |
| marshalRecord.predicateAttribute(xPathFragment, namespaceResolver); |
| marshalRecord.closeStartElement(); |
| } |
| } |
| marshalRecord.setGroupingElement(null); |
| |
| } |
| return xPathFragment; |
| |
| |
| } |
| |
| @Override |
| public void attribute(UnmarshalRecord unmarshalRecord, String namespaceURI, String localName, String value) { |
| unmarshalRecord.removeNullCapableValue(this); |
| Field xmlField = (Field) xmlDirectMapping.getField(); |
| CoreAbstractSession session = unmarshalRecord.getSession(); |
| Object realValue = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, (ConversionManager) session.getDatasourcePlatform().getConversionManager(), unmarshalRecord); |
| |
| // Perform operations on the object based on the null policy |
| Object convertedValue = xmlDirectMapping.getAttributeValue(realValue, session, unmarshalRecord); |
| xmlDirectMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), convertedValue); |
| } |
| |
| @Override |
| public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { |
| if(unmarshalRecord.isNil() && xmlDirectMapping.getNullPolicy().isNullRepresentedByXsiNil()){ |
| Object convertedValue = xmlDirectMapping.getAttributeValue(org.eclipse.persistence.oxm.record.XMLRecord.NIL, unmarshalRecord.getSession(), unmarshalRecord); |
| unmarshalRecord.setAttributeValue(convertedValue, xmlDirectMapping); |
| unmarshalRecord.resetStringBuffer(); |
| return; |
| } |
| |
| unmarshalRecord.removeNullCapableValue(this); |
| Field xmlField = (Field) xmlDirectMapping.getField(); |
| if (!xmlField.getLastXPathFragment().nameIsText) { |
| return; |
| } |
| Object value; |
| CharSequence unmarshalRecordCharacters = unmarshalRecord.getCharacters(); |
| if (unmarshalRecordCharacters.length() == 0) { |
| value = xmlDirectMapping.getNullValue(); |
| } else { |
| value = unmarshalRecordCharacters.toString(); |
| } |
| unmarshalRecord.resetStringBuffer(); |
| CoreAbstractSession session = unmarshalRecord.getSession(); |
| ConversionManager conversionManager = (ConversionManager) session.getDatasourcePlatform().getConversionManager(); |
| QName typeQName = unmarshalRecord.getTypeQName(); |
| if (typeQName != null) { |
| Class typeClass = xmlField.getJavaClass(typeQName, conversionManager); |
| value = conversionManager.convertObject(value, typeClass, typeQName); |
| } else { |
| value = unmarshalRecord.getXMLReader().convertValueBasedOnSchemaType(xmlField, value, conversionManager, unmarshalRecord); |
| } |
| |
| Object convertedValue = xmlDirectMapping.getAttributeValue(value, session, unmarshalRecord); |
| unmarshalRecord.setAttributeValue(convertedValue, xmlDirectMapping); |
| } |
| |
| @Override |
| public void setNullValue(Object object, CoreSession session) { |
| Object value = xmlDirectMapping.getObjectValue(null, session); |
| xmlDirectMapping.setAttributeValueInObject(object, value); |
| } |
| |
| @Override |
| public boolean isNullCapableValue() { |
| if(xmlDirectMapping.getAttributeAccessor().isInstanceVariableAttributeAccessor() && !xmlDirectMapping.hasConverter() && xmlDirectMapping.getNullValue() == null) { |
| return false; |
| } |
| return xmlDirectMapping.getNullPolicy().getIsSetPerformedForAbsentNode(); |
| } |
| |
| @Override |
| public DirectMapping getMapping() { |
| return xmlDirectMapping; |
| } |
| |
| @Override |
| public boolean isWhitespaceAware() { |
| return !xmlDirectMapping.getNullPolicy().isNullRepresentedByEmptyNode(); |
| } |
| |
| } |