You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fury.apache.org by "theigl (via GitHub)" <gi...@apache.org> on 2024/09/25 15:57:07 UTC
[I] Cannot de-serialize serializable JDK proxy [fury]
theigl opened a new issue, #1854:
URL: https://github.com/apache/fury/issues/1854
### Search before asking
- [X] I had searched in the [issues](https://github.com/apache/fury/issues) and found no similar issues.
### Version
Fury: 0.71
JDK: 21
### Component(s)
Java
### Minimal reproduce step
```java
import org.apache.fury.Fury;
import org.apache.fury.config.Language;
import org.junit.jupiter.api.Test;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ProxySerializerTest {
@Test
void serializeProxy() {
final Fury fury = Fury.builder()
.withLanguage(Language.JAVA)
.requireClassRegistration(false)
.build();
final Object o = ProxyFactory.createProxy(TestInterface.class);
final byte[] s = fury.serialize(o);
assertEquals(fury.deserialize(s), o);
}
interface TestInterface {
void test();
}
static class ProxyFactory {
static <T> T createProxy(final Class<T> type) {
return new JdkProxyFactory().createProxy(type);
}
static final class JdkProxyFactory {
@SuppressWarnings("unchecked")
<T> T createProxy(final Class<T> type) {
final JdkHandler handler = new JdkHandler(type);
try {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
return (T) Proxy.newProxyInstance(cl, new Class[]{type, Serializable.class}, handler);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Could not create proxy for type [" + type.getName() + "]", e);
}
}
static class JdkHandler implements InvocationHandler, Serializable {
private final String typeName;
private JdkHandler(Class<?> type) {
typeName = type.getName();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
return null;
}
public Object writeReplace() throws ObjectStreamException {
return new ProxyReplacement(typeName);
}
}
static final class ProxyReplacement implements Serializable {
private final String type;
ProxyReplacement(final String type) {
this.type = type;
}
private Object readResolve() throws ObjectStreamException {
final Class<?> clazz;
try {
clazz = Class.forName(type, false, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
}
return ProxyFactory.createProxy(clazz);
}
}
}
}
}
```
### What did you expect to see?
Serializable JDK proxies can be de-serialized.
### What did you see instead?
The following exception is thrown:
> java.lang.ClassCastException: class xyz.$Proxy8 cannot be cast to class java.lang.reflect.InvocationHandler
The problem seems to be the `JdkProxySerializer` and the `ReplaceResolveSerializer` get in each other's way because the `InvocationHandler` implements `writeReplace`.
### Anything Else?
_No response_
### Are you willing to submit a PR?
- [ ] I'm willing to submit a PR!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "chaokunyang (via GitHub)" <gi...@apache.org>.
chaokunyang commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2375437501
Hi @theigl , I used JDK serialization to serialize your object, it throw ClassCastException too:
```java
java.lang.RuntimeException: java.lang.ClassCastException: cannot assign instance of org.apache.fury.serializer.$Proxy6 to field java.lang.reflect.Proxy.h of type java.lang.reflect.InvocationHandler in instance of org.apache.fury.serializer.$Proxy6
at org.apache.fury.FuryTestBase.jdkDeserialize(FuryTestBase.java:339)
at org.apache.fury.serializer.JdkProxySerializerTest.serializeProxy(JdkProxySerializerTest.java:142)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:136)
at org.testng.internal.invokers.TestInvoker.invokeMethod(TestInvoker.java:658)
at org.testng.internal.invokers.TestInvoker.invokeTestMethod(TestInvoker.java:219)
at org.testng.internal.invokers.MethodRunner.runInSequence(MethodRunner.java:50)
at org.testng.internal.invokers.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:923)
at org.testng.internal.invokers.TestInvoker.invokeTestMethods(TestInvoker.java:192)
at org.testng.internal.invokers.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.invokers.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
at org.testng.TestRunner.privateRun(TestRunner.java:808)
at org.testng.TestRunner.run(TestRunner.java:603)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:429)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:423)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:383)
at org.testng.SuiteRunner.run(SuiteRunner.java:326)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:95)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1249)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.runSuites(TestNG.java:1092)
at org.testng.TestNG.run(TestNG.java:1060)
at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:105)
Caused by: java.lang.ClassCastException: cannot assign instance of org.apache.fury.serializer.$Proxy6 to field java.lang.reflect.Proxy.h of type java.lang.reflect.InvocationHandler in instance of org.apache.fury.serializer.$Proxy6
at java.base/java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2102)
at java.base/java.io.ObjectStreamClass$FieldReflector.checkObjectFieldValueTypes(ObjectStreamClass.java:2066)
at java.base/java.io.ObjectStreamClass.checkObjFieldValueTypes(ObjectStreamClass.java:1355)
at java.base/java.io.ObjectInputStream$FieldValues.defaultCheckFieldValues(ObjectInputStream.java:2682)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2483)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2269)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1747)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:525)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:483)
at org.apache.fury.FuryTestBase.jdkDeserialize(FuryTestBase.java:337)
... 26 more
```
Here is my code for JDK serialization invocation:
```java
public static byte[] jdkSerialize(Object o) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(bos)) {
objectOutputStream.writeObject(o);
objectOutputStream.flush();
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Object jdkDeserialize(byte[] data) {
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream objectInputStream =
new ClassLoaderObjectInputStream(Thread.currentThread().getContextClassLoader(), bis)) {
return objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
```
Seems `ProxyFactory.JdkProxyFactory.ProxyReplacement#readResolve` should return `JdkHandler` instead of `Proxy` instance.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "chaokunyang (via GitHub)" <gi...@apache.org>.
chaokunyang closed issue #1854: Cannot de-serialize serializable JDK proxy
URL: https://github.com/apache/fury/issues/1854
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "theigl (via GitHub)" <gi...@apache.org>.
theigl commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2376806383
Thank you very much @chaokunyang!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "chaokunyang (via GitHub)" <gi...@apache.org>.
chaokunyang commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2374816806
Thanks for reporting this issue. I thought we've addressed all corner case for jdk serialization compatibility. I will take a look at it today later
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "theigl (via GitHub)" <gi...@apache.org>.
theigl commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2376148388
There was an important interface missing on the proxy: `IWriteReplace` that exposes the `writeReplace` method. This code now serializes fine with JDK serialization:
```java
static class ProxyFactory {
static <T> T createProxy(final Class<T> type) {
return new JdkProxyFactory().createProxy(type);
}
public interface IWriteReplace {
Object writeReplace() throws ObjectStreamException;
}
static final class JdkProxyFactory {
@SuppressWarnings("unchecked")
<T> T createProxy(final Class<T> type) {
final JdkHandler handler = new JdkHandler(type);
try {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
return (T) Proxy.newProxyInstance(cl, new Class[]{type, IWriteReplace.class, Serializable.class}, handler);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Could not create proxy for type [" + type.getName() + "]", e);
}
}
static class JdkHandler implements InvocationHandler, IWriteReplace, Serializable {
private final String typeName;
private JdkHandler(Class<?> type) {
typeName = type.getName();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isWriteReplaceMethod(method)) {
return writeReplace();
}
return null;
}
public Object writeReplace() throws ObjectStreamException {
return new ProxyReplacement(typeName);
}
static boolean isWriteReplaceMethod(final Method method) {
return (method.getReturnType() == Object.class) &&
(method.getParameterTypes().length == 0) && method.getName().equals("writeReplace");
}
}
public static final class ProxyReplacement implements Serializable {
private final String type;
public ProxyReplacement(final String type) {
this.type = type;
}
private Object readResolve() throws ObjectStreamException {
try {
final Class<?> clazz = Class.forName(type, false, Thread.currentThread().getContextClassLoader());
return ProxyFactory.createProxy(clazz);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
}
}
}
}
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "chaokunyang (via GitHub)" <gi...@apache.org>.
chaokunyang commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2376435859
I see, Fury does not handle this right, thanks for reporting this up. It's really a subtle bug. I fixed it in https://github.com/apache/fury/pull/1857
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org
Re: [I] Cannot de-serialize serializable JDK proxy [fury]
Posted by "theigl (via GitHub)" <gi...@apache.org>.
theigl commented on issue #1854:
URL: https://github.com/apache/fury/issues/1854#issuecomment-2376109886
You are right. This code is taken from Apache Wicket and I greatly simplified it. It seems I simplified it a bit too much. I will re-check my example and get back to you later today.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fury.apache.org
For additional commands, e-mail: commits-help@fury.apache.org