/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.graal;
import com.oracle.svm.core.configure.ResourcesRegistry;
import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry;
import io.micronaut.core.util.ArrayUtils;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature.BeforeAnalysisAccess;
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.ArrayList;
import java.util.List;
import java.util.Optional;
Utility methods for implementing Graal's AutomaticFeature
. Author: Álvaro Sánchez-Mariscal, graemerocher Since: 2.0.0
/**
* Utility methods for implementing Graal's {@link com.oracle.svm.core.annotate.AutomaticFeature}.
*
* @author Álvaro Sánchez-Mariscal
* @author graemerocher
* @since 2.0.0
*/
public final class AutomaticFeatureUtils {
Marks the given class to be initialized at build time, only if it is present.
Params: - access – the
BeforeAnalysisAccess
instance - className – the class name
/**
* Marks the given class to be initialized at build time, only if it is present.
*
* @param access the {@link BeforeAnalysisAccess} instance
* @param className the class name
*/
public static void initializeAtBuildTime(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(RuntimeClassInitialization::initializeAtBuildTime);
}
Marks the given class to be initialized at build time, only if it is present.
Params: - access – The
BeforeAnalysisAccess
instance - classNames – The class names
/**
* Marks the given class to be initialized at build time, only if it is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param classNames The class names
*/
public static void initializeAtBuildTime(BeforeAnalysisAccess access, String... classNames) {
for (String className : classNames) {
initializeAtBuildTime(access, className);
}
}
Marks the given class to be initialized at runtime, only if it is present.
Params: - access – the
BeforeAnalysisAccess
instance - className – the class name
/**
* Marks the given class to be initialized at runtime, only if it is present.
*
* @param access the {@link BeforeAnalysisAccess} instance
* @param className the class name
*/
public static void initializeAtRunTime(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(RuntimeClassInitialization::initializeAtRunTime);
}
Marks the given class to be initialized at runtime, only if it is present.
Params: - access – The
BeforeAnalysisAccess
instance - classNames – The class names
/**
* Marks the given class to be initialized at runtime, only if it is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param classNames The class names
*/
public static void initializeAtRunTime(BeforeAnalysisAccess access, String... classNames) {
for (String className : classNames) {
initializeAtRunTime(access, className);
}
}
Initializes the packages at build time.
Params: - packages – The packages
/**
* Initializes the packages at build time.
*
* @param packages The packages
*/
public static void initializePackagesAtBuildTime(String... packages) {
RuntimeClassInitialization.initializeAtBuildTime(packages);
}
Initializes the packages at run time.
Params: - packages – The packages
/**
* Initializes the packages at run time.
*
* @param packages The packages
*/
public static void initializePackagesAtRunTime(String... packages) {
RuntimeClassInitialization.initializeAtRunTime(packages);
}
Register all constructors of the given class for runtime reflection, only if the class is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register all constructors of the given class for runtime reflection, only if the class is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerConstructorsForRuntimeReflection(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerConstructorsForRuntimeReflection);
}
Allows reflection instantiation of the given class, only if it is present.
Params: - access – the
BeforeAnalysisAccess
instance - className – the class name
/**
* Allows reflection instantiation of the given class, only if it is present.
*
* @param access the {@link BeforeAnalysisAccess} instance
* @param className the class name
*/
public static void registerClassForRuntimeReflection(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerForRuntimeReflection);
}
Register the class for reflective instantiation at runtime, only if it is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register the class for reflective instantiation at runtime, only if it is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerClassForRuntimeReflectiveInstantiation(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerForReflectiveInstantiation);
}
Register the class and allow reflective instantiation at runtime, only if it is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register the class and allow reflective instantiation at runtime, only if it is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerClassForRuntimeReflectionAndReflectiveInstantiation(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerForRuntimeReflectionAndReflectiveInstantiation);
}
Allows reflection usage for all methods of the given class, only if it is present.
Params: - access – the
BeforeAnalysisAccess
instance - className – the class name
/**
* Allows reflection usage for all methods of the given class, only if it is present.
*
* @param access the {@link BeforeAnalysisAccess} instance
* @param className the class name
*/
public static void registerMethodsForRuntimeReflection(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerMethodsForRuntimeReflection);
}
Allows reflection usage for all fields of the given class, only if it is present.
Params: - access – the
BeforeAnalysisAccess
instance - className – the class name
/**
* Allows reflection usage for all fields of the given class, only if it is present.
*
* @param access the {@link BeforeAnalysisAccess} instance
* @param className the class name
*/
public static void registerFieldsForRuntimeReflection(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerFieldsForRuntimeReflection);
}
Registers the given interfaces for dynamic proxy generation.
Params: - access – The
BeforeAnalysisAccess
instance - interfaces – the list of interfaces that the generated proxy can implement
/**
* Registers the given interfaces for dynamic proxy generation.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param interfaces the list of interfaces that the generated proxy can implement
*/
public static void addProxyClass(BeforeAnalysisAccess access, String... interfaces) {
List<Class<?>> classList = new ArrayList<>();
for (String anInterface : interfaces) {
Class<?> clazz = access.findClassByName(anInterface);
if (clazz != null) {
classList.add(clazz);
}
}
if (classList.size() == interfaces.length) {
ImageSingletons.lookup(DynamicProxyRegistry.class).addProxyClass(classList.toArray(new Class<?>[interfaces.length]));
}
}
Adds resource patterns.
Params: - patterns – The patterns
/**
* Adds resource patterns.
*
* @param patterns The patterns
*/
public static void addResourcePatterns(String... patterns) {
if (ArrayUtils.isNotEmpty(patterns)) {
ResourcesRegistry resourcesRegistry = ImageSingletons.lookup(ResourcesRegistry.class);
if (resourcesRegistry != null) {
for (String resource : patterns) {
resourcesRegistry.addResources(resource);
}
}
}
}
Adds resource bundles.
Params: - bundles – The bundles
/**
* Adds resource bundles.
*
* @param bundles The bundles
*/
public static void addResourceBundles(String... bundles) {
if (ArrayUtils.isNotEmpty(bundles)) {
ResourcesRegistry resourcesRegistry = ImageSingletons.lookup(ResourcesRegistry.class);
if (resourcesRegistry != null) {
for (String resource : bundles) {
resourcesRegistry.addResourceBundles(resource);
}
}
}
}
Register class for runtime reflection and allows reflective instantiation. Also register all fields, methods and
constructors for runtime reflection; only if the class is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register class for runtime reflection and allows reflective instantiation. Also register all fields, methods and
* constructors for runtime reflection; only if the class is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerAllForRuntimeReflectionAndReflectiveInstantiation(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerAllForRuntimeReflectionAndReflectiveInstantiation);
}
Register class for runtime reflection without allowing reflective instantiation. Also register all fields, methods
and constructors for runtime reflection; only if the class is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register class for runtime reflection without allowing reflective instantiation. Also register all fields, methods
* and constructors for runtime reflection; only if the class is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerAllForRuntimeReflection(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerAllForRuntimeReflection);
}
Register class for runtime reflection and allows reflective instantiation. Also register all fields and methods
for runtime reflection; only if the class is present.
Params: - access – The
BeforeAnalysisAccess
instance - className – The class name
/**
* Register class for runtime reflection and allows reflective instantiation. Also register all fields and methods
* for runtime reflection; only if the class is present.
*
* @param access The {@link BeforeAnalysisAccess} instance
* @param className The class name
*/
public static void registerFieldsAndMethodsWithReflectiveAccess(BeforeAnalysisAccess access, String className) {
findClass(access, className).ifPresent(AutomaticFeatureUtils::registerFieldsAndMethodsWithReflectiveAccess);
}
private static void registerAllForRuntimeReflectionAndReflectiveInstantiation(Class<?> clazz) {
registerForRuntimeReflection(clazz);
registerForReflectiveInstantiation(clazz);
registerFieldsForRuntimeReflection(clazz);
registerMethodsForRuntimeReflection(clazz);
registerConstructorsForRuntimeReflection(clazz);
}
private static void registerAllForRuntimeReflection(Class<?> clazz) {
registerForRuntimeReflection(clazz);
registerFieldsForRuntimeReflection(clazz);
registerMethodsForRuntimeReflection(clazz);
registerConstructorsForRuntimeReflection(clazz);
}
private static void registerFieldsAndMethodsWithReflectiveAccess(Class<?> clazz) {
registerForRuntimeReflectionAndReflectiveInstantiation(clazz);
registerMethodsForRuntimeReflection(clazz);
registerFieldsForRuntimeReflection(clazz);
}
private static void registerForRuntimeReflection(Class<?> clazz) {
RuntimeReflection.register(clazz);
}
private static void registerForReflectiveInstantiation(Class<?> clazz) {
RuntimeReflection.registerForReflectiveInstantiation(clazz);
}
private static void registerForRuntimeReflectionAndReflectiveInstantiation(Class<?> clazz) {
RuntimeReflection.register(clazz);
RuntimeReflection.registerForReflectiveInstantiation(clazz);
}
private static void registerMethodsForRuntimeReflection(Class<?> clazz) {
for (Method method : clazz.getMethods()) {
RuntimeReflection.register(method);
}
}
private static void registerFieldsForRuntimeReflection(Class<?> clazz) {
for (Field field : clazz.getFields()) {
RuntimeReflection.register(field);
}
}
private static void registerConstructorsForRuntimeReflection(Class<?> clazz) {
for (Constructor<?> constructor : clazz.getConstructors()) {
RuntimeReflection.register(constructor);
}
}
private static Optional<Class<?>> findClass(BeforeAnalysisAccess access, String className) {
return Optional.ofNullable(access.findClassByName(className));
}
}