| /* |
| * Copyright (c) 1998, 2019 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.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); |
| Descriptor xmlDescriptor = (Descriptor)getDescriptor(); |
| |
| // INHERITANCE |
| if (xmlDescriptor.hasInheritance()) { |
| CoreInheritancePolicy inheritancePolicy = xmlDescriptor.getInheritancePolicy(); |
| |
| if (!inheritancePolicy.hasClassExtractor()) { |
| Field 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); |
| } |
| |
| } |
| |
| } |