Skip to content

Commit 1148544

Browse files
committed
HHH-19918 Avoid reflection when instantiating known FormatMapper
1 parent 76ff348 commit 1148544

File tree

3 files changed

+37
-50
lines changed

3 files changed

+37
-50
lines changed

hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonIntegration.java

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
*/
55
package org.hibernate.type.format.jackson;
66

7+
import java.util.List;
8+
9+
import com.fasterxml.jackson.databind.Module;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
711
import org.checkerframework.checker.nullness.qual.Nullable;
12+
813
import org.hibernate.type.format.FormatMapper;
914
import org.hibernate.type.format.FormatMapperCreationContext;
1015

@@ -36,72 +41,37 @@ private static boolean ableToLoadJacksonXMLMapper() {
3641
*/
3742
private static boolean ableToLoadJacksonOSONFactory() {
3843
return ableToLoadJacksonJSONMapper() &&
39-
canLoad( "oracle.jdbc.provider.oson.OsonFactory" );
44+
canLoad( "oracle.jdbc.provider.oson.OsonFactory" );
4045
}
4146

4247
public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
4348
return JACKSON_XML_AVAILABLE
44-
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper", creationContext )
49+
? new JacksonXmlFormatMapper( creationContext )
4550
: null;
4651
}
4752

4853
public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
4954
return JACKSON_JSON_AVAILABLE
50-
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", creationContext )
55+
? new JacksonJsonFormatMapper( creationContext )
5156
: null;
5257
}
5358
public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
5459
return JACKSON_OSON_AVAILABLE
55-
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", creationContext )
60+
? new JacksonOsonFormatMapper( creationContext )
5661
: null;
5762
}
5863

59-
public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(boolean legacyFormat) {
60-
if ( JACKSON_XML_AVAILABLE ) {
61-
try {
62-
final Class<?> formatMapperClass = JacksonIntegration.class.getClassLoader()
63-
.loadClass( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper" );
64-
return (FormatMapper) formatMapperClass.getDeclaredConstructor( boolean.class )
65-
.newInstance( legacyFormat );
66-
}
67-
catch (Exception e) {
68-
throw new RuntimeException( "Couldn't instantiate Jackson XML FormatMapper", e );
69-
}
70-
}
71-
return null;
72-
}
73-
7464
public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull() {
7565
return JACKSON_JSON_AVAILABLE
76-
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", null )
66+
? new JacksonJsonFormatMapper()
7767
: null;
7868
}
7969
public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull() {
8070
return JACKSON_OSON_AVAILABLE
81-
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", null )
71+
? new JacksonOsonFormatMapper()
8272
: null;
8373
}
8474

85-
private static FormatMapper createFormatMapper(String className, @Nullable FormatMapperCreationContext creationContext) {
86-
try {
87-
if ( creationContext == null ) {
88-
final Class<?> formatMapperClass = JacksonIntegration.class.getClassLoader()
89-
.loadClass( className );
90-
return (FormatMapper) formatMapperClass.getDeclaredConstructor().newInstance();
91-
}
92-
else {
93-
return (FormatMapper) creationContext.getBootstrapContext()
94-
.getClassLoaderAccess()
95-
.classForName( className )
96-
.getDeclaredConstructor( FormatMapperCreationContext.class )
97-
.newInstance( creationContext );
98-
}
99-
}
100-
catch (Exception e) {
101-
throw new RuntimeException( "Couldn't instantiate Jackson FormatMapper", e );
102-
}
103-
}
104-
10575
/**
10676
* Checks that Oracle OSON extension available
10777
*
@@ -124,4 +94,27 @@ private static boolean canLoad(String name) {
12494
return false;
12595
}
12696
}
97+
98+
static List<Module> loadModules(FormatMapperCreationContext creationContext) {
99+
final ClassLoader classLoader = JacksonIntegration.class.getClassLoader();
100+
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
101+
if ( contextClassLoader != null && classLoader != contextClassLoader ) {
102+
try {
103+
// The context class loader represents the application class loader in a Jakarta EE deployment.
104+
// We have to check if the ObjectMapper that is visible to Hibernate ORM is the same that is visible
105+
// to the application class loader. Only if it is, we can use the application class loader or rather
106+
// our AggregatedClassLoader for loading Jackson Module via ServiceLoader, as otherwise the loaded
107+
// Jackson Module instances would have a different class loader, leading to a ClassCastException.
108+
if ( ObjectMapper.class == contextClassLoader.loadClass( "com.fasterxml.jackson.databind.ObjectMapper" ) ) {
109+
return creationContext.getBootstrapContext()
110+
.getClassLoaderService()
111+
.<List<Module>>workWithClassLoader( ObjectMapper::findModules );
112+
}
113+
}
114+
catch (ClassNotFoundException | LinkageError e) {
115+
// Ignore if the context/application class loader doesn't know Jackson classes
116+
}
117+
}
118+
return ObjectMapper.findModules( classLoader );
119+
}
127120
}

hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,7 @@ public JacksonJsonFormatMapper() {
3434
}
3535

3636
public JacksonJsonFormatMapper(FormatMapperCreationContext creationContext) {
37-
this(
38-
creationContext.getBootstrapContext()
39-
.getClassLoaderService()
40-
.<List<Module>>workWithClassLoader( ObjectMapper::findModules )
41-
);
37+
this( JacksonIntegration.loadModules( creationContext ) );
4238
}
4339

4440
private JacksonJsonFormatMapper(List<Module> modules) {

hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,15 @@ public JacksonXmlFormatMapper() {
5757

5858
public JacksonXmlFormatMapper(boolean legacyFormat) {
5959
this(
60-
createXmlMapper( XmlMapper.findModules( JacksonXmlFormatMapper.class.getClassLoader() ), legacyFormat ),
60+
createXmlMapper( ObjectMapper.findModules( JacksonXmlFormatMapper.class.getClassLoader() ), legacyFormat ),
6161
legacyFormat
6262
);
6363
}
6464

6565
public JacksonXmlFormatMapper(FormatMapperCreationContext creationContext) {
6666
this(
6767
createXmlMapper(
68-
creationContext.getBootstrapContext()
69-
.getClassLoaderService()
70-
.<List<Module>>workWithClassLoader( XmlMapper::findModules ),
68+
JacksonIntegration.loadModules( creationContext ),
7169
creationContext.getBootstrapContext()
7270
.getMetadataBuildingOptions()
7371
.isXmlFormatMapperLegacyFormatEnabled()

0 commit comments

Comments
 (0)