This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fury.git


The following commit(s) were added to refs/heads/main by this push:
     new 12a6c83a fix(java): fix jdk proxy serialization when proxy writePlace 
method (#1857)
12a6c83a is described below

commit 12a6c83ad3705289a41c35767dbd523fff81278e
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Sep 26 02:43:46 2024 -0700

    fix(java): fix jdk proxy serialization when proxy writePlace method (#1857)
    
    ## What does this PR do?
    
    fix jdk proxy serialization when proxy writePlace method
    ## Related issues
    
    Closes #1854
    
    ## Does this PR introduce any user-facing change?
    
    <!--
    If any user-facing interface changes, please [open an
    issue](https://github.com/apache/fury/issues/new/choose) describing the
    need to do so and update the document if necessary.
    -->
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    <!--
    When the PR has an impact on performance (if you don't know whether the
    PR will have an impact on performance, you can submit the PR first, and
    if it will have impact on performance, the code reviewer will explain
    it), be sure to attach a benchmark data here.
    -->
---
 .../java/org/apache/fury/resolver/ClassInfo.java   |  2 +-
 .../org/apache/fury/resolver/ClassResolver.java    |  6 +-
 .../fury/serializer/JdkProxySerializerTest.java    | 90 ++++++++++++++++++++++
 3 files changed, 96 insertions(+), 2 deletions(-)

diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
index c08f8f86..57efd230 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
@@ -114,7 +114,7 @@ public class ClassInfo {
     this.classId = classId;
     if (cls != null) {
       boolean isLambda = Functions.isLambda(cls);
-      boolean isProxy = ReflectionUtils.isJdkProxy(cls);
+      boolean isProxy = classId != ClassResolver.REPLACE_STUB_ID && 
ReflectionUtils.isJdkProxy(cls);
       this.isDynamicGeneratedClass = isLambda || isProxy;
       if (isLambda) {
         this.classId = ClassResolver.LAMBDA_STUB_ID;
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
index 21adfb76..387b6985 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
@@ -853,7 +853,11 @@ public class ClassResolver {
       } else if (Functions.isLambda(cls)) {
         return LambdaSerializer.class;
       } else if (ReflectionUtils.isJdkProxy(cls)) {
-        return JdkProxySerializer.class;
+        if (JavaSerializer.getWriteReplaceMethod(cls) != null) {
+          return ReplaceResolveSerializer.class;
+        } else {
+          return JdkProxySerializer.class;
+        }
       } else if (Calendar.class.isAssignableFrom(cls)) {
         return TimeSerializers.CalendarSerializer.class;
       } else if (ZoneId.class.isAssignableFrom(cls)) {
diff --git 
a/java/fury-core/src/test/java/org/apache/fury/serializer/JdkProxySerializerTest.java
 
b/java/fury-core/src/test/java/org/apache/fury/serializer/JdkProxySerializerTest.java
index 0f892fb1..233b8910 100644
--- 
a/java/fury-core/src/test/java/org/apache/fury/serializer/JdkProxySerializerTest.java
+++ 
b/java/fury-core/src/test/java/org/apache/fury/serializer/JdkProxySerializerTest.java
@@ -21,7 +21,9 @@ package org.apache.fury.serializer;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertTrue;
 
+import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
@@ -30,6 +32,7 @@ import java.util.function.Function;
 import org.apache.fury.Fury;
 import org.apache.fury.FuryTestBase;
 import org.apache.fury.config.Language;
+import org.apache.fury.reflect.ReflectionUtils;
 import org.testng.annotations.Test;
 
 @SuppressWarnings({"unchecked", "rawtypes"})
@@ -129,4 +132,91 @@ public class JdkProxySerializerTest extends FuryTestBase {
         (RefTestInvocationHandler) Proxy.getInvocationHandler(copy);
     assertEquals(copyHandler.getProxy(), copy);
   }
+
+  @Test
+  public void testSerializeProxyWriteReplace() {
+    final Fury fury =
+        
Fury.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
+
+    final Object o = ProxyFactory.createProxy(TestInterface.class);
+    final byte[] s = fury.serialize(o);
+    assertTrue(ReflectionUtils.isJdkProxy(fury.deserialize(s).getClass()));
+  }
+
+  interface TestInterface {
+    void test();
+  }
+
+  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);
+          }
+        }
+      }
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to