From ca2088ad39e889f2388d86397af3b71f4b128a0c Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 21 Jul 2022 18:42:36 +0100 Subject: [PATCH] HHH-15415 Jackson integration to not break GraalVM native image compilation --- .../SessionFactoryOptionsBuilder.java | 27 ++++-------- .../type/JacksonJsonFormatMapper.java | 1 - .../type/JacksonXmlFormatMapper.java | 1 - .../hibernate/type/JaxbXmlFormatMapper.java | 1 - .../type/jackson/JacksonIntegration.java | 42 +++++++++++++++++++ 5 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/type/jackson/JacksonIntegration.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index a2a604cd35..386f3bb04d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -72,9 +72,9 @@ import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.stat.Statistics; import org.hibernate.type.FormatMapper; import org.hibernate.type.JacksonJsonFormatMapper; -import org.hibernate.type.JacksonXmlFormatMapper; import org.hibernate.type.JaxbXmlFormatMapper; import org.hibernate.type.JsonBJsonFormatMapper; +import org.hibernate.type.jackson.JacksonIntegration; import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS; import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY; @@ -797,13 +797,9 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { FormatMapper.class, setting, (Callable) () -> { - try { - // Force initialization of the instance - JacksonJsonFormatMapper.INSTANCE.hashCode(); - return JacksonJsonFormatMapper.INSTANCE; - } - catch (NoClassDefFoundError ex) { - // Ignore + final FormatMapper jsonJacksonFormatMapper = JacksonIntegration.getJsonJacksonFormatMapperOrNull(); + if (jsonJacksonFormatMapper != null) { + return jsonJacksonFormatMapper; } try { // Force initialization of the instance @@ -823,18 +819,13 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { FormatMapper.class, setting, (Callable) () -> { - try { - // Force initialization of the instance - JacksonXmlFormatMapper.INSTANCE.hashCode(); - return JacksonXmlFormatMapper.INSTANCE; - } - catch (NoClassDefFoundError ex) { - // Ignore + final FormatMapper jacksonFormatMapper = JacksonIntegration.getXMLJacksonFormatMapperOrNull(); + if (jacksonFormatMapper != null) { + return jacksonFormatMapper; } + try { - // Force initialization of the instance - JaxbXmlFormatMapper.INSTANCE.hashCode(); - return JaxbXmlFormatMapper.INSTANCE; + return new JaxbXmlFormatMapper(); } catch (NoClassDefFoundError ex) { // Ignore diff --git a/hibernate-core/src/main/java/org/hibernate/type/JacksonJsonFormatMapper.java b/hibernate-core/src/main/java/org/hibernate/type/JacksonJsonFormatMapper.java index 33509beaff..209aa909ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/JacksonJsonFormatMapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/JacksonJsonFormatMapper.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class JacksonJsonFormatMapper implements FormatMapper { public static final String SHORT_NAME = "jackson"; - public static final JacksonJsonFormatMapper INSTANCE = new JacksonJsonFormatMapper(); private final ObjectMapper objectMapper; diff --git a/hibernate-core/src/main/java/org/hibernate/type/JacksonXmlFormatMapper.java b/hibernate-core/src/main/java/org/hibernate/type/JacksonXmlFormatMapper.java index f2167b6c09..f4339e3faa 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/JacksonXmlFormatMapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/JacksonXmlFormatMapper.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class JacksonXmlFormatMapper implements FormatMapper { public static final String SHORT_NAME = "jackson-xml"; - public static final JacksonXmlFormatMapper INSTANCE = new JacksonXmlFormatMapper(); private final ObjectMapper objectMapper; diff --git a/hibernate-core/src/main/java/org/hibernate/type/JaxbXmlFormatMapper.java b/hibernate-core/src/main/java/org/hibernate/type/JaxbXmlFormatMapper.java index 1ea89c22bd..c8ae08d890 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/JaxbXmlFormatMapper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/JaxbXmlFormatMapper.java @@ -44,7 +44,6 @@ import org.w3c.dom.Node; public class JaxbXmlFormatMapper implements FormatMapper { public static final String SHORT_NAME = "jaxb"; - public static final JaxbXmlFormatMapper INSTANCE = new JaxbXmlFormatMapper(); public JaxbXmlFormatMapper() { } diff --git a/hibernate-core/src/main/java/org/hibernate/type/jackson/JacksonIntegration.java b/hibernate-core/src/main/java/org/hibernate/type/jackson/JacksonIntegration.java new file mode 100644 index 0000000000..da240edaab --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/jackson/JacksonIntegration.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.type.jackson; + +import org.hibernate.type.FormatMapper; +import org.hibernate.type.JacksonJsonFormatMapper; +import org.hibernate.type.JacksonXmlFormatMapper; + +public final class JacksonIntegration { + + // Implementation note: we rely on the following two fields to be folded as constants + // when GraalVM native image is initializing them. + private static final boolean JACKSON_AVAILABLE = ableToLoadJackson(); + private static final JacksonXmlFormatMapper XML_FORMAT_MAPPER = JACKSON_AVAILABLE ? new JacksonXmlFormatMapper() : null; + private static final JacksonJsonFormatMapper JSON_FORMAT_MAPPER = JACKSON_AVAILABLE ? new JacksonJsonFormatMapper() : null; + + private JacksonIntegration() { + //To not be instantiated: static helpers only + } + + private static boolean ableToLoadJackson() { + try { + JacksonIntegration.class.getClassLoader().loadClass( "com.fasterxml.jackson.dataformat.xml.XmlMapper" ); + return true; + } + catch (ClassNotFoundException | LinkageError e) { + return false; + } + } + + public static FormatMapper getXMLJacksonFormatMapperOrNull() { + return XML_FORMAT_MAPPER; + } + + public static FormatMapper getJsonJacksonFormatMapperOrNull() { + return JSON_FORMAT_MAPPER; + } +}