How to make Serializable function in general

I know that we can use the function as Serializablewhere we need it.

However, I would like to move this casting to a generic method to make the usage code less cluttered. I am unable to create such a method.

My particular problem is that the map below is not Serializable:

final Map<MyObject, String> map =
        new TreeMap<>(Comparator.comparing(MyObject::getCode));

I can fix this using:

final Map<MyObject, String> map =
        new TreeMap<>(Comparator.comparing((Function<MyObject, String> & Serializable) MyObject::getCode));

But I would like to be able to do something like:

final Map<MyObject, String> map =
        new TreeMap<>(Comparator.comparing(makeSerializable(MyObject::getCode)));

public static <T, U> Function<T, U> makeSerializable(Function<T, U> function) {
    return (Function<T, U> & Serializable) function;
}

This is fine for the compiler, but at runtime I get ClassCastException:

java.lang.ClassCastException: SerializableTest$$Lambda$1/801197928 cannot be cast to java.io.Serializable

I also tried the following options, without success:

// ClassCastException
public static <T extends Serializable, U extends Serializable> Function<T, U> makeSerializable(Function<T, U> function) {
    return (Function<T, U> & Serializable) function;
}

// No ClassCastException, but NotSerializableException upon Serializing
public static <T, U> Function<T, U> makeSerializable2(Function<T, U> function) {
    return (Function<T, U> & Serializable) t -> function.apply(t);
}

Is it possible to create such a method?

Implementation MyObject:

static class MyObject implements Serializable {

    private final String code;

    MyObject(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

}
+4
source share
2 answers

, , Function<T, U> .

, Function, Serializable:

interface SerFunc<T, U> extends Function<T, U>, Serializable { }

. , , , SerFunc Function:

public static <T, U> SerFunc<T, U> makeSerializable(SerFunc<T, U> function) {
    return function;
}

Serializable -, . , .. .

, :

Map<MyObject, String> map =
    new TreeMap<>(Comparator.comparing(makeSerializable(MyObject::getCode)));

, , , (, @Eugene), , :

. , , .

Lambda , ( .)

( makeSerializable ) Serializable, , ( ), .

+6

, ( , input Function, - ), Function, , ...

public static <T, U> Function<T, U> makeSerializable(
        Class<T> targetType, // MyObject
        Class<U> returnType, // String
        String methodName) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType methodType = MethodType.methodType(returnType, targetType);
    Function<T, U> fun = (Function<T, U>) LambdaMetafactory.altMetafactory(
            lookup,
            "apply",
            MethodType.methodType(Function.class),
            methodType,
            lookup.findVirtual(targetType, methodName, MethodType.methodType(returnType)),
            methodType,
            1) // this signals for serialization 
            .getTarget().invokeExact();
    return fun;
}

...

:

Map<MyObject, String> map = new TreeMap(Comparator.comparing(makeSerializable(
            MyObject.class, String.class, "getCode")));
+1

Source: https://habr.com/ru/post/1695987/


All Articles