Serializing an arbitrary Java object with Kryo (getting IllegalAccessError)

拟墨画扇 提交于 2019-12-04 03:33:05

问题


Motivation:

To aid in remote debugging (Java), it's useful to be able to request remote servers to send over arbitrary objects to my local machine for inspection. However, this means that the remote server must be able to serialize an arbitrary java object that is not known in advance at runtime.

So I asked around and stumbled on the Kryo serialization library. From Kryo's documentation, a major feature is that it's very robust at serializing arbitrary java objects. Objects don't have to implement Serializable, don't need no-arg constructors to be deserializable and I don't even need to know anything about the structure of the object prior to serialization. Perfect!

Problem:

So to test Kryo out, I tried to see if I could serialize and then deserialize a PrintWriter object (i.e. an arbitrary object):

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.*;

public class SerializationTest {

    private static final String ioFileName = "someIO.bin";

    public static void main(String[] args) {

        // Create a PrintWriter object that I will later attempt to serialize
        PrintWriter outObj = null;
        try {
            outObj = new PrintWriter("textfile.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        // Change the PrintWriter's state as a test for later to see if state is restored after serialization and deserialization
        outObj.println("Hello");   // "Hello" held in PrintWriter's buffer

        Kryo kryo = new Kryo();    // Initialize Kryo serialization
        writeObj(kryo, outObj);    // Save PrintWriter object to file with "Hello" still in its buffer

        // Read the previously saved Printwriter object (still with "Hello" in its buffer)
        PrintWriter inObj = (PrintWriter) readObj(kryo);

        inObj.close();    // commit "Hello" to disk (using deserialized object)
        outObj.close();   // commit "Hello" to disk (using original object)

        System.out.println(inObj);
    }

    public static Object readObj(Kryo kryo) {
        Object obj = null;
        try {
            Input input = new Input(new FileInputStream(ioFileName));
            obj = kryo.readClassAndObject(input);   // ERROR HERE!!
            input.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public static void writeObj(Kryo kryo, Object obj) {
        try {
            Output output = new Output(new FileOutputStream(ioFileName));
            kryo.writeClassAndObject(output, obj);
            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Serialization works fine, but upon deserialization the call to kryo.readClassAndObject(input) on line 39 gives the following IllegalAccessError:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class sun.nio.cs.UTF_8 from class sun.nio.cs.UTF_8ConstructorAccess
    at sun.nio.cs.UTF_8ConstructorAccess.newInstance(Unknown Source)
    at com.esotericsoftware.kryo.Kryo$DefaultInstantiatorStrategy$1.newInstance(Kryo.java:1234)
    at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:1086)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.create(FieldSerializer.java:547)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:523)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:704)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:704)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:704)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:704)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:786)
    at SerializationTest.readObj(SerializationTest.java:39)
    at SerializationTest.main(SerializationTest.java:27)

I had hoped that I could serialize and deserialize the PrintWriter object outObj, and the object's state would remain in tact so I could still use the deserialized object to write "Hello" which would have been held in buffer.

Does anyone know what's going on and how to rectify this error?


回答1:


I think, you want kryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); to avoid constructor invocation. More info here.

But, if I may ask, why in the world would you want to serialize a PrintWriter? That is definitely asking for trouble. Kryo is not a "silver bullet", while its default derializers can work with most classes, that are practical (and even then there are always corner cases for which you need to write custom plugins), you can certainly not expect it to be able to handle every single exotic thing you can come up with (and serializing classes backed by internal jvm-specific code, like sun.* definitely qualifies as exotic).




回答2:


This error is pretty common with Kryo. Problem is that UTF_8 class is not public and hence Kryo fails. Adding below custom serializer helped me to resolve it. It would be a good idea to ship below kind of serializer along with Kryo as lot of people struggles with this.

Custom serializer for kryo for UTF-8 and other charsets

This way you are telling Kryo that for all registered Charset classes, call my custom serializer. Where I am just emitting string name.



来源:https://stackoverflow.com/questions/27731969/serializing-an-arbitrary-java-object-with-kryo-getting-illegalaccesserror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!