|
Lines 14-20
Link Here
|
| 14 |
* Map, ElementCollection and Embeddable types on MappedSuperclass descriptors |
14 |
* Map, ElementCollection and Embeddable types on MappedSuperclass descriptors |
| 15 |
* - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) |
15 |
* - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) |
| 16 |
* 11/05/2009-2.0 mobrien - DI 86: MapKey support when only generics |
16 |
* 11/05/2009-2.0 mobrien - DI 86: MapKey support when only generics |
| 17 |
* are used to determine the keyType for an IdClass that used an embeddable |
17 |
* are used to determine the keyType for an IdClass that used an embeddable |
|
|
18 |
* 11/10/2009-2.0 mobrien - DI 98: Use keyMapping on MappedKeyMappedContainerPolicy |
| 19 |
* keep workaround for bug# 294765 for Basic keyType when MapKey annotation not specified. |
| 20 |
* keep workaround for bug# 294811 for Entity, Embeddable, Transient keyType support |
| 21 |
* when MapKey name attribute not specified (MapContainerPolicy) |
| 22 |
* add BasicMap support via DirectMapContainerPolicy |
| 18 |
******************************************************************************/ |
23 |
******************************************************************************/ |
| 19 |
package org.eclipse.persistence.internal.jpa.metamodel; |
24 |
package org.eclipse.persistence.internal.jpa.metamodel; |
| 20 |
|
25 |
|
|
Lines 60-115
Link Here
|
| 60 |
* @param managedType |
65 |
* @param managedType |
| 61 |
* @param mapping |
66 |
* @param mapping |
| 62 |
*/ |
67 |
*/ |
| 63 |
protected MapAttributeImpl(ManagedTypeImpl<X> managedType, CollectionMapping mapping) { |
68 |
protected MapAttributeImpl(IdentifiableTypeImpl<X> managedType, CollectionMapping mapping) { |
| 64 |
this(managedType, mapping, false); |
69 |
this(managedType, mapping, false); |
| 65 |
} |
70 |
} |
| 66 |
|
71 |
|
| 67 |
/** |
72 |
/** |
| 68 |
* INTERNAL: |
73 |
* INTERNAL: |
| 69 |
* @param managedType |
74 |
* Create a new MapAttribute instance. |
| 70 |
* @param mapping |
75 |
* The elementType field is instantiated in the superclass. |
| 71 |
* @param validationEnabled |
76 |
* The keyType field is instantiated in this constructor by using one of the following |
|
|
77 |
* A) MapContainerPolicy by consulting the keyField or PK class |
| 78 |
* B) MappedKeyMapContainerPolicy by using the mapKeyTargetType on the keyMapping or the attributeClassification on the attributeAccessor |
| 79 |
* @param managedType - the owning type (EmbeddableTypes do not support mappings) |
| 80 |
* @param mapping - contains the mapping policy |
| 81 |
* @param validationEnabled - report errors in the metamodel |
| 72 |
*/ |
82 |
*/ |
| 73 |
protected MapAttributeImpl(ManagedTypeImpl<X> managedType, CollectionMapping mapping, boolean validationEnabled) { |
83 |
protected MapAttributeImpl(IdentifiableTypeImpl<X> managedType, CollectionMapping mapping, boolean validationEnabled) { |
| 74 |
// Set the managedType (X or owning Type) |
84 |
// Set the managedType (X or owning Type) - Note: EmbeddableTypes are only supported as Map keys here |
| 75 |
super(managedType, mapping, validationEnabled); |
85 |
super(managedType, mapping, validationEnabled); |
| 76 |
// Override the elementType (V or Map value) |
|
|
| 77 |
// We need to set the keyType Type that represents the type of the Map key for this mapping |
86 |
// We need to set the keyType Type that represents the type of the Map key for this mapping |
| 78 |
ContainerPolicy policy = mapping.getContainerPolicy(); |
87 |
ContainerPolicy policy = mapping.getContainerPolicy(); |
|
|
88 |
Class<?> javaClass = null; |
| 89 |
MapKeyMapping keyMapping = null; |
| 79 |
ClassDescriptor policyElementDescriptor = policy.getElementDescriptor(); |
90 |
ClassDescriptor policyElementDescriptor = policy.getElementDescriptor(); |
| 80 |
Object policyKeyType = policy.getKeyType(); // returns a Class<?> or descriptor (via AggregateObjectMapping) |
91 |
Object policyKeyType = null; |
| 81 |
Type<?> aKeyType = null; |
92 |
|
| 82 |
// Default to Object class for any variant cases that are not handled |
93 |
/** |
| 83 |
Class<?> javaClass = null; |
94 |
* Note: the (at) sign for annotations has been replaced by the & sign for javadoc processing. |
|
|
95 |
* |
| 96 |
* We have the following policy structure and behavior |
| 97 |
* ContainerPolicy (A) |
| 98 |
* +=== InterfaceContainerPolicy (A) |
| 99 |
* +=== DirectMapContainerPolicy |
| 100 |
* +=== MapContainerPolicy (use keyField or PK class) |
| 101 |
* +=== MappedKeyMapContainerPolicy (use keyMapping.mapKeyTargetType or attributeClassification) |
| 102 |
* |
| 103 |
* Use Case segmentation for keyType |
| 104 |
A) MapContainerPolicy |
| 105 |
A1) keyField set (lazy loaded) |
| 106 |
UC2 - name attribute defines mapKey, generics are not required and are secondary |
| 107 |
&OneToMany(cascade=ALL, mappedBy="mappedEmployerUC2") |
| 108 |
&MapKey(name="name") |
| 109 |
private Map<String, HardwareDesigner> hardwareDesignersMapUC2; |
| 110 |
UC4 - name attribute defines mapKey, generics are not required |
| 111 |
&OneToMany(targetEntity=HardwareDesigner.class, cascade=ALL, mappedBy="mappedEmployerUC4") |
| 112 |
&MapKey(name="name") |
| 113 |
private Map hardwareDesignersMapUC4; |
| 114 |
UC8 - mapKey defined via generics |
| 115 |
&OneToMany(cascade=ALL, mappedBy="mappedEmployerUC8") |
| 116 |
&MapKey // name attribute will default to "id" |
| 117 |
private Map<Integer, HardwareDesigner> hardwareDesignersMapUC8; |
| 118 |
A2) Use mapPolicy.elementDescriptor.cmppolicy.pkClass (since KeyField == null) |
| 119 |
UC10 - mapKey defined via generics and is a java class defined as an IdClass on the element(value) class - here Enclosure |
| 120 |
&OneToMany(mappedBy="computer", cascade=ALL, fetch=EAGER) |
| 121 |
&MapKey // key defaults to an instance of the composite pk class |
| 122 |
private Map<EnclosureIdClassPK, Enclosure> enclosures; |
| 123 |
&Entity &IdClass(EnclosureIdClassPK.class) public class Enclosure {} |
| 124 |
UC11 - or (get keyClass from mapping if the Id is a get() function) |
| 125 |
TBD - use reflection |
| 126 |
B) MappedKeyMapContainerPolicy |
| 127 |
B1) mapKeyTargetType set on the keyMapping - normal processing |
| 128 |
UC9 - mapKey defined by generics in the absence of a MapKey annotation |
| 129 |
&OneToMany(cascade=CascadeType.ALL, mappedBy="mappedManufacturerUC9") |
| 130 |
private Map<Board, Enclosure> enclosureByBoardMapUC9; |
| 131 |
UC13 - mapKey defined by generics in the absence of a MapKey name attribute (unidirectional M:1 becomes M:M) |
| 132 |
&MapKey // on Computer inverse |
| 133 |
private Map<EmbeddedPK, GalacticPosition> position; |
| 134 |
&ManyToOne(fetch=EAGER) // on GalacticPosition owner |
| 135 |
private Computer computer; |
| 136 |
B2) - secondary processing for Basic (DirectToField) mappings |
| 137 |
Use AttributeClassification (since keyMapping.attributeAccessor.attributeClass == null) |
| 138 |
UC1a - mapKey defined by generics in the absence of a MapKey annotation |
| 139 |
&OneToMany(cascade=ALL, mappedBy="mappedEmployerUC1a") |
| 140 |
private Map<String, HardwareDesigner> hardwareDesignersMapUC1a; |
| 141 |
UC7 - mapKey defined by generics in the absence of a MapKey annotation |
| 142 |
&OneToMany(targetEntity=HardwareDesigner.class, cascade=ALL, mappedBy="mappedEmployerUC7") |
| 143 |
private Map<String, HardwareDesigner> hardwareDesignersMapUC7; |
| 144 |
*/ |
| 145 |
// Step 1: We check via the ContainerPolicy interface for a mapPolicy for the keyMapping (covers MappedKeyMapContainerPolicy and its superclass MapContainerPolicy |
| 146 |
if(policy.isMapPolicy() || policy.isDirectMapPolicy()) { |
| 147 |
// check for Either a generic Map (MapContainerPolicy) or specific MappedKeyMapContainerPolicy subclass |
| 148 |
if(policy.isMappedKeyMapPolicy()) { |
| 149 |
// See UC9 |
| 150 |
// The cast below is unavoidable because getKeyMapping() is not overridden from the MapContainerPolicy superclass |
| 151 |
keyMapping = ((MappedKeyMapContainerPolicy)policy).getKeyMapping(); |
| 152 |
policyKeyType = keyMapping.getMapKeyTargetType(); |
| 153 |
/** |
| 154 |
* If the policyKeyType is not found - it is because the keyMapping is a Basic (DirectToFieldMapping implements MapKeyMapping). |
| 155 |
* Normally we get the pk type via the referenceClass on a OneToOneMapping for example. |
| 156 |
* However, in this case MappedKeyMapContainerPolicy.keyMapping.attributeAccessor.attributeField is null - |
| 157 |
* we workaround this by getting the key from the attributeClassification instead. |
| 158 |
* See UC1a, UC7 |
| 159 |
*/ |
| 160 |
if(null == policyKeyType) { |
| 161 |
// This workaround for bug# 294765 should be moved up into AbstractDirectMapping.getMapKeyTargetType |
| 162 |
policyKeyType = ((DatabaseMapping)keyMapping).getAttributeClassification(); |
| 163 |
} |
| 164 |
} else { |
| 165 |
/** |
| 166 |
* Assume we have a MapContainerPolicy general superclass with a lazy-loaded keyType |
| 167 |
* or a DirectMapContainerPolicy using a &BasicMap |
| 168 |
* See UC2, UC4, UC8, UC13 (unidirectional ManyToOne becomes ManyToMany) |
| 169 |
* returns a Class<?> or descriptor (via AggregateObjectMapping) or null in 2 cases - |
| 170 |
* 1 - if the ContainerPolicy does not support maps |
| 171 |
* 2 - If the keyField is null (we handle this below by consulting the CMPPolicy) |
| 172 |
*/ |
| 173 |
policyKeyType = policy.getKeyType(); |
| 174 |
} |
| 175 |
} |
| 176 |
|
| 177 |
/** |
| 178 |
* Step 2: We determine the java class from the policyKeyType (class or ClassDecriptor) |
| 179 |
* We also perform alternate keyType lookup for the case where |
| 180 |
* the name attribute is not specified in a MapKey annotation where |
| 181 |
* the map key is one of the following (via the MapContainerPolicy superclass of MappedKeyMapContainerPolicy) |
| 182 |
* - map key is an Entity with an IdClass |
| 183 |
* - map key is Java class that is defined as the IdClass of an Entity (above) |
| 184 |
*/ |
| 84 |
if(null == policyKeyType) { |
185 |
if(null == policyKeyType) { |
| 85 |
// No policy key type = IdClass (use CMP3Policy.pkClass) |
186 |
// The keyType will be null on a MapContainerPolicy when the keyField is null - usually a composite key |
| 86 |
if(managedType.isIdentifiableType()) { |
187 |
// Use the PK of the element - not the one on the managedType |
| 87 |
// Use the CMPPolicy on the element not the one on the managedType |
188 |
// Case: @MapKey private Map<K,V> // no name column specified |
| 88 |
if(policyElementDescriptor != null && |
189 |
if(policyElementDescriptor != null && policyElementDescriptor.getCMPPolicy() != null) { |
| 89 |
policyElementDescriptor.getCMPPolicy() != null) { |
190 |
// See UC9, UC10, UC12(embeddable), UC13 |
| 90 |
javaClass = policy.getElementDescriptor().getCMPPolicy().getPKClass(); |
191 |
// This workaround for bug# 294811 should be moved up into the MapKeyMapping.getMapKeyTargetType() interface method |
|
|
192 |
javaClass = policy.getElementDescriptor().getCMPPolicy().getPKClass(); |
| 193 |
} |
| 194 |
// Pending reproduction case: @MapKey private Map<K,V> // no name column specified and the PK is defined by a method |
| 195 |
if(null == javaClass) { |
| 196 |
if(policy.isMappedKeyMapPolicy()) { |
| 197 |
// See UC10, UC11 |
| 198 |
javaClass = getOwningPKTypeWhenMapKeyAnnotationMissingOrDefaulted( |
| 199 |
(MappedKeyMapContainerPolicy)policy); |
| 91 |
} |
200 |
} |
| 92 |
if(null == javaClass) { |
|
|
| 93 |
// check for a @MapKeyClass annotation |
| 94 |
if(policy.isMappedKeyMapPolicy()) { |
| 95 |
javaClass = getOwningPKTypeWhenMapKeyAnnotationMissingOrDefaulted( |
| 96 |
(MappedKeyMapContainerPolicy)policy); |
| 97 |
} |
| 98 |
} |
| 99 |
} |
201 |
} |
| 100 |
} else { |
202 |
} else { |
|
|
203 |
// Process the policyKeyType normally |
| 101 |
if(policyKeyType instanceof ClassDescriptor) { // from AggregateObjectMapping |
204 |
if(policyKeyType instanceof ClassDescriptor) { // from AggregateObjectMapping |
| 102 |
javaClass = ((ClassDescriptor)policyKeyType).getJavaClass(); |
205 |
javaClass = ((ClassDescriptor)policyKeyType).getJavaClass(); |
| 103 |
} else { |
206 |
} else { |
| 104 |
javaClass = (Class<?>)policyKeyType; |
207 |
javaClass = (Class<?>)policyKeyType; |
| 105 |
} |
208 |
} |
| 106 |
} |
209 |
} |
|
|
210 |
|
| 211 |
// Optional: catch any holes in our keyType logic (8 hits in clover coverage) |
| 107 |
if(null == javaClass) { |
212 |
if(null == javaClass) { |
| 108 |
javaClass = Object.class; |
213 |
javaClass = Object.class; |
| 109 |
} |
214 |
} |
| 110 |
|
215 |
|
| 111 |
aKeyType = getMetamodel().getType(javaClass); |
216 |
// Step 3: We wrap the java type in a Metamodel Type instance or retrieve an existing Type |
| 112 |
this.keyType = (Type<K>) aKeyType; |
217 |
this.keyType = (Type<K>) getMetamodel().getType(javaClass); |
| 113 |
} |
218 |
} |
| 114 |
|
219 |
|
| 115 |
/** |
220 |
/** |