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

Commit 664202b

Browse files
committed
more progress
1 parent 36562fd commit 664202b

30 files changed

+429
-83
lines changed

grails-datastore-gorm-hibernate/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ dependencies {
6767
testImplementation "org.hibernate:hibernate-jcache:$hibernate6Version"
6868

6969
// groovy proxy fixes bytebuddy to be a bit smarter when it comes to groovy metaClass
70-
// testImplementation "org.yakworks:hibernate-groovy-proxy:$yakworksHibernateGroovyProxyVersion", {
71-
// exclude group: "org.codehaus.groovy", module: "groovy"
72-
// }
70+
testImplementation "org.yakworks:hibernate-groovy-proxy:$yakworksHibernateGroovyProxyVersion", {
71+
exclude group: "org.codehaus.groovy", module: "groovy"
72+
}
7373

7474
testImplementation "org.apache.tomcat:tomcat-jdbc"
7575
testRuntimeOnly "org.springframework:spring-aop"

grails-datastore-gorm-hibernate/src/main/groovy/org/grails/orm/hibernate/HibernateSession.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
import org.grails.datastore.gorm.timestamp.DefaultTimestampProvider;
2828
import org.grails.datastore.mapping.model.PersistentProperty;
2929
import org.grails.datastore.mapping.model.config.GormProperties;
30+
import org.grails.datastore.mapping.proxy.ProxyHandler;
3031
import org.grails.datastore.mapping.query.event.PostQueryEvent;
3132
import org.grails.datastore.mapping.query.event.PreQueryEvent;
33+
import org.grails.orm.hibernate.proxy.HibernateProxyHandler;
3234
import org.grails.orm.hibernate.query.HibernateHqlQuery;
3335
import org.grails.orm.hibernate.query.HibernateQuery;
3436
import org.grails.datastore.mapping.model.PersistentEntity;
@@ -38,6 +40,7 @@
3840
import org.grails.datastore.mapping.query.jpa.JpaQueryInfo;
3941
import org.grails.datastore.mapping.reflect.ClassPropertyFetcher;
4042
import org.hibernate.*;
43+
import org.hibernate.proxy.HibernateProxy;
4144
import org.springframework.context.ApplicationEventPublisher;
4245

4346
/**
@@ -49,6 +52,7 @@
4952
@SuppressWarnings("rawtypes")
5053
public class HibernateSession extends AbstractHibernateSession {
5154

55+
ProxyHandler proxyHandler = new HibernateProxyHandler();
5256
DefaultTimestampProvider timestampProvider;
5357

5458
public HibernateSession(HibernateDatastore hibernateDatastore, SessionFactory sessionFactory, int defaultFlushMode) {
@@ -64,6 +68,9 @@ public HibernateSession(HibernateDatastore hibernateDatastore, SessionFactory se
6468
@Override
6569
public Serializable getObjectIdentifier(Object instance) {
6670
if(instance == null) return null;
71+
if(proxyHandler.isProxy(instance)) {
72+
return (Serializable) ((HibernateProxy)instance).getHibernateLazyInitializer().getIdentifier();
73+
}
6774
Class<?> type = instance.getClass();
6875
ClassPropertyFetcher cpf = ClassPropertyFetcher.forClass(type);
6976
final PersistentEntity persistentEntity = getMappingContext().getPersistentEntity(type.getName());

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

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.hibernate.boot.spi.*;
3737
import org.hibernate.cfg.*;
3838
import org.hibernate.engine.OptimisticLockStyle;
39+
import org.hibernate.engine.spi.FilterDefinition;
3940
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
4041
import org.hibernate.id.PersistentIdentifierGenerator;
4142
import org.hibernate.id.enhanced.SequenceStyleGenerator;
@@ -45,6 +46,7 @@
4546
import org.hibernate.mapping.OneToMany;
4647
import org.hibernate.mapping.OneToOne;
4748
import org.hibernate.mapping.Table;
49+
import org.hibernate.metamodel.mapping.JdbcMapping;
4850
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
4951
import org.hibernate.type.*;
5052
import org.hibernate.usertype.UserCollectionType;
@@ -1429,30 +1431,31 @@ protected void addMultiTenantFilterIfNecessary(
14291431
InFlightMetadataCollector mappings, String sessionFactoryBeanName) {
14301432

14311433
if (entity.isMultiTenant()) {
1432-
throw new RuntimeException("Multitenant not supported yet");
1433-
// TenantId tenantId = entity.getTenantId();
1434-
//
1435-
// if (tenantId != null) {
1436-
// String filterCondition = getMultiTenantFilterCondition(sessionFactoryBeanName, entity);
1437-
//
1438-
// persistentClass.addFilter(
1439-
// GormProperties.TENANT_IDENTITY,
1440-
// filterCondition,
1441-
// true,
1442-
// Collections.emptyMap(),
1443-
// Collections.emptyMap()
1444-
// );
1445-
//
1446-
// Property property = getProperty(persistentClass, tenantId.getName());
1447-
// Type type = property.getType();
1448-
// Map<String, Type> stringVMap = Collections.singletonMap(GormProperties.TENANT_IDENTITY, type);
1449-
// FilterDefinition definition = new FilterDefinition(
1450-
// GormProperties.TENANT_IDENTITY,
1451-
// filterCondition,
1452-
// stringVMap
1453-
// );
1454-
// mappings.addFilterDefinition(definition);
1455-
// }
1434+
TenantId tenantId = entity.getTenantId();
1435+
1436+
if (tenantId != null) {
1437+
String filterCondition = getMultiTenantFilterCondition(sessionFactoryBeanName, entity);
1438+
1439+
persistentClass.addFilter(
1440+
GormProperties.TENANT_IDENTITY,
1441+
filterCondition,
1442+
true,
1443+
Collections.emptyMap(),
1444+
Collections.emptyMap()
1445+
);
1446+
1447+
Property property = getProperty(persistentClass, tenantId.getName());
1448+
if (property.getValue() instanceof BasicValue basicValue) {
1449+
JdbcMapping jdbcMapping = basicValue.resolve().getJdbcMapping();
1450+
var stringVMap = Collections.singletonMap(GormProperties.TENANT_IDENTITY, jdbcMapping);
1451+
FilterDefinition definition = new FilterDefinition(
1452+
GormProperties.TENANT_IDENTITY,
1453+
filterCondition,
1454+
stringVMap
1455+
);
1456+
mappings.addFilterDefinition(definition);
1457+
}
1458+
}
14561459
}
14571460
}
14581461

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.grails.datastore.mapping.reflect.ClassUtils;
2626
import org.grails.orm.hibernate.AbstractHibernateDatastore;
2727
import org.grails.orm.hibernate.datasource.MultipleDataSourceSupport;
28+
import org.grails.orm.hibernate.proxy.HibernateProxyHandler;
2829
import org.grails.orm.hibernate.support.HibernateRuntimeUtils;
2930
import org.hibernate.FetchMode;
3031
import org.hibernate.FlushMode;
@@ -71,7 +72,7 @@ public class GrailsHibernateUtil extends HibernateRuntimeUtils {
7172
public static final Class<?>[] EMPTY_CLASS_ARRAY = {};
7273

7374

74-
75+
private static HibernateProxyHandler proxyHandler = new HibernateProxyHandler();
7576

7677

7778

@@ -177,6 +178,45 @@ public static void ensureCorrectGroovyMetaClass(Object target, Class<?> persiste
177178
}
178179
}
179180

181+
/**
182+
* Unwraps and initializes a HibernateProxy.
183+
* @param proxy The proxy
184+
* @return the unproxied instance
185+
*/
186+
public static Object unwrapProxy(HibernateProxy proxy) {
187+
return proxyHandler.unwrap(proxy);
188+
}
189+
190+
/**
191+
* Returns the proxy for a given association or null if it is not proxied
192+
*
193+
* @param obj The object
194+
* @param associationName The named assoication
195+
* @return A proxy
196+
*/
197+
public static HibernateProxy getAssociationProxy(Object obj, String associationName) {
198+
return proxyHandler.getAssociationProxy(obj, associationName);
199+
}
200+
201+
/**
202+
* Checks whether an associated property is initialized and returns true if it is
203+
*
204+
* @param obj The name of the object
205+
* @param associationName The name of the association
206+
* @return true if is initialized
207+
*/
208+
public static boolean isInitialized(Object obj, String associationName) {
209+
return proxyHandler.isInitialized(obj, associationName);
210+
}
211+
212+
/**
213+
* Unproxies a HibernateProxy. If the proxy is uninitialized, it automatically triggers an initialization.
214+
* In case the supplied object is null or not a proxy, the object will be returned as-is.
215+
*/
216+
public static Object unwrapIfProxy(Object instance) {
217+
return proxyHandler.unwrap(instance);
218+
}
219+
180220

181221

182222
public static boolean isMappedWithHibernate(PersistentEntity domainClass) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.grails.datastore.mapping.model.config.JpaMappingConfigurationStrategy;
2929
import org.grails.datastore.mapping.reflect.ClassUtils;
3030
import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings;
31+
import org.grails.orm.hibernate.proxy.HibernateProxyHandler;
3132
import org.springframework.validation.Errors;
3233

3334
import java.lang.annotation.Annotation;
@@ -68,6 +69,7 @@ protected boolean supportsCustomType(Class<?> propertyType) {
6869
return !Errors.class.isAssignableFrom(propertyType);
6970
}
7071
};
72+
this.proxyFactory = new HibernateProxyHandler();
7173
addPersistentEntities(persistentClasses);
7274
}
7375

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright 2004-2008 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.grails.orm.hibernate.proxy;
17+
18+
import org.grails.datastore.mapping.core.Session;
19+
import org.grails.datastore.mapping.engine.AssociationQueryExecutor;
20+
import org.grails.datastore.mapping.proxy.ProxyFactory;
21+
import org.grails.datastore.mapping.proxy.ProxyHandler;
22+
import org.grails.datastore.mapping.reflect.ClassPropertyFetcher;
23+
import org.hibernate.Hibernate;
24+
import org.hibernate.collection.spi.PersistentCollection;
25+
import org.hibernate.proxy.HibernateProxy;
26+
import org.hibernate.proxy.HibernateProxyHelper;
27+
//import org.hibernate.proxy.HibernateProxyHelper;
28+
29+
import java.io.Serializable;
30+
31+
/**
32+
* Implementation of the ProxyHandler interface for Hibernate using org.hibernate.Hibernate
33+
* and HibernateProxyHelper where possible.
34+
*
35+
* @author Graeme Rocher
36+
* @since 1.2.2
37+
*/
38+
public class HibernateProxyHandler implements ProxyHandler, ProxyFactory {
39+
40+
/**
41+
* Check if the proxy or persistent collection is initialized.
42+
* {@inheritDoc}
43+
*/
44+
@Override
45+
public boolean isInitialized(Object o) {
46+
return Hibernate.isInitialized(o);
47+
}
48+
49+
/**
50+
* Check if an association proxy or persistent collection is initialized.
51+
* {@inheritDoc}
52+
*/
53+
@Override
54+
public boolean isInitialized(Object obj, String associationName) {
55+
try {
56+
Object proxy = ClassPropertyFetcher.getInstancePropertyValue(obj, associationName);
57+
return isInitialized(proxy);
58+
}
59+
catch (RuntimeException e) {
60+
return false;
61+
}
62+
}
63+
64+
/**
65+
* Unproxies a HibernateProxy. If the proxy is uninitialized, it automatically triggers an initialization.
66+
* In case the supplied object is null or not a proxy, the object will be returned as-is.
67+
* {@inheritDoc}
68+
* @see Hibernate#unproxy
69+
*/
70+
@Override
71+
public Object unwrap(Object object) {
72+
if (object instanceof PersistentCollection) {
73+
initialize(object);
74+
return object;
75+
}
76+
return Hibernate.unproxy(object);
77+
}
78+
79+
/**
80+
* {@inheritDoc}
81+
* @see org.hibernate.proxy.AbstractLazyInitializer#getIdentifier
82+
*/
83+
@Override
84+
public Serializable getIdentifier(Object o) {
85+
if (o instanceof HibernateProxy) {
86+
return null;
87+
//This line does not compile
88+
// return ((HibernateProxy)o).getHibernateLazyInitializer().getIdentifier();
89+
}
90+
else {
91+
//TODO seems we can get the id here if its has normal getId
92+
// PersistentEntity persistentEntity = GormEnhancer.findStaticApi(o.getClass()).getGormPersistentEntity();
93+
// return persistentEntity.getMappingContext().getEntityReflector(persistentEntity).getIdentifier(o);
94+
return null;
95+
}
96+
}
97+
98+
/**
99+
* {@inheritDoc}
100+
* @see HibernateProxyHelper#getClassWithoutInitializingProxy
101+
*/
102+
@Override
103+
public Class<?> getProxiedClass(Object o) {
104+
return HibernateProxyHelper.getClassWithoutInitializingProxy(o);
105+
}
106+
107+
/**
108+
* calls unwrap which calls unproxy
109+
* @see #unwrap(Object)
110+
* @deprecated use unwrap
111+
*/
112+
@Deprecated
113+
public Object unwrapIfProxy(Object instance) {
114+
return unwrap(instance);
115+
}
116+
117+
/**
118+
* {@inheritDoc}
119+
*/
120+
@Override
121+
public boolean isProxy(Object o) {
122+
return (o instanceof HibernateProxy) || (o instanceof PersistentCollection);
123+
}
124+
125+
/**
126+
* Force initialization of a proxy or persistent collection.
127+
* {@inheritDoc}
128+
*/
129+
@Override
130+
public void initialize(Object o) {
131+
Hibernate.initialize(o);
132+
}
133+
134+
@Override
135+
public <T> T createProxy(Session session, Class<T> type, Serializable key) {
136+
throw new UnsupportedOperationException("createProxy not supported in HibernateProxyHandler");
137+
}
138+
139+
@Override
140+
public <T, K extends Serializable> T createProxy(Session session, AssociationQueryExecutor<K, T> executor, K associationKey) {
141+
throw new UnsupportedOperationException("createProxy not supported in HibernateProxyHandler");
142+
}
143+
144+
/**
145+
* @deprecated use unwrap
146+
*/
147+
@Deprecated
148+
public Object unwrapProxy(Object proxy) {
149+
return unwrap(proxy);
150+
}
151+
152+
/**
153+
* returns the proxy for an association. returns null if its not a proxy.
154+
* Note: Only used in a test. Deprecate?
155+
*/
156+
public HibernateProxy getAssociationProxy(Object obj, String associationName) {
157+
try {
158+
Object proxy = ClassPropertyFetcher.getInstancePropertyValue(obj, associationName);
159+
if (proxy instanceof HibernateProxy) {
160+
return (HibernateProxy) proxy;
161+
}
162+
return null;
163+
}
164+
catch (RuntimeException e) {
165+
return null;
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)