| /* |
| * 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.jpa.parsing; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.mappings.DirectCollectionMapping; |
| import org.eclipse.persistence.mappings.querykeys.ForeignReferenceQueryKey; |
| import org.eclipse.persistence.mappings.querykeys.QueryKey; |
| import org.eclipse.persistence.internal.queries.ContainerPolicy; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedClassForName; |
| import org.eclipse.persistence.internal.helper.BasicTypeHelperImpl; |
| |
| /** |
| * INTERNAL |
| * <p><b>Purpose</b>: Implement type helper methods specified by TypeHelper. |
| * This implementation uses Class instances to represent a type. |
| */ |
| public class TypeHelperImpl |
| extends BasicTypeHelperImpl implements TypeHelper { |
| |
| /** The session. */ |
| private final AbstractSession session; |
| |
| /** The class loader used to resolve type names. */ |
| private final ClassLoader classLoader; |
| |
| /** */ |
| public TypeHelperImpl(AbstractSession session, ClassLoader classLoader) { |
| this.session = session; |
| this.classLoader = classLoader; |
| } |
| |
| /** Returns a type representation for the specified type name or null if |
| * there is no such type. |
| */ |
| @Override |
| public Object resolveTypeName(String typeName) { |
| try { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| return AccessController.doPrivileged( |
| new PrivilegedClassForName<>(typeName, true, classLoader)); |
| } catch (PrivilegedActionException exception) { |
| return null; |
| } |
| } else { |
| return PrivilegedAccessHelper.getClassForName(typeName, true, classLoader); |
| } |
| } catch (ClassNotFoundException ex) { |
| return null; |
| } |
| } |
| |
| /** Returns the type of the attribute with the specified name in the |
| * specified owner class. |
| */ |
| @Override |
| public Object resolveAttribute(Object ownerClass, String attribute) { |
| DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); |
| if (mapping != null) { |
| return getType(mapping); |
| } |
| QueryKey queryKey = resolveQueryKey(ownerClass, attribute); |
| if (queryKey == null) { |
| return null; |
| } else if (queryKey.isForeignReferenceQueryKey()) { |
| return ((ForeignReferenceQueryKey)queryKey).getReferenceClass(); |
| } else { |
| return Object.class; |
| } |
| } |
| |
| /** Returns the type of the map key for the mapping on ownerClass named attribute |
| * Returns null if that mapping does not exist or does not contain a map key |
| */ |
| @Override |
| public Object resolveMapKey(Object ownerClass, String attribute) { |
| Object type = null; |
| DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); |
| if (mapping.isCollectionMapping()){ |
| ContainerPolicy cp = mapping.getContainerPolicy(); |
| type = cp.getKeyType(); |
| } |
| return type; |
| } |
| |
| /** Returns the type of the class corresponding to the specified abstract |
| * schema type. |
| */ |
| @Override |
| public Object resolveSchema(String schemaName) { |
| ClassDescriptor descriptor = session.getDescriptorForAlias(schemaName); |
| return (descriptor != null) ? descriptor.getJavaClass() : null; |
| } |
| |
| /** Returns the enum constant if the specified type denotes an enum type |
| * and the specified constant denotes a constant of the enum type. |
| */ |
| @Override |
| public Object resolveEnumConstant(Object type, String constant) { |
| Class<?> clazz = getJavaClass(type); |
| Object[] constants = clazz.getEnumConstants(); |
| if (constants != null) { |
| for (int i = 0; i < constants.length; i++) { |
| Enum<?> enumConstant = (Enum<?>) constants[i]; |
| if (enumConstant.name().equals(constant)) { |
| return enumConstant; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** Returns true if the specified type denotes an entity class. */ |
| @Override |
| public boolean isEntityClass(Object type) { |
| ClassDescriptor desc = getDescriptor(type); |
| return (desc != null) && !desc.isAggregateDescriptor(); |
| } |
| |
| /** Returns true if the specified type denotes an orderable type */ |
| @Override |
| public boolean isOrderableType(Object type) { |
| return !(isEntityClass(type) || isEmbeddable(type)); |
| } |
| |
| /** Returns true if the specified type denotes an embedded class. */ |
| @Override |
| public boolean isEmbeddable(Object type) { |
| ClassDescriptor desc = getDescriptor(type); |
| return (desc != null) && desc.isAggregateDescriptor(); |
| } |
| |
| /** Returns true if the specified type denotes an embedded attribute. */ |
| @Override |
| public boolean isEmbeddedAttribute(Object ownerClass, String attribute) { |
| DatabaseMapping mapping = |
| resolveAttributeMapping(ownerClass, attribute); |
| return (mapping != null) && mapping.isAggregateObjectMapping(); |
| } |
| |
| /** Returns true if the specified type denotes a simple state attribute. */ |
| @Override |
| public boolean isSimpleStateAttribute(Object ownerClass, String attribute) { |
| DatabaseMapping mapping = |
| resolveAttributeMapping(ownerClass, attribute); |
| return (mapping != null) && mapping.isDirectToFieldMapping(); |
| } |
| |
| /** Returns true if the specified attribute denotes a single valued |
| * or collection valued relationship attribute. |
| */ |
| @Override |
| public boolean isRelationship(Object ownerClass, String attribute) { |
| DatabaseMapping mapping = |
| resolveAttributeMapping(ownerClass, attribute); |
| return (mapping != null) && mapping.isForeignReferenceMapping(); |
| } |
| |
| /** Returns true if the specified attribute denotes a single valued |
| * relationship attribute. |
| */ |
| @Override |
| public boolean isSingleValuedRelationship(Object ownerClass, |
| String attribute) { |
| DatabaseMapping mapping = |
| resolveAttributeMapping(ownerClass, attribute); |
| return (mapping != null) && mapping.isObjectReferenceMapping(); |
| } |
| |
| /** Returns true if the specified attribute denotes a collection valued |
| * relationship attribute. |
| */ |
| @Override |
| public boolean isCollectionValuedRelationship(Object ownerClass, |
| String attribute) { |
| DatabaseMapping mapping = |
| resolveAttributeMapping(ownerClass, attribute); |
| return (mapping != null) && |
| (mapping.isOneToManyMapping() || mapping.isManyToManyMapping()); |
| } |
| |
| // ===== Internal helper methods ===== |
| |
| /** Returns the class descriptor if the specified non-null type is a class |
| * object. |
| */ |
| private ClassDescriptor getDescriptor(Object type) { |
| ClassDescriptor desc = null; |
| if (type instanceof Class) { |
| desc = session.getDescriptor((Class<?>)type); |
| } else if (type instanceof ClassDescriptor) { |
| desc = (ClassDescriptor)type; |
| } |
| return desc; |
| } |
| |
| /** Returns the mapping for the specified attribute of the specified |
| * class. The method returns null if the class is not known or if the |
| * class does not have an attribute of the specified name. |
| */ |
| private DatabaseMapping resolveAttributeMapping(Object ownerClass, String attribute) { |
| ClassDescriptor descriptor = getDescriptor(ownerClass); |
| return (descriptor == null) ? null : descriptor.getObjectBuilder().getMappingForAttributeName(attribute); |
| } |
| |
| @Override |
| public QueryKey resolveQueryKey(Object ownerClass, String attribute) { |
| ClassDescriptor descriptor = getDescriptor(ownerClass); |
| if (descriptor == null) { |
| return null; |
| } |
| return descriptor.getQueryKeyNamed(attribute); |
| } |
| |
| private Object getType(DatabaseMapping mapping) { |
| if (mapping == null) { |
| return null; |
| } |
| Object type = null; |
| if (mapping.isDirectCollectionMapping()){ |
| type = ((DirectCollectionMapping)mapping).getDirectField().getType(); |
| if (type == null){ |
| type = Object.class; |
| } |
| } else if (mapping.isAggregateCollectionMapping()) { |
| // Return the ClassDescriptor as the type representation in case |
| // of an embedded. This makes sure that any property or field |
| // access of the embedded uses the correct mapping information and |
| // not the shell of the descriptors as stored by the session. |
| type = mapping.getReferenceDescriptor(); |
| } else if (mapping.isForeignReferenceMapping()) { |
| ClassDescriptor descriptor = mapping.getReferenceDescriptor(); |
| type = descriptor == null ? null : descriptor.getJavaClass(); |
| } else if (mapping.isAggregateMapping()) { |
| // Return the ClassDescriptor as the type representation in case |
| // of an embedded. This makes sure that any property or field |
| // access of the embedded uses the correct mapping information and |
| // not the shell of the descriptors as stored by the session. |
| type = mapping.getReferenceDescriptor(); |
| } else { |
| type = mapping.getAttributeAccessor().getAttributeClass(); |
| } |
| return type; |
| } |
| |
| } |
| |