如何使用Kyro序列化Exception对象?

时间:2015-12-22 06:16:34

标签: java serialization kryo

我有以下自定义异常,我需要使用kryo库进行序列化。

public class CustomException extends Exception {
 public CustomException(){}
}

这是我的seralizer

Kryo kryo = new Kryo();
kryo.writeClassAndObject(out, obj);

但序列化会抛出异常。

com.esotericsoftware.kryo.KryoException: Class cannot be created (missing no-arg constructor):    java.util.Collections$UnmodifiableRandomAccessList
Serialization trace:
suppressedExceptions (CustomException)
at      com.esotericsoftware.kryo.Kryo$DefaultInstantiatorStrategy.newInstantiatorOf(      Kryo.java:1272)
    at com.esotericsoftware.kryo.Kryo.newInstantiator(Kryo.java:1078)

我已经解决了使用CustomException

注册JavaSerializer的问题
 kryo.register(CustomException.class, new JavaSerializer());

但是因为JavaSerializer非常低效(建议在JavaSerializer javadoc中尽可能避免使用)还有其他方法来序列化kryo中的Exception对象吗?

1 个答案:

答案 0 :(得分:0)

根据文档,可以通过多种方式解决此问题:

  

特定类型的序列化程序使用Java代码创建新实例   那种诸如FieldSerializer之类的序列化程序是通用的,必须   处理创建任何类的新实例。默认情况下,如果是一个类   有一个零参数构造函数,然后通过ReflectASM或   反射,否则抛出异常。如果是零参数   构造函数是私有的,尝试通过反射访问它   使用setAccessible。如果这是可以接受的,则为私有零参数   构造函数是允许Kryo创建类实例的好方法   而不影响公共API。

     

当无法使用ReflectASM或反射时,可以配置Kryo   使用InstantiatorStrategy来处理创建的实例   类。 Objenesis提供了使用JVM的StdInstantiatorStrategy   特定的API,用于创建类的实例而不调用任何类   构造函数。虽然这适用于许多JVM,但零参数是   通常更便携。

kryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); Note that classes must be designed to be created in this way. If a class
     

期望调用它的构造函数,它可能是未初始化的   通过这种机制创建的状态。

     

在许多情况下,你可能想要一个策略,Kryo首先在哪里   尝试查找并使用无参数构造函数,如果没有这样做,   它应该尝试使用StdInstantiatorStrategy作为后备,因为   这个根本不会调用任何构造函数。的配置   这种行为可以这样表达:

     

kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new   StdInstantiatorStrategy()));但是,默认行为是   需要一个无参数的构造函数。

     

Objenesis还可以使用Java内置的方法创建新对象   序列化机制。使用它,该类必须实现   java.io.Serializable和a中的第一个零参数构造函数   调用超类。

kryo.setInstantiatorStrategy(new SerializingInstantiatorStrategy()); You may also write your own
     

InstantiatorStrategy。

     

要仅自定义特定类型的创建方式,请执行以下操作:   可以设置ObjectInstantiator。这将覆盖ReflectASM,   反射和InstantiatorStrategy。

Registration registration = kryo.register(SomeClass.class);
registration.setObjectInstantiator(...); Alternatively, some serializers provide methods that can be overridden to customize object
     

创建

kryo.register(SomeClass.class, new FieldSerializer(kryo, SomeClass.class) {
   public Object create (Kryo kryo, Input input, Class type) {
      return new SomeClass("some constructor arguments", 1234);
   }
});

示例:

/**
 * Because the creation/initialization of Kryo instances is rather expensive, 
 * in a multithreaded scenario you should pool Kryo instances. A very simple solution 
 * is to bind Kryo instances to Threads using ThreadLocal, like this:
 */
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
    @Override
    protected Kryo initialValue() {
        Kryo kryo = new Kryo();
        /*
         * In many situations, you may want to have a strategy, where Kryo first tries to find and use a no-arg constructor 
         * and if it fails to do so, it should try to use StdInstantiatorStrategy as a fallback, because this one does 
         * not invoke any constructor at all. The configuration for this behavior could be expressed like this:
         */
        kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
        return kryo;
    }
};