Migrate Maven Projects to Java 11

So you want to migrate to Java 11 but your Maven project is still sitting on Java 8? You don't care much about the new module system (Jigsaw) introduced in Java 9, you just want your application to run on the latest JDK version? Then this guide is for you. It includes everything I've learned while migrating our product to Java 11.

As of 2019 Oracle Java 8 will no longer receive free security updates. So now is the time to migrate to JDK 11.

Clean up your pom.xml files

The first thing you should do before even thinking about upgrading the Java version is to clean up your pom.xml files. If your project is a multi-module Maven project then it helps to establish a parent POM and maintain dependencyManagement und pluginManagement in this file. That way all your plugins and dependencies are defined in a single file and are not spread across multiple POM files what makes managing versions easier.

In order to migrate your project to the latest Java version 11 it's highly recommended to update as much plugins and dependencies to the latest stable version as possible. Many plugins such as the compiler plugin, surefire or failsafe are not compatible with Java 9 if you use older versions. Also a lot of libraries are incompatible without migrating to the latest version.

Make sure you have the versions plugin configured in your master POM:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.5</version>
<configuration>
<generateBackupPoms>false</generateBackupPoms>
</configuration>
</plugin>

This plugin helps finding the latest plugin or dependency versions for your modules. Open up the terminal and execute this command to find the plugin versions you have to update:

mvn versions:display-plugin-updates

You will see a list of plugins used in your project with newer versions available. Update all of those plugins to the lastest stable version. After you've updated your plugin versions make sure that your project still compiles and runs properly.

You can use mvn -N ... from your projects root directory to just check your parent POM in case of multi-module projects.

Configure plugins for Java 11

The most important plugins for Java 11 are the compiler plugin, surefire (for unit-tests) and failsafe (for integration-tests).

In order to compile your project for Java 11 add the release configuration to the compiler plugin, a new compiler parameter to replace the source and target version parameters:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>

Also don't forget to set your IDEs project SDK to same JDK version. In Intellij IDEA go to Module Settings -> Project -> SDK.

For surefire and failsafe plugins we add an additional argument --illegal-access=permit to allow all reflection access for third party libraries:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<argLine>
--illegal-access=permit
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<argLine>
--illegal-access=permit
</argLine>
</configuration>
</plugin>

This is only needed if your dependencies make heavy use of reflection. If you're unsure whether you need this you can add the argLine later if your tests run into trouble.

You'll see warnings like this when a library tries to illegally access classes via setAccessible(true):

WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.reflection.CachedClass
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

Keep in mind that later you probably also have to pass the --illegal-access=permitparameter when starting your application.

Update dependencies

As mentioned before the best thing you can do is to migrate all your dependencies to the latest stable versions to make sure everything works fine with Java 11. While many older dependencies might work just fine there's a couple of dependencies where version updates are mandatory, e.g. all those various bytecode enhancement libaries such as javassistcglibasm or byte-buddy. Those libraries often come as transitive dependencies so make sure at least those libaries are up-to-date.

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.23.1-GA</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.7</version>
</dependency>

This command helps to find outdated dependency versions from your modules:

mvn versions:display-dependency-updates

Update as much libaries as possible to the latest stable version. If there's some dependency that you can't update due to compatibility issues in your project than leave it as is. Chances are that it just runs fine with Java 11.

Now is a good time to compile your project with JDK 11 for the first time:

mvn clean test-compile compile

Hint: You can speed up multi-module Maven projects by using parallel builds, e.g. mvn -T 4 compile compiles all modules in parallel on 4 CPU cores.

You will eventually face different compiler errors such as ClassNotFoundException. Every project is different so I cannot provide solutions for every problem you will face. The rest of this article describes solutions to various problems we had to solve in order to run our application with JDK 11.

Add missing modules

With the introduction of the Java module system (Jigsaw) in Java 9 the Java standard libary has been divided into separate modules. While most classes are still available without any changes, some are not. You have to explicitely define which additional modules your application needs access to or you can just add those modules from the Maven central repository.

The command java --list-modules lists all available modules.

When migrating our web project to Java 11 we had to add jaxb and javax.annotations to prevent ClassNotFoundException. We've added the following libaries as additional Maven dependencies to our POMs:

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180725.0427</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.4.0-b180725.0644</version>
</dependency>

Instead of adding those libaries via Maven we could utilize the –add-modules Java parameter to add additional JDK modules to the project.

Fixing sun.* and com.sun.* imports

While some classes have been moved to additional Java modules other classes can no longer been used in user code, namely classes from sun.* packages and also some classes from com.sun.*. If you get compiler errors because your code links to classes from those packages you have to remove those imports from your code.

Here's a few things we had to fix in our project:

  • sun.misc.BASE64Encoder: This can simply be replaced by java.util.Base64.getEncoder() which is available since Java 8.
  • sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl: This class has accidentally been used in our code base and can simply be replaced by the interface type java.lang.reflect.ParameterizedType.
  • sun.reflect.annotation.AnnotationParser: We use this class to programmatically create annotation instances. The class is no longer accessible but can be replaced by AnnotationFactory from Hibernate Validator.
  • com.sun.org.apache.xml.internal.utils.DefaultErrorHandler: We've replaced this class with a custom implementation of the interface.

Currency formats

We've encountered a curious case with number formats for locales such as Locale.GERMANY which let a bunch of our tests fail with a rather strange assertion error:

java.lang.AssertionError:
Expected: is "9,80 €"
but: was "9,80 €"

The underlying code uses NumberFormat.getCurrencyInstance(Locale.GERMANY) to format numbers into the german currency format. So what the heck is happening here?

Javas number formats have been modified to use non-breaking spaces instead of normal spaces between the number and the currency symbol. This change makes perfectly sense because it prevents line-breaks between the number and the currency symbol in various presentation formats. Changing the strings in our tests to use non-breaking spaces (use OPTION SPACE on Mac OSX keyboards) fixed this issue.

Servlet Container

When running web applications with Apache Tomcat you need at least Apache Tomcat 7.0.85 or later. Otherwise Tomcat will not start on Java 9 and above and you would see the following error:

/path/to/apache-tomcat-7.0.64/bin/catalina.sh run
-Djava.endorsed.dirs=/path/to/apache-tomcat-7.0.64/endorsed is not supported. Endorsed standards and standalone APIs
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
in modular form will be supported via the concept of upgradeable modules.
Disconnected from server

Also don't forget to eventually add the additional startup parameter --illegal-access=permit to your servlet container.

That's all

I hope these tips are somewhat useful to you and helps you migrating your application from Java 8 to 11. If you like this guide please consider sharing the link with your followers. Also let me know on Twitter if your migration was successful.

Good luck!

============== End

Migrate Maven Projects to Java 11的更多相关文章

  1. Solving “Dynamic Web Module 3.0 requires Java 1.6 or newer” in Maven Projects

    不一定是在Maven Projects里才有这种情况,但解决方法是一样的. 转自:http://qussay.com/2013/09/13/solving-dynamic-web-module-3-0 ...

  2. java组件不存在解决方案:右侧Maven Projects展开后左上角第一个刷新按钮 刷新后就会从新加载所有java的依赖项了

    java组件不存在解决方案:右侧Maven Projects展开后左上角第一个刷新按钮 刷新后就会从新加载所有java的依赖项了 软件:idea 问题产生:其他同事进行开发,引入新java组件后提交 ...

  3. 将 Maven生成的java项目转化为支持 Eclipse IDE的项目

    转自: http://www.xuebuyuan.com/1297046.html 将 Maven生成的java项目转化为支持 Eclipse IDE的项目   在前一篇文章中,我们使用maven创建 ...

  4. IntelliJ IDEA: maven & jetty 开发 java web

    之前使用eclipse + maven + jetty开发java web应用,本着no zuo no gain的想法, 折腾了一下Intellj idea下开发环境的搭建,顺带学习了maven re ...

  5. Java 11 Tutorial

    Java 11 Tutorial 参考 https://blog.csdn.net/sihai12345/article/details/82889827 原文 https://winterbe.co ...

  6. 图文详解 IntelliJ IDEA 15 创建 Maven 构建的 Java Web 项目(使用 Jetty 容器)

    图文详解 IntelliJ IDEA 15 创建 maven 的 Web 项目 搭建 maven 项目结构 1.使用 IntelliJ IDEA 15 新建一个项目.  2.设置 GAV 坐标  3. ...

  7. 图文具体解释 IntelliJ IDEA 15 创建 Maven 构建的 Java Web 项目(使用 Jetty 容器)

    图文具体解释 IntelliJ IDEA 15 创建 maven 的 Web 项目 搭建 maven 项目结构 1.使用 IntelliJ IDEA 15 新建一个项目. 2.设置 GAV 坐标 3. ...

  8. 像Maven一样构建java项目的目录,更好的管理java工程的源码

    都知道maven具有管理Java或者Javaweb的功能.我个人尤其看中的是其代码层次的分离.不同的代码在不同的文件夹下.这是在eclipse新建一个普通的工程无法实现的.而如果用maven实现有时候 ...

  9. IntelliJ IDEA14 和 Maven 系列:使用IntelliJ IDEA 14和Maven 7 创建java web项目(一)

    Intellij IDEA作为最好的Java IDE,创建Maven项目还是比较简单的,但是创建一个Maven Web项目还是要修改一些配置的,下面进行总结整理. 1前言 在创建项目中,IDEA提供了 ...

随机推荐

  1. [06] Bean属性的注入

    之前我们提到了Bean实例化的三种方式:构造器方式.静态工厂方式.普通工厂方式.那么对于Bean中的属性,又是如何进行注入的(依赖注入),这个篇章就来提一提. 1.先提提什么是"依赖注入&q ...

  2. 通过jQuery Ajax使用FormData对象上传文件 (转载)

    XMLHttpRequest Level 2 添加了一个新的接口——FormData.与普通的 Ajax 相比,使用 FormData 的最大优点就是我们可以异步上传二进制文件.jQuery 2.0+ ...

  3. TensorFlow框架下的RNN实践小结

    截至目前,TensorFlow的RNN APIs还处于Draft阶段.不过据官方解释,RNN的相关API已经出现在Tutorials里了,大幅度的改动应该是不大可能,现在入手TF的RNN APIs风险 ...

  4. Python爬虫利器二之Beautiful Soup的用法

    上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Be ...

  5. item 6: 当auto推导出一个不想要的类型时,使用显式类型初始化的语法

    本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 Item 5解释了比起显式指定类型,使用auto来 ...

  6. Slurm任务调度系统部署和测试(源码)(1)

    1. 概述1.1 节点信息2. 节点准备3. 部署NTP服务器4. 部署LDAP服务器5. 部署Munge认证服务6. 部署Mysql数据库服务7. 部署slurm7.1 创建slurm用户7.2 挂 ...

  7. ruby安装及升级

    在centos6.x下执行上面的"gem install redis"操作可能会报错,坑很多!默认yum安装的ruby版本是1.8.7,版本太低,需要升级到ruby2.2以上,否则 ...

  8. Nginx负载均衡中后端节点服务器健康检查的操作梳理

    正常情况下,nginx做反向代理,如果后端节点服务器宕掉的话,nginx默认是不能把这台realserver踢出upstream负载集群的,所以还会有请求转发到后端的这台realserver上面,这样 ...

  9. Spring RPC 入门学习(2)-获取Map对象

    Spring RPC传递Map用例编写 1. 新建RPC接口类 package com.cvicse.ump.rpc.interfaceDefine; import java.util.Map; pu ...

  10. Week 1 工程表格

    PSP2.1 Personal Software Process Stages Time Planning 计划 · Estimate · 估计这个任务需要多少时间 6h30min Developme ...