blob: 83138290209f04d2864c63df03941e2bcd0bcc5d [file] [log] [blame]
/*
* 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 java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
import org.eclipse.persistence.internal.core.queries.CoreMappedKeyMapContainerPolicy;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.AnyAttributeMapping;
import org.eclipse.persistence.internal.oxm.record.MarshalContext;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
/**
* INTERNAL:
* <p><b>Purpose</b>: This is how the XML Any Attribute Mapping is handled when
* used with the TreeObjectBuilder.</p>
*/
public class XMLAnyAttributeMappingNodeValue extends MappingNodeValue implements ContainerValue {
private AnyAttributeMapping xmlAnyAttributeMapping;
private int index = -1;
public XMLAnyAttributeMappingNodeValue(AnyAttributeMapping xmlAnyAttributeMapping) {
super();
this.xmlAnyAttributeMapping = xmlAnyAttributeMapping;
}
@Override
public boolean isOwningNode(XPathFragment xPathFragment) {
return xPathFragment == null;
}
@Override
public boolean isWrapperAllowedAsCollectionName() {
return false;
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) {
if (xmlAnyAttributeMapping.isReadOnly()) {
return false;
}
Object collection = xmlAnyAttributeMapping.getAttributeValueFromObject(object);
if (collection == null) {
return false;
}
CoreContainerPolicy cp = getContainerPolicy();
Object iter = cp.iteratorFor(collection);
if (!cp.hasNext(iter)) {
return false;
}
XPathFragment groupingElements = marshalRecord.openStartGroupingElements(namespaceResolver);
List extraNamespaces = new ArrayList();
NamespaceResolver nr = marshalRecord.getNamespaceResolver();
while (cp.hasNext(iter)) {
Map.Entry entry = (Map.Entry)cp.nextEntry(iter, session);
Object key = entry.getKey();
if (key instanceof QName) {
QName name = (QName) key;
String value = entry.getValue().toString();
String qualifiedName = name.getLocalPart();
if (nr != null) {
String prefix = nr.resolveNamespaceURI(name.getNamespaceURI());
if ((prefix != null) && prefix.length() > 0) {
qualifiedName = prefix + Constants.COLON+ qualifiedName;
} else if (name.getNamespaceURI() != null && name.getNamespaceURI().length() > 0) {
String generatedPrefix = nr.generatePrefix();
if(marshalRecord.hasCustomNamespaceMapper()) {
String customPrefix = marshalRecord.getMarshaller().getNamespacePrefixMapper().getPreferredPrefix(name.getNamespaceURI(), generatedPrefix, true);
if(customPrefix != null && customPrefix.length() > 0) {
generatedPrefix = customPrefix;
}
}
qualifiedName = generatedPrefix + Constants.COLON + qualifiedName;
nr.put(generatedPrefix, name.getNamespaceURI());
extraNamespaces.add(generatedPrefix);
marshalRecord.namespaceDeclaration(generatedPrefix, name.getNamespaceURI());
}
}
if(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(name.getNamespaceURI())){
marshalRecord.namespaceDeclaration(name.getLocalPart(), name.getNamespaceURI());
}else{
marshalRecord.attribute(name.getNamespaceURI(), name.getLocalPart(), qualifiedName, value);
}
}
}
for (int i = 0; i < extraNamespaces.size(); i++) {
marshalRecord.getNamespaceResolver().removeNamespace((String) extraNamespaces.get(i));
}
marshalRecord.closeStartGroupingElements(groupingElements);
return true;
}
@Override
public void attribute(UnmarshalRecord unmarshalRecord, String namespaceURI, String localName, String value) {
boolean includeAttribute = true;
if(!xmlAnyAttributeMapping.isNamespaceDeclarationIncluded() && javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)){
includeAttribute = false;
}else if(!xmlAnyAttributeMapping.isSchemaInstanceIncluded() && javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(namespaceURI)){
includeAttribute = false;
}
if(includeAttribute){
CoreContainerPolicy cp = xmlAnyAttributeMapping.getContainerPolicy();
Object containerInstance = unmarshalRecord.getContainerInstance(this);
QName key = new QName(namespaceURI, localName);
cp.addInto(key, value, containerInstance, unmarshalRecord.getSession());
}
}
@Override
public Object getContainerInstance() {
return xmlAnyAttributeMapping.getContainerPolicy().containerInstance();
}
@Override
public void setContainerInstance(Object object, Object container) {
xmlAnyAttributeMapping.setAttributeValueInObject(object, container);
}
@Override
public CoreMappedKeyMapContainerPolicy getContainerPolicy() {
return (CoreMappedKeyMapContainerPolicy) xmlAnyAttributeMapping.getContainerPolicy();
}
@Override
public boolean isContainerValue() {
return true;
}
@Override
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) {
return true;
}
@Override
public AnyAttributeMapping getMapping() {
return xmlAnyAttributeMapping;
}
@Override
public boolean getReuseContainer() {
return getMapping().getReuseContainer();
}
/**
* 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();
}
}