-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
HHH-18904 Improve check for unsupported property access properties during bytecode-enhancement #9372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
...rnate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
Fixed
Show fixed
Hide fixed
|
Backported via #9343. |
...rnate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
Show resolved
Hide resolved
| } | ||
| } | ||
| // We can assume AccessType.PROPERTY here | ||
| return AccessType.PROPERTY; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to walk through the methods to check for jakarta.persistence annotations as if there are no annotations on methods or fields then I think there is no default (e.g. what the spec calls [undefined](https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a113)) if I understand correctly. Perhaps Hibernate ORM prefers to default to one or the other in other parts of the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @Id annotation must be found within an entity mapping, or it would be invalid. The same is not true for mapped superclasses and embeddables, though for these defaulting to PROPERTY is fine: the JPA spec says they should work the same as if they were defined either FIELD or PROPERTY, so the executing the enhancement check seems like the right thing to do.
...rnate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
Show resolved
Hide resolved
| } | ||
| } | ||
| } | ||
| if ( propertyHasAnnotation && !propertyNameMatchesFieldName ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find myself reading https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a113 again for checking this section. My question here is whether we can really remove the check if any method has a Persistence annotation? With the current code in this change determines the access type is PROPERTY than I guess its not FIELD. I'd like to have more confidence but we should move forward with this change and correct later if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the question.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pasting from spec:
The explicit access type may be overridden at the attribute level. That is, a class which explicitly specifies an access type using the Access annotation may also have fields or properties annotated Access, and so the class may have a mix of access types.
- When Access(FIELD) is specified at the class level, an individual attribute within the class may be selectively designated for property access by annotating a property getter Access(PROPERTY). Mapping annotations for this attribute must be placed on the getter. If a mapping annotation is placed on a property getter which is not annotated Access(PROPERTY), the behavior is undefined.
- When Access(PROPERTY) is specified at the class level, an individual attribute within the class may be selectively designated for field access by annotating an instance variable Access(FIELD). Mapping annotations for this attribute must be placed on the field. If a mapping annotation is placed on a field which is not annotated Access(FIELD), the behavior is undefined.
Question is does ^ mean we need to check property accessors even if the class is tagged with access type FIELD?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the spec you only need to check fields and properties for @Access if the class is explicitly annotated @Access. If an entity class has no class-level @Access annotation you simply don't need to search the fields/properties for @Access. That's what this means:
The explicit access type may be overridden at the attribute level. That is, a class which explicitly specifies an access type using the
Accessannotation may also have fields or properties annotatedAccess
Now, in Hibernate the rule is a bit different I believe, because @sebersole added additional semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran some local Jakarta EE 10 TCK tests and I'm seeing a TCK failure reported by https://hibernate.atlassian.net/browse/HHH-18928:
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_appmanaged
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_appmanagedNoTx
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_pmservlet
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_puservlet
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_stateful3
[javatest.batch] FAILED........com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#getJavaMember_from_stateless3
In HHH-18928 I mentioned:
It looks like we are enhancing https://github.com/jakartaee/platform-tck/blob/10.0.x/src/com/sun/ts/tests/jpa/core/metamodelapi/attribute/Order.java but I think the default access type for Order entity is PROPERTY so with this change shouldn't we not enhance https://github.com/jakartaee/platform-tck/blob/10.0.x/src/com/sun/ts/tests/jpa/core/metamodelapi/attribute/Order.java?
Note that https://github.com/jakartaee/platform-tck/blob/10.0.x/src/com/sun/ts/tests/jpa/core/metamodelapi/attribute/Order.java#L47 has an ID annotation so the default access type should be PROPERTY:
@Id
public int getId() {
return id;
}
From test output for https://github.com/jakartaee/platform-tck/blob/10.0.x/src/com/sun/ts/tests/jpa/core/metamodelapi/attribute/Client.java#L248C16-L248C36:
[javatest.batch] 12-12-2024 11:28:24: SVR-TRACE: attribute JavaMember = total
[javatest.batch] 12-12-2024 11:28:24: SVR-ERROR: Expected: getTotal, actual:total
I'm not 100% sure if this is a bug or should be a challenge.
From the TCK description of the test assertion:
<assertion required="true" impl-spec="false" status="active" testable="true">
<id>PERSISTENCE:JAVADOC:1214</id>
<description>Return the java.lang.reflect.Member for the represented attribute.</description>
<package>jakarta.persistence.metamodel</package>
<class-interface>Attribute</class-interface>
<method name="getJavaMember" return-type="java.lang.reflect.Member"/>
</assertion>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scottmarlow right, Order has an @Id annotation so it should default to AccessType.PROPERTY. However, the TCK test seems to assert the java member returned by the metamodel, so I do not think it's related with the bytecode enhancement process at all; maybe there's an issue somewhere else in how Hibernate determines which member to return.
You can try creating a test in Hibernate with the same entity mapping and the same assertions, and see if it fails. Then, we can try to identify the cause of this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scottmarlow right, Order has an
@Idannotation so it should default toAccessType.PROPERTY. However, the TCK test seems to assert the java member returned by the metamodel, so I do not think it's related with the bytecode enhancement process at all; maybe there's an issue somewhere else in how Hibernate determines which member to return.
For what it is worth, the TCK test passes if the Order class is not enhanced. With my #9405 change, I had added an else if access type == PROPERTY check that would ensure we do not enhance the Order class. Of course, this also caused around 20-30 test failures as well (I forget the exact count) so my change was incomplete. Paste of code from that PR:
if ( propertyHasAnnotation && !propertyNameMatchesFieldName ) {
switch ( strategy ) {
case SKIP:
@@ -501,11 +528,71 @@ else if (methodName.startsWith("get") ||
// We shouldn't even be in this method if using LEGACY, see top of this method.
throw new AssertionFailure( "Unexpected strategy at this point: " + strategy );
}
} else if ( propertyHasAnnotation && (defaultAccessType == null || AccessType.PROPERTY.equals( defaultAccessType ) ) ) {
Also worth noting that the TCK test is calling https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/metamodel/attribute#getJavaMember() which returns a https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Member.html so Java reflection is involved and we need to understand how/why that returns JavaMember that returns the wrong name from the JavaMember.getName() call.
You can try creating a test in Hibernate with the same entity mapping and the same assertions, and see if it fails. Then, we can try to identify the cause of this behavior.
Is there an existing Hibernate ORM test that combines metamodel + bytecode enhancement that we could update to also do what this TCK does?
|
HHH-18928 also fails without this pull request, didn't mean it was caused
by this change.
…On Thu, Dec 12, 2024, 11:22 AM Gavin King ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In
hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java
<#9372 (comment)>
:
> }
}
}
- }
- if ( propertyHasAnnotation && !propertyNameMatchesFieldName ) {
According to the spec you *only* need to check fields and properties for
@access if the class is explicitly annotated @access. If an entity class
has no class-level @access annotation you simply don't need to search the
fields/properties for @access. That's what this means:
The explicit access type may be overridden at the attribute level. That
is, a class which explicitly specifies an access type using the Access
annotation may also have fields or properties annotated Access
Now, in *Hibernate* the rule is a bit different I believe, because
@sebersole <https://github.com/sebersole> added additional semantics.
—
Reply to this email directly, view it on GitHub
<#9372 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACRJED24MY3KCQ43KWRFET2FGZ4FAVCNFSM6AAAAABTAYRUKWVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDKMBQGE2TQOBYHE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.
https://hibernate.atlassian.net/browse/HHH-18904
https://hibernate.atlassian.net/browse/HHH-18903