How to serialize a lambda?

JavaSerializationLambdaJava 8

Java Problem Overview


How can I elegantly serialize a lambda?

For example, the code below throws a NotSerializableException. How can I fix it without creating a SerializableRunnable "dummy" interface?

public static void main(String[] args) throws Exception {
    File file = Files.createTempFile("lambda", "ser").toFile();
    try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(file))) {
        Runnable r = () -> System.out.println("Can I be serialized?");
        oo.writeObject(r);
    }

    try (ObjectInput oi = new ObjectInputStream(new FileInputStream(file))) {
        Runnable  r = (Runnable) oi.readObject();
        r.run();
    }
}

Java Solutions


Solution 1 - Java

Java 8 introduces the possibility to cast an object to an intersection of types by adding multiple bounds. In the case of serialization, it is therefore possible to write:

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");

And the lambda automagically becomes serializable.

Solution 2 - Java

The same construction can be used for method references. For example this code:

import java.io.Serializable;

public class Test {
    static Object bar(String s) {
        return "make serializable";
    }

    void m () {
        SAM s1 = (SAM & Serializable) Test::bar;
        SAM s2 = (SAM & Serializable) t -> "make serializable";
    }

    interface SAM {
        Object action(String s);
    }
}

defines a lambda expression and a method reference with a serializable target type.

Solution 3 - Java

Very ugly cast. I prefer to define a Serializable extension to the functional interface I'm using

For example:

interface SerializableFunction<T,R> extends Function<T,R>, Serializable {}
interface SerializableConsumer<T> extends Consumer<T>, Serializable {}

then the method accepting the lambda can be defined as such :

private void someFunction(SerializableFunction<String, Object> function) {
   ...
}

and calling the function you can pass your lambda without any ugly cast:

someFunction(arg -> doXYZ(arg));

Solution 4 - Java

In case someone falls here while creating Beam/Dataflow code :

Beam has his own SerializableFunction Interface so no need for dummy interface or verbose casts.

Solution 5 - Java

If you are willing to switch to another serialization framework like Kryo, you can get rid of the multiple bounds or the requirement that the implemented interface must implement Serializable. The approach is to

  1. Modify the InnerClassLambdaMetafactory to always generate the code required for serialization
  2. Directly call the LambdaMetaFactory during deserialization

For details and code see this blog post

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionassyliasView Question on Stackoverflow
Solution 1 - JavaassyliasView Answer on Stackoverflow
Solution 2 - JavaVicente RomeroView Answer on Stackoverflow
Solution 3 - JavaPascalView Answer on Stackoverflow
Solution 4 - JavaRafaëlView Answer on Stackoverflow
Solution 5 - JavaruedisteView Answer on Stackoverflow