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]