I finally figured out how to do modules with JNI
M README.md +3 -3
@@ 3,11 3,11 @@ WofiJ is a Java API for Wofi
 
 ## Dependencies
 	wofi
-	openjdk-11-jdk
-	pkg-config
+	openjdk-17-jdk
+	pkgconf
 	meson
 ## Building
 	hg clone https://hg.sr.ht/~scoopta/WofiJ
 	cd WofiJ/src
-	meson -Djdk_home=$JAVA_HOME -Dmode_class=org/example/MyMode ../build
+	meson -Djdk_home=$JAVA_HOME -Dwofij_path=/path/to/wofij.jar -Dmode_class=com.example.my_mode/com.example.my_mode.Main -Dmode_path=/path/to/my/mode.jar ../build
 	ninja -C ../build

          
M src/meson.build +7 -6
@@ 5,13 5,13 @@ wofi = dependency('wofi')
 pixbuf = dependency('gdk-pixbuf-2.0')
 
 java_home = get_option('jdk_home')
+wofij_path = get_option('wofij_path')
 mode_class = get_option('mode_class')
-class_path = get_option('class_path')
-add_project_arguments('-DMODE_CLASS="' + mode_class + '"', language : 'c')
+mode_path = get_option('mode_path')
 
-if class_path != ''
-	add_project_arguments('-DCLASS_PATH="' + class_path + '"', language : 'c')
-endif
+add_project_arguments('-DMODULE_PATH="' + wofij_path + '"', language : 'c')
+add_project_arguments('-DMODE_CLASS="' + mode_class + '"', language : 'c')
+add_project_arguments('-DMODE_PATH="' + mode_path + '"', language : 'c')
 
 jvm = cc.find_library('jvm', dirs : [java_home + '/lib/j9vm', java_home + '/lib/server'])
 

          
@@ 23,7 23,8 @@ inc = include_directories('../wofi_jni/i
 
 deps = [wofi, jvm, pixbuf]
 
-jsources = [jsrcdir + '/Cache.java',
+jsources = ['module-info.java',
+			jsrcdir + '/Cache.java',
 			jsrcdir + '/Map.java',
 			jsrcdir + '/Mode.java',
 			jsrcdir + '/Widget.java',

          
M src/meson_options.txt +2 -1
@@ 1,3 1,4 @@ 
 option('jdk_home', type : 'string', description : 'The path to the jdk install folder')
+option('wofij_path', type : 'string', description : 'The path to the wofij jar')
 option('mode_class', type : 'string', description : 'The class that implements mode')
-option('class_path', type : 'string', description : 'The class path to use, defaults to the path of the DSO determined at runtime, primarily used for debugging')
  No newline at end of file
+option('mode_path', type : 'string', description : 'The path to your mode\'s module')

          
A => src/module-info.java +3 -0
@@ 0,0 1,3 @@ 
+module ninja.scoopta.software.wofij {
+	exports ninja.scoopta.software.wofij;
+}
  No newline at end of file

          
M src/ninja/scoopta/software/wofij/Wofi.java +18 -3
@@ 1,5 1,5 @@ 
 /*
- *  Copyright (C) 2020 Scoopta
+ *  Copyright (C) 2020-2023 Scoopta
  *  This file is part of WofiJ
  *  WofiJ is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by

          
@@ 17,6 17,10 @@ 
 
 package ninja.scoopta.software.wofij;
 
+import java.util.Set;
+import java.nio.file.*;
+import java.lang.module.*;
+
 public final class Wofi {
 	final long mode;
 	private static Wofi wofi;

          
@@ 35,9 39,20 @@ public final class Wofi {
 		}
 	}
 	
-	private static final void load(long mode, Class<?> clazz) {
+	private static final void load(long mode, byte[] clazz, byte[] path) {
 		try {
-			impl = (Mode) clazz.getConstructor().newInstance();
+			String[] p = new String(path).split(":");
+			Path[] paths = new Path[p.length];
+			for(int count = 0; count < p.length; ++count) {
+				paths[count] = Paths.get(p[count]);
+			}
+			String[] split = new String(clazz).split("/");
+			
+			ModuleLayer boot = ModuleLayer.boot();
+			Configuration config = boot.configuration().resolve(ModuleFinder.of(paths), ModuleFinder.of(), Set.of(split[0]));
+			ModuleLayer layer = boot.defineModulesWithOneLoader(config, ClassLoader.getSystemClassLoader());
+			Module module = layer.findModule(split[0]).get();
+			impl = (Mode) Class.forName(module, split[1]).getConstructor().newInstance();
 			wofi = new Wofi(mode);
 			impl.load(wofi);
 		} catch(Exception e) {

          
M wofi_jni/src/wofi_jni.c +17 -16
@@ 1,5 1,5 @@ 
 /*
- *  Copyright (C) 2020-2022 Scoopta
+ *  Copyright (C) 2020-2023 Scoopta
  *  This file is part of WofiJ
  *  WofiJ is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by

          
@@ 155,15 155,12 @@ void init(struct mode* _mode, struct map
 void load(struct mode* _mode) {
 	mode = _mode;
 	JavaVMInitArgs args;
-	JavaVMOption options[1];
-#ifdef CLASS_PATH
-	char* cp = CLASS_PATH;
-#else
-	char* cp = wofi_get_dso_path(mode);
-#endif
-	options[0].optionString = utils_concat(2, "-Djava.class.path=", cp);
+	JavaVMOption options[2];
+	char* p = MODULE_PATH;
+	options[0].optionString = "-Djdk.module.main=ninja.scoopta.software.wofij";
+	options[1].optionString = utils_concat(2, "--module-path=", p);
 	args.version = JNI_VERSION_10;
-	args.nOptions = 1;
+	args.nOptions = 2;
 	args.options = options;
 	args.ignoreUnrecognized = false;
 

          
@@ 226,13 223,17 @@ void load(struct mode* _mode) {
 	wofi = (*env)->NewGlobalRef(env, class);
 	(*env)->RegisterNatives(env, wofi, natives, sizeof(natives) / sizeof(JNINativeMethod));
 
-	jmethodID method = (*env)->GetStaticMethodID(env, wofi, "load", "(JLjava/lang/Class;)V");
-	jclass mode_class = (*env)->FindClass(env, MODE_CLASS);
-	if(mode_class == NULL) {
-		fprintf(stderr, "Cannot find main class\n");
-		exit(1);
-	}
-	(*env)->CallStaticVoidMethod(env, wofi, method, mode, mode_class);
+	jmethodID method = (*env)->GetStaticMethodID(env, wofi, "load", "(J[B[B)V");
+
+	size_t mode_class_l = strlen(MODE_CLASS);
+	jbyteArray arr = (*env)->NewByteArray(env, mode_class_l);
+	(*env)->SetByteArrayRegion(env, arr, 0, mode_class_l, (jbyte*) MODE_CLASS);
+
+	size_t mode_path_l = strlen(MODE_PATH);
+	jbyteArray arr2 = (*env)->NewByteArray(env, mode_path_l);
+	(*env)->SetByteArrayRegion(env, arr2, 0, mode_path_l, (jbyte*) MODE_PATH);
+
+	(*env)->CallStaticVoidMethod(env, wofi, method, mode, arr, arr2);
 
 	map_jni_init(env);
 	cache_jni_init(env);