3

I am messing around with Java serialization of lambdas.

I have two completely separate projects that have a single class in them.

Project 1:

class TestMain {

    public static void main(String[] args) {
        Runnable r = (Runnable & Serializable) () -> {};

        // Serialize r to C:/file.ser;
    }
}

Project 2:

class TestMain2 {

    public static void main(String[] args) {
        // Deserialize C:/file.ser to runnable;
    }
}

However, upon attempting to deserialize the runnable, it throws an exception saying it can't find TestMain

...is there any way I can avoid this?

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
Cheetah
  • 13,785
  • 31
  • 106
  • 190

2 Answers2

5

The solution is to include TestMain on the classpath when you are deserializing.

The lambda implicitly depends on the outer class in which it is declared.

Also, the Java Tutorial says this:

However, like inner classes, the serialization of lambda expressions is strongly discouraged.


Besides ... as @Tim points out ... even if you didn't need the TestMain.class file, you would still need the TestMain$xxx.class file that contained the lambda's code.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2
...is there any way I can avoid this?

Broadly speaking, no.

Serialization is a method for persisting data, not code. The code for the serialized class needs to exist at deserialization time, inside the JVM in which you are doing the deserializing.

It sounds like you're trying to pass code between two JVMs.
There are techniques for doing that, but not via serialization.

Tim
  • 6,406
  • 22
  • 34
  • `There are techniques for doing that, but not via serialization.`...do you have some topics I can google (with the exception of inbuild RMI)? – Cheetah Mar 16 '15 at 13:21
  • 1
    There are simple mechanisms like defining/using an expression language so that you're just passing around strings: any one of MVEL, OGNL, Spring EL, JBoss EL could work for you. The more complex method, of actually passing around real java code would require using custom classloaders, probably in conjunction with a byte code library like asm or cglib. – Tim Mar 16 '15 at 13:29
  • Problem is, to achieve the interface I would like, I can't convert to an EL. Looking at the bytecode solution, in an actual scenario, it would mean I would have to load `TestMain` and **any of `TestMain`'s dependencies**, which could be quite alot! In reality, I just want to load the lamda as that is all I am interested in! – Cheetah Mar 16 '15 at 13:54
  • 1
    @Cheetah: if you don’t want `TestMain`’s dependencies, declare the lambda within a class which doesn’t have these dependencies. – Holger Mar 16 '15 at 14:29
  • @Holger - I am not in control of that....this is for a client library. – Cheetah Mar 16 '15 at 14:46
  • @Cheetah: but you’re in control to ensure that the objects you want to serialize are serializable lambda expressions? – Holger Mar 16 '15 at 15:29
  • @Holger - yes. I wanted a client that had something like `void runRemotely(Consumer consumer)`, where consumer is a lambda expression that I want to serialize. I know that the lambda won't depent on any classes outside the JDK. – Cheetah Mar 16 '15 at 15:41
  • @Cheetah: two mistakes: 1. you don’t know whether the `Consumer` passed in was created via a lambda expression, 2. Your assumption “that the lambda won't depend on any classes outside the JDK” is wrong. – Holger Mar 16 '15 at 15:51
  • @Holger - I was hoping that since the byte code was no different (as far as I understand), that I should be ok. For point 2, it wasn't an assumption, it was a restriction of using my client library,...the user CANNOT use an class outside the JDK if they wanted to use my library since the class would not be loaded by the classloader. – Cheetah Mar 16 '15 at 15:55
  • It don’t know what you mean with “since the byte code was no different”, different from what? If you assume that the bytecode is “no different” compared to other `Consumer` implementations, why do you assume that you can deserialize such instances without the actual implementation class? If you constrain your API to only JDK provided `Consumer` implementations, there will be very little use cases… – Holger Mar 16 '15 at 17:15