2

I am aware that to make Java 8 Consumer serializable I have to cast it:

return (Consumer<Type> & Serializable) () -> {...}

That works fine.

To make is easier I have introduced my own SerializableConsumer that implements java.io.Serializable and I use it in my APIs:

private interface SerializableConsumer<T> extends Consumer<T>, Serializable {}

Now I want whenever someone uses SerializableConsumer#andThen() to return again a consumer that is serializable.
Here are my attempts but so far I cannot make it work. Any ideas are welcome!

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.function.Consumer;

public class SerializeLambdas {

    private interface SerializableConsumer<T> extends Consumer<T>, Serializable {}

    // attempt 1
    private interface SerializableConsumerAndThen<T> extends Consumer<T>, Serializable {
        @Override
        default SerializableConsumerAndThen<T> andThen(Consumer<? super T> after) {
            return (SerializableConsumerAndThen<T>) Consumer.super.andThen(after);
        }
    }

    // attempt 2
    private interface SerializableConsumerAndThen2<T> extends Consumer<T>, Serializable {
        @Override
        default Consumer<T> andThen(Consumer<? super T> after) {
             return (Consumer<T> & Serializable) (T t) -> { accept(t); after.accept(t); };
        }
    }

    private static <T> T serializeCopy(T t) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(t);

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        return (T) ois.readObject();
    }

    public static void main(String[] args) throws Exception {
        // this works!
        SerializableConsumer<String> consumer = (s) -> System.out.println(s);
        SerializableConsumer<String> copy = serializeCopy(consumer);
        copy.accept("It works!");


        // this doesn't work
        SerializableConsumerAndThen<String> consumer2 = (s) -> System.out.println(s);
        Consumer<String> consumerAndThen = consumer2.andThen((s2) -> System.out.println(s2));
        Consumer<String> copy2 = serializeCopy(consumerAndThen);
        copy2.accept("SerializableConsumerAndThen works!");


        // this doesn't work too
        SerializableConsumerAndThen2<String> consumer3 = (s) -> System.out.println(s);
        Consumer<String> consumerAndThen2 = consumer3.andThen((s2) -> System.out.println(s2));
        Consumer<String> copy3 = serializeCopy(consumerAndThen2);
        copy3.accept("SerializableConsumerAndThen2 works!");
    }
 }

Both fail with:

Exception in thread "main" java.lang.ClassCastException: java.util.function.Consumer$$Lambda$5/1334729950 cannot be cast to app.SerializeLambdas$SerializableConsumerAndThen
at app.SerializeLambdas$SerializableConsumerAndThen.andThen(SerializeLambdas.java:17)
at app.SerializeLambdas.main(SerializeLambdas.java:46)
....
martin-g
  • 17,243
  • 2
  • 23
  • 35
  • 1
    Why not just define `public static SerializableConsumer andThen(SerializableConsumer other)` in your interface? – fge Mar 12 '16 at 16:12
  • 4
    I don't think you understand what the cast means. For a lambda expression or method ref, a cast context provides a _target type_ for the lambda/mref. But, you can't take an ordinary `Consumer` and cast it to `SerializerConsumer` unless it is _already_ an instance of `SerializableConsumer`. The cast only works to provide extra target-type information for the lambda conversion; once you evaluate your lambda, its just an instance of `Consumer` like any other, and casting means just what it means on any other `Consumer`. – Brian Goetz Mar 12 '16 at 16:28
  • 2
    I believe this is a duplicate of http://stackoverflow.com/q/25391656/1743880 – Tunaki Mar 12 '16 at 16:33
  • Thank you, @BrianGoetz! It is clear now. – martin-g Mar 12 '16 at 20:12

0 Answers0