-6

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?

J Fabian Meier
  • 33,516
  • 10
  • 64
  • 142
  • If you adhere to all (interface) contracts, nothing. Java is downwards-compatible (that is the reason why we still have raw types...). – Turing85 Jul 31 '20 at 19:48
  • Not true. If you e.g. use Apache Jackrabbit 2.14.x, then it will run on JDK 8, but break on JDK 11. – J Fabian Meier Jul 31 '20 at 19:51
  • 1
    Read the Release notes. – Jens Jul 31 '20 at 19:52
  • 1
    Why is this question received so badly? – J Fabian Meier Jul 31 '20 at 19:52
  • Ok, three downvotes, the question is essentially dead. What a shame. I tried to figure out a solution for this, I googled, found some hints, but it just be great to get a real answer for this. We really face this problem. – J Fabian Meier Jul 31 '20 at 19:54
  • Furthermore, see e.g. https://stackoverflow.com/q/43574426/927493 – J Fabian Meier Jul 31 '20 at 19:55
  • A major change I would say in JDK 11 they have removed com.sun and javax packages. For this being available, we need to add an explicit dependency. Again they removed more dependencies from JDK but those are available explicit. So as per your question this mentioned package use cases will break. – hitesh bedre Jul 31 '20 at 19:58
  • 4
    The question does bring out the actual problems that people might face, but that would be specific to each library/service developed. So, what could break, depends on what you already have and how things went around it. For example, you quoted in the comments, the dependencies of your projects are best known to you and others would not be able to provide an answer to it. The expectation from the JDK developers would be that nothing should break as long as you are running your code on classpath which is the same as JDK-8. To start off with - release notes and migration guides. – Naman Jul 31 '20 at 20:13
  • But libraries that run on JDK 8 but break on JDK 11 must have something in common. There must be some changes in the JDK that cause this code to break. – J Fabian Meier Jul 31 '20 at 20:28
  • My problem: Our company has a huge number of Java artifacts. When we change the JDK, we want to be prepared for all the developers coming around and asking why their code breaks. So I was looking for common problems. – J Fabian Meier Jul 31 '20 at 20:31
  • Your question is reasonable. I have submitted an answer but the practical advice I would add is to review your runtime dependencies and closely review those that have different variants for different releases of the JRE/JDK. No doubt those artifacts have specific dependencies on the JRE version. – Allen D. Ball Aug 01 '20 at 01:15

2 Answers2

2

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);
Allen D. Ball
  • 1,916
  • 1
  • 9
  • 16
0

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.