Improve error message for non-existent functions #337

Merged
jwharm merged 1 commit from non-existent-functions into main 2026-03-14 21:50:26 +01:00
Owner

Java-GI generates method handles for functions defined in GIR files. But those functions are not guaranteed to exist at runtime. This can happen for a variety of reasons:

  • A function only exists on another platform or operating system
  • A library is not installed
  • An old version of a library is being used, and the function was added in a later version

We don't want to silently fail in this case; a runtime exception is the only responsible way to handle this.

In older versions of Java-GI, a non-existing function resulted in a null method handle, and calling invokeExact() raised a NullPointerException.

In later versions, I wanted to get rid of the null value, so I tried to return a "fallback" method handle to special method Object functionNotFound(Object... args) that, because of its varargs argument, would always work, regardless of the type signature of the missing function. The functionNotFound() method would throw a nice UnsupportedOperationException.

However, in reality this didn't work, because MethodHandle.invokeExact() is very picky about its parameter types, so now a very confusing exception was raised: java.lang.invoke.WrongMethodTypeException: handle's method type (Object[])Object but found [actual method type].

To fix this, we could use MethodHandle.invoke() instead of invokeExact(), but that can have a large performance impact. So I really want to keep using invokeExact().

This PR introduces a new solution: When a function is not found and therefore the MethodHandle cannot be created, we use the new JEP 484 class-file API to generate a small class during runtime, with a single method with the exact type signature that was expected, that throws an UnsupportedOperationException. A MethodHandle to this on-the-fly-generated method is then installed so that when the user tries to execute it, the UnsupportedOperationException is raised. The exception even tells the user which function is missing.

Also added a test case.

Java-GI generates method handles for functions defined in GIR files. But those functions are not guaranteed to exist at runtime. This can happen for a variety of reasons: - A function only exists on another platform or operating system - A library is not installed - An old version of a library is being used, and the function was added in a later version We don't want to silently fail in this case; a runtime exception is the only responsible way to handle this. In older versions of Java-GI, a non-existing function resulted in a `null` method handle, and calling `invokeExact()` raised a NullPointerException. In later versions, I wanted to get rid of the null value, so I tried to return a "fallback" method handle to special method `Object functionNotFound(Object... args)` that, because of its varargs argument, would always work, regardless of the type signature of the missing function. The `functionNotFound()` method would throw a nice UnsupportedOperationException. However, in reality this didn't work, because `MethodHandle.invokeExact()` is very picky about its parameter types, so now a very confusing exception was raised: `java.lang.invoke.WrongMethodTypeException: handle's method type (Object[])Object but found [actual method type]`. To fix this, we could use `MethodHandle.invoke()` instead of `invokeExact()`, but that can have a large performance impact. So I really want to keep using `invokeExact()`. This PR introduces a new solution: When a function is not found and therefore the MethodHandle cannot be created, we use the new JEP 484 class-file API to generate a small class during runtime, with a single method with the exact type signature that was expected, that throws an UnsupportedOperationException. A MethodHandle to this on-the-fly-generated method is then installed so that when the user tries to execute it, the UnsupportedOperationException is raised. The exception even tells the user which function is missing. Also added a test case.
jwharm merged commit a28224aa56 into main 2026-03-14 21:50:26 +01:00
jwharm deleted branch non-existent-functions 2026-03-14 21:50:33 +01:00
Sign in to join this conversation.
No description provided.