This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 284877 - JPA 2: Implement recursive ManagedType.getDeclared* algorithm to differentiate by IdentifiableType
Summary: JPA 2: Implement recursive ManagedType.getDeclared* algorithm to differentiat...
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P2 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Michael OBrien CLA
QA Contact:
URL: http://wiki.eclipse.org/EclipseLink/D...
Whiteboard:
Keywords:
Depends on:
Blocks: 266912
  Show dependency tree
 
Reported: 2009-07-28 11:13 EDT by Michael OBrien CLA
Modified: 2022-06-09 10:03 EDT (History)
1 user (show)

See Also:


Attachments
ManagedType.hasDeclaredAttribute() unoptimized recursive changes (27.77 KB, patch)
2009-07-29 10:39 EDT, Michael OBrien CLA
no flags Details | Diff
DI: 52 refactor: ManagedTypeImpl.hasNoDeclaredAttributeInSuperType refactor (24.26 KB, patch)
2009-08-17 15:00 EDT, Michael OBrien CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael OBrien CLA 2009-07-28 11:13:51 EDT
>The get*Declared* functions in '''ManagedType''' will require a recursive search on their superType inheritance tree to correctly determine whether an attribute is declared on the current '''IdentifiableType''' or not.
We need to take into account whether the superType is an Entity or MappedSuperclass - as this will affect whether we continue to search up when a current IdentifiableType is missing the attribute.
- If superType is entity then inheriting entities will not have copies of the inherited mappings
- however, if superType is mappedSuperclass then all inheriting mappedSuperclasses and the first entity will have copies of the inherited mappings
- Note: a sub-entity can override a mapping above it - we need to handle this.

>The current implementation of the private helper function does not differentiate between mappedSuperclasses, entities or overrides.

private boolean hasDeclaredAttribute(String attributeName)
Comment 1 Michael OBrien CLA 2009-07-28 11:50:55 EDT
>Use Cases:
UC1 Superclass declares attribute 
UC1.1: Entity (searched) --> Entity --> Entity (declares attribute) 
UC1.2: Entity (searched) --> Entity (copy of attribute) --> MappedSuperclass (declares attribute) 
UC1.3: Entity (searched) --> MappedSuperclass --> Entity (declares attribute) 
UC1.4: Entity (copy of attribute) (searched) --> MappedSuperclass (copy of attribute) (searched) --> MappedSuperclass (declares attribute) (searched) 
UC2 Nobody declares attribute 
UC2.1: Entity (searched) --> Entity --> MappedSuperclass (declares attribute) 
UC2.2: Entity (searched) --> Entity --> Entity (declares attribute) 
UC2.3: Entity (searched) --> MappedSuperclass (searched) --> MappedSuperclass (declares attribute) 
UC2.4: Entity (searched) --> MappedSuperclass (searched) --> Entity (declares attribute) 
UC3 Superclass declares attribute but child overrides it 
UC3.1: Entity (searched) --> Entity --> MappedSuperclass (declares attribute) 
UC3.2: Entity (searched) --> Entity --> Entity (declares attribute) 
UC3.3: Entity (searched) --> MappedSuperclass (override attribute) (searched) --> MappedSuperclass (declares attribute) 
UC3.4: Entity (searched) --> MappedSuperclass (override attribute) (searched) --> Entity (declares attribute) (searched) 
UC3.5: Entity (override attribute) (searched) --> MappedSuperclass (searched) --> MappedSuperclass (declares attribute) (searched) 
UC3.6: Entity (override attribute) (searched) --> MappedSuperclass (searched) --> Entity (declares attribute) 
>Solution:
Results Expected for hasDeclaredAttribute() 
True = attribute declared only on current type 
False = attribute not found in superType tree or attribute found in more than one(1) level of the superType tree 
Base Case 
attribute found && no superType exists = true 
attribute not found && no superType exists = false 
Recursive Case 
Exit(false) as soon as attribute is found in a superType - without continuing to the root 
continue as long as we find an attribute in the superType (essentially only MappedSuperclass parents) 
Comment 2 Michael OBrien CLA 2009-07-29 10:39:47 EDT
Created attachment 142895 [details]
ManagedType.hasDeclaredAttribute() unoptimized recursive changes
Comment 3 Michael OBrien CLA 2009-07-29 12:19:55 EDT
>See rev# 4754
http://fisheye2.atlassian.com/changelog/eclipselink/?cs=4754

Comment 4 Michael OBrien CLA 2009-08-12 15:39:51 EDT
>this change has been in the build for 2 weeks - resolving
Comment 5 Michael OBrien CLA 2009-08-17 14:23:30 EDT
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI:52_Refactor:_20090817

>DI 52: Refactor: 20090817
The base case for the recursive function managedTypeImpl.hasDeclaredAttribute() does not handle use case 1.4 (root-level managedType) when the caller of the function does not do it's own inheritedType check. 
This occurs only for managedType.getDeclaredAttributes() - here the returned Set is empty. 
There are two sets of internal references to hasDeclaredAttribute() - the call getDeclaredAttributes() does not do optimization before calling this recursive function - all the other getDeclaredList()|getDeclaredMap etc - check the immediate hierarchy and only call the recursive hasDeclaredAttribute() if needed. 
Why are we checking the superType tree recursively in the first place? Because a possible MappedSuperclass hierarchy will not declare their own copies of a parent superclass - only the first inheriting entity will get copies of attributes declared at the top of a MappedSuperclass hierarchy tree. 

A possible time-space optimization would be to store the java members in a separate data structure from the metamodel members. 

>The fix is to change the following code 
ManagedTypeImpl.java:897
private boolean hasDeclaredAttribute(String attributeName, Attribute firstLevelAttribute) {
        // Base Case: If we are at the root, check for the attribute and return results immediately
        if(null == aSuperType) {
            if(null == anAttribute && null != firstLevelAttribute) { 
                return true; 
            } else {
                // UC 1.3 (part of the else condition (anAttribute != null)) is handled by the return false in null != aSuperTypeAttribute
--->expand      return false;
            }
        } else {

>To the expanded version below that handles the case where we are checking the root when the type is declared there. 
ManagedTypeImpl.java:897
private boolean hasDeclaredAttribute(String attributeName, Attribute firstLevelAttribute) {
        // Base Case: If we are at the root, check for the attribute and return results immediately
        if(null == aSuperType) {
            if(null == anAttribute && null != firstLevelAttribute) { 
                return true; 
            } else {
                // UC 1.3 (part of the else condition (anAttribute != null)) is handled by the return false in null != aSuperTypeAttribute
                // UC 1.4 (when caller is firstLevel) superType does not contain the attribute - check that the current attribute and the first differ
                if(null != anAttribute && anAttribute == firstLevelAttribute) {
                    return true;
                } else {
                    return false;
                }
            }
        } else {

>New testing that fails without this fix (no managedTypes were returned for a person.getDeclaredAttributes() call) 
Set<Attribute<Person, ?>> declaredAttributesSetForPerson = msPerson.getDeclaredAttributes();
                assertNotNull(declaredAttributesSetForPerson);
                // We should see 3 declared out of 3 attributes for Person 
                assertEquals(3, declaredAttributesSetForPerson.size());
                // Id is declared at this level
                assertTrue(declaredAttributesSetForPerson.contains(msPerson.getAttribute("id"))); //
                // name is declared at this level
                assertTrue(declaredAttributesSetForPerson.contains(msPerson.getAttribute("name"))); //
                // historicalEmployers is declared at this level
                assertTrue(declaredAttributesSetForPerson.contains(msPerson.getAttribute("historicalEmployers"))); //
Comment 6 Michael OBrien CLA 2009-08-17 15:00:19 EDT
Created attachment 144716 [details]
DI: 52 refactor: ManagedTypeImpl.hasNoDeclaredAttributeInSuperType refactor

>The function is renamed hasNoDeclaredAttributeInSuperType from  hasDeclaredAttribute to avoid any developer confusion - since I am really returning the opposite boolean of what my function is named - thank you Chris.

>New tests for getDeclaredAttributes() on the root MappedSuperclass added around line 870 of MetamodelMetamodelTest.java
Comment 7 Michael OBrien CLA 2009-08-17 15:03:05 EDT
>See line 935 of ManagedTypeImpl for the core change above
https://bugs.eclipse.org/bugs/attachment.cgi?id=144716&action=diff#jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metamodel/ManagedTypeImpl.java_sec11

Testing LRG before/after SVN update
Comment 8 Michael OBrien CLA 2009-08-17 16:30:26 EDT
>See SVN rev# 4883
http://fisheye2.atlassian.com/changelog/eclipselink/?cs=4883
Comment 9 Peter Krogh CLA 2009-08-26 09:57:49 EDT
Mass update to change fixed in target.
Comment 10 Peter Krogh CLA 2009-08-26 10:00:25 EDT
Mass update to change fixed in target.
Comment 11 Peter Krogh CLA 2009-08-26 10:05:44 EDT
Mass update to change fixed in target.
Comment 12 Peter Krogh CLA 2009-08-26 10:07:37 EDT
Mass update to change fixed in target.
Comment 13 Eclipse Webmaster CLA 2022-06-09 10:03:22 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink