'Unable to find method sun.misc.Unsafe.defineClass

I am using jdk-10.0.2 and gradle 4.7, I am getting this error while building my project.

    Unable to find method 'sun.misc.Unsafe.defineClass(Ljava/lang/String;[BIILjava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;'.

Possible causes for this unexpected error include:
Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)
Re-download dependencies and sync project (requires network)

The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.
Stop Gradle build processes (requires restart)

Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.

In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.


Solution 1:[1]

I had the same issue (but using JDK 11):

Unable to find method 'sun.misc.Unsafe.defineClass(Ljava/lang/String;[BIILjava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;'.

with version gradle 4.7 as you.

My gradle-wrapper.properties file was:

    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip

To solve the issue I changed to 4.9 version of wrapper using parameter distributionUrl:

 distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip

And rebuild the project without any errors.

Solution 2:[2]

Did you specify the module dependency mentioned here? Since JDK 9 the Unsafe API seems to be hidden.

Thus, adding

module jdk.unsupported {
    exports sun.misc;
    opens sun.misc;
    ...
}

to your project might help.

Solution 3:[3]

There are problems with the dependencies in the .gradle file in Gradle. or pom.xml file (if you are using Maven). There could be many reasons for that: a conflict in versions, or conflict declaring the same dependency twice. or else check the jar_file versions you added into the library.

Solution 4:[4]

Since the defineClass method was removed from sun.misc.Unsafe in later versions of java, we need to invoke the method in the internal Unsafe. Since this entire package is hidden by default, we need to invoke everything reflectively. This code works as of java 17

try {
    Field f = Unsafe.class.getDeclaredField("theUnsafe"),
            f1 = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    f1.setAccessible(false);
    Unsafe unsafe = (Unsafe) f.get(null);
    int i;//override boolean byte offset. should result in 12 for java 17
    for (i = 0; unsafe.getBoolean(f, i) == unsafe.getBoolean(f1, i); i++);
    Field f2 = Unsafe.class.getDeclaredField("theInternalUnsafe");
    unsafe.putBoolean(f2, i, true);//write directly into override to bypass perms
    Object internalUnsafe = f2.get(null);

    Method defineClass = internalUnsafe.getClass().getDeclaredMethod("defineClass",
            String.class, byte[].class, int.class, int.class,
            ClassLoader.class, ProtectionDomain.class);
    unsafe.putBoolean(defineClass, i, true);

    Class<?> newClass = (Class<?>) defineClass.invoke(internalUnsafe,
            className, byteCode, offset, length,
            Object.class.getClassLoader(), Object.class.getProtectionDomain());

} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
    throw new RuntimeException(e);
}

I'll explain what this is doing step by step

  • use reflections to access the sun.misc.Unsafe instance directly.
  • get another copy of the sun Unsafe field, set it to inaccessible
  • imperically iterate through the bytes in these two instances until a discrepency is found. this is the variable "override" in the AccessibleObject class which fields and methods use to determine if they are accessible.
  • Get the internalUnsafe field from the sun Unsafe class, set it to accessible using the sun Unsafe instance (although we can obtain the field object, java won't let us set anything in the internal or reflections package to accessible directly)
  • get the internalUnsafe instance, save it to an Object pointer because we can't reference internal.misc.Unsafe directly
  • get the defineClass Method from internalUnsafe reflectively
  • set the method to accessible using the same offset with the sun Unsafe
  • invoke it with our parameters

Hopefully this stays working so long as Unsafe remains in the jdk.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 invzbl3
Solution 2 cmoetzing
Solution 3 MangduYogii
Solution 4 Java Noob