|
Description
Roger Suen
>This issue is directly related to DI 95 from 20091017 when i was investigating javaMember code coverage - except that it involves MethodAttributeAccessors http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_95:_20091017:_Attribute.getJavaMember.28.29_returns_null_for_a_BasicType_on_a_MappedSuperclass_because_of_an_uninitialized_accessor "Found this one while testing code coverage for Attribute.getJavaMember. It looks like we will need to add to the initialization of the descriptor for MappedSuperclasses that is pending for DI 93 - pkClass initialization in CMP3Policy The AttributeAccessor on the DirectToField" Mapping is missing the attributeField required by getJavaMember()." >Embeddable and AggregateCollection handling is lacking >The test model includes @Embeddable Observation - however this attribute as collection is commented in GalacticPosition @Embeddable CompositePK - is not used anywhere @Embeddable CPUEmbeddedId - is @EmbeddedId on CPU >see testMetamodelEmbeddedIdDirectlyOnMappedSuperclassRootPassesValidation() embedCPUEmbeddedId EmbeddableTypeImpl<X> (id=1301) descriptor RelationalDescriptor (id=1307) javaClass Class<T> (org.eclipse.persistence.testing.models.jpa.metamodel.CPUEmbeddedId) (id=1310) members HashMap<K,V> (id=1312) size 1 table HashMap$Entry<K,V>[16] (id=1321) [1] HashMap$Entry<K,V> (id=1327) key "pk_part1" (id=1331) value SingularAttributeImpl<X,T> (id=1332) >For the following API ManagedType<CPUEmbeddedId> embedCPUEmbeddedId = metamodel.managedType(CPUEmbeddedId.class); assertNotNull(embedCPUEmbeddedId); assertEquals(Type.PersistenceType.EMBEDDABLE, embedCPUEmbeddedId.getPersistenceType()); // 316991 Check Embedded Attributes Attribute embeddedAttribute = embedCPUEmbeddedId.getAttribute("pk_part1"); assertNotNull(embeddedAttribute); Member aMember = embeddedAttribute.getJavaMember(); assertNotNull(aMember); >we get null on the return of public Member getJavaMember() { AttributeAccessor accessor = getMapping().getAttributeAccessor(); if (accessor.isMethodAttributeAccessor()) { return ((MethodAttributeAccessor) accessor).getGetMethod(); >where the getMethod is null on the accessor accessor MethodAttributeAccessor (id=101) attributeName "pk_part1" (id=131) getMethod null getMethodName "getPk_part1" (id=135) isReadOnly false isWriteOnly false setMethod null setMethodName "setPk_part1" (id=136) aMember null >at Thread [Thread-4] (Suspended) SingularAttributeImpl<X,T>(AttributeImpl<X,T>).getJavaMember() line: 101 MetamodelMetamodelTest.testMetamodelEmbeddedIdDirectlyOnMappedSuperclassRootPassesValidation() line: 341 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25 Method.invoke(Object, Object...) line: 597 MetamodelMetamodelTest(TestCase).runTest() line: 168 MetamodelMetamodelTest(TestCase).runBare() line: 134 MetamodelMetamodelTest(JUnitTestCase).runBare() line: 454 TestResult$1.protect() line: 110 TestResult.runProtected(Test, Protectable) line: 128 TestResult.run(TestCase) line: 113 MetamodelMetamodelTest(TestCase).run(TestResult) line: 124 TestExecutor.execute(Test) line: 248 TestExecutor.runTest(Test) line: 671 SynchronizedTestExecutor.run() line: 61 >Fix: we need the same reflective code from ManagedTypeImpl.initialize() that gets the Member using the method or attribute name when the getMethod is missing Method aMethod = null; String getMethodName = null; try { getMethodName = ((MethodAttributeAccessor)mapping.getAttributeAccessor()).getGetMethodName(); if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { aMethod = (Method) AccessController.doPrivileged(new PrivilegedGetDeclaredMethod( this.getManagedTypeImpl().getJavaType(), getMethodName, null)); } else { aMethod = PrivilegedAccessHelper.getDeclaredMethod( this.getManagedTypeImpl().getJavaType(), getMethodName, null); } } catch (PrivilegedActionException pae) { pae.printStackTrace(); } catch (NoSuchMethodException nsfe) { nsfe.printStackTrace(); } >Results are aMethod Method (id=136) clazz Class<T> (org.eclipse.persistence.testing.models.jpa.metamodel.CPUEmbeddedId) (id=115) name "getPk_part1" (id=148) returnType Class<T> (int) (id=163) >formal patch pending Created attachment 172046 [details]
Fix: DI95 getJavaMethod() call on attribute of @Embeddable requires handling for null getMethod by doing reflective call on managedType using method name
>P1 is the temporary holder for 2.1.1 queued ports
>Also verify
Does this occur for all attributes including those from Entities and MappedSuperclasses (also check Basic)
The fix is for Method level access, verify Field level access for Embeddables - however we should be OK as reflective code already existed for Field level in getJavaMember()
Created attachment 172086 [details]
test persistence unit
The attachment is the original persistence unit I used to test against the metamodel API. All embeddable types are annotated like this:
@Embeddable
@Access(AccessType.FIELD)
public class Address implements Serializable {
...
}
(In reply to comment #5) > Created an attachment (id=172086) [details] > test persistence unit > The attachment is the original persistence unit I used to test against the > metamodel API. All embeddable types are annotated like this: > @Embeddable > @Access(AccessType.FIELD) > public class Address implements Serializable { > ... > } Here's the code snippet I used to access the java member: Object value = null; Member member = attribute.getJavaMember(); if (member instanceof Field) { Field field = (Field) member; try { field.setAccessible(true); value = field.get(data); } catch (Exception ex) { throw new RuntimeException( "Unexpected exception occurred when trying to " + "reflectively get the value of the field: " + field.getName(), ex); } } else if (member instanceof Method) { Method method = (Method) member; try { method.setAccessible(true); value = method.invoke(data, (Object[]) null); } catch (Exception ex) { throw new RuntimeException( "Unexpected exception occurred when trying to " + "reflectively invoke the method: " + method.toGenericString(), ex); } } else { logger.log( Level.SEVERE, "Invalid java member [{0}] corresponding to " + "the attribute [{1}] of the data [{2}] represented by the " + "managed type [{3}]. The attribute value will be " + "unavaliable for viewing." + "This is possibly an issue of the persistence provider " + "implementation. By far, eclipselink 2.0.2 is known to " + "return null member for attributes of embeddable type. " + "Please check the documentation of the provider for " + "more information. ", new Object[] { member, attribute.getName(), data, managedType }); } Created attachment 172243 [details]
Updated test patch with support for field/method level access of entity @OneToOne attributes on Entity or MappedSuperclass (unidirectional)
Created attachment 172257 [details]
Fix: updated dev/test patch with with support for field/method level access of entity @OneToOne attributes on Entity or MappedSuperclass (unidirectional)
(In reply to comment #5) > Created an attachment (id=172086) [details] > test persistence unit > The attachment is the original persistence unit I used to test against the > metamodel API. All embeddable types are annotated like this: > @Embeddable > @Access(AccessType.FIELD) > public class Address implements Serializable { > ... > } >The AccessType may not be set at design time via annotation - it will be determined at runtime. Also, the null Method returns from getJavaMember() on Embeddables are occuring with accessType.PROPERTY as well - see extended test model patch Created attachment 172264 [details]
Fix: DI95: updated dev/test patch with with support for field/method level access of entity @OneToOne attributes on Entity or MappedSuperclass (unidirectional)
>See SVN Rev# 7636 http://fisheye2.atlassian.com/changelog/eclipselink/?cs=7636 The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |