Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 2e2fd44

Browse files
authored
HibernateProxy and hibernate-groovy-bytebuddy lib (#624)
* HibernateProxy no longer extends SimpleHibernateProxyHandler to avoid Javassist collions. uses Hibernate helpers. Mark SimpleHibernateProxyHandler as deprecated. Add tests to show the proxy problems with groovy Add example test project for hibernate-groovy-bytebuddy Ignore BookControllerSpec for now as cant get github actions working. * move tests, use GormDatastoreSpec as base. change to new pacakge for hibernate-groovy-proxy * added test for isDirty * clean up javadocs on HibernateProxyHandler and GrailsHibernateUtil
1 parent 6559bd2 commit 2e2fd44

File tree

15 files changed

+469
-21
lines changed

15 files changed

+469
-21
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
group "examples"
2+
3+
dependencies {
4+
implementation "org.yakworks:hibernate-groovy-proxy:$hibernateGroovyProxy"
5+
6+
implementation "org.springframework.boot:spring-boot-starter-logging"
7+
implementation "org.springframework.boot:spring-boot-autoconfigure"
8+
// implementation "javax.servlet:javax.servlet-api:$servletApiVersion"
9+
implementation "org.grails:grails-core:$grailsVersion"
10+
implementation "org.grails:grails-dependencies:$grailsVersion", {
11+
exclude module:'grails-datastore-simple'
12+
}
13+
implementation "org.grails:grails-web-boot:$grailsVersion"
14+
implementation project(":grails-plugin")
15+
16+
implementation "org.hibernate:hibernate-core:$hibernate5Version"
17+
18+
// runtimeOnly "com.bertramlabs.plugins:asset-pipeline-grails:$assetPipelineVersion"
19+
runtimeOnly "com.h2database:h2"
20+
runtimeOnly "org.yaml:snakeyaml:$snakeyamlVersion"
21+
runtimeOnly "org.apache.tomcat:tomcat-jdbc:$tomcatVersion"
22+
// runtimeOnly "org.grails.plugins:fields:$fieldsVersion"
23+
// runtimeOnly "org.grails.plugins:scaffolding:$scaffoldingVersion"
24+
25+
testImplementation "org.grails:grails-gorm-testing-support:$testingSupportVersion"
26+
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
grails:
3+
profile: web
4+
codegen:
5+
defaultPackage: datasources
6+
info:
7+
app:
8+
name: '@info.app.name@'
9+
version: '@info.app.version@'
10+
grailsVersion: '@info.app.grailsVersion@'
11+
spring:
12+
groovy:
13+
template:
14+
check-template-location: false
15+
main:
16+
allow-circular-references: true
17+
18+
---
19+
dataSource:
20+
pooled: true
21+
jmxExport: true
22+
driverClassName: org.h2.Driver
23+
dbCreate: create-drop
24+
url: jdbc:h2:mem:books;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
25+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration>
3+
4+
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
5+
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
6+
7+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
8+
<encoder>
9+
<charset>UTF-8</charset>
10+
<pattern>'%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex'</pattern>
11+
</encoder>
12+
</appender>
13+
14+
<root level="error">
15+
<appender-ref ref="STDOUT" />
16+
</root>
17+
</configuration>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package example
2+
3+
import grails.compiler.GrailsCompileStatic
4+
import grails.persistence.Entity
5+
6+
@Entity
7+
@GrailsCompileStatic
8+
class Customer implements Serializable {
9+
10+
String name
11+
12+
Customer(Long id, String name) {
13+
this.id = id
14+
this.name = name
15+
}
16+
17+
static mapping = {
18+
id generator: 'assigned'
19+
}
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package datasources
2+
3+
import grails.boot.GrailsApp
4+
import grails.boot.config.GrailsAutoConfiguration
5+
import groovy.transform.CompileStatic
6+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
7+
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
8+
9+
//@EnableAutoConfiguration(exclude = DataSourceTransactionManagerAutoConfiguration)
10+
@CompileStatic
11+
class Application extends GrailsAutoConfiguration {
12+
static void main(String[] args) {
13+
GrailsApp.run(Application)
14+
}
15+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package example
2+
3+
import org.hibernate.Hibernate
4+
5+
import grails.gorm.transactions.Rollback
6+
import grails.test.hibernate.HibernateSpec
7+
8+
/**
9+
* Tests Proxy with hibernate-groovy-proxy
10+
*/
11+
class ProxySpec extends HibernateSpec {
12+
13+
@Rollback
14+
void "Test Proxy"() {
15+
when:
16+
new Customer(1, "Bob").save(failOnError: true, flush: true)
17+
hibernateDatastore.currentSession.clear()
18+
19+
def proxy
20+
Customer.withNewSession {
21+
proxy = Customer.load(1)
22+
}
23+
24+
then:
25+
//without ByteBuddyGroovyInterceptor this would normally cause the proxy to init
26+
proxy
27+
proxy.metaClass
28+
proxy.getMetaClass()
29+
!Hibernate.isInitialized(proxy)
30+
//id calls
31+
proxy.id == 1
32+
proxy.getId() == 1
33+
proxy["id"] == 1
34+
!Hibernate.isInitialized(proxy)
35+
// gorms trait implements in the class so no way to tell
36+
// proxy.toString() == "Customer : 1 (proxy)"
37+
// !Hibernate.isInitialized(proxy)
38+
}
39+
40+
}

examples/grails3-hibernate5/src/integration-test/groovy/functional/tests/BookControllerSpec.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package functional.tests
22

33
import grails.testing.mixin.integration.Integration
44
import geb.spock.GebSpec
5+
import spock.lang.Ignore
56

67
@Integration(applicationClass = Application)
8+
@Ignore //FAILING downloading the firefox driver
79
class BookControllerSpec extends GebSpec {
810

911
void "Test list books"() {

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ groovyVersion=3.0.11
88
h2Version=1.4.200
99
hibernate5Version=5.6.11.Final
1010
hibernateValidatorVersion=6.2.5.Final
11+
hibernateGroovyProxy=1.1
1112
jansiVersion=2.4.0
1213
javaParserCoreVersion=3.23.0
1314
jaxbVersion=2.3.1

grails-datastore-gorm-hibernate5/build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ dependencies {
5050

5151
testImplementation "net.sf.ehcache:ehcache-core:2.6.11"
5252
testImplementation "org.hibernate:hibernate-ehcache:$hibernate5Version"
53-
53+
54+
// groovy proxy fixes bytebuddy to be a bit smarter when it comes to groovy metaClass
55+
testImplementation "org.yakworks:hibernate-groovy-proxy:$hibernateGroovyProxy"
56+
5457
testImplementation "org.apache.tomcat:tomcat-jdbc:$tomcatVersion"
5558
testRuntimeOnly "org.springframework:spring-aop:$springVersion"
5659
testRuntimeOnly "org.apache.tomcat.embed:tomcat-embed-logging-log4j:$tomcatLog4jVersion"

grails-datastore-gorm-hibernate5/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernateUtil.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ public static void ensureCorrectGroovyMetaClass(Object target, Class<?> persiste
376376
* @return the unproxied instance
377377
*/
378378
public static Object unwrapProxy(HibernateProxy proxy) {
379-
return proxyHandler.unwrapProxy(proxy);
379+
return proxyHandler.unwrap(proxy);
380380
}
381381

382382
/**
@@ -401,8 +401,12 @@ public static boolean isInitialized(Object obj, String associationName) {
401401
return proxyHandler.isInitialized(obj, associationName);
402402
}
403403

404+
/**
405+
* Unproxies a HibernateProxy. If the proxy is uninitialized, it automatically triggers an initialization.
406+
* In case the supplied object is null or not a proxy, the object will be returned as-is.
407+
*/
404408
public static Object unwrapIfProxy(Object instance) {
405-
return proxyHandler.unwrapIfProxy(instance);
409+
return proxyHandler.unwrap(instance);
406410
}
407411

408412
/**

0 commit comments

Comments
 (0)