From f90d8d5865a5784b5131508e28d768b65de62a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20L=C3=B3pez?= Date: Wed, 21 Oct 2020 15:24:38 +0200 Subject: [PATCH] Use GraalVM utility class from core (#278) * Use GraalVM utility class from core. Fixes #275 * Upgrade to Micronaut 2.1 and fix compilation issue * Add missing class for H2 --- gradle.properties | 2 +- .../hibernate/jpa/graal/HibernateFeature.java | 26 +- .../jdbc/nativeimage/JdbcFeature.java | 306 +++++++----------- 3 files changed, 122 insertions(+), 212 deletions(-) diff --git a/gradle.properties b/gradle.properties index 346b1e18b..abe3231a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ projectVersion=3.2.0.BUILD-SNAPSHOT micronautBuildVersion=1.1.5 micronautDocsVersion=1.0.24 -micronautVersion=2.0.0 +micronautVersion=2.1.1 micronautTestVersion=2.1.1 groovyVersion=3.0.3 diff --git a/hibernate-jpa/src/main/java/io/micronaut/configuration/hibernate/jpa/graal/HibernateFeature.java b/hibernate-jpa/src/main/java/io/micronaut/configuration/hibernate/jpa/graal/HibernateFeature.java index 86033bd2b..98b1f0499 100644 --- a/hibernate-jpa/src/main/java/io/micronaut/configuration/hibernate/jpa/graal/HibernateFeature.java +++ b/hibernate-jpa/src/main/java/io/micronaut/configuration/hibernate/jpa/graal/HibernateFeature.java @@ -16,8 +16,9 @@ package io.micronaut.configuration.hibernate.jpa.graal; import com.oracle.svm.core.annotate.AutomaticFeature; +import io.micronaut.core.annotation.Internal; +import io.micronaut.core.graal.AutomaticFeatureUtils; import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.hibernate.dialect.*; /** @@ -28,16 +29,14 @@ * @since 2.2.1 */ @AutomaticFeature +@Internal final class HibernateFeature implements Feature { + @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - if (registerIfPresent(access, "org.h2.Driver", H2Dialect.class)) { - Class constClass = access.findClassByName("org.h2.engine.Constants"); - if (constClass != null) { - RuntimeReflection.register(constClass); - RuntimeReflection.register(constClass.getDeclaredFields()); - } - } + registerIfPresent(access, "org.h2.Driver", + H2Dialect.class + ); registerIfPresent(access, "org.postgresql.Driver", PostgreSQL9Dialect.class, @@ -51,11 +50,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { PostgreSQL82Dialect.class ); - registerIfPresent(access, "com.microsoft.sqlserver.jdbc.SQLServerResource", - SQLServer2005Dialect.class, - SQLServer2008Dialect.class, - SQLServer2012Dialect.class); - registerIfPresent(access, "org.mariadb.jdbc.Driver", MariaDBDialect.class, MariaDB10Dialect.class, @@ -82,15 +76,13 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { MySQL8Dialect.class); } - private boolean registerIfPresent(BeforeAnalysisAccess access, String name, Class... dialects) { + private void registerIfPresent(BeforeAnalysisAccess access, String name, Class... dialects) { Class driver = access.findClassByName(name); boolean present = driver != null; if (present) { for (Class dialect : dialects) { - RuntimeReflection.register(dialect); - RuntimeReflection.registerForReflectiveInstantiation(dialect); + AutomaticFeatureUtils.registerClassForRuntimeReflectionAndReflectiveInstantiation(access, dialect.getName()); } } - return present; } } diff --git a/jdbc/src/main/java/io/micronaut/jdbc/nativeimage/JdbcFeature.java b/jdbc/src/main/java/io/micronaut/jdbc/nativeimage/JdbcFeature.java index 76b627048..9a023d03d 100644 --- a/jdbc/src/main/java/io/micronaut/jdbc/nativeimage/JdbcFeature.java +++ b/jdbc/src/main/java/io/micronaut/jdbc/nativeimage/JdbcFeature.java @@ -18,14 +18,23 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.configure.ResourcesRegistry; import io.micronaut.core.annotation.Internal; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; -import org.graalvm.nativeimage.hosted.RuntimeReflection; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; + +import static io.micronaut.core.graal.AutomaticFeatureUtils.addResourceBundles; +import static io.micronaut.core.graal.AutomaticFeatureUtils.addResourcePatterns; +import static io.micronaut.core.graal.AutomaticFeatureUtils.initializeAtBuildTime; +import static io.micronaut.core.graal.AutomaticFeatureUtils.initializeAtRunTime; +import static io.micronaut.core.graal.AutomaticFeatureUtils.initializePackagesAtBuildTime; +import static io.micronaut.core.graal.AutomaticFeatureUtils.initializePackagesAtRunTime; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerAllForRuntimeReflection; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerClassForRuntimeReflection; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerClassForRuntimeReflectionAndReflectiveInstantiation; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerFieldsAndMethodsWithReflectiveAccess; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerFieldsForRuntimeReflection; +import static io.micronaut.core.graal.AutomaticFeatureUtils.registerMethodsForRuntimeReflection; /** * A JDBC feature that configures JDBC drivers correctly for native image. @@ -49,52 +58,55 @@ final class JdbcFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - // h2 handleH2(access); - // postgres handlePostgres(access); - // sql server - handleSqlServer(access); - - // mariadb handleMariadb(access); - // oracle handleOracle(access); - // mysql + handleSqlServer(access); + handleMySql(access); } private void handleH2(BeforeAnalysisAccess access) { Class h2Driver = access.findClassByName(H2_DRIVER); if (h2Driver != null) { - registerAllIfPresent(access, "org.h2.mvstore.db.MVTableEngine"); + registerFieldsAndMethodsWithReflectiveAccess(access, "org.h2.mvstore.db.MVTableEngine"); + + registerClassForRuntimeReflection(access, H2_DRIVER); + initializeAtBuildTime(access, H2_DRIVER); - RuntimeReflection.register(h2Driver); - RuntimeClassInitialization.initializeAtBuildTime(h2Driver); + Collections.singletonList("org.h2.engine.Constants") + .forEach(s -> { + registerClassForRuntimeReflection(access, s); + registerMethodsForRuntimeReflection(access, s); + registerFieldsForRuntimeReflection(access, s); + }); // required for file-based H2 databases - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathDisk"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathMem"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathMemLZF"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathNioMem"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathNioMemLZF"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathSplit"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathNio"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathNioMapped"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathAsync"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathZip"); - registerForRuntimeReflectiveInstantiation(access, "org.h2.store.fs.FilePathRetryOnInterrupt"); - initializeAtRuntime(access, "sun.nio.ch.WindowsAsynchronousFileChannelImpl$DefaultIocpHolder"); - - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - resourcesRegistry.addResources("org/h2/util/data.zip"); - } + Arrays.asList( + "org.h2.store.fs.FilePathDisk", + "org.h2.store.fs.FilePathMem", + "org.h2.store.fs.FilePathMemLZF", + "org.h2.store.fs.FilePathNioMem", + "org.h2.store.fs.FilePathNioMemLZF", + "org.h2.store.fs.FilePathSplit", + "org.h2.store.fs.FilePathNio", + "org.h2.store.fs.FilePathNioMapped", + "org.h2.store.fs.FilePathAsync", + "org.h2.store.fs.FilePathZip", + "org.h2.store.fs.FilePathRetryOnInterrupt" + ).forEach(c -> registerClassForRuntimeReflectionAndReflectiveInstantiation(access, c)); + + initializeAtRunTime(access, "sun.nio.ch.WindowsAsynchronousFileChannelImpl$DefaultIocpHolder"); + + addResourcePatterns( + "META-INF/services/java.sql.Driver", + "org/h2/util/data.zip" + ); initializeAtBuildTime(access, "java.sql.DriverManager"); } @@ -103,20 +115,35 @@ private void handleH2(BeforeAnalysisAccess access) { private void handlePostgres(BeforeAnalysisAccess access) { Class postgresDriver = access.findClassByName(POSTGRESQL_DRIVER); if (postgresDriver != null) { - RuntimeReflection.register(postgresDriver); - RuntimeClassInitialization.initializeAtBuildTime(postgresDriver); + registerClassForRuntimeReflection(access, POSTGRESQL_DRIVER); initializeAtBuildTime(access, POSTGRESQL_DRIVER, "org.postgresql.util.SharedTimer" ); - registerAllFields(access, "org.postgresql.PGProperty"); + registerAllForRuntimeReflection(access, "org.postgresql.PGProperty"); + + addResourcePatterns("META-INF/services/java.sql.Driver"); + + initializeAtBuildTime(access, "java.sql.DriverManager"); + } + } + + private void handleMariadb(BeforeAnalysisAccess access) { + Class mariaDriver = access.findClassByName(MARIADB_DRIVER); + if (mariaDriver != null) { + registerFieldsAndMethodsWithReflectiveAccess(access, MARIADB_DRIVER); + + addResourcePatterns("META-INF/services/java.sql.Driver"); + + registerFieldsAndMethodsWithReflectiveAccess(access, "org.mariadb.jdbc.util.Options"); - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - } + initializePackagesAtBuildTime("org.mariadb"); + initializePackagesAtRunTime("org.mariadb.jdbc.credential.aws"); + + initializeAtRunTime(access, "org.mariadb.jdbc.internal.failover.impl.MastersSlavesListener"); + initializeAtRunTime(access, "org.mariadb.jdbc.internal.com.send.authentication.SendPamAuthPacket"); initializeAtBuildTime(access, "java.sql.DriverManager"); } @@ -125,26 +152,30 @@ private void handlePostgres(BeforeAnalysisAccess access) { private void handleOracle(BeforeAnalysisAccess access) { Class oracleDriver = access.findClassByName(ORACLE_DRIVER); if (oracleDriver != null) { - registerAllIfPresent(access, "oracle.jdbc.driver.T4CDriverExtension"); - registerAllIfPresent(access, "oracle.jdbc.driver.T2CDriverExtension"); - registerAllIfPresent(access, "oracle.net.ano.Ano"); - registerAllIfPresent(access, "oracle.net.ano.AuthenticationService"); - registerAllIfPresent(access, "oracle.net.ano.DataIntegrityService"); - registerAllIfPresent(access, "oracle.net.ano.EncryptionService"); - registerAllIfPresent(access, "oracle.net.ano.SupervisorService"); + Arrays.asList( + "oracle.jdbc.driver.T4CDriverExtension", + "oracle.jdbc.driver.T2CDriverExtension", + "oracle.net.ano.Ano", + "oracle.net.ano.AuthenticationService", + "oracle.net.ano.DataIntegrityService", + "oracle.net.ano.EncryptionService", + "oracle.net.ano.SupervisorService" + ).forEach(c -> registerFieldsAndMethodsWithReflectiveAccess(access, c)); registerAllForRuntimeReflection(access, "oracle.jdbc.logging.annotations.Supports"); registerAllForRuntimeReflection(access, "oracle.jdbc.logging.annotations.Feature"); - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - resourcesRegistry.addResources("oracle/sql/converter_xcharset/lx20002.glb"); - resourcesRegistry.addResources("oracle/sql/converter_xcharset/lx2001f.glb"); - resourcesRegistry.addResources("oracle/sql/converter_xcharset/lx200b2.glb"); - resourcesRegistry.addResourceBundles("oracle.net.jdbc.nl.mesg.NLSR"); - resourcesRegistry.addResourceBundles("oracle.net.mesg.Message"); - } + addResourcePatterns( + "META-INF/services/java.sql.Driver", + "oracle/sql/converter_xcharset/lx20002.glb", + "oracle/sql/converter_xcharset/lx2001f.glb", + "oracle/sql/converter_xcharset/lx200b2.glb" + ); + + addResourceBundles( + "oracle.net.jdbc.nl.mesg.NLSR", + "oracle.net.mesg.Message" + ); initializeAtBuildTime( access, @@ -160,132 +191,26 @@ private void handleOracle(BeforeAnalysisAccess access) { "com.sun.jmx.defaults.JmxProperties" ); - initializeAtRuntime(access, "java.sql.DriverManager"); - } - } - - private void handleMariadb(BeforeAnalysisAccess access) { - Class mariaDriver = access.findClassByName(MARIADB_DRIVER); - if (mariaDriver != null) { - RuntimeReflection.register(mariaDriver); - registerAllAccess(mariaDriver); - - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - } - - registerAllIfPresent(access, "org.mariadb.jdbc.util.Options"); - - RuntimeClassInitialization.initializeAtBuildTime("org.mariadb"); - RuntimeClassInitialization.initializeAtRunTime("org.mariadb.jdbc.credential.aws"); - - initializeAtRuntime(access, "org.mariadb.jdbc.internal.failover.impl.MastersSlavesListener"); - initializeAtRuntime(access, "org.mariadb.jdbc.internal.com.send.authentication.SendPamAuthPacket"); - - initializeAtBuildTime(access, "java.sql.DriverManager"); - } - } - - private void initializeAtRuntime(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - RuntimeClassInitialization.initializeAtRunTime(t); - } - } - - private void initializeAtBuildTime(BeforeAnalysisAccess access, String... names) { - for (String name : names) { - Class t = access.findClassByName(name); - if (t != null) { - RuntimeClassInitialization.initializeAtBuildTime(t); - } - } - } - - private void registerAllIfPresent(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - registerAllAccess(t); - } - } - - private void registerAllAccess(Class t) { - RuntimeReflection.register(t); - RuntimeReflection.registerForReflectiveInstantiation(t); - for (Method method : t.getMethods()) { - RuntimeReflection.register(method); - } - Field[] fields = t.getFields(); - for (Field field : fields) { - RuntimeReflection.register(field); - } - } - - private void registerAllForRuntimeReflection(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - RuntimeReflection.register(t); - registerAllFields(access, n); - registerAllMethods(access, n); - registerAllConstructors(access, n); - } - } - - private void registerAllFields(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - Field[] fields = t.getFields(); - for (Field field : fields) { - RuntimeReflection.register(field); - } - } - } - - private void registerAllMethods(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - for (Method method : t.getMethods()) { - RuntimeReflection.register(method); - } - } - } - - private void registerAllConstructors(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - for (Constructor constructor : t.getConstructors()) { - RuntimeReflection.register(constructor); - } - } - } - - private void registerForRuntimeReflectiveInstantiation(BeforeAnalysisAccess access, String n) { - Class t = access.findClassByName(n); - if (t != null) { - RuntimeReflection.register(t); - RuntimeReflection.registerForReflectiveInstantiation(t); + initializeAtRunTime(access, "java.sql.DriverManager"); } } private void handleSqlServer(BeforeAnalysisAccess access) { Class sqlServerDriver = access.findClassByName(SQL_SERVER_DRIVER); if (sqlServerDriver != null) { - RuntimeReflection.register(sqlServerDriver); - registerAllAccess(sqlServerDriver); - - RuntimeClassInitialization.initializeAtBuildTime(SQL_SERVER_DRIVER); + registerFieldsAndMethodsWithReflectiveAccess(access, SQL_SERVER_DRIVER); - initializeAtBuildTime(access, "com.microsoft.sqlserver.jdbc.Util"); - initializeAtBuildTime(access, "com.microsoft.sqlserver.jdbc.SQLServerException"); - registerAllIfPresent(access, "com.microsoft.sqlserver.jdbc.SQLServerDriver"); + initializeAtBuildTime(access, + SQL_SERVER_DRIVER, + "com.microsoft.sqlserver.jdbc.Util", + "com.microsoft.sqlserver.jdbc.SQLServerException" + ); - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - resourcesRegistry.addResources("javax.crypto.Cipher.class"); - resourcesRegistry.addResourceBundles("com.microsoft.sqlserver.jdbc.SQLServerResource"); - } + addResourcePatterns( + "META-INF/services/java.sql.Driver", + "javax.crypto.Cipher.class" + ); + addResourceBundles("com.microsoft.sqlserver.jdbc.SQLServerResource"); initializeAtBuildTime(access, "java.sql.DriverManager"); } @@ -294,31 +219,24 @@ private void handleSqlServer(BeforeAnalysisAccess access) { private void handleMySql(BeforeAnalysisAccess access) { Class mysqlDriver = access.findClassByName(MYSQL_DRIVER); if (mysqlDriver != null) { - registerAllAccess(mysqlDriver); + registerFieldsAndMethodsWithReflectiveAccess(access, MYSQL_DRIVER); registerAllForRuntimeReflection(access, "com.mysql.cj.log.StandardLogger"); registerAllForRuntimeReflection(access, "com.mysql.cj.conf.url.SingleConnectionUrl"); - registerAllIfPresent(access, "com.mysql.cj.protocol.StandardSocketFactory"); - registerAllIfPresent(access, "com.mysql.cj.jdbc.AbandonedConnectionCleanupThread"); + registerFieldsAndMethodsWithReflectiveAccess(access, "com.mysql.cj.protocol.StandardSocketFactory"); + registerFieldsAndMethodsWithReflectiveAccess(access, "com.mysql.cj.jdbc.AbandonedConnectionCleanupThread"); - ResourcesRegistry resourcesRegistry = getResourceRegistry(); - if (resourcesRegistry != null) { - resourcesRegistry.addResources("META-INF/services/java.sql.Driver"); - resourcesRegistry.addResources("com/mysql/cj/TlsSettings.properties"); - resourcesRegistry.addResources("com/mysql/cj/LocalizedErrorMessages.properties"); - resourcesRegistry.addResources("com/mysql/cj/util/TimeZoneMapping.properties"); - resourcesRegistry.addResourceBundles("com.mysql.cj.LocalizedErrorMessages"); - } + addResourcePatterns( + "META-INF/services/java.sql.Driver", + "com/mysql/cj/TlsSettings.properties", + "com/mysql/cj/LocalizedErrorMessages.properties", + "com/mysql/cj/util/TimeZoneMapping.properties" + ); + addResourceBundles("com.mysql.cj.LocalizedErrorMessages"); - initializeAtRuntime(access, "java.sql.DriverManager"); + initializeAtRunTime(access, "java.sql.DriverManager"); } } - private ResourcesRegistry getResourceRegistry() { - if (resourcesRegistry == null) { - resourcesRegistry = ImageSingletons.lookup(ResourcesRegistry.class); - } - return resourcesRegistry; - } }