blob: 7e3248b665667c7efa4840a0a84016282fa98af4 [file] [log] [blame]
/*
* 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:
// 03/19/2009-2.0 dclarke - initial API start
// 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
// - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API)
// 08/19/2009-2.0 mobrien - Extend Collection support
// http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_59:_20090818:_PluralAttribute.elementType_not_set_for_non-lazy_instantiated_Collection_Attribute
// 06/14/2010-2.1 mobrien - 314906: getJavaType should return the
// collection javaType C in <X,C,V) of <X, List<V>, V> instead off the elementType V
// 08/06/2010-2.2 mobrien 322018 - reduce protected instance variables to private to enforce encapsulation
package org.eclipse.persistence.internal.jpa.metamodel;
import jakarta.persistence.metamodel.Bindable;
import jakarta.persistence.metamodel.PluralAttribute;
import jakarta.persistence.metamodel.Type;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.queries.MapContainerPolicy;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.mappings.AggregateCollectionMapping;
import org.eclipse.persistence.mappings.CollectionMapping;
/**
* <p>
* <b>Purpose</b>: Provides the implementation for the PluralAttribute 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 PluralAttribute represent
* persistent collection-valued attributes.
*
* @see jakarta.persistence.metamodel.PluralAttribute
*
* @since EclipseLink 1.2 - JPA 2.0
*
* @param <X> The type the represented collection belongs to
* @param <C> The type of the represented collection
* @param <V> The element type of the represented collection
*
*/
public abstract class PluralAttributeImpl<X, C, V> extends AttributeImpl<X, C> implements PluralAttribute<X, C, V> {
/** The type representing this collection type **/
private Type<V> elementType;
/**
* INTERNAL:
* Create an Attribute instance with a passed in validation flag (usually set to true only during Metamodel initialization)
*/
protected PluralAttributeImpl(ManagedTypeImpl<X> managedType, CollectionMapping mapping, boolean validationEnabled) {
super(managedType, mapping);
// 1) Check the mapping type first
// 2) Get the type set on the policy
ClassDescriptor elementDesc = mapping.getContainerPolicy().getElementDescriptor();
// Set the element type on this attribute (the value parameter for a MapAttribute)
if (elementDesc != null && !(mapping.isMapKeyMapping() || mapping.isDirectMapMapping())) {
// Mappings: OneToMany, UnidirectionalOneToMany, ManyToMany
this.elementType = getMetamodel().getType(elementDesc.getJavaClass());
} else {
// See CollectionContainerPolicy
Class attributeClass = null;
// TODO: handle AggregateCollectionMapping and verify isAbstractDirectMapping
if(mapping.isDirectCollectionMapping() || mapping.isAbstractCompositeDirectCollectionMapping()
|| mapping.isDirectCollectionMapping()) {
/**
* The Map Value parameter was set during metadata processing in DirectCollectionMapping.convertClassNamesToClasses() for example.
* The attributeClassification is set from the valueField.typeName String instead of the type Class because of the
* way that converters shadow the type/typeName in bug# 289487
*/
attributeClass = mapping.getAttributeClassification();
/**
* REFACTOR
* We were unable to get the type because it is not declared as a generic parameter on the method level attribute.
* It may be declared on the field.
* See design issue 65 - we need a way to parse the signature of the declaration on the java class - if it exists.
* http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_65:_20090827:_Handle_DirectCollection_elementType_retrieval_in_the_absence_of_a_generic_type
* Example:
*
* Collection<String> basicCollection;
* @BasicCollection
* Collection getBasicCollection()
*/
// Note: a call to managedType.getTypeClassFromAttributeOrMethodLevelAccesso will only return the class of the collection on the method accessor
if (null == attributeClass) {
//attributeClass = managedType.getTypeClassFromAttributeOrMethodLevelAccessor(mapping);
AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_unable_to_determine_element_type_in_absence_of_generic_parameters", this);
}
} else if(mapping.isMapKeyMapping()) {
ContainerPolicy policy = mapping.getContainerPolicy();
if (policy.isMapPolicy()) {
MapContainerPolicy mapPolicy = (MapContainerPolicy) mapping.getContainerPolicy();
attributeClass = mapPolicy.getElementClass();
} else {
// TODO: refactor: default to the managedType
attributeClass = managedType.getJavaType();
}
} else if (mapping.isManyToManyMapping() || mapping.isOneToManyMapping()) {
// Example: Collection with an instantiated Set/List
attributeClass = mapping.getReferenceClass();
} else if (mapping.isAggregateCollectionMapping()) {
// get reference class and check if managedType is a MappedSuperclass
attributeClass = mapping.getReferenceClass();
}
// TODO: refactor exception handling
if (null == attributeClass && validationEnabled) {
attributeClass = Object.class;
AbstractSessionLog.getLog().log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_attribute_class_type_is_null", this);
}
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<V> getBindableJavaType() {
// For PLURAL_ATTRIBUTE - return the java element type
return elementType.getJavaType();
}
/**
* Return the bindable type of the represented object.
* @return bindable type
*/
@Override
public BindableType getBindableType() {
return Bindable.BindableType.PLURAL_ATTRIBUTE;
}
/**
* INTERNAL:
* Return the mapping associated with this PluralAttribute.
*/
public CollectionMapping getCollectionMapping() {
return (CollectionMapping) getMapping();
}
/**
* Return the collection type.
* @return collection type
*/
@Override
public abstract CollectionType getCollectionType();
/**
* Return the type representing the element type of the
* collection.
* @return element type
*/
@Override
public Type<V> getElementType() {
return this.elementType;
}
@Override
public boolean isPlural() {
return true;
}
@Override
public String toString() {
StringBuffer aBuffer = new StringBuffer(getJavaType().getSimpleName());
aBuffer.append("AttributeImpl[");
//aBuffer.append(getElementType());
//aBuffer.append(",");
aBuffer.append(getMapping());
aBuffer.append("]");
return aBuffer.toString();
}
}