jdaugherty commented on code in PR #16721:
URL: https://github.com/apache/grails-core/pull/16721#discussion_r4348541740


##########
grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/reflect/NameUtils.java:
##########
@@ -104,9 +104,8 @@ public static String getGetterName(String propertyName, 
boolean useBooleanPrefix
      * @return The class name
      */
     public static String getClassName(Class clazz) {
-        final String sn = clazz.getSimpleName();
-        if (sn.contains(DOLLAR_SEPARATOR)) {
-            return clazz.getSuperclass().getName();
+        while (clazz.getSimpleName().contains(DOLLAR_SEPARATOR) && 
clazz.getSuperclass() != null) {

Review Comment:
   `DomainClassArtefactHandler.isDomainClass(Class, boolean)` in grails-core 
(lines 111-116) has the same one-level unwrap and regressed the same way with 
#16625: `@Artefact` and both `@Entity` annotations are not `@Inherited`, so 
neither generated layer carries them (the probe prints an empty annotation 
array for the wrapper and for the stock proxy), and the single 
`getSuperclass()` step now lands on the stock proxy, which fails the check 
where the entity used to pass it. It is reached from `DefaultLinkGenerator` and 
`AbstractLinkingRenderer` only when there is no mapping context to answer 
first, so the impact is small, but it is the same bug. Loop there too, or open 
a follow-up so it is not lost.



##########
grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/proxy/ByteBuddyGroovyProxyFactorySpec.groovy:
##########
@@ -41,6 +43,29 @@ class ByteBuddyGroovyProxyFactorySpec extends Specification {
     ByteBuddyState state = new ByteBuddyState()
     ByteBuddyProxyHelper helper = new ByteBuddyProxyHelper(state)
 
+    void "a wrapped Hibernate proxy resolves the entity name and validation 
API without initialization"() {
+        given:
+        Session session = datastore.sessionFactory.openSession()
+        Class entityAlias = GroovyProxyFactoryEntity
+
+        when:
+        def proxy = session.getReference(entityAlias, 1L)
+        Class proxyClass = proxy.getClass()
+
+        then:
+        proxyClass.superclass.superclass == entityAlias
+        NameUtils.getClassName(entityAlias) == entityAlias.name
+        NameUtils.getClassName(proxyClass.superclass) == entityAlias.name
+        NameUtils.getClassName(proxyClass) == entityAlias.name
+        GormEnhancer.findValidationApi(proxyClass) != null

Review Comment:
   #16714 lists the instance and static API lookups as well. The probe shows 
`GormEnhancer.findStaticApi(proxyClass)` and `findInstanceApi(proxyClass)` 
resolve to the entity's now, so two more `.is(...)` lines here, and in the H5 
twin, would close the issue's regression list.



##########
grails-datastore-core/src/test/groovy/org/grails/datastore/mapping/reflect/NameUtilsSpec.groovy:
##########
@@ -23,6 +23,24 @@ import spock.lang.Unroll
 
 class NameUtilsSpec extends Specification {
 
+    @Unroll
+    void "getClassName unwraps every proxy layer for #type.simpleName"() {
+        expect:
+        NameUtils.getClassName(type) == NameUtilsEntity.name
+
+        where:
+        type << [NameUtilsEntity, NameUtilsEntity$Proxy, 
NameUtilsEntity$Proxy$Wrapper,
+                 NameUtilsEntity$Proxy$Wrapper$Outer]
+    }
+
+    void "getClassName preserves a real entity referenced by a local alias"() {

Review Comment:
   This feature repeats the first `where:` row: a `Class` local is the same 
object as the literal, so nothing new reaches `getClassName`. Drop it. The 
`entityAlias` locals in the two Hibernate specs can be the class literal for 
the same reason.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to