66 */
77package org .hibernate .type .format .jackson ;
88
9+ import java .util .List ;
10+
11+ import com .fasterxml .jackson .databind .Module ;
12+ import com .fasterxml .jackson .databind .ObjectMapper ;
913import org .checkerframework .checker .nullness .qual .Nullable ;
14+
15+ import org .hibernate .boot .registry .classloading .spi .ClassLoaderService ;
1016import org .hibernate .type .format .FormatMapper ;
1117import org .hibernate .type .format .FormatMapperCreationContext ;
1218
@@ -30,69 +36,24 @@ private static boolean ableToLoadJacksonXMLMapper() {
3036 return canLoad ( "com.fasterxml.jackson.dataformat.xml.XmlMapper" );
3137 }
3238
33- /**
34- * Checks that Jackson is available and that we have the Oracle OSON extension available
35- * in the classpath.
36- * @return true if we can load the OSON support, false otherwise.
37- */
38- private static boolean ableToLoadJacksonOSONFactory () {
39- return ableToLoadJacksonJSONMapper () &&
40- canLoad ( "oracle.jdbc.provider.oson.OsonFactory" );
41- }
42-
4339 public static @ Nullable FormatMapper getXMLJacksonFormatMapperOrNull (FormatMapperCreationContext creationContext ) {
4440 return JACKSON_XML_AVAILABLE
45- ? createFormatMapper ( "org.hibernate.type.format.jackson. JacksonXmlFormatMapper" , creationContext )
41+ ? new JacksonXmlFormatMapper ( creationContext )
4642 : null ;
4743 }
4844
4945 public static @ Nullable FormatMapper getJsonJacksonFormatMapperOrNull (FormatMapperCreationContext creationContext ) {
5046 return JACKSON_JSON_AVAILABLE
51- ? createFormatMapper ( "org.hibernate.type.format.jackson. JacksonJsonFormatMapper" , creationContext )
47+ ? new JacksonJsonFormatMapper ( creationContext )
5248 : null ;
5349 }
5450
55- public static @ Nullable FormatMapper getXMLJacksonFormatMapperOrNull (boolean legacyFormat ) {
56- if ( JACKSON_XML_AVAILABLE ) {
57- try {
58- final Class <?> formatMapperClass = JacksonIntegration .class .getClassLoader ()
59- .loadClass ( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper" );
60- return (FormatMapper ) formatMapperClass .getDeclaredConstructor ( boolean .class )
61- .newInstance ( legacyFormat );
62- }
63- catch (Exception e ) {
64- throw new RuntimeException ( "Couldn't instantiate Jackson XML FormatMapper" , e );
65- }
66- }
67- return null ;
68- }
69-
7051 public static @ Nullable FormatMapper getJsonJacksonFormatMapperOrNull () {
7152 return JACKSON_JSON_AVAILABLE
72- ? createFormatMapper ( "org.hibernate.type.format.jackson. JacksonJsonFormatMapper" , null )
53+ ? new JacksonJsonFormatMapper ( )
7354 : null ;
7455 }
7556
76- private static FormatMapper createFormatMapper (String className , @ Nullable FormatMapperCreationContext creationContext ) {
77- try {
78- if ( creationContext == null ) {
79- final Class <?> formatMapperClass = JacksonIntegration .class .getClassLoader ()
80- .loadClass ( className );
81- return (FormatMapper ) formatMapperClass .getDeclaredConstructor ().newInstance ();
82- }
83- else {
84- return (FormatMapper ) creationContext .getBootstrapContext ()
85- .getClassLoaderAccess ()
86- .classForName ( className )
87- .getDeclaredConstructor ( FormatMapperCreationContext .class )
88- .newInstance ( creationContext );
89- }
90- }
91- catch (Exception e ) {
92- throw new RuntimeException ( "Couldn't instantiate Jackson FormatMapper" , e );
93- }
94- }
95-
9657 private static boolean canLoad (String name ) {
9758 try {
9859 //N.B. intentionally not using the context classloader
@@ -106,4 +67,28 @@ private static boolean canLoad(String name) {
10667 return false ;
10768 }
10869 }
70+
71+ static List <Module > loadModules (FormatMapperCreationContext creationContext ) {
72+ final ClassLoader classLoader = JacksonIntegration .class .getClassLoader ();
73+ final ClassLoader contextClassLoader = Thread .currentThread ().getContextClassLoader ();
74+ if ( contextClassLoader != null && classLoader != contextClassLoader ) {
75+ try {
76+ // The context class loader represents the application class loader in a Jakarta EE deployment.
77+ // We have to check if the ObjectMapper that is visible to Hibernate ORM is the same that is visible
78+ // to the application class loader. Only if it is, we can use the application class loader or rather
79+ // our AggregatedClassLoader for loading Jackson Module via ServiceLoader, as otherwise the loaded
80+ // Jackson Module instances would have a different class loader, leading to a ClassCastException.
81+ if ( ObjectMapper .class == contextClassLoader .loadClass ( "com.fasterxml.jackson.databind.ObjectMapper" ) ) {
82+ return creationContext .getBootstrapContext ()
83+ .getServiceRegistry ()
84+ .requireService ( ClassLoaderService .class )
85+ .<List <Module >>workWithClassLoader ( ObjectMapper ::findModules );
86+ }
87+ }
88+ catch (ClassNotFoundException | LinkageError e ) {
89+ // Ignore if the context/application class loader doesn't know Jackson classes
90+ }
91+ }
92+ return ObjectMapper .findModules ( classLoader );
93+ }
10994}
0 commit comments