| /* |
| * 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: |
| // 09 Jan 2013-2.5 Gordon Yorke |
| // - 397772: JPA 2.1 Entity Graph Support |
| package org.eclipse.persistence.internal.jpa; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import jakarta.persistence.AttributeNode; |
| import jakarta.persistence.EntityGraph; |
| import jakarta.persistence.Subgraph; |
| import jakarta.persistence.metamodel.Attribute; |
| import jakarta.persistence.metamodel.PluralAttribute; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.internal.core.helper.CoreClassConstants; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.internal.localization.ExceptionLocalization; |
| import org.eclipse.persistence.internal.queries.AttributeItem; |
| import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.queries.AttributeGroup; |
| |
| /** |
| * Concrete JPA EntityGraph class. For this implementation the EntityGraphImpl |
| * wraps the EclipseLink AttributeGroup type. |
| */ |
| public class EntityGraphImpl<X> extends AttributeNodeImpl<X> implements EntityGraph<X>, Subgraph<X> { |
| |
| protected AttributeGroup attributeGroup; |
| |
| protected transient boolean isMutable = false; |
| |
| protected transient ClassDescriptor descriptor; |
| |
| protected Class<X> classType; |
| |
| protected Map<String, AttributeNodeImpl> attributeNodes; |
| |
| protected EntityGraphImpl(AttributeGroup group, ClassDescriptor descriptor) { |
| super(); |
| this.attributeGroup = group; |
| this.classType = descriptor.getJavaClass(); |
| this.isMutable = true; |
| this.descriptor = descriptor; |
| } |
| |
| public EntityGraphImpl(AttributeGroup group) { |
| super(); |
| this.attributeGroup = group; |
| this.classType = group.getType(); |
| if (this.classType == null){ |
| this.classType = (Class<X>) CoreClassConstants.OBJECT; |
| } |
| } |
| |
| protected EntityGraphImpl(AttributeGroup group, ClassDescriptor descriptor, String attribute) { |
| this(group, descriptor); |
| this.currentAttribute = attribute; |
| } |
| |
| @Override |
| public String getName() { |
| return attributeGroup.getName(); |
| } |
| |
| @Override |
| public void addAttributeNodes(String... attributeNames) { |
| if (!this.isMutable) { |
| throw new IllegalStateException("immutable_entitygraph"); |
| } |
| for (String attrName : attributeNames) { |
| if (this.descriptor.getMappingForAttributeName(attrName) == null){ |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("metamodel_managed_type_attribute_not_present", new Object[]{attrName, this.getClassType()})); |
| } |
| this.addAttributeNodeImpl(new AttributeNodeImpl<X>(attrName)); |
| //order is important here, must add attribute node to node list before adding to group or it will appear in node list twice. |
| this.attributeGroup.addAttribute(attrName, (AttributeGroup) null); |
| } |
| |
| } |
| |
| protected void addAttributeNodeImpl(AttributeNodeImpl attributeNode) { |
| if (this.attributeNodes == null) { |
| buildAttributeNodes(); |
| } |
| |
| this.attributeNodes.put(attributeNode.getAttributeName(), attributeNode); |
| } |
| |
| @Override |
| public void addAttributeNodes(Attribute<X, ?>... attribute) { |
| if (!this.isMutable) { |
| throw new IllegalStateException("immutable_entitygraph"); |
| } |
| for (Attribute<X, ?> attrNode : attribute) { |
| this.addAttributeNodeImpl(new AttributeNodeImpl<X>(attrNode.getName())); |
| //order is important here, must add attribute node to node list before adding to group or it will appear in node list twice. |
| this.attributeGroup.addAttribute(attrNode.getName()); |
| } |
| } |
| |
| @Override |
| public <T> Subgraph<T> addSubgraph(Attribute<X, T> attribute) { |
| Class<T> type = attribute.getJavaType(); |
| if (attribute.isCollection()) { |
| type = ((PluralAttribute) attribute).getBindableJavaType(); |
| } |
| return addSubgraph(attribute.getName(), type); |
| } |
| |
| @Override |
| public <T> Subgraph<? extends T> addSubgraph(Attribute<X, T> attribute, Class<? extends T> type) { |
| return addSubgraph(attribute.getName(), type); |
| } |
| |
| @Override |
| public <X> Subgraph<X> addSubgraph(String attributeName) { |
| return this.addSubgraph(attributeName, null); |
| } |
| |
| @Override |
| public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) { |
| if (!this.isMutable) { |
| throw new IllegalStateException(ExceptionLocalization.buildMessage("immutable_entitygraph")); |
| } |
| AttributeNodeImpl node = null; |
| if (this.attributeNodes != null){ |
| node = this.attributeNodes.get(attributeName); |
| } |
| if (node == null){ |
| node = new AttributeNodeImpl<X>(attributeName); |
| addAttributeNodeImpl(node); |
| } |
| AttributeGroup localGroup = null; |
| DatabaseMapping mapping = descriptor.getMappingForAttributeName(attributeName); |
| if (mapping == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("metamodel_managed_type_attribute_not_present", new Object[] { attributeName, this.descriptor.getJavaClassName() })); |
| } |
| |
| localGroup = new AttributeGroup(attributeName, type, true); |
| |
| ClassDescriptor targetDesc = mapping.getReferenceDescriptor(); |
| if (type != null && targetDesc.hasInheritance()) { |
| targetDesc = targetDesc.getInheritancePolicy().getDescriptor(type); |
| if (targetDesc == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("type_unkown_for_this_attribute", new Object[] { type.getName(), attributeName })); |
| } |
| } |
| EntityGraphImpl entityGraph = new EntityGraphImpl(localGroup, targetDesc, attributeName); |
| node.addSubgraph(entityGraph); |
| //order is important here, must add entity graph to node list before adding to group or it will appear in node list twice. |
| this.attributeGroup.addAttribute(attributeName, localGroup); |
| return entityGraph; |
| } |
| |
| @Override |
| public <T> Subgraph<T> addKeySubgraph(Attribute<X, T> attribute) { |
| if (!this.isMutable) { |
| throw new IllegalStateException("immutable_entitygraph"); |
| } |
| Class<T> type = attribute.getJavaType(); |
| if (attribute.isCollection()) { |
| type = ((PluralAttribute) attribute).getBindableJavaType(); |
| } |
| return addKeySubgraph(attribute.getName(), type); |
| } |
| |
| @Override |
| public <T> Subgraph<? extends T> addKeySubgraph(Attribute<X, T> attribute, Class<? extends T> type) { |
| return addKeySubgraph(attribute.getName(), type); |
| } |
| |
| @Override |
| public <X> Subgraph<X> addKeySubgraph(String attributeName) { |
| return this.addKeySubgraph(attributeName, null); |
| } |
| |
| @Override |
| public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) { |
| if (!this.isMutable) { |
| throw new IllegalStateException(ExceptionLocalization.buildMessage("immutable_entitygraph")); |
| } |
| AttributeNodeImpl node = null; |
| if (this.attributeNodes != null){ |
| node = this.attributeNodes.get(attributeName); |
| } |
| if (node == null){ |
| node = new AttributeNodeImpl<X>(attributeName); |
| addAttributeNodeImpl(node); |
| } |
| AttributeGroup localGroup = null; |
| DatabaseMapping mapping = descriptor.getMappingForAttributeName(attributeName); |
| if (mapping == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("metamodel_managed_type_attribute_not_present", new Object[] { this.descriptor.getJavaClassName(), attributeName })); |
| } |
| if (!mapping.getContainerPolicy().isMappedKeyMapPolicy() && !((MappedKeyMapContainerPolicy) mapping.getContainerPolicy()).isMapKeyAttribute()) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("attribute_is_not_map_with_managed_key", new Object[] { attributeName, descriptor.getJavaClassName() })); |
| } |
| |
| localGroup = new AttributeGroup(attributeName, type, true); |
| |
| ClassDescriptor targetDesc = mapping.getContainerPolicy().getDescriptorForMapKey(); |
| if (type != null && targetDesc.hasInheritance()) { |
| targetDesc = targetDesc.getInheritancePolicy().getDescriptor(type); |
| if (targetDesc == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("type_unkown_for_this_attribute", new Object[] { type.getName(), attributeName })); |
| } |
| } |
| EntityGraphImpl entityGraph = new EntityGraphImpl(localGroup, targetDesc, attributeName); |
| node.addKeySubgraph(entityGraph); |
| //order is important here, must add entity graph to node list before adding to group or it will appear in node list twice. |
| this.attributeGroup.addAttributeKey(attributeName, localGroup); |
| return entityGraph; |
| } |
| |
| @Override |
| public <T> Subgraph<? extends T> addSubclassSubgraph(Class<? extends T> type) { |
| if (!this.isMutable) { |
| throw new IllegalStateException("immutable_entitygraph"); |
| } |
| ClassDescriptor targetDesc = this.descriptor; |
| if (targetDesc.hasInheritance()) { |
| targetDesc = targetDesc.getInheritancePolicy().getDescriptor(type); |
| if (targetDesc == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("type_unkown_for_this_entity", new Object[] { type.getName(), this.descriptor.getJavaClassName() })); |
| } |
| } |
| AttributeGroup subGroup = new AttributeGroup(this.attributeGroup.getName(), type, true); |
| this.attributeGroup.getSubClassGroups().put(type, subGroup); |
| subGroup.setAllSubclasses(this.attributeGroup.getSubClassGroups()); |
| this.attributeGroup.insertSubClass(subGroup); |
| return new EntityGraphImpl(subGroup, targetDesc); |
| } |
| |
| @Override |
| public List<AttributeNode<?>> getAttributeNodes() { |
| if (this.attributeNodes == null) { |
| buildAttributeNodes(); |
| } |
| return new ArrayList(this.attributeNodes.values()); |
| } |
| |
| @Override |
| public Class<X> getClassType() { |
| return this.classType; |
| } |
| |
| /** |
| * @return the attributeGroup |
| */ |
| public AttributeGroup getAttributeGroup() { |
| return attributeGroup; |
| } |
| |
| @Override |
| public String getAttributeName() { |
| return currentAttribute; |
| } |
| |
| protected void buildAttributeNodes() { |
| //this instance was built from a pre-existing attribute group so we need to rebuild |
| //and entity graph |
| this.attributeNodes = new HashMap<String, AttributeNodeImpl>(); |
| for (AttributeItem item : this.attributeGroup.getItems().values()) { |
| AttributeNodeImpl node = new AttributeNodeImpl(item.getAttributeName()); |
| ClassDescriptor localDescriptor = null; |
| if (this.descriptor != null) { |
| localDescriptor = this.descriptor.getMappingForAttributeName(item.getAttributeName()).getReferenceDescriptor(); |
| } |
| if (item.getGroups() != null && ! item.getGroups().isEmpty()) { |
| for (AttributeGroup subGroup : item.getGroups().values()) { |
| Class type = subGroup.getType(); |
| if (type == null) { |
| type = CoreClassConstants.OBJECT; |
| } |
| if (localDescriptor != null) { |
| if (!type.equals(CoreClassConstants.OBJECT) && localDescriptor.hasInheritance()) { |
| localDescriptor = localDescriptor.getInheritancePolicy().getDescriptor(type); |
| } |
| node.addSubgraph(new EntityGraphImpl(subGroup, localDescriptor)); |
| } else { |
| node.addSubgraph(new EntityGraphImpl(subGroup)); |
| } |
| |
| } |
| } |
| if (item.getKeyGroups() != null && ! item.getKeyGroups().isEmpty()) { |
| for (AttributeGroup subGroup : item.getKeyGroups().values()) { |
| Class type = subGroup.getType(); |
| if (type == null) { |
| type = CoreClassConstants.OBJECT; |
| } |
| if (localDescriptor != null) { |
| if (!type.equals(CoreClassConstants.OBJECT) && localDescriptor.hasInheritance()) { |
| localDescriptor = localDescriptor.getInheritancePolicy().getDescriptor(type); |
| } |
| node.addKeySubgraph(new EntityGraphImpl(subGroup, localDescriptor)); |
| } else { |
| node.addKeySubgraph(new EntityGraphImpl(subGroup)); |
| } |
| } |
| } |
| this.attributeNodes.put(item.getAttributeName(), node); |
| } |
| |
| } |
| |
| } |