HPCS
HPCS

Reputation: 1454

How to run code on jre9 that was compiled with jdk8 and use Unsafe

I have code that was compiled with jdk8 as target and source for java 1.8 and use Unsafe. I tried to run this program with jdk9 but it fails with following exception:

java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte

Package sun.misc.Unsafe is not removed from jdk9, so I expected the code to run. I can not recompile the code with jdk9, I expected that java should be backward compatible.

I create little test that is not working for me. Test class:

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Test {

  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    System.out.println("before");
    Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    theUnsafeField.setAccessible(true);

    Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
    unsafe.getByte(new Object(), 4);
    System.out.println("after");
  }
}

Then I compile the code with jdk8.

C:\Java-IDE\jdk1.8.0_121\bin\javac.exe Test.java

Then if I run it with jdk8 it works:

C:\Java-IDE\jdk1.8.0_121\bin\java.exe Test
before
after

If i run it with jdk9 it throws exception:

C:\Java-IDE\jdk-9.0.4_windows-x64_bin\bin\java.exe Test
before
Exception in thread "main" java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte(Ljava/lang/Object;I)B
        at Test.main(Test.java:13)

I believe it should be also possible to run it under jdk9. Is it possible?

Upvotes: 1

Views: 781

Answers (2)

Holger
Holger

Reputation: 298459

The method byte Unsafe.getByte(Object, int) has been removed in Java 9, but recompiling fixes the issue, as it will cause the invocation of byte Unsafe.getByte(Object, long) then, which is indeed the intended replacement.

Note that even besides the fact that Unsafe is an unofficial, unsupported API that should not be used by applications, the methods using int offsets are deprecated in favor of methods using long since 1.4.1, which means that there were one and a half decades time to adapt old code, but your statement that the code “was compiled with jdk8 as target” indicates that it is actually even younger than that.

Given the fact that the planned entire removal of sun.misc.Unsafe has been announced multiple times, there will be no way around changing the code, if it shall run on future JVM versions. If you are not able to recompile it, ask yourself, how the future maintenance of code that you can’t recompile should look like. If the code is supposed to be frozen, freeze the JVM version as well. Otherwise, you need to find a way to recompile it or replace it.

Upvotes: 3

Mumrah81
Mumrah81

Reputation: 2054

Yes java is backward compatible, but it is for the java API. The package sun.misc is one of the packages that Sun/Oracle advertised as moveable/updatable/deletable without any prior warning.

So it was

To answer your question, you will need to update your code

EDIT:

Like Alan Bateman said in his comment the obvious solution would be to recompile

But if you can't and if you're not against ugly hacks you can :

  1. get the source of sun.misc.Unsafe and insert your needed/missing methods

  2. create a custom classloader which will essentialy do the same as the system classloader but when sun.misc.Unsafe will be requested for loading will load your version of Unsafe instead

  3. Start your application with your custom classloader

    java -Djava.system.class.loader=com.xxx.MyCustomClassLoader xxx

Ugly but may work without recompiling

Upvotes: -1

Related Questions