Skip to content

Commit e5a330a

Browse files
authored
Merge pull request #100 from mshima/2.8
Hibernate 5.2 support by reflection
2 parents c9c786a + 2f237c5 commit e5a330a

File tree

8 files changed

+284
-11
lines changed

8 files changed

+284
-11
lines changed

hibernate5/pom.xml

+12
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ Hibernate (http://hibernate.org) version 5.x data types.
9696

9797
<build>
9898
<plugins>
99+
<plugin>
100+
<groupId>org.apache.maven.plugins</groupId>
101+
<artifactId>maven-jar-plugin</artifactId>
102+
<version>3.0.2</version>
103+
<executions>
104+
<execution>
105+
<goals>
106+
<goal>test-jar</goal>
107+
</goals>
108+
</execution>
109+
</executions>
110+
</plugin>
99111
<plugin>
100112
<!-- Inherited from oss-base. Generate PackageVersion.java.-->
101113
<groupId>com.google.code.maven-replacer-plugin</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.fasterxml.jackson.datatype.hibernate5;
2+
3+
public class Hibernate5Version {
4+
5+
public static String getHibernateVersion(){
6+
try {
7+
return Class.forName("org.hibernate.Version").getPackage().getImplementationVersion();
8+
} catch (Exception e) {
9+
// Should not happen: hibernate not found in the classpath
10+
throw new RuntimeException(e);
11+
}
12+
}
13+
14+
public static boolean isHibernate5_2_Plus(){
15+
String version = getHibernateVersion();
16+
String[] split = version.split("\\.");
17+
int isV5 = split[0].compareTo("5");
18+
if(isV5 != 0){
19+
return isV5 > 0;
20+
}
21+
int isV52 = split[1].compareTo("2");
22+
return isV52 >= 0;
23+
}
24+
25+
public static Class<?> getTransactionCoordinatorClass() {
26+
try {
27+
return Class.forName("org.hibernate.resource.transaction.TransactionCoordinator");
28+
} catch (ClassNotFoundException e) {
29+
try {
30+
return Class.forName("org.hibernate.resource.transaction.spi.TransactionCoordinator");
31+
} catch (Exception e2) {
32+
// should never happen
33+
throw new RuntimeException(e);
34+
}
35+
}
36+
}
37+
38+
}

hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateProxySerializer.java

+51-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
1919

2020
import org.hibernate.engine.spi.Mapping;
21+
import org.hibernate.engine.spi.SessionFactoryImplementor;
2122
import org.hibernate.engine.spi.SessionImplementor;
2223
import org.hibernate.proxy.HibernateProxy;
2324
import org.hibernate.proxy.LazyInitializer;
@@ -182,10 +183,8 @@ protected Object findProxied(HibernateProxy proxy)
182183
if (_mapping != null) {
183184
idName = _mapping.getIdentifierPropertyName(init.getEntityName());
184185
} else {
185-
final SessionImplementor session = init.getSession();
186-
if (session != null) {
187-
idName = session.getFactory().getIdentifierPropertyName(init.getEntityName());
188-
} else {
186+
idName = ProxySessionReader.getIdentifierPropertyName(init);
187+
if (idName == null) {
189188
idName = ProxyReader.getIdentifierPropertyName(init);
190189
if (idName == null) {
191190
idName = init.getEntityName();
@@ -218,7 +217,7 @@ protected static class ProxyReader {
218217
getIdentifierMethodField = BasicLazyInitializer.class.getDeclaredField("getIdentifierMethod");
219218
getIdentifierMethodField.setAccessible(true);
220219
} catch (Exception e) {
221-
// should never happen: the field exists in all versions of hibernate 4 and 5
220+
// should never happen: the field exists in all versions of hibernate 4 and 5
222221
throw new RuntimeException(e);
223222
}
224223
}
@@ -230,7 +229,7 @@ static String getIdentifierPropertyName(LazyInitializer init) {
230229
try {
231230
Method idGetter = (Method) getIdentifierMethodField.get(init);
232231
if (idGetter == null) {
233-
return null;
232+
return null;
234233
}
235234
String name = idGetter.getName();
236235
if (name.startsWith("get")) {
@@ -242,4 +241,50 @@ static String getIdentifierPropertyName(LazyInitializer init) {
242241
}
243242
}
244243
}
244+
245+
/**
246+
* Hibernate 5.2 broke abi compatibility of org.hibernate.proxy.LazyInitializer.getSession()
247+
* The api contract changed
248+
* from org.hibernate.proxy.LazyInitializer.getSession()Lorg.hibernate.engine.spi.SessionImplementor;
249+
* to org.hibernate.proxy.LazyInitializer.getSession()Lorg.hibernate.engine.spi.SharedSessionContractImplementor
250+
*
251+
* On hibernate 5.2 the interface SessionImplementor extends SharedSessionContractImplementor.
252+
* And an instance of org.hibernate.internal.SessionImpl is returned from getSession().
253+
*/
254+
protected static class ProxySessionReader {
255+
256+
/**
257+
* The getSession method must be executed using reflection for compatibility purpose.
258+
* For efficiency keep the method cached.
259+
*/
260+
protected static final Method lazyInitializerGetSessionMethod;
261+
262+
static {
263+
try {
264+
lazyInitializerGetSessionMethod = LazyInitializer.class.getMethod("getSession");
265+
} catch (Exception e) {
266+
// should never happen: the class and method exists in all versions of hibernate 5
267+
throw new RuntimeException(e);
268+
}
269+
}
270+
271+
static String getIdentifierPropertyName(LazyInitializer init) {
272+
final Object session;
273+
try{
274+
session = lazyInitializerGetSessionMethod.invoke(init);
275+
} catch (Exception e) {
276+
// Should never happen
277+
throw new RuntimeException(e);
278+
}
279+
if(session instanceof SessionImplementor){
280+
SessionFactoryImplementor factory = ((SessionImplementor)session).getFactory();
281+
return factory.getIdentifierPropertyName(init.getEntityName());
282+
}else if (session != null) {
283+
// Should never happen: session should be an instance of org.hibernate.internal.SessionImpl
284+
// factory = session.getClass().getMethod("getFactory").invoke(session);
285+
throw new RuntimeException("Session is not instance of SessionImplementor");
286+
}
287+
return null;
288+
}
289+
}
245290
}

hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/PersistentCollectionSerializer.java

+53-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.fasterxml.jackson.datatype.hibernate5;
22

33
import java.io.IOException;
4+
import java.lang.reflect.Method;
45
import java.util.ArrayList;
56
import java.util.Collection;
67
import java.util.HashMap;
@@ -340,9 +341,7 @@ private void initializeCollection(PersistentCollection coll, Session session) {
340341
// .getTransactionFactory()
341342
// .compatibleWithJtaSynchronization();
342343
//Above is removed after Hibernate 5
343-
boolean isJTA = ((SessionImplementor) session).getTransactionCoordinator()
344-
.getTransactionCoordinatorBuilder()
345-
.isJta();
344+
boolean isJTA = SessionReader.isJTA(session);
346345

347346
if (!isJTA) {
348347
session.beginTransaction();
@@ -422,4 +421,55 @@ private Object convertToMap(Map<?, ?> value) {
422421
private Object convertToSet(Set<?> value) {
423422
return new HashSet<>(value);
424423
}
424+
425+
protected static class SessionReader {
426+
427+
/**
428+
* Return changed from org.hibernate.resource.transaction.TransactionCoordinator
429+
* to org.hibernate.resource.transaction.spi.TransactionCoordinator
430+
*/
431+
protected static final Method getTransactionCoordinatorMethod;
432+
/**
433+
* Return changed from org.hibernate.resource.transaction.TransactionCoordinatorBuilder
434+
* to org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder
435+
*/
436+
protected static final Method getTransactionCoordinatorBuilderMethod;
437+
/**
438+
* Class changed from org.hibernate.resource.transaction.TransactionCoordinatorBuilder
439+
* to org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder
440+
*/
441+
protected static final Method isJtaMethod;
442+
443+
static {
444+
try {
445+
getTransactionCoordinatorMethod = SessionImplementor.class.getMethod("getTransactionCoordinator");
446+
} catch (Exception e) {
447+
// should never happen: the class and method exists in all versions of hibernate 5
448+
throw new RuntimeException(e);
449+
}
450+
try{
451+
getTransactionCoordinatorBuilderMethod = Hibernate5Version.getTransactionCoordinatorClass().getMethod("getTransactionCoordinatorBuilder");
452+
} catch (Exception e) {
453+
// should never happen
454+
throw new RuntimeException(e);
455+
}
456+
try{
457+
isJtaMethod = Hibernate5Version.getTransactionCoordinatorClass().getMethod("isJta");
458+
} catch (Exception e) {
459+
// should never happen
460+
throw new RuntimeException(e);
461+
}
462+
}
463+
464+
public static boolean isJTA(Session session) {
465+
try {
466+
Object transactionCoordinator = getTransactionCoordinatorMethod.invoke(session);
467+
Object transactionCoordinatorBuilder = getTransactionCoordinatorBuilderMethod.invoke(transactionCoordinator);
468+
return (boolean) isJtaMethod.invoke(transactionCoordinatorBuilder);
469+
} catch (Exception e) {
470+
// Should never happen
471+
throw new RuntimeException(e);
472+
}
473+
}
474+
}
425475
}

hibernate5/src/test/java/com/fasterxml/jackson/datatype/hibernate5/BaseTest.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@
22

33
import java.util.Arrays;
44

5+
import org.apache.log4j.Logger;
6+
57
import com.fasterxml.jackson.databind.ObjectMapper;
68

79
public abstract class BaseTest extends junit.framework.TestCase
810
{
9-
protected BaseTest() { }
11+
protected BaseTest() {
12+
try {
13+
System.out.println(Hibernate5Version.getHibernateVersion());
14+
System.out.println(Hibernate5Version.isHibernate5_2_Plus());
15+
Logger.getLogger(this.getClass()).info("Testing using hibernate " + Hibernate5Version.getHibernateVersion() +
16+
", is 5.2+: " + Hibernate5Version.isHibernate5_2_Plus());
17+
} catch (Exception e) {
18+
// Should not happen
19+
throw new RuntimeException(e);
20+
}
21+
}
1022

1123
protected ObjectMapper mapperWithModule(boolean forceLazyLoading)
1224
{

hibernate5/src/test/resources/META-INF/persistence.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
66

77
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
8-
<provider>org.hibernate.ejb.HibernatePersistence</provider>
8+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
99
<class>com.fasterxml.jackson.datatype.hibernate5.data.Contrato</class>
1010
<class>com.fasterxml.jackson.datatype.hibernate5.data.Customer</class>
1111
<class>com.fasterxml.jackson.datatype.hibernate5.data.Employee</class>

hibernate5_2-test/pom.xml

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>com.fasterxml.jackson.datatype</groupId>
5+
<artifactId>jackson-datatype-hibernate-parent</artifactId>
6+
<version>2.8.6-SNAPSHOT</version>
7+
</parent>
8+
<artifactId>jackson-datatype-hibernate5_2-test</artifactId>
9+
<dependencies>
10+
<dependency>
11+
<groupId>com.fasterxml.jackson.datatype</groupId>
12+
<artifactId>jackson-datatype-hibernate5</artifactId>
13+
<version>2.8.6-SNAPSHOT</version>
14+
<scope>test</scope>
15+
</dependency>
16+
<dependency>
17+
<groupId>com.fasterxml.jackson.datatype</groupId>
18+
<artifactId>jackson-datatype-hibernate5</artifactId>
19+
<version>2.8.6-SNAPSHOT</version>
20+
<type>test-jar</type>
21+
<scope>test</scope>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.hibernate</groupId>
25+
<artifactId>hibernate-core</artifactId>
26+
<version>5.2.0.Final</version>
27+
<scope>provided</scope>
28+
</dependency>
29+
30+
<!-- and for testing, JUnit is needed -->
31+
<dependency>
32+
<groupId>junit</groupId>
33+
<artifactId>junit</artifactId>
34+
<version>4.8.2</version>
35+
<scope>test</scope>
36+
</dependency>
37+
<!-- and for some contributed tests Mockito -->
38+
<dependency>
39+
<groupId>org.mockito</groupId>
40+
<artifactId>mockito-core</artifactId>
41+
<version>1.10.19</version>
42+
<scope>test</scope>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.fasterxml.jackson.core</groupId>
46+
<artifactId>jackson-annotations</artifactId>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.slf4j</groupId>
51+
<artifactId>slf4j-log4j12</artifactId>
52+
<version>1.6.1</version>
53+
<scope>test</scope>
54+
</dependency>
55+
<dependency>
56+
<groupId>log4j</groupId>
57+
<artifactId>log4j</artifactId>
58+
<version>1.2.16</version>
59+
<scope>test</scope>
60+
</dependency>
61+
<dependency>
62+
<groupId>com.h2database</groupId>
63+
<artifactId>h2</artifactId>
64+
<version>1.3.155</version>
65+
<scope>test</scope>
66+
</dependency>
67+
</dependencies>
68+
<build>
69+
<plugins>
70+
<plugin>
71+
<!-- Don't generate a jar -->
72+
<groupId>org.apache.maven.plugins</groupId>
73+
<artifactId>maven-jar-plugin</artifactId>
74+
<executions>
75+
<execution>
76+
<id>default-jar</id>
77+
<phase/>
78+
</execution>
79+
</executions>
80+
</plugin>
81+
<plugin>
82+
<!-- No jar to install, skip configuration needs 2.4+ -->
83+
<groupId>org.apache.maven.plugins</groupId>
84+
<artifactId>maven-install-plugin</artifactId>
85+
<version>2.4</version>
86+
<configuration>
87+
<skip>true</skip>
88+
</configuration>
89+
</plugin>
90+
</plugins>
91+
</build>
92+
<profiles>
93+
<profile>
94+
<id>hibernate5_2-test</id>
95+
<activation>
96+
<jdk>1.8</jdk>
97+
</activation>
98+
<build>
99+
<plugins>
100+
<plugin>
101+
<groupId>org.apache.maven.plugins</groupId>
102+
<artifactId>maven-surefire-plugin</artifactId>
103+
<configuration>
104+
<!-- Configure surefire to look for tests inside jackson-datatype-hibernate5 test-jar
105+
package, otherwise no test runs -->
106+
<dependenciesToScan>
107+
<dependency>com.fasterxml.jackson.datatype:jackson-datatype-hibernate5</dependency>
108+
</dependenciesToScan>
109+
</configuration>
110+
</plugin>
111+
</plugins>
112+
</build>
113+
</profile>
114+
</profiles>
115+
</project>

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<module>hibernate3</module>
1818
<module>hibernate4</module>
1919
<module>hibernate5</module>
20+
<module>hibernate5_2-test</module>
2021
</modules>
2122

2223
<url>https://github.com/FasterXML/jackson-datatype-hibernate</url>

0 commit comments

Comments
 (0)