blob: 654340d09b43fdd4a50d077bbdc6da09befe3737 [file] [log] [blame]
/*
* 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:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.oxm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.persistence.core.descriptors.CoreInheritancePolicy;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecord;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DatabaseMapping.WriteType;
import org.eclipse.persistence.oxm.NamespaceResolver;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.XMLField;
import org.eclipse.persistence.oxm.record.NodeRecord;
import org.eclipse.persistence.oxm.record.UnmarshalRecord;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* INTERNAL:
* <p><b>Purpose</b>: Perform the unmarshal and marshal operations based on the
* object-to-XML mapping metadata.</p>
* <p><b>Responsibilities</b>:<ul>
* <li>Convert mapping metadata to a tree of XPathNodes. This tree is then
* traversed during unmarshal and marshal operations.</li>
* <li>Create records appropriate to this implementation of ObjectBuilder.</li>
* </ul>
*/
public class TreeObjectBuilder extends XMLObjectBuilder implements ObjectBuilder<AbstractRecord, AbstractSession, ClassDescriptor, XMLMarshaller> {
private XPathObjectBuilder xPathObjectBuilder;
public TreeObjectBuilder(ClassDescriptor descriptor) {
super(descriptor);
xPathObjectBuilder = new XPathObjectBuilder(descriptor);
}
@Override
protected void initialize(ClassDescriptor descriptor) {
int descriptorMappingsSize = descriptor.getMappings().size();
this.mappingsByField = new HashMap(descriptorMappingsSize);
this.fieldsMap = new HashMap(descriptorMappingsSize);
this.cloningMappings = new ArrayList(descriptorMappingsSize);
}
@Override
public XPathNode getRootXPathNode() {
return xPathObjectBuilder.getRootXPathNode();
}
@Override
public List<DatabaseMapping> getPrimaryKeyMappings() {
if(null == primaryKeyMappings) {
primaryKeyMappings = new ArrayList<>(1);
}
return primaryKeyMappings;
}
@Override
public List getTransformationMappings() {
return xPathObjectBuilder.getTransformationMappings();
}
@Override
public List getContainerValues() {
return xPathObjectBuilder.getContainerValues();
}
@Override
public List getNullCapableValues() {
return xPathObjectBuilder.getNullCapableValues();
}
@Override
public List getDefaultEmptyContainerValues() {
return xPathObjectBuilder.getDefaultEmptyContainerValues();
}
@Override
public void initialize(org.eclipse.persistence.internal.sessions.AbstractSession session) {
super.initialize(session);
XMLDescriptor xmlDescriptor = (XMLDescriptor)getDescriptor();
// INHERITANCE
if (xmlDescriptor.hasInheritance()) {
CoreInheritancePolicy<AbstractRecord, AbstractSession, ClassDescriptor, DatabaseField> inheritancePolicy = xmlDescriptor.getInheritancePolicy();
if (!inheritancePolicy.hasClassExtractor()) {
Field<XMLConversionManager, NamespaceResolver> classIndicatorField = new XMLField(inheritancePolicy.getClassIndicatorFieldName());
classIndicatorField.setNamespaceResolver(xmlDescriptor.getNamespaceResolver());
}
}
if(!xmlDescriptor.isLazilyInitialized()) {
xPathObjectBuilder.lazyInitialize();
}
}
@Override
public AbstractRecord buildRow(AbstractRecord record, Object object, org.eclipse.persistence.internal.sessions.AbstractSession session, WriteType writeType) {
return (AbstractRecord) buildRow((XMLRecord) record, object, session, null, null);
}
@Override
public org.eclipse.persistence.internal.oxm.record.XMLRecord buildRow(org.eclipse.persistence.internal.oxm.record.XMLRecord record, Object object, CoreAbstractSession session, XMLMarshaller marshaller, XPathFragment rootFragment) {
return xPathObjectBuilder.buildRow(record, object, session, marshaller, rootFragment);
}
@Override
public boolean marshalAttributes(MarshalRecord marshalRecord, Object object, CoreAbstractSession session) {
return xPathObjectBuilder.marshalAttributes(marshalRecord, object, session);
}
/**
* Create a new row/record for the object builder.
* This allows subclasses to define different record types.
*/
@Override
public AbstractRecord createRecord(AbstractSession session) {
xPathObjectBuilder.lazyInitialize();
org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl uRec = new org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl(this);
uRec.setSession(session);
return new UnmarshalRecord(uRec);
}
/**
* Create a new row/record for the object builder with the given name.
* This allows subclasses to define different record types.
*/
@Override
public AbstractMarshalRecord createRecord(String rootName, AbstractSession session) {
NodeRecord nRec = new NodeRecord(rootName, getNamespaceResolver());
nRec.setSession(session);
return nRec;
}
/**
* Create a new row/record for the object builder with the given name.
* This allows subclasses to define different record types.
*/
@Override
public AbstractMarshalRecord createRecord(String rootName, Node parent, AbstractSession session) {
NodeRecord nRec = new NodeRecord(rootName, getNamespaceResolver(), parent);
nRec.setSession(session);
return nRec;
}
/**
* Create a new row/record for the object builder.
* This allows subclasses to define different record types.
*/
@Override
public AbstractRecord createRecord(int size, AbstractSession session) {
return createRecord(session);
}
@Override
public List addExtraNamespacesToNamespaceResolver(Descriptor desc, AbstractMarshalRecord marshalRecord, CoreAbstractSession session, boolean allowOverride, boolean ignoreEqualResolvers) {
return xPathObjectBuilder.addExtraNamespacesToNamespaceResolver(desc, marshalRecord, session, allowOverride, ignoreEqualResolvers);
}
@Override
public boolean addClassIndicatorFieldToRow(AbstractMarshalRecord abstractMarshalRecord) {
if (descriptor.hasInheritance() && !xPathObjectBuilder.isXsiTypeIndicatorField()) {
InheritanceRecord inheritanceRecord = new InheritanceRecord(abstractMarshalRecord);
descriptor.getInheritancePolicy().addClassIndicatorFieldToRow(inheritanceRecord);
return true;
}
return false;
}
@Override
public Class<?> classFromRow(org.eclipse.persistence.internal.oxm.record.UnmarshalRecord unmarshalRecord, AbstractSession session) {
UnmarshalRecord inheritanceRecord = new UnmarshalRecord(unmarshalRecord);
return descriptor.getInheritancePolicy().classFromRow(inheritanceRecord, session);
}
private static class InheritanceRecord extends org.eclipse.persistence.oxm.record.XMLRecord {
private AbstractMarshalRecord abstractMarshalRecord;
public InheritanceRecord(AbstractMarshalRecord abstractMarshalRecord) {
this.abstractMarshalRecord = abstractMarshalRecord;
}
@Override
public String getLocalName() {
throw new UnsupportedOperationException();
}
@Override
public String getNamespaceURI() {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public Document getDocument() {
throw new UnsupportedOperationException();
}
@Override
public Node getDOM() {
throw new UnsupportedOperationException();
}
@Override
public String transformToXML() {
throw new UnsupportedOperationException();
}
@Override
public boolean isNamespaceAware() {
return abstractMarshalRecord.isNamespaceAware();
}
@Override
public boolean hasCustomNamespaceMapper() {
return abstractMarshalRecord.hasCustomNamespaceMapper();
}
@Override
public char getNamespaceSeparator() {
return abstractMarshalRecord.getNamespaceSeparator();
}
@Override
public Object put(DatabaseField key, Object value) {
return abstractMarshalRecord.put(key, value);
}
}
}