Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Invalid lambda deserialization" when lambda used for interface implementation

I have a wicket project with lambda expressions. On one page when user clicks on back button my application crashes on:

java.lang.IllegalArgumentException: Invalid lambda deserialization
at x.y.z.MyPage$3.$deserializeLambda$(MyPage.java:1)

In the page class (where I return) I'm using lambda expression for implementation of this interface:

public interface Localizator extends Serializable {
    String getLocalizedString(String key);
}

And the lambda:

protected void someMethod() {
    localize((String key) -> getString(key));
}

When I change lambda to anonymous class, everything works fine. How should I use lambda in this case?

Env: Java 1.8.0_25, Netbeans 8.0.2, Wicket 6.17.0.

EDIT: This is real (but simplified) method with lambda:

@Override
protected DataLoader createDataLoader() {

    return new DataLoader(){

        @Override
        public List loadData() {
            ...
        }

        @Override
        public List convertToTableRows(List data) {
            return Converter.asRowList(
                data, 
                (Record record) -> {...}, // this lambda is OK
                (String key) -> getString(key)); // this lambda is crashing
        }

        @Override
        public List filterTableRow() {
            ...
        }

    };
}

Converter class:

public class Converter implements Serializable { 
    public static ArrayList asRowList(List data, OtherLoader loader, Localizator localizator){...}

DataLoader also extends Serializable.

like image 510
Michal Avatar asked Feb 11 '23 17:02

Michal


1 Answers

To enable Serialization support, having an interface extending Serializable is sufficient. There is no need to do an additional cast then. This is indicated by the fact that your code could serialize the lambda expression instance. It failed when deserializing, which is an indicator for a class incompatibility, so if inserting the cast helped, it’s very likely, that it was a side effect because inserting the cast forced recompiling of the class containing the lambda expression.


If you want to continue using serialized lambdas, you should understand how it works, as explained in the documentation of SerializedLambda:

Implementors of serializable lambdas, such as compilers or language runtime libraries, are expected to ensure that instances deserialize properly. One means to do so is to ensure that the writeReplace method returns an instance of SerializedLambda, rather than allowing default serialization to proceed.

SerializedLambda has a readResolve method that looks for a (possibly private) static method called $deserializeLambda$(SerializedLambda) in the capturing class, invokes that with itself as the first argument, and returns the result. Lambda classes implementing $deserializeLambda$ are responsible for validating that the properties of the SerializedLambda are consistent with a lambda actually captured by that class.

So when the $deserializeLambda$ rejects the deserialization with an exception, it implies that the properties of the serialized lambda do not match the properties of a known serializable lambda defined inside the class. These properties may turn out to be very fragile.

They include the functional interface, the captured arguments and a target method. In case of a lambda expression (rather than a method reference), the target method is a synthetic method inside the defining class with a compiler-chosen, unspecified name that might depend even on other lambda expressions within the same class as inserting another expression might cause a name change due to a numbering scheme.

Unlike ordinary classes where inserting a serialVersionUID might tell the Serialization framework that it shouldn’t care about apparent inconsistencies, you can’t tell lambda expressions to show more robustness. In other words, once you have serialized lambda instances which ought to persist, you must not change the their defining class. See also this answer

like image 189
Holger Avatar answered Feb 18 '23 17:02

Holger