From a79d2a6c53ece290110e11fd4154af8d20e2da18 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Tue, 6 Sep 2022 19:48:02 +0100 Subject: [PATCH] Switch sample jni config programmatic - Now generating jni-config.json via hints to test that side instead of having manually crafted file. - Relates #490 --- .../samples/config/SamplesRuntimeHints.java | 296 +++++++++++++++++- .../META-INF/native-image/jni-config.json | 286 ----------------- 2 files changed, 295 insertions(+), 287 deletions(-) delete mode 100644 spring-shell-samples/src/main/resources/META-INF/native-image/jni-config.json diff --git a/spring-shell-samples/src/main/java/org/springframework/shell/samples/config/SamplesRuntimeHints.java b/spring-shell-samples/src/main/java/org/springframework/shell/samples/config/SamplesRuntimeHints.java index 4ed687a8..9deea05e 100644 --- a/spring-shell-samples/src/main/java/org/springframework/shell/samples/config/SamplesRuntimeHints.java +++ b/spring-shell-samples/src/main/java/org/springframework/shell/samples/config/SamplesRuntimeHints.java @@ -15,6 +15,7 @@ */ package org.springframework.shell.samples.config; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -24,6 +25,7 @@ import org.springframework.aot.hint.ReflectionHints; import org.springframework.aot.hint.ResourceHints; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeHint; import org.springframework.aot.hint.TypeReference; public class SamplesRuntimeHints implements RuntimeHintsRegistrar { @@ -33,6 +35,7 @@ public class SamplesRuntimeHints implements RuntimeHintsRegistrar { ResourceHints resource = hints.resources(); ProxyHints proxy = hints.proxies(); ReflectionHints reflection = hints.reflection(); + ReflectionHints jni = hints.jni(); // should go graalvm-reachability-metadata registerResources(resource); // should go graalvm-reachability-metadata @@ -57,6 +60,7 @@ public class SamplesRuntimeHints implements RuntimeHintsRegistrar { "org.jline.terminal.impl.jna.win.Kernel32$FOCUS_EVENT_RECORD", "org.jline.terminal.impl.jna.win.Kernel32$SMALL_RECT", "org.jline.terminal.impl.jna.win.Kernel32$UnionChar"); + registerJni(jni); } private void registerResources(ResourceHints resource) { @@ -77,8 +81,298 @@ public class SamplesRuntimeHints implements RuntimeHintsRegistrar { }); } - private Iterable typeReferences(String... classNames) { + private List typeReferences(String... classNames) { return Stream.of(classNames).map(TypeReference::of).collect(Collectors.toList()); } + private void registerJni(ReflectionHints jni) { + TypeReference reachableType = TypeReference.of("org.jline.terminal.impl.jna.win.Kernel32"); + + registerForJni(jni, reachableType, "com.sun.jna.Callback", + Methods.of(), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.CallbackReference", + Methods.of( + Method.of("getCallback", "java.lang.Class", "com.sun.jna.Pointer", "boolean"), + Method.of("getFunctionPointer", "com.sun.jna.Callback", "boolean"), + Method.of("getNativeString", "java.lang.Object", "boolean"), + Method.of("initializeThread", "com.sun.jna.Callback", + "com.sun.jna.CallbackReference$AttachOptions")), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.CallbackReference$AttachOptions", + Methods.of(), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.FromNativeConverter", + Methods.of( + Method.of("nativeType") + ), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.IntegerType", + Methods.of(), + Fields.of("value")); + + registerForJni(jni, reachableType, "com.sun.jna.JNIEnv", + Methods.of(), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.Native", + Methods.of( + Method.of("dispose"), + Method.of("fromNative", "com.sun.jna.FromNativeConverter", "java.lang.Object", + "java.lang.reflect.Method"), + Method.of("fromNative", "java.lang.Class", "java.lang.Object"), + Method.of("fromNative", "java.lang.reflect.Method", "java.lang.Object"), + Method.of("nativeType", "java.lang.Class"), + Method.of("toNative", "com.sun.jna.ToNativeConverter","java.lang.Object") + ), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.Native$ffi_callback", + Methods.of( + Method.of("invoke", "long", "long", "long") + ), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.NativeMapped", + Methods.of( + Method.of("toNative") + ), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.Pointer", + Methods.of( + Method.of("", "long") + ), + Fields.of("peer")); + + registerForJni(jni, reachableType, "com.sun.jna.PointerType", + Methods.of(), + Fields.of("pointer")); + + registerForJni(jni, reachableType, "com.sun.jna.Structure", + Methods.of( + Method.of("autoRead"), + Method.of("autoWrite"), + Method.of("getTypeInfo"), + Method.of("newInstance", "java.lang.Class", "long") + ), + Fields.of("memory", "typeInfo")); + + registerForJni(jni, reachableType, "com.sun.jna.Structure$ByValue", + Methods.of(), + Fields.of()); + + registerForJni(jni, reachableType, "com.sun.jna.Structure$FFIType$FFITypes", + Methods.of(), + Fields.of("ffi_type_double", "ffi_type_float", "ffi_type_longdouble", "ffi_type_pointer", + "ffi_type_sint16", "ffi_type_sint32", "ffi_type_sint64", "ffi_type_sint8", "ffi_type_uint16", + "ffi_type_uint32", "ffi_type_uint64", "ffi_type_uint8", + "ffi_type_void")); + + registerForJni(jni, reachableType, "com.sun.jna.WString", + Methods.of( + Method.of("", "java.lang.String") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.Boolean", + Methods.of( + Method.of("", "boolean") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Byte", + Methods.of( + Method.of("", "byte") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Character", + Methods.of( + Method.of("", "char") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Class", + Methods.of( + Method.of("getComponentType") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.Double", + Methods.of( + Method.of("", "double") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Float", + Methods.of( + Method.of("", "float") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Integer", + Methods.of( + Method.of("", "int") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Long", + Methods.of( + Method.of("", "long") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.Object", + Methods.of( + Method.of("toString") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.Short", + Methods.of( + Method.of("", "short") + ), + Fields.of("TYPE", "value")); + + registerForJni(jni, reachableType, "java.lang.String", + Methods.of( + Method.of("", "byte[]"), + Method.of("", "byte[]", "java.lang.String"), + Method.of("getBytes"), + Method.of("getBytes", "java.lang.String"), + Method.of("toCharArray") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.System", + Methods.of( + Method.of("getProperty", "java.lang.String") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.UnsatisfiedLinkError", + Methods.of( + Method.of("","java.lang.String") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.lang.Void", + Methods.of(), + Fields.of("TYPE")); + + registerForJni(jni, reachableType, "java.lang.reflect.Method", + Methods.of( + Method.of("getParameterTypes"), + Method.of("getReturnType") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.Buffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.ByteBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.CharBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.DoubleBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.FloatBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.IntBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.LongBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + registerForJni(jni, reachableType, "java.nio.ShortBuffer", + Methods.of( + Method.of("array"), + Method.of("arrayOffset") + ), + Fields.of()); + + } + + private void registerForJni(ReflectionHints jni, TypeReference reachableType, String type, + Methods methods, Fields fields) { + jni.registerType(TypeReference.of(type), hint -> { + hint.onReachableType(reachableType); + methods.withHints(hint); + fields.withHints(hint); + }); + } + + record Fields(String... names) { + + static Fields of(String... names) { + return new Fields(names); + } + + void withHints(TypeHint.Builder hint) { + Stream.of(names()).forEach(f -> hint.withField(f)); + } + } + + record Method(String name, String... parameterTypes) { + + static Method of(String name, String... parameterTypes) { + return new Method(name, parameterTypes); + } + + private List asTypeReferences() { + return Stream.of(parameterTypes).map(TypeReference::of).collect(Collectors.toList()); + } + + void withHints(TypeHint.Builder hint) { + hint.withMethod(name, asTypeReferences()); + } + } + + record Methods(Method... methods) { + + static Methods of(Method... methods) { + return new Methods(methods); + } + + void withHints(TypeHint.Builder hint) { + Stream.of(methods()).forEach(m -> m.withHints(hint)); + } + } } diff --git a/spring-shell-samples/src/main/resources/META-INF/native-image/jni-config.json b/spring-shell-samples/src/main/resources/META-INF/native-image/jni-config.json deleted file mode 100644 index dbd3523b..00000000 --- a/spring-shell-samples/src/main/resources/META-INF/native-image/jni-config.json +++ /dev/null @@ -1,286 +0,0 @@ -[ -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Callback" -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.CallbackReference", - "methods":[ - {"name":"getCallback","parameterTypes":["java.lang.Class","com.sun.jna.Pointer","boolean"] }, - {"name":"getFunctionPointer","parameterTypes":["com.sun.jna.Callback","boolean"] }, - {"name":"getNativeString","parameterTypes":["java.lang.Object","boolean"] }, - {"name":"initializeThread","parameterTypes":["com.sun.jna.Callback","com.sun.jna.CallbackReference$AttachOptions"] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.CallbackReference$AttachOptions" -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.FromNativeConverter", - "methods":[{"name":"nativeType","parameterTypes":[] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.IntegerType", - "fields":[{"name":"value"}] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.JNIEnv" -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Native", - "methods":[ - {"name":"dispose","parameterTypes":[] }, - {"name":"fromNative","parameterTypes":["com.sun.jna.FromNativeConverter","java.lang.Object","java.lang.reflect.Method"] }, - {"name":"fromNative","parameterTypes":["java.lang.Class","java.lang.Object"] }, - {"name":"fromNative","parameterTypes":["java.lang.reflect.Method","java.lang.Object"] }, - {"name":"nativeType","parameterTypes":["java.lang.Class"] }, - {"name":"toNative","parameterTypes":["com.sun.jna.ToNativeConverter","java.lang.Object"] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Native$ffi_callback", - "methods":[{"name":"invoke","parameterTypes":["long","long","long"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.NativeMapped", - "methods":[{"name":"toNative","parameterTypes":[] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Pointer", - "fields":[{"name":"peer"}], - "methods":[{"name":"","parameterTypes":["long"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.PointerType", - "fields":[{"name":"pointer"}] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Structure", - "fields":[ - {"name":"memory"}, - {"name":"typeInfo"} - ], - "methods":[ - {"name":"autoRead","parameterTypes":[] }, - {"name":"autoWrite","parameterTypes":[] }, - {"name":"getTypeInfo","parameterTypes":[] }, - {"name":"newInstance","parameterTypes":["java.lang.Class","long"] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Structure$ByValue" -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.Structure$FFIType$FFITypes", - "fields":[ - {"name":"ffi_type_double"}, - {"name":"ffi_type_float"}, - {"name":"ffi_type_longdouble"}, - {"name":"ffi_type_pointer"}, - {"name":"ffi_type_sint16"}, - {"name":"ffi_type_sint32"}, - {"name":"ffi_type_sint64"}, - {"name":"ffi_type_sint8"}, - {"name":"ffi_type_uint16"}, - {"name":"ffi_type_uint32"}, - {"name":"ffi_type_uint64"}, - {"name":"ffi_type_uint8"}, - {"name":"ffi_type_void"} - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"com.sun.jna.WString", - "methods":[{"name":"","parameterTypes":["java.lang.String"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Boolean", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["boolean"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Byte", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["byte"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Character", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["char"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Class", - "methods":[{"name":"getComponentType","parameterTypes":[] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Double", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["double"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Float", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["float"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Integer", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["int"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Long", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["long"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Object", - "methods":[{"name":"toString","parameterTypes":[] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Short", - "fields":[ - {"name":"TYPE"}, - {"name":"value"} - ], - "methods":[{"name":"","parameterTypes":["short"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.String", - "methods":[ - {"name":"","parameterTypes":["byte[]"] }, - {"name":"","parameterTypes":["byte[]","java.lang.String"] }, - {"name":"getBytes","parameterTypes":[] }, - {"name":"getBytes","parameterTypes":["java.lang.String"] }, - {"name":"toCharArray","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.System", - "methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.$Proxy43"}, - "name":"java.lang.UnsatisfiedLinkError", - "methods":[{"name":"","parameterTypes":["java.lang.String"] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.Void", - "fields":[{"name":"TYPE"}] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.lang.reflect.Method", - "methods":[ - {"name":"getParameterTypes","parameterTypes":[] }, - {"name":"getReturnType","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.Buffer", - "methods":[{"name":"position","parameterTypes":[] }] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.ByteBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.CharBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.DoubleBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.FloatBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.IntBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.LongBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -}, -{ - "condition":{"typeReachable":"org.jline.terminal.impl.jna.win.Kernel32"}, - "name":"java.nio.ShortBuffer", - "methods":[ - {"name":"array","parameterTypes":[] }, - {"name":"arrayOffset","parameterTypes":[] } - ] -} -]