package org.stianloader.mrjmania; import java.lang.invoke.MethodHandle; import java.lang.reflect.AccessibleObject; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * Polyfills for reflection-related workloads. */ public class MRJReflection { private MRJReflection() { throw new UnsupportedOperationException(); } /** * Invoke AccessibleObject#canAccess if available (J9+), or use the more imprecise * {@link AccessibleObject#isAccessible()} that can be error-prone in a post-JPMS world. * * @param subject The field/method/constructor that is the subject of this operation. * @param accessedInstance The instance for non-static fields and methods. Otherwise {@code null}. * @return true if the {@code subject} can be accessed if using {@code accessedInstance} as the implementing instance of the member. * @throws IllegalStateException If the nullability constraints for {@code accessedInstance} were violated. */ @Contract(pure = true) public static boolean canAccess(@NotNull AccessibleObject subject, @Nullable Object accessedInstance) { return subject.canAccess(accessedInstance); } /** * Returns a {@link MethodHandle}, that has the same method signature and behaviour as the input {@link MethodHandle}, * but returns {@code void} and discards the result value. * *

This method uses a polyfill for Java versions ≤ 15 that seems to work but might not be guaranteed * to do so as even I don't quite understand it. If this method doesn't work as advertised, then that might be the cause. * * @param handle The {@link MethodHandle} that has a return value to drop. * @return The {@link MethodHandle} without a return value. */ @NotNull @Contract(pure = true) public static MethodHandle dropReturn(@NotNull MethodHandle handle) { return handle.asType(handle.type().changeReturnType(void.class)); } /** * Attempt to make the given {@link AccessibleObject} (constructor/method/field) accessible. * *

This method will swallow any somewhat expected exceptions, which might not always be desirable. * Just use your debugger though. * * @param subject The {@link AccessibleObject} that is the subject of this operation. * @return {@code true} if succeeded, false otherwise. */ public static final boolean trySetAccessible(@NotNull AccessibleObject subject) { return subject.trySetAccessible(); } }