EsotericSoftware / kryo

Java binary serialization and cloning: fast, efficient, automatic
BSD 3-Clause "New" or "Revised" License
6.19k stars 824 forks source link

Support for Java 11 #626

Closed nirupamarachuri closed 5 years ago

nirupamarachuri commented 6 years ago

Is there any release planned for kryo-serializers and kryo-shaded that supports Java 11? If yes, when is it planned to release?

free2bcreative commented 5 years ago

I've been testing my project with java 11 and noticed the following warning:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.esotericsoftware.kryo.util.UnsafeUtil (...) to constructor java.nio.DirectByteBuffer(long,int,java.lang.Object)
WARNING: Please consider reporting this to the maintainers of com.esotericsoftware.kryo.util.UnsafeUtil
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

I don't know if this fits under "support for Java 11", because my project still works fine. I don't know when java will start denying illegal access, but I would hope kryo can avoid it early on - it's been a great library.

NathanSweet commented 5 years ago

@nirupamarachuri Kryo works fine with Java 11. When reflection is disallowed (note it is allowed in Java 11 by default), many Kryo serializers will no longer work. Kryo itself should still work fine, but you would need to use serializers that don't rely on reflection. I don't personally have a need to use Java with reflection disabled, so I don't currently have plans to work on alternate serializers.

@free2bcreative It's just a warning. You can read more about it here: https://groups.google.com/forum/#!topic/kryo-users/bcsag2KfbvA

lucianoRM commented 5 years ago

I am also interested in Java 11 support. I see the following error when trying to serialize a java.io.FileInputStream:

Serialization trace:
cleanup (java.io.FileDescriptor)
fd (java.io.FileInputStream)
    at org.mule.tooling.client.tests.integration.tooling.client.KryoTestCase.serializeBufferedInputStream(KryoTestCase.java:32)
Caused by: java.lang.IllegalArgumentException: Unable to create serializer "com.esotericsoftware.kryo.serializers.FieldSerializer" for class: java.io.FileCleanable
    at org.mule.tooling.client.tests.integration.tooling.client.KryoTestCase.serializeBufferedInputStream(KryoTestCase.java:32)
Caused by: java.lang.reflect.InvocationTargetException
    at org.mule.tooling.client.tests.integration.tooling.client.KryoTestCase.serializeBufferedInputStream(KryoTestCase.java:32)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field jdk.internal.ref.PhantomCleanable jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does not "opens jdk.internal.ref" to unnamed module @37f1104d
    at org.mule.tooling.client.tests.integration.tooling.client.KryoTestCase.serializeBufferedInputStream(KryoTestCase.java:32)

I debugged the code and the error is indeed because "jdk.internal.ref" is not opened in java.base module. I tried using --add-opens and --illegal-access=permit flags but i still get this error. I think is because PhantomCleanable is a new class that was not included in Java 8 and as i could understand, with those flags you only get reflection access to pre-java 9 classes. (https://docs.oracle.com/javase/9/tools/java.htm#JSWOR624)

@NathanSweet Is this one example of one of the many Kryo serializers that will no longer work? Do you suggest any kind of workaround?

By the way, the code i'm running is the following:

FileInputStream bis =
        new FileInputStream(currentThread().getContextClassLoader().getResource("test-file").getPath());

    Kryo kryo = new Kryo();

    kryo.register(FileInputStream.class);

    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
      try (Output output = new Output(byteArrayOutputStream)) {
        kryo.writeClassAndObject(output, bis);
      }
    }
NathanSweet commented 5 years ago

@lucianoRM That is not about Java 11 at all. You register FileInputStream with the default serializer, which is FieldSerialier. You can't just point FieldSerializer at any class. See here: https://github.com/EsotericSoftware/kryo/#fieldserializer

FieldSerializer works by serializing each non-transient field. It can serialize POJOs and many other classes without any configuration. All non-public fields are written and read by default, so it is important to evaluate each class that will be serialized.

lucianoRM commented 5 years ago

I relate this to Java 11 because the same example works in Java 8 and the error described relates to module encapsulation. Maybe it was just a coincidence that it worked before updating to Java 11.

magro commented 5 years ago

I just submitted PR #636 which adds running tests with jdk 9/11 to verify that kryo is working with these versions. Is this sufficient to consider this issue to be resolved, or is anything else required?

Slightly related to the modules stuff is kryo's module name: as suggested here I'd say we should set the "Automatic-Module-Name" to "com.esotericsoftware.kryo" (and accordingly for reflectasm and minlog). WDYT?

dustContributor commented 5 years ago

I was trying out Kryo in Java 11 and got that warning.

Just an idea but unless I'm mistaken, UnsafeUtil would be only be used if you use the Unsafe I/O classes, right? The issue is that for now, even if you don't use them, you get the warning anyway because the static initializer in Util triggers UnsafeUtil's class initialization.

https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/util/Util.java#L41

I'm thinking you could give a way to "opt out" of this by having a system property to disable unsafe usage in Kryo, and skipping that Class.forName call so UnsafeUtil doesn't gets initialized and you stop getting that warning in Java 9+

Something like:

static {
  boolean found = false;
  String tryLoadUnsafe = System.getProperty("kryo.tryloadunsafe");
  if(!Objects.equals("false", tryLoadUnsafe)) {
    try {
      // By default if the property is missing or not 'false', try to load Unsafe.
      found = Class.forName("com.esotericsoftware.kryo.unsafe.UnsafeUtil", true, FieldSerializer.class.getClassLoader())
        .getField("unsafe").get(null) != null;
    } catch (Throwable ex) {
      ex.printStackTrace();
      if (TRACE) trace("kryo", "Unsafe is unavailable.");
    }
  } else {
    // Property was present and explicitly set to 'false', disable Unsafe usage.
    if (TRACE) trace("kryo", "Unsafe is disabled.");
  }
  unsafe = found;
}
piyushbajaj0704 commented 5 years ago

I got the error during the run, "unable to make jdk.internal.ref.phantomcleanable() accessible: module java.base does not" on Java 11, when I switched to Java 9 in Intellij under Project structure, the error was gone and I was able to execute successfully.

AbstractAlao commented 2 years ago

Not sure if this has been fixed. I'm using spring state machine and got this message

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.esotericsoftware.kryo.util.UnsafeUtil (file:/C:/Users/aaats/.m2/repository/com/esotericsoftware/kryo-shaded/4.0.2/kryo-shaded-4.0.2.jar) to constructor java.nio.DirectByteBuffer(long,int,java.lang.Object)
WARNING: Please consider reporting this to the maintainers of com.esotericsoftware.kryo.util.UnsafeUtil
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