0

I am having difficulties in accessing java methods from a shared library built with GraalVM.

Imagine this code loading a GraalVM Shared library:

public class Main {
    static native int onEnable(long isolateThread, int a);
    static native long createIsolate();
    public static void main(String[] args) throws Exception {
        try {
            System.loadLibrary("simplelib");
        } catch (UnsatisfiedLinkError e) {
            NativeHelper.loadFromJar("simplelib", Main.class);
        }
        System.out.println("Loaded simplelib");
        System.out.println(
            "onEnable returned: " + onEnable(createIsolate(), 1)
        );
    }

    public static void printedFromGraal() {
        System.out.println("Printed from GraalVM");
    }
}

Then, I can easily implement onEnable() with GraalVM as follows:

    @CEntryPoint(name = "Java_com_daysling_dllloader_Main_onEnable")
    public static int onEnable(Pointer env, Pointer clazz, IsolateThread thread, int a) throws Exception {
        return a + 10;
    }

    @CEntryPoint(name = "Java_com_daysling_dllloader_Main_createIsolate", builtin=CEntryPoint.Builtin.CREATE_ISOLATE)
    public static native IsolateThread createIsolate();

It's not really a big deal, but the problem comes when trying to call the printedFromGraal() function from inside the GraalVM shared library. I've read documentation, searched on slack and much more but I still haven't found anything useful or any kind of examples.

The most concerning thing to be me is, if I were to implement a ReflectionHelper in my main application in order to ease JNI (if this is even possible possible) from the GraalVM:

package com.daysling.simplelib.reflections;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflectionHelper {
    public static ReflectionPackage getPackage(String packageName) {
        return new ReflectionPackage(packageName);
    }

    public static class ReflectionPackage {
        private final String packageName;

        private ReflectionPackage(String packageName) {
            this.packageName = packageName;
        }

        public ReflectedClass getClass(String className) throws ClassNotFoundException {
            String fullClassName = packageName + "." + className;
            Class<?> clazz = Class.forName(fullClassName);
            return new ReflectedClass(clazz);
        }

        public List<ReflectedClass> findAllClasses() throws ClassNotFoundException {
            List<ReflectedClass> classes = new ArrayList<>();
            String packagePath = packageName.replace('.', '/');
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            if (classLoader == null) {
                classLoader = ReflectionHelper.class.getClassLoader();
            }
            java.net.URL resource = classLoader.getResource(packagePath);
            if (resource != null) {
                String filePath = resource.getFile();
                if (filePath != null) {
                    java.io.File folder = new java.io.File(filePath);
                    java.io.File[] files = folder.listFiles();
                    if (files != null) {
                        for (java.io.File file : files) {
                            if (file.isFile() && file.getName().endsWith(".class")) {
                                String className = file.getName().substring(0, file.getName().lastIndexOf('.'));
                                classes.add(getClass(className));
                            }
                        }
                    }
                }
            }
            return classes;
        }

        public static class ReflectedClass {
            private final Class<?> clazz;

            private ReflectedClass(Class<?> clazz) {
                this.clazz = clazz;
            }

            public String getName() {
                return clazz.getName();
            }

            public ReflectedClass getSuperclass() {
                Class<?> superclass = clazz.getSuperclass();
                return (superclass != null) ? new ReflectedClass(superclass) : null;
            }

            public List<ReflectedMethod> findAllMethods() {
                List<ReflectedMethod> methods = new ArrayList<>();
                Method[] declaredMethods = clazz.getDeclaredMethods();
                for (Method method : declaredMethods) {
                    methods.add(new ReflectedMethod(method));
                }
                return methods;
            }

            public List<ReflectedField> findAllFields() {
                List<ReflectedField> fields = new ArrayList<>();
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field field : declaredFields) {
                    fields.add(new ReflectedField(field));
                }
                return fields;
            }

            public ReflectedMethod findMethod(String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
                Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
                return new ReflectedMethod(method);
            }

            public ReflectedField findField(String fieldName) throws NoSuchFieldException {
                Field field = clazz.getDeclaredField(fieldName);
                return new ReflectedField(field);
            }
        }
    }

    public static class ReflectedMethod {
        private final Method method;

        private ReflectedMethod(Method method) {
            this.method = method;
        }

        public String getName() {
            return method.getName();
        }

        public Class<?> getReturnType() {
            return method.getReturnType();
        }

        public Class<?>[] getParameterTypes() {
            return method.getParameterTypes();
        }

        public ReflectedObject invoke(Object object, Object... args) throws Exception {
            Object result = method.invoke(object, args);
            return new ReflectedObject(result);
        }

    }
    public static class ReflectedObject {
        private final Object object;

        public ReflectedObject(Object object) {
            this.object = object;
        }

        public ReflectionPackage.ReflectedClass getJavaClass() {
            return new ReflectionPackage.ReflectedClass(object.getClass());
        }

        public ReflectedObject callMethod(String methodName, Object... args) throws Exception {
            Class<?>[] parameterTypes = new Class<?>[args.length];
            for (int i = 0; i < args.length; i++) {
                parameterTypes[i] = args[i].getClass();
            }
            Method method = object.getClass().getDeclaredMethod(methodName, parameterTypes);
            Object result = method.invoke(object, args);
            return new ReflectedObject(result);
        }

        public Object getObject() {
            return object;
        }

        public static ReflectedObject getAsReflectedObject(Object object) {
            return new ReflectedObject(object);
        }
    }

    public static class ReflectedField {
        private final Field field;

        private ReflectedField(Field field) {
            this.field = field;
        }

        public String getName() {
            return field.getName();
        }

        public Class<?> getType() {
            return field.getType();
        }

        public Object get(Object object) throws IllegalAccessException {
            return field.get(object);
        }

        public void set(Object object, Object value) throws IllegalAccessException {
            field.set(object, value);
        }
    }
}

I don't think I can replicate an wrapper exact to how it'd looking in any java code.

dan1st
  • 12,568
  • 8
  • 34
  • 67
daysling
  • 118
  • 10

0 Answers0