7

I want to know if reference to an instance method of an arbitrary object of a particular type is serializable or not?

Example:

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
}

SerializableConsumer

@FunctionalInterface
public interface SerializableConsumer<T> extends Consumer<T>, Serializable {
}

and field is:

SerializableConsumer<MyClass> serializableMethod = MyClass::foo;

EDITED

Saljack
  • 2,072
  • 21
  • 24
  • 1
    Why are you asking about that particular type of method reference? Do you think, it is special compared to other method references or lambda expressions? – Holger May 05 '17 at 13:15
  • I believe your question is good material for thought, so I upvoted it. However, I'm curious about your use case... Why do you need to serialize a method reference? – fps May 05 '17 at 14:55
  • It is field of CDI bean with conversation scope. So it must be serializable. – Saljack May 09 '17 at 06:41

2 Answers2

8

Assuming that SerializableFunction refers to a type that extends Serializable, the method reference will be serializable. There is nothing special about the particular type of method reference your are asking for.

Most notably, the “reference to an instance method of an arbitrary object” is not capturing any instance of MyClass, hence, the fact that MyClass isn’t Serializable is not important. It would be different if you were referring to an instance method of a particular instance like object::foo, as in that case, the object had to be serialized as well, which will fail at runtime, if its class doesn’t implement Serializable.

What will not work, is to refer to a void method as a Function of return type Void. I don’t know how your SerializableFunction<MyClass, Void> is defined, but if it is equivalent to Function<MyClass, Void>&Serializable, it will not work.

When you have an appropriate functional interface, serializing the method reference is no problem:

import java.io.*;
import java.util.function.Consumer;

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Consumer<MyClass> consumer = (Consumer<MyClass>&Serializable)MyClass::foo;

        byte[] serialized;
        try(ByteArrayOutputStream baos=new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(consumer);
            oos.flush();
            serialized=baos.toByteArray();
        }

        Consumer<MyClass> deserialized;
        try(ByteArrayInputStream bais=new ByteArrayInputStream(serialized);
            ObjectInputStream ois=new ObjectInputStream(bais)) {
            deserialized = (Consumer<MyClass>)ois.readObject();
        }

        deserialized.accept(new MyClass());
    }
}

As said, references to a specific instance have to serialize the target instance, hence, depend on the serializability of that instance so

import java.io.*;
import java.util.function.Consumer;

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Runnable runnable = (Runnable&Serializable)new MyClass()::foo;

        byte[] serialized;
        try(ByteArrayOutputStream baos=new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(runnable);
            oos.flush();
            serialized=baos.toByteArray();
        }

        Runnable deserialized;
        try(ByteArrayInputStream bais=new ByteArrayInputStream(serialized);
            ObjectInputStream ois=new ObjectInputStream(bais)) {
            deserialized = (Runnable)ois.readObject();
        }

        deserialized.run();
    }
}

will fail at runtime with a java.io.NotSerializableException: MyClass, unless you change MyClass to implement Serializable.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks for your answer. SerializableFunction is interface which extends Serializable. My real return type is Integer so this is my mistake. – Saljack May 05 '17 at 13:46
0

I know you can serialize a lambda expresion (as you can see here)

Now, what you want to do is only serialize a the variable by itself? or the method?... I don't know why, but I don't think you can. Maybe you can go for other way, like creates a lambda and serialize it, like in the post above:

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
Community
  • 1
  • 1
developer_hatch
  • 15,898
  • 3
  • 42
  • 75