| /* |
| * Copyright (c) 2011, 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: |
| // 05/26/2009-2.0 mobrien - API update |
| // - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) |
| // 06/30/2009-2.0 mobrien - finish JPA Metadata API modifications in support |
| // of the Metamodel implementation for EclipseLink 2.0 release involving |
| // Map, ElementCollection and Embeddable types on MappedSuperclass descriptors |
| // 08/06/2010-2.2 mobrien 322018 - reduce protected instance variables to private to enforce encapsulation |
| // 11/10/2011-2.4 Guy Pelletier |
| // - 357474: Address primaryKey option from tenant discriminator column |
| package org.eclipse.persistence.internal.jpa.metamodel; |
| |
| import java.lang.reflect.Field; |
| |
| import jakarta.persistence.metamodel.Bindable; |
| import jakarta.persistence.metamodel.SingularAttribute; |
| import jakarta.persistence.metamodel.Type; |
| |
| import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy; |
| import org.eclipse.persistence.logging.AbstractSessionLog; |
| import org.eclipse.persistence.logging.SessionLog; |
| import org.eclipse.persistence.mappings.AggregateMapping; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.mappings.ForeignReferenceMapping; |
| import org.eclipse.persistence.mappings.VariableOneToOneMapping; |
| import org.eclipse.persistence.mappings.structures.ReferenceMapping; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Provides the implementation for the SingularAttribute interface |
| * of the JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) |
| * <p> |
| * <b>Description</b>: |
| * Instances of the type SingularAttribute represents persistent |
| * single-valued properties or fields. |
| * |
| * @author Michael O'Brien |
| * @see jakarta.persistence.metamodel.SingularAttribute |
| * @since EclipseLink 1.2 - JPA 2.0 |
| * |
| * @param <X> The type containing the represented attribute |
| * @param <T> The type of the represented attribute |
| * |
| */ |
| public class SingularAttributeImpl<X, T> extends AttributeImpl<X, T> implements SingularAttribute<X, T> { |
| |
| /** Item 54: DI 89: explicit UID will avoid performance hit runtime generation of one */ |
| private static final long serialVersionUID = 3928292425281232234L; |
| |
| /** The Type representing this Entity or Basic type **/ |
| private Type<T> elementType; |
| |
| /** |
| * Create an instance of the Attribute |
| * @param managedType |
| * @param mapping |
| */ |
| protected SingularAttributeImpl(ManagedTypeImpl<X> managedType, DatabaseMapping mapping) { |
| this(managedType, mapping, false); |
| } |
| /** |
| * INTERNAL: |
| * Create an Attribute instance with a passed in validation flag (usually set to true only during Metamodel initialization) |
| * @param managedType |
| * @param mapping |
| * @param validationEnabled |
| */ |
| protected SingularAttributeImpl(ManagedTypeImpl<X> managedType, DatabaseMapping mapping, boolean validationEnabled) { |
| super(managedType, mapping); |
| // Case: Handle primitive or java lang type (non-Entity) targets |
| Class attributeClass = mapping.getAttributeClassification(); |
| /** |
| * Case: Handle Entity targets |
| * Process supported mappings by assigning their elementType. |
| * For unsupported mappings we default to MetamodelImpl.DEFAULT_ELEMENT_TYPE. |
| * If attribute is a primitive type (non-null) - we will wrap it in a BasicType automatically in getType below |
| * The attribute classification is null for non-collection mappings such as embeddable keys. |
| */ |
| if (null == attributeClass) { |
| |
| // We support @OneToOne but not EIS, Reference or VariableOneToOne |
| // Note: OneToMany, ManyToMany are handled by PluralAttributeImpl |
| if(mapping instanceof ForeignReferenceMapping) {// handles @ManyToOne |
| attributeClass = ((ForeignReferenceMapping)mapping).getReferenceClass(); |
| } else if (mapping.isAbstractDirectMapping()) { // Also handles the keys of an EmbeddedId |
| attributeClass = mapping.getField().getType(); |
| if(null == attributeClass) { |
| // lookup the attribute on the containing class |
| attributeClass = managedType.getTypeClassFromAttributeOrMethodLevelAccessor(mapping); |
| } |
| } else if (mapping.isAggregateObjectMapping()) { // IE: EmbeddedId |
| attributeClass = ((AggregateMapping)mapping).getReferenceClass(); |
| } else if (mapping.isVariableOneToOneMapping()) { // interfaces are unsupported in the JPA 2.0 spec for the Metamodel API |
| if(validationEnabled) { |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_mapping_type_is_unsupported", mapping, this); |
| } |
| // see JUnitCriteriaUnitTestSuite.testSelectPhoneNumberAreaCode() line: 246 |
| // VariableOneToOne mappings are unsupported - default to referenceClass (Interface) anyway |
| // see interface org.eclipse.persistence.testing.models.jpa.relationships.Distributor |
| attributeClass = ((VariableOneToOneMapping)mapping).getReferenceClass(); |
| } else if (mapping.isEISMapping() || mapping.isTransformationMapping()) { // unsupported in the JPA 2.0 spec for the Metamodel API |
| if(validationEnabled) { |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_mapping_type_is_unsupported", mapping, this); |
| } |
| } else if ( mapping.isReferenceMapping()) { // unsupported in the JPA 2.0 spec for the Metamodel API |
| if(validationEnabled) { |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_mapping_type_is_unsupported", mapping, this); |
| } |
| // Reference mappings are unsupported - default to referenceClass anyway |
| attributeClass = ((ReferenceMapping)mapping).getReferenceClass(); |
| } |
| } |
| // All unsupported mappings such as TransformationMapping |
| if(null == attributeClass && validationEnabled) { |
| // TODO: refactor |
| attributeClass = MetamodelImpl.DEFAULT_ELEMENT_TYPE_FOR_UNSUPPORTED_MAPPINGS; |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_attribute_class_type_is_null", this); |
| } |
| elementType = getMetamodel().getType(attributeClass); |
| } |
| |
| /** |
| * Return the Java type of the represented object. |
| * If the bindable type of the object is <code>PLURAL_ATTRIBUTE</code>, |
| * the Java element type is returned. If the bindable type is |
| * <code>SINGULAR_ATTRIBUTE</code> or <code>ENTITY_TYPE</code>, |
| * the Java type of the |
| * represented entity or attribute is returned. |
| * @return Java type |
| */ |
| @Override |
| public Class<T> getBindableJavaType() { |
| // In SingularAttribute our BindableType is SINGLE_ATTRIBUTE - return the java type of the represented entity |
| return this.elementType.getJavaType(); |
| } |
| |
| /** |
| * Is the attribute an id attribute. |
| * @return boolean indicating whether or not attribute is an id |
| */ |
| @Override |
| public boolean isId() { |
| if(this.getManagedTypeImpl().isMappedSuperclass()) { |
| // The field on the mapping is the same field in the pkFields list on the descriptor |
| // 288792: We can use the new isJPAId field here |
| return (this.getDescriptor().getPrimaryKeyFields().contains(this.getMapping().getField())); |
| } else { |
| // 288792: Some id mappings will return false for isPrimaryKeyMapping but true for isJPAId |
| return getMapping().isPrimaryKeyMapping() || getMapping().isJPAId(); |
| } |
| } |
| |
| /** |
| * Can the attribute be null. |
| * @return boolean indicating whether or not the attribute can |
| * be null |
| */ |
| @Override |
| public boolean isOptional() { |
| return getMapping().isOptional(); |
| } |
| |
| |
| /** |
| * INTERNAL: |
| * Return whether the attribute is plural or singular |
| * @return |
| */ |
| @Override |
| public boolean isPlural() { |
| return false; |
| } |
| |
| /** |
| * Is the attribute a version attribute. |
| * @return boolean indicating whether or not attribute is |
| * a version attribute |
| */ |
| @Override |
| public boolean isVersion() { |
| if (getDescriptor().usesOptimisticLocking() && getMapping().isDirectToFieldMapping()) { |
| OptimisticLockingPolicy policy = getDescriptor().getOptimisticLockingPolicy(); |
| |
| return policy.getWriteLockField().equals(getMapping().getField()); |
| } |
| return false; |
| } |
| |
| @Override |
| public Bindable.BindableType getBindableType() { |
| return Bindable.BindableType.SINGULAR_ATTRIBUTE; |
| } |
| |
| /** |
| * Return the Java type of the represented attribute. |
| * @return Java type |
| */ |
| @Override |
| public Class<T> getJavaType() { |
| if(null == elementType) { |
| Class aJavaType = getMapping().getAttributeClassification(); |
| if(null == aJavaType) { |
| aJavaType = getMapping().getField().getType(); |
| if(null == aJavaType) { |
| // lookup the attribute on the containing class |
| Class containingClass = getMapping().getDescriptor().getJavaClass(); |
| Field aField = null; |
| try { |
| aField = containingClass.getDeclaredField(getMapping().getAttributeName()); |
| aJavaType = aField.getType(); |
| return aJavaType; |
| } catch (NoSuchFieldException nsfe) { |
| // This exception will be warned about below |
| if(null == aJavaType) { |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_attribute_class_type_is_null", this); |
| return (Class<T>) MetamodelImpl.DEFAULT_ELEMENT_TYPE_FOR_UNSUPPORTED_MAPPINGS; |
| } |
| } |
| } |
| } |
| return aJavaType; |
| } else { |
| return this.elementType.getJavaType(); |
| } |
| } |
| |
| /** |
| * Return the type that represents the type of the attribute. |
| * @return type of attribute |
| */ |
| @Override |
| public Type<T> getType() { |
| return elementType; |
| } |
| |
| /** |
| * Return the String representation of the receiver. |
| */ |
| @Override |
| public String toString() { |
| StringBuffer aBuffer = new StringBuffer("SingularAttributeImpl["); |
| aBuffer.append(getType()); |
| aBuffer.append(","); |
| aBuffer.append(getMapping()); |
| aBuffer.append("]"); |
| return aBuffer.toString(); |
| } |
| } |