Max*_*sev 7 java lambda serialization classcastexception java-8
ClassCastException Java8在满足以下条件时反序列化lambda时抛出:
Serializablelambda在Oracle Java编译器和运行时版本1.8.0_91上测试.请查找有关如何重现的测试代码:
import java.io.*;
/**
* @author Max Myslyvtsev
* @since 7/6/16
*/
public class LambdaSerializationTest implements Serializable {
static abstract class AbstractConverter implements Serializable {
String convert(String input) {
return doConvert(input);
}
abstract String doConvert(String input);
}
static class ConverterA extends AbstractConverter {
@Override
String doConvert(String input) {
return input + "_A";
}
}
static class ConverterB extends AbstractConverter {
@Override
String doConvert(String input) {
return input + "_B";
}
}
static class ConverterC extends AbstractConverter {
@Override
String doConvert(String input) {
return input + "_C";
}
}
interface MyFunction<T, R> extends Serializable {
R call(T var);
}
public static void main(String[] args) throws Exception {
System.out.println(System.getProperty("java.version"));
ConverterA converterA = new ConverterA();
ConverterB converterB = new ConverterB();
ConverterC converterC = new ConverterC();
giveFunction(converterA::convert);
giveFunction(converterB::convert);
giveFunction(converterC::convert);
}
private static void giveFunction(MyFunction<String, String> f) {
f = serializeDeserialize(f);
System.out.println(f.call("test"));
}
private static <T> T serializeDeserialize(T object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
@SuppressWarnings("unchecked")
T result = (T) ois.readObject();
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
它给出了以下输出:
1.8.0_91
test_A
Exception in thread "main" java.lang.RuntimeException: java.io.IOException: unexpected exception type
at LambdaSerializationTest.serializeDeserialize(LambdaSerializationTest.java:68)
at LambdaSerializationTest.giveFunction(LambdaSerializationTest.java:52)
at LambdaSerializationTest.main(LambdaSerializationTest.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.io.IOException: unexpected exception type
at java.io.ObjectStreamClass.throwMiscException(ObjectStreamClass.java:1582)
at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1154)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1817)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at LambdaSerializationTest.serializeDeserialize(LambdaSerializationTest.java:65)
... 7 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:230)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1148)
... 11 more
Caused by: java.lang.ClassCastException: LambdaSerializationTest$ConverterB cannot be cast to LambdaSerializationTest$ConverterA
at LambdaSerializationTest.$deserializeLambda$(LambdaSerializationTest.java:7)
... 21 more
Run Code Online (Sandbox Code Playgroud)
在$deserializeLambda$使用CFR 反编译此方法后,显示以下代码:
private static /* synthetic */ Object $deserializeLambda$(SerializedLambda lambda) {
switch (lambda.getImplMethodName()) {
case "convert": {
if (lambda.getImplMethodKind() == 5 && lambda.getFunctionalInterfaceClass().equals("LambdaSerializationTest$MyFunction") && lambda.getFunctionalInterfaceMethodName().equals("call") && lambda.getFunctionalInterfaceMethodSignature().equals("(Ljava/lang/Object;)Ljava/lang/Object;") && lambda.getImplClass().equals("LambdaSerializationTest$AbstractConverter") && lambda.getImplMethodSignature().equals("(Ljava/lang/String;)Ljava/lang/String;")) {
return (MyFunction<String, String>)LambdaMetafactory.altMetafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, convert(java.lang.String ), (Ljava/lang/String;)Ljava/lang/String;)((ConverterA)((ConverterA)lambda.getCapturedArg(0)));
}
if (lambda.getImplMethodKind() == 5 && lambda.getFunctionalInterfaceClass().equals("LambdaSerializationTest$MyFunction") && lambda.getFunctionalInterfaceMethodName().equals("call") && lambda.getFunctionalInterfaceMethodSignature().equals("(Ljava/lang/Object;)Ljava/lang/Object;") && lambda.getImplClass().equals("LambdaSerializationTest$AbstractConverter") && lambda.getImplMethodSignature().equals("(Ljava/lang/String;)Ljava/lang/String;")) {
return (MyFunction<String, String>)LambdaMetafactory.altMetafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, convert(java.lang.String ), (Ljava/lang/String;)Ljava/lang/String;)((ConverterB)((ConverterB)lambda.getCapturedArg(0)));
}
if (lambda.getImplMethodKind() != 5 || !lambda.getFunctionalInterfaceClass().equals("LambdaSerializationTest$MyFunction") || !lambda.getFunctionalInterfaceMethodName().equals("call") || !lambda.getFunctionalInterfaceMethodSignature().equals("(Ljava/lang/Object;)Ljava/lang/Object;") || !lambda.getImplClass().equals("LambdaSerializationTest$AbstractConverter") || !lambda.getImplMethodSignature().equals("(Ljava/lang/String;)Ljava/lang/String;")) break;
return (MyFunction<String, String>)LambdaMetafactory.altMetafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, convert(java.lang.String ), (Ljava/lang/String;)Ljava/lang/String;)((ConverterC)((ConverterC)lambda.getCapturedArg(0)));
}
}
throw new IllegalArgumentException("Invalid lambda deserialization");
}
Run Code Online (Sandbox Code Playgroud)
因此,似乎实际捕获的参数不用于确定哪个精确的lambda必须反序列化.所有3个lambdas将满足第一个if条件ConverterA并将被假设.
在调试时,我们可以观察到在运行时lambda.getCapturedArg(0)具有正确的类型(ConverterB抛出异常时),并且值得注意的是不需要强制转换,因为要调用的方法存在于基AbstractConverter类中.
这是预期的行为吗?如果是,推荐的解决方法是什么?
| 归档时间: |
|
| 查看次数: |
893 次 |
| 最近记录: |