There are (at least) two specific things to look for:
-
Reflective access to private APIs
-
Use of MethodHandles
Java 9 and subsequent introduced the module system which enforces (lack of) access to private APIs, even through reflection. Java 8 applications would only run without modification on Java 9 but there are no guarantees for subsequent JREs. As a practical example, I have some Processor implementations that find the JavaFileManager through reflection:
try {
/*
* com.sun.tools.javac.processing.JavacProcessingEnvironment
* .getContext() -> com.sun.tools.javac.util.Context
*/
Object context =
processingEnv.getClass()
.getMethod("getContext")
.invoke(processingEnv);
fm =
(JavaFileManager)
context.getClass()
.getMethod("get", Class.class)
.invoke(context, JavaFileManager.class);
} catch (Exception exception) {
}
that now generates a warning:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ball.annotation.processing.AbstractProcessor (file:/Users/ball/.m2/repository/ball/ball-util/6.0.1-SNAPSHOT/ball-util-6.0.1-SNAPSHOT.jar) to method com.sun.tools.javac.processing.JavacProcessi\
ngEnvironment.getContext()
WARNING: Please consider reporting this to the maintainers of ball.annotation.processing.AbstractProcessor
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
The method for accessing MethodHandles in Java 8 will not work in Java 9 and subsequent and vice versa.
Java 8’s
Constructor<MethodHandles.Lookup> constructor =
MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
Class<?> declarer = method.getDeclaringClass();
Object result =
constructor.newInstance(declarer)
.in(declarer)
.unreflectSpecial(method, declarer)
.bindTo(proxy)
.invokeWithArguments(argv);
In Java 9 and later must be replaced with:
Class<?> declarer = method.getDeclaringClass();
Object result =
MethodHandles.lookup()
.findSpecial(declarer, method.getName(),
methodType(method.getReturnType(),
method.getParameterTypes()),
declarer)
.bindTo(proxy)
.invokeWithArguments(argv);