Run Java 8 code on JDK 11 – what might break? [closed]

There are (at least) two specific things to look for:

  1. Reflective access to private APIs

  2. 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);

Browse More Popular Posts

Leave a Comment