2017-10-01

Migrating a project from java 8 to java 9


Now that Java 9 is out, I decided to migrate to it my pet project, which is around 120K lines of java.  The first step is to just start compiling and running against jdk9, without using any of its features yet.  This is an account of the surprisingly few issues that I encountered during this first step and how I resolved them.




Issue #1: Object.finalize() has been deprecated.



The javadoc of Object.finalize() explains why it has been deprecated and suggests the use of java.lang.ref.Cleaner and java.lang.ref.PhantomReference as alternatives.

Solution: For now, an acceptable solution is to just mark any overrides of Object.finalize() as also deprecated, so that no warnings are issued.

Issue #2: AccessibleObject.isAccessible() has been deprecated.


This means that method.isAccessible() and field.isAccessible() should not be used anymore.

Solution:

Replace this:

    Object callMethod( Object instance, Method method )
    {
        boolean access = method.isAccessible();

with this:

    Object callMethod( Object instance, Method method )
    {
        boolean access = method.canAccess( instance );


Issue #3: com.sun.xml.internal.stream.XMLInputFactoryImpl is not visible anymore.


Solution:

Replace this:

XMLInputFactory xmlInputFactory = new XMLInputFactoryImpl();

with this:

XMLInputFactory xmlInputFactory = XMLInputFactory.newDefaultFactory();


Issue #4: Class.newInstance() has been deprecated.


Solution:

Replace this:

Class.forName( "com.mysql.jdbc.Driver" ).newInstance();

with this:

Class.forName( "com.mysql.jdbc.Driver" ).getDeclaredConstructor().newInstance();


Issue #5: com.sun.nio.file.ExtendedOpenOption does not exist anymore.


I was making use of ExtendedOpenOption.NOSHARE_WRITE, but the ExtendedOpenOption enum has now been moved into some module called jdk.unsupported and even though IntelliJ IDEA somehow does see the type, the compiler does not see it.

Solution:

Stop using com.sun.nio.file.ExtendedOpenOption. I wish I knew of an alternative.


Issue #6 The java compiler now resolves symbolic links of source files


This is a problem for me, because I have all my projects in C:\Users\Michael\Projects, but this is actually a link to D:\Michael\Docs\Projects, which I normally never touch.  This has been working fine for years, but now with java 9 when an error occurs in a source file, javac reports the error using the resolved source pathname, which is on drive D:, and this completely confuses the IDE which does not know of any source file with that pathname.

Solution:

Abandon the practice of accessing the project from a path which contains a symbolic link, work on the project in its actual location.

Issue #7 ClassLoader.getSystemClassLoader() cannot be cast to URLClassLoader anymore.


This was definitely to be expected.

Solution:

Replace this:

URLClassLoader urlClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
for( URL url : urlClassLoader.getURLs() ) { ...

with this:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
for( URL url : Collections.list( classLoader.getResources( "" ) ) ) { ...


Issue #8 Jackson fails to deserialize exceptions from JSON.


For debugging purposes, I used to have exceptions serialized into JSON and deserialized later.  For some unknown reason, this does not work anymore.  Now each element of the stackTrace contains several additional fields, like classLoaderName, moduleName and moduleVersion, and although Jackson serializes them just fine, for some reason it fails to deserialize them.  Upgrading to the latest version of jackson-jaxrs-json-provider (version 2.9.0) did not fix this problem.

Solution: stop serializing and deserializing exceptions.


At the end of all this, my 817 tests passed, so I consider the migration complete.

No comments:

Post a Comment