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

huangapple go评论85阅读模式
英文:

Run Java 8 code on JDK 11 - what might break?

问题

If we just change the runtime environment to JDK 11, what might break?

英文:

At the moment we are building our Java code with JDK 8 for Java 8, and run it on a JDK 8.

If we just change the runtime environment to JDK 11, what might break?

答案1

得分: 2

以下是翻译好的部分:

有(至少)两个特定要注意的事项:

  1. 对私有API的反射访问

  2. 使用MethodHandles

Java 9及其后续版本引入了模块系统,强制执行(缺乏)对私有API的访问,即使是通过反射方式。 Java 8应用程序仅在Java 9上无需修改即可运行,但不能保证对后续的JRE版本具有兼容性。 作为一个实际示例,我有一些Processor的实现,通过反射查找JavaFileManager:

            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) {                                     
            }

现在会生成一个警告:

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

在Java 8中用于访问MethodHandles的方法在Java 9及以后版本以及反之亦然都不起作用。

Java 8的:

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

在Java 9及以后必须替换为:

        Class<?> declarer = method.getDeclaringClass();                         
        Object result =                                                         
            MethodHandles.lookup()                                              
            .findSpecial(declarer, method.getName(),                            
                         methodType(method.getReturnType(),                     
                                    method.getParameterTypes()),                
                         declarer)                                              
            .bindTo(proxy)                                                      
            .invokeWithArguments(argv);
英文:

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() -&gt; com.sun.tools.javac.util.Context            
                 */                                                             
                Object context =                                                
                    processingEnv.getClass()                                    
                    .getMethod(&quot;getContext&quot;)                                    
                    .invoke(processingEnv);                                     
                                                                                
                fm =                                                            
                    (JavaFileManager)                                           
                    context.getClass()                                          
                    .getMethod(&quot;get&quot;, 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&lt;MethodHandles.Lookup&gt; constructor =                         
            MethodHandles.Lookup.class                                          
            .getDeclaredConstructor(Class.class);                               
                                                                                
        constructor.setAccessible(true);                                        
                                                                                
        Class&lt;?&gt; 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&lt;?&gt; declarer = method.getDeclaringClass();                         
        Object result =                                                         
            MethodHandles.lookup()                                              
            .findSpecial(declarer, method.getName(),                            
                         methodType(method.getReturnType(),                     
                                    method.getParameterTypes()),                
                         declarer)                                              
            .bindTo(proxy)                                                      
            .invokeWithArguments(argv);

答案2

得分: 0

除了已经说过的,一些库在JRE更新时可能会出现问题。我曾经在Jasper(Tomcat中使用的JSP编译器)上有过这种经历,因为Jasper需要从JRE读取类文件,旧版的Jasper与新版的JRE相结合会导致错误。

最后,你只需要测试一下,看看会发生什么。

英文:

In addition to what already has been said, some libraries break on JRE updates. I've had that experience with Jasper (the JSP compiler used in Tomcat), because Jasper needs to read classfiles from the JRE, and old Jasper version + new JRE version = error.

In the end, you'll just have to test it and see what happens.

huangapple
  • 本文由 发表于 2020年8月1日 03:46:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63198249.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定