Невозможно десериализовать lambda
Так же, как небольшой проект, я пытаюсь сделать нечто вроде считывания сериализованных lambdas (локально или с FTP) и вызывает их функции запуска как часть теста для экспериментов с ассоциациями файлов в Windows (т.е. открытие определенных типов файлов открывает их с определенной программой) и еще много чего, но независимо от того, что я пытаюсь, он никогда не кажется должным образом десериализованным.
Лямбда была объявлена так
Runnable r = (Runnable & Serializable) () -> { // blah blah // made sure not to capture anything };
и сериализован с использованием FileOutputStream, завернутый в [n optional] BufferedOutputStream, завершенный ObjectOutputStream без проблем. Однако, когда десериализован [в другом проекте], он терпит неудачу, заявив, что он не смог найти охватывающий class, содержащий код для его сериализации. Я пробовал различные вещи, например, обертывать их в сериализуемый class (w / serialVersionUID = 0L для целей тестирования) или определять интерфейс, который расширяет Runnable и Serializable, но безрезультатно.
- Deserialize JSON в динамический объект C #?
- Исключить свойство из сериализации через пользовательский атрибут (json.net)
- Json.NET: десериализация вложенных словарей
- jackson - Как обрабатывать (десериализовать) вложенный JSON?
- Сериализация classа, который содержит std :: string
Да, я знаю, что сериализация lambdas на самом деле не очень хорошая практика (или, как нам сказали), но я не уверен, как переходить функции и подпрограммы во что-то, что я могу хранить как файл или FTP. Если это даже не правильный путь, расскажите.
О, я использую Eclipse Luna из любой последней версии.
Редактировать:
Дезериализованный
File f = new File(somePath); FileInputStream fish = new FileInputStream(f); BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary ObjectInputStream ois = new ObjectInputStream(bos); Runnable r = (Runnable) ois.readObject(); ois.close(); r.run();
- Сохранение / загрузка данных в Unity
- jQuery serializeArray не включает кнопку отправки, которая была нажата
- Рекомендации по сериализации объектов в пользовательский строковый формат для использования в выходном файле
- Может ли Json.NET сериализовать / десериализовать в / из streamа?
- Почему, когда конструктор аннотируется с помощью @JsonCreator, его аргументы должны быть аннотированы с помощью @JsonProperty?
- EF 4.1 - Code First - Ошибка серийной ссылки JSON
- Служба WCF Максимальная квота длины массива (16384) превышена
- XSLT: как преобразовать XML-узел в строку
Вы не можете десериализовать объект без classа, определяющего его. Это не изменилось с lambda-выражениями.
Лямбда-выражения немного сложнее, поскольку их сгенерированный class времени выполнения не является classом, который его определял, но их определяющий class является тем, у кого есть код тела лямбды, а в случае сериализуемых lambda – метод поддержки десериализации, который вызывается для проверки и повторное создание экземпляра лямбды.
См. Раздел SerializedLambda
:
Ожидается, что разработчики сериализуемых lambdas, таких как компиляторы или языковые библиотеки времени выполнения, гарантируют, что экземпляры десериализуются должным образом. Один из них означает, что метод
writeReplace
возвращает экземплярSerializedLambda
, а не разрешает сериализацию по умолчанию.
SerializedLambda
имеет методreadResolve
который ищет (возможно частный) статический метод$deserializeLambda$(SerializedLambda)
в classе захвата, вызывает его с собой как первый аргумент и возвращает результат. Лямбда-classы, реализующие$deserializeLambda$
, отвечают за проверку того, что свойстваSerializedLambda
согласуются с лямбдой, фактически захваченной этим classом.
Поэтому даже если ваш экземпляр не ссылался на синтетический метод внутри определяющего classа (например, в случае ссылки метода на метод вне этого classа), десериализация все еще требует $deserializeLambda$
для правильной проверки правильности экземпляра.
Что касается «хорошей практики» сериализации lambda, имейте в виду, что lambda-выражения инкапсулируют поведение , а не состояние. Сохранение поведения всегда подразумевает сохранение только некоторой ссылки и требует кода, предназначенного для ее восстановления, для реализации связанного с ней поведения. Это также сработает, если вы просто ссылаетесь на предполагаемое поведение с помощью символического имени или просто сохраняете, например, связанные значения enum
.
В этом вопросе объясняется более подробно вопрос о возможности сериализации lambda.
Когда вы десериализуете объект, код, выполняющий десериализацию, должен знать о classе сериализованного объекта. Вы не можете сериализовать произвольную лямбду и десериализовать ее в другой кодовой базе.
Более или менее код сериализации и десериализации должен находиться в одной и той же базе кода или, по крайней мере, должен делиться зависимостью от кода, содержащего исходную лямбду.