Возможна ли десериализация SerializedLambda с различными реализациями? - PullRequest
1 голос
/ 27 апреля 2020

Допустим, есть класс A с лямбда-функцией с именем foo (для простоты).

Насколько я понимаю, если существует клиент, сериализующий этот foo (который будет сериализован в "SerializedLambda"), и отправьте что касается сервера, то на сервере также будет класс A с лямбда-функцией с именем foo.

Теперь мой вопрос заключается в том, что если реализация A.foo отличается между клиентом и сервером? (при условии, что типы arg и типы возврата совпадают) Делает ли сервер

  1. десериализацию «SerializedLambda» в соответствии со своим собственным определением без ошибок.

  2. не удалось десериализовать.

Учитывая, как лямбды создаются динамически, а сама "SerializedLambda" просто содержит сигнатуру, аргументы и т. Д. c вместо реального кода, я подозреваю, что это 1 , но я новичок ie, которому нужно больше узнать о том, как это работает.

1 Ответ

4 голосов
/ 27 апреля 2020

Лямбда-выражения скомпилированы в синтетические c методы с неопределенным именем. Могут быть и другие неуказанные тонкости, например порядок аргументов метода для захваченных переменных. Кроме того, когда лямбда-выражение обращается к экземпляру this, есть две опции: скомпилировать его с методом экземпляра или скомпилировать с методом static, получая экземпляр как обычный параметр.

Для получающегося в результате Поведение лямбда-выражения, это не имеет значения. Но сериализованная форма зависит от этих деталей и, следовательно, очень fr agile. Вам даже не нужно менять класс, перекомпиляция его с другим компилятором может изменить эти детали. Фактически, даже перекомпиляция с одним и тем же компилятором может изменить результат, например, когда поведение компилятора зависит от некоторой карты ha sh с рандомизацией порядка итераций.

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

Таким образом, измененный класс A может быть несовместим с вашим сериализованным лямбда-выражением, и лучшая вещь Это может произойти, это исключение во время десериализации из-за несоответствия. Хуже того, он мог выбрать неправильное лямбда-выражение, потому что у него оказалось совместимое сочетание имени и подписи.

Более безопасная конструкция - это ссылки на метод, поскольку они ссылаются на фактический целевой метод, который не является подвержены влиянию других лямбда-выражений или ссылок на методы в том же классе. Однако не каждая ссылка на метод компилируется как прямая ссылка на уровне байтового кода. В некоторых случаях, например при обращении к методу varargs или к вызову метода super или метода типа пересечения, класс объявления которого не соответствует стертому типу, компилятор может сгенерировать метод-заглушку для вызова, подобный лямбде выражение. Так что вы все равно должны быть осторожны.

...