All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.jpa.metamodel.MapAttributeImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2011, 2018 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)
//     11/05/2009-2.0  mobrien - DI 86: MapKey support when only generics
//         are used to determine the keyType for an IdClass that used an embeddable
//     11/10/2009-2.0  mobrien - DI 98: Use keyMapping on MappedKeyMappedContainerPolicy
//         keep workaround for bug# 294765 for Basic keyType when MapKey annotation not specified.
//         keep workaround for bug# 294811 for Entity, Embeddable, Transient keyType support
//           when MapKey name attribute not specified (MapContainerPolicy)
//         add BasicMap support via DirectMapContainerPolicy
//     13/10/2009-2.0  mobrien - 294765 - fix allows removal of workaround for
//        when MapKey annotation not specified
//     06/14/2010-2.1  mobrien - 314906: getJavaType should return the
//       collection javaType C in , V> instead off the elementType V
package org.eclipse.persistence.internal.jpa.metamodel;

import java.util.Map;

import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.Type;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy;
import org.eclipse.persistence.mappings.CollectionMapping;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.foundation.MapKeyMapping;

/**
 * 

* Purpose: Provides the implementation for the MapAttribute interface * of the JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) *

* Description: * Instances of the type MapAttribute represent persistent Map-valued * attributes. * * @see javax.persistence.metamodel.MapAttribute * * @since EclipseLink 1.2 - JPA 2.0 * * @param The type the represented Map belongs to * @param The type of the key of the represented Map * @param The type of the value of the represented Map */ public class MapAttributeImpl extends PluralAttributeImpl, V> implements MapAttribute { /** Item 54: DI 89: explicit UID will avoid performance hit runtime generation of one */ private static final long serialVersionUID = 5702748112869113135L; /** The key type that this Map type is based on **/ private Type keyType; /** * INTERNAL: * @param managedType * @param mapping */ protected MapAttributeImpl(ManagedTypeImpl managedType, CollectionMapping mapping) { this(managedType, mapping, false); } /** * INTERNAL: * Create a new MapAttribute instance. * The elementType field is instantiated in the superclass. * The keyType field is instantiated in this constructor by using one of the following * A) MapContainerPolicy by consulting the keyField or PK class * B) MappedKeyMapContainerPolicy by using the mapKeyTargetType on the keyMapping or the attributeClassification on the attributeAccessor * @param managedType - the owning type (EmbeddableTypes do not support mappings) * @param mapping - contains the mapping policy * @param validationEnabled - report errors in the metamodel */ protected MapAttributeImpl(ManagedTypeImpl managedType, CollectionMapping mapping, boolean validationEnabled) { // Set the managedType (X or owning Type) - Note: EmbeddableTypes are only supported as Map keys here super(managedType, mapping, validationEnabled); // We need to set the keyType Type that represents the type of the Map key for this mapping ContainerPolicy policy = mapping.getContainerPolicy(); Class javaClass = null; MapKeyMapping keyMapping = null; Object policyKeyType = null; /** * Note: the (at) sign for annotations has been replaced by the & sign for javadoc processing. * * We have the following policy structure and behavior * ContainerPolicy (A) * +=== InterfaceContainerPolicy (A) * +=== DirectMapContainerPolicy * +=== MapContainerPolicy (use keyField or PK class) * +=== MappedKeyMapContainerPolicy (use keyMapping.mapKeyTargetType or attributeClassification) * * Use Case segmentation for keyType A) MapContainerPolicy A1) keyField set (lazy loaded) UC2 - name attribute defines mapKey, generics are not required and are secondary &OneToMany(cascade=ALL, mappedBy="mappedEmployerUC2") &MapKey(name="name") private Map hardwareDesignersMapUC2; UC4 - name attribute defines mapKey, generics are not required &OneToMany(targetEntity=HardwareDesigner.class, cascade=ALL, mappedBy="mappedEmployerUC4") &MapKey(name="name") private Map hardwareDesignersMapUC4; UC8 - mapKey defined via generics &OneToMany(cascade=ALL, mappedBy="mappedEmployerUC8") &MapKey // name attribute will default to "id" private Map hardwareDesignersMapUC8; A2) Use mapPolicy.elementDescriptor.cmppolicy.pkClass (since KeyField == null) UC10 - mapKey defined via generics and is a java class defined as an IdClass on the element(value) class - here Enclosure &OneToMany(mappedBy="computer", cascade=ALL, fetch=EAGER) &MapKey // key defaults to an instance of the composite pk class private Map enclosures; &Entity &IdClass(EnclosureIdClassPK.class) public class Enclosure {} UC11 - or (get keyClass from mapping if the Id is a get() function) TBD - use reflection B) MappedKeyMapContainerPolicy B1) mapKeyTargetType set on the keyMapping - normal processing UC9 - mapKey defined by generics in the absence of a MapKey annotation &OneToMany(cascade=CascadeType.ALL, mappedBy="mappedManufacturerUC9") private Map enclosureByBoardMapUC9; UC13 - mapKey defined by generics in the absence of a MapKey name attribute (unidirectional M:1 becomes M:M) &MapKey // on Computer inverse private Map position; &ManyToOne(fetch=EAGER) // on GalacticPosition owner private Computer computer; B2) - secondary processing for Basic (DirectToField) mappings Use AttributeClassification (since keyMapping.attributeAccessor.attributeClass == null) UC1a - mapKey defined by generics in the absence of a MapKey annotation &OneToMany(cascade=ALL, mappedBy="mappedEmployerUC1a") private Map hardwareDesignersMapUC1a; UC7 - mapKey defined by generics in the absence of a MapKey annotation &OneToMany(targetEntity=HardwareDesigner.class, cascade=ALL, mappedBy="mappedEmployerUC7") private Map hardwareDesignersMapUC7; */ // Step 1: We check via the ContainerPolicy interface for a mapPolicy for the keyMapping (covers MappedKeyMapContainerPolicy and its superclass MapContainerPolicy if (policy.isMapPolicy()) { // check for Either a generic Map (MapContainerPolicy) or specific MappedKeyMapContainerPolicy subclass if (policy.isMappedKeyMapPolicy()) { // See UC9 // The cast below is unavoidable because getKeyMapping() is not overridden from the MapContainerPolicy superclass keyMapping = ((MappedKeyMapContainerPolicy)policy).getKeyMapping(); policyKeyType = keyMapping.getMapKeyTargetType(); } else { /** * Assume we have a MapContainerPolicy general superclass with a lazy-loaded keyType * or a DirectMapContainerPolicy using a &BasicMap * See UC2, UC4, UC8, UC13 (unidirectional ManyToOne becomes ManyToMany) * returns a Class or descriptor (via AggregateObjectMapping) or null in 2 cases - * 1 - if the ContainerPolicy does not support maps * 2 - If the keyField is null (we handle this below by consulting the CMPPolicy) */ policyKeyType = policy.getKeyType(); } } /** * Step 2: We determine the java class from the policyKeyType (class or ClassDecriptor) * We also perform alternate keyType lookup for the case where * the name attribute is not specified in a MapKey annotation where * the map key is one of the following (via the MapContainerPolicy superclass of MappedKeyMapContainerPolicy) * - map key is an Entity with an IdClass * - map key is Java class that is defined as the IdClass of an Entity (above) */ if(null == policyKeyType) { // Pending reproduction case: @MapKey private Map // no name column specified and the PK is defined by a method if(null == javaClass) { if(policy.isMappedKeyMapPolicy()) { // See UC10, UC11 javaClass = getOwningPKTypeWhenMapKeyAnnotationMissingOrDefaulted( (MappedKeyMapContainerPolicy)policy); } } } else { // Process the policyKeyType normally if(policyKeyType instanceof ClassDescriptor) { // from AggregateObjectMapping javaClass = ((ClassDescriptor)policyKeyType).getJavaClass(); } else { javaClass = (Class)policyKeyType; } } // Optional: catch any holes in our keyType logic (8 hits in clover coverage) if(null == javaClass) { javaClass = Object.class; } // Step 3: We wrap the java type in a Metamodel Type instance or retrieve an existing Type this.keyType = (Type) getMetamodel().getType(javaClass); } /** * INTERNAL: * Default to the PK of the owning descriptor when no MapKey or MapKey:name attribute is specified. * Prerequisites: policy on the mapping is of type MappedKeyMapPolicy * @return */ private Class getOwningPKTypeWhenMapKeyAnnotationMissingOrDefaulted(MappedKeyMapContainerPolicy policy) { Class javaClass = null;; MapKeyMapping mapKeyMapping = policy.getKeyMapping(); ClassDescriptor descriptor = ((DatabaseMapping)mapKeyMapping).getDescriptor(); // If the reference descriptor is null then we are on a direct mapping if(null != descriptor) { javaClass = ((DatabaseMapping)mapKeyMapping).getAttributeClassification(); if(null == javaClass) { // Default to the PK of the owning descriptor when no MapKey or MapKey:name attribute is specified if (descriptor.getCMPPolicy() != null) { javaClass = descriptor.getCMPPolicy().getPKClass(); } } } return javaClass; } /** * Return the collection type. * @return collection type */ @Override public CollectionType getCollectionType() { return CollectionType.MAP; } /** * Return the Java type of the represented attribute. * @return Java type */ @Override public Class getJavaType() { return Map.class; } /** * Return the Java type of the map key. * @return Java key type * @see MapAttribute */ public Class getKeyJavaType() { return keyType.getJavaType(); } /** * Return the type representing the key type of the map. * @return type representing key type * @see MapAttribute */ public Type getKeyType() { return this.keyType; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy