diff --git a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonIntegration.java b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonIntegration.java index 1c071cfdb935..11bd31e78915 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonIntegration.java +++ b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonIntegration.java @@ -4,7 +4,12 @@ */ package org.hibernate.type.format.jackson; +import java.util.List; + +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.ObjectMapper; import org.checkerframework.checker.nullness.qual.Nullable; + import org.hibernate.type.format.FormatMapper; import org.hibernate.type.format.FormatMapperCreationContext; @@ -36,72 +41,37 @@ private static boolean ableToLoadJacksonXMLMapper() { */ private static boolean ableToLoadJacksonOSONFactory() { return ableToLoadJacksonJSONMapper() && - canLoad( "oracle.jdbc.provider.oson.OsonFactory" ); + canLoad( "oracle.jdbc.provider.oson.OsonFactory" ); } public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) { return JACKSON_XML_AVAILABLE - ? createFormatMapper( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper", creationContext ) + ? new JacksonXmlFormatMapper( creationContext ) : null; } public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) { return JACKSON_JSON_AVAILABLE - ? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", creationContext ) + ? new JacksonJsonFormatMapper( creationContext ) : null; } public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) { return JACKSON_OSON_AVAILABLE - ? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", creationContext ) + ? new JacksonOsonFormatMapper( creationContext ) : null; } - public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(boolean legacyFormat) { - if ( JACKSON_XML_AVAILABLE ) { - try { - final Class formatMapperClass = JacksonIntegration.class.getClassLoader() - .loadClass( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper" ); - return (FormatMapper) formatMapperClass.getDeclaredConstructor( boolean.class ) - .newInstance( legacyFormat ); - } - catch (Exception e) { - throw new RuntimeException( "Couldn't instantiate Jackson XML FormatMapper", e ); - } - } - return null; - } - public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull() { return JACKSON_JSON_AVAILABLE - ? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", null ) + ? new JacksonJsonFormatMapper() : null; } public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull() { return JACKSON_OSON_AVAILABLE - ? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", null ) + ? new JacksonOsonFormatMapper() : null; } - private static FormatMapper createFormatMapper(String className, @Nullable FormatMapperCreationContext creationContext) { - try { - if ( creationContext == null ) { - final Class formatMapperClass = JacksonIntegration.class.getClassLoader() - .loadClass( className ); - return (FormatMapper) formatMapperClass.getDeclaredConstructor().newInstance(); - } - else { - return (FormatMapper) creationContext.getBootstrapContext() - .getClassLoaderAccess() - .classForName( className ) - .getDeclaredConstructor( FormatMapperCreationContext.class ) - .newInstance( creationContext ); - } - } - catch (Exception e) { - throw new RuntimeException( "Couldn't instantiate Jackson FormatMapper", e ); - } - } - /** * Checks that Oracle OSON extension available * @@ -124,4 +94,27 @@ private static boolean canLoad(String name) { return false; } } + + static List loadModules(FormatMapperCreationContext creationContext) { + final ClassLoader classLoader = JacksonIntegration.class.getClassLoader(); + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if ( contextClassLoader != null && classLoader != contextClassLoader ) { + try { + // The context class loader represents the application class loader in a Jakarta EE deployment. + // We have to check if the ObjectMapper that is visible to Hibernate ORM is the same that is visible + // to the application class loader. Only if it is, we can use the application class loader or rather + // our AggregatedClassLoader for loading Jackson Module via ServiceLoader, as otherwise the loaded + // Jackson Module instances would have a different class loader, leading to a ClassCastException. + if ( ObjectMapper.class == contextClassLoader.loadClass( "com.fasterxml.jackson.databind.ObjectMapper" ) ) { + return creationContext.getBootstrapContext() + .getClassLoaderService() + .>workWithClassLoader( ObjectMapper::findModules ); + } + } + catch (ClassNotFoundException | LinkageError e) { + // Ignore if the context/application class loader doesn't know Jackson classes + } + } + return ObjectMapper.findModules( classLoader ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java index 6fef7847ec06..a1d4e30b7dcb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java @@ -34,11 +34,7 @@ public JacksonJsonFormatMapper() { } public JacksonJsonFormatMapper(FormatMapperCreationContext creationContext) { - this( - creationContext.getBootstrapContext() - .getClassLoaderService() - .>workWithClassLoader( ObjectMapper::findModules ) - ); + this( JacksonIntegration.loadModules( creationContext ) ); } private JacksonJsonFormatMapper(List modules) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java index de6d610209fd..762750db04c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java @@ -57,7 +57,7 @@ public JacksonXmlFormatMapper() { public JacksonXmlFormatMapper(boolean legacyFormat) { this( - createXmlMapper( XmlMapper.findModules( JacksonXmlFormatMapper.class.getClassLoader() ), legacyFormat ), + createXmlMapper( ObjectMapper.findModules( JacksonXmlFormatMapper.class.getClassLoader() ), legacyFormat ), legacyFormat ); } @@ -65,9 +65,7 @@ public JacksonXmlFormatMapper(boolean legacyFormat) { public JacksonXmlFormatMapper(FormatMapperCreationContext creationContext) { this( createXmlMapper( - creationContext.getBootstrapContext() - .getClassLoaderService() - .>workWithClassLoader( XmlMapper::findModules ), + JacksonIntegration.loadModules( creationContext ), creationContext.getBootstrapContext() .getMetadataBuildingOptions() .isXmlFormatMapperLegacyFormatEnabled()