Как сериализовать объект Exception с помощью Kyro?

У меня есть следующие пользовательские исключения, которые мне нужно сериализовать с помощью библиотеки крио.

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

Это мой серализатор

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), есть ли другой способ сериализации объекта Exception в kryo?

1 ответ

Согласно документации, это можно исправить несколькими способами:

Сериализаторы для определенного типа используют код Java для создания нового экземпляра этого типа. Сериализаторы, такие как FieldSerializer, являются общими и должны обрабатывать создание нового экземпляра любого класса. По умолчанию, если класс имеет конструктор с нулевым аргументом, он вызывается через ReflectASM или отражение, в противном случае выдается исключение. Если конструктор с нулевым аргументом является закрытым, делается попытка получить к нему доступ через отражение с помощью setAccessible. Если это приемлемо, частный конструктор с нулевым аргументом - это хороший способ позволить Kryo создавать экземпляры класса, не затрагивая общедоступный API.

Когда ReflectASM или отражение нельзя использовать, Kryo можно настроить на использование InstantiatorStrategy для обработки создания экземпляров класса. Objenesis предоставляет StdInstantiatorStrategy, который использует специальные API JVM для создания экземпляра класса без какого-либо вызова конструктора. Хотя это работает на многих JVM, нулевой аргумент обычно более переносим.

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

ожидает, что его конструктор будет вызван, он может находиться в неинициализированном состоянии при создании с помощью этого механизма.

Во многих ситуациях вам может понадобиться стратегия, в которой Kryo сначала пытается найти и использовать конструктор без аргументов, а если он не может этого сделать, он должен попытаться использовать StdInstantiatorStrategy в качестве запасного варианта, потому что этот метод не вызывает никакой конструктор вообще. Конфигурация для этого поведения может быть выражена так:

kryo.setInstantiatorStrategy (новый Kryo.DefaultInstantiatorStrategy(новый StdInstantiatorStrategy())); Тем не менее, поведение по умолчанию требует конструктора без аргументов.

Objenesis также может создавать новые объекты, используя встроенный механизм сериализации Java. Используя это, класс должен реализовывать java.io.Serializable, и вызывается первый конструктор с нулевым аргументом в суперклассе.

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;
    }
};
Другие вопросы по тегам