Aliothmoon opened a new issue, #1884:
URL: https://github.com/apache/fury/issues/1884

   ### Search before asking
   
   - [X] I had searched in the [issues](https://github.com/apache/fury/issues) 
and found no similar issues.
   
   
   ### Version
   
   Fury  0.8.0
   JDK openjdk version "17.0.4"
   
   ### Component(s)
   
   Java
   
   ### Minimal reproduce step
   
   ```java
   package com.alioth.bootstrap;
   
   import java.nio.file.Files;
   import java.nio.file.Path;
   import java.nio.file.Paths;
   
   /**
    * Loading classes from external locations
    * similar to the behavior of Spring Boot's LaunchedURLClassLoader
    *
    */
   public class ExternalClassLoader extends ClassLoader {
   
       /**
        * Classes to be loaded externally
        */
       public static final String[] externalClass = {
               "com.alioth.bootstrap.ExternalClassBootStrap",
               "com.alioth.bootstrap.ExternalClass"
       };
   
       @Override
       protected Class<?> findClass(String name) throws ClassNotFoundException {
           for (String clz : externalClass) {
               if (clz.equals(name)) {
                   Class<?> c = findLoadedClass(name);
                   if (c == null) {
                       try {
                           int index = name.lastIndexOf('.');
                           String pos = name.substring(index + 1) + ".class";
                           // prefix System.getProperty("user.dir")
                           Path path = Paths.get(pos);
                           byte[] bytes = Files.readAllBytes(path);
                           return defineClass(name, bytes, 0, bytes.length);
                       } catch (Exception ignore) {
                       }
                   }
               }
   
           }
           return super.findClass(name);
       }
   }
   
   ```
   ```java
   /**
    * Classes used for Fury testing
    * Should not appear in the default ClassPath.
    */
   public class ExternalClass {
       private int a;
       private String b;
   
       public int getA() {
           return a;
       }
   
       public void setA(int a) {
           this.a = a;
       }
   
       public String getB() {
           return b;
       }
   
       public void setB(String b) {
           this.b = b;
       }
   }
   
   
   ```
   
   ```java
   package com.alioth.bootstrap;
   
   import org.apache.fury.Fury;
   import org.apache.fury.ThreadLocalFury;
   import org.apache.fury.config.Language;
   
   import java.util.concurrent.ForkJoinPool;
   import java.util.concurrent.ForkJoinTask;
   
   
   /**
    * The class used to launch tests  
    * Should not appear in the default ClassPath.
    */
   public class ExternalClassBootStrap {
   
       public static final ClassLoader loader = 
ExternalClassBootStrap.class.getClassLoader();
   
       public static final ThreadLocalFury FURY = Fury.builder()
               .withLanguage(Language.JAVA)
               .requireClassRegistration(false)
               .withClassLoader(loader)
               .buildThreadLocalFury();
   
   
       static byte[] bytes;
   
       static {
           ExternalClass obj = new ExternalClass();
           obj.setA(1);
           obj.setB("2");
           bytes = FURY.serialize(obj);
       }
   
       public static void main(String[] args) throws Exception {
   
           // The withClassLoader method of FuryBuilder only affects the Fury 
instance in the current thread, and does not affect Fury instances in other 
threads.
           // Other Fury instances will, by default, use the 
ThreadContextClassLoader.
           System.out.println(Thread.currentThread() + " Classloader " + 
loader);
           Object o1 = FURY.deserialize(bytes);
   
   
           ForkJoinTask<?> task = ForkJoinPool.commonPool().submit(() -> {
               ClassLoader cl = Thread.currentThread().getContextClassLoader();
               System.out.println(Thread.currentThread() + " ClassLoader " + 
cl);
               // ClassNotFoundException occurred because the 
ThreadContextClassLoader was used instead of the specified loader.
               Object o2 = FURY.deserialize(bytes);
           });
   
           // Wait for a moment to prevent the ForkJoinPool tasks from being 
executed by the main thread instead of asynchronously.
           Thread.sleep(500);
   
           task.get();
       }
   }
   
   ```
   
   
   ```java
   package com.alioth.bootstrap;
   
   import org.junit.jupiter.api.Test;
   
   import java.lang.reflect.Method;
   import java.util.concurrent.ForkJoinPool;
   
   public class FuryTest {
   
   
       @Test
       public void testFuryForkJoinPoolAndClassLoader() throws Exception {
   
           
           ClassLoader loader = new ExternalClassLoader();
           Thread.currentThread().setContextClassLoader(loader);
   
           String bootstrap = "com.alioth.bootstrap.ExternalClassBootStrap";
           Class<?> clz = Class.forName(bootstrap, true, loader);
   
           Method main = clz.getMethod("main", String[].class);
           main.invoke(null, new Object[]{new String[]{}});
       }
   
   }
   ```
   
   ### What did you expect to see?
   
   Complete the deserialization process correctly.
   
   
   ### What did you see instead?
   
   An incorrect class loader was selected, making it unable to retrieve the 
metadata correctly
   
   
   The stack trace is as follows:
   
   ```java
   Thread[main,5,main] Classloader 
com.alioth.bootstrap.ExternalClassLoader@69b2283a
   Thread[ForkJoinPool.commonPool-worker-1,5,main] ClassLoader 
jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
   2024-10-13 12:02:38 INFO  Fury:160 [ForkJoinPool.commonPool-worker-1] - 
Created new fury org.apache.fury.Fury@40f1c094
   
   java.util.concurrent.ExecutionException: java.lang.IllegalStateException: 
java.lang.IllegalStateException: Class com.alioth.bootstrap.ExternalClass not 
found from classloaders 
[jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b, 
jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b]
   
        at 
java.base/java.util.concurrent.ForkJoinTask.reportExecutionException(ForkJoinTask.java:605)
        at 
java.base/java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:981)
        at 
com.alioth.bootstrap.ExternalClassBootStrap.main(ExternalClassBootStrap.java:45)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at 
com.alioth.bootstrap.FuryTest.testMultiThreadClassLoader(FuryTest.java:25)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at 
org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
        at 
org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
        at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
        at 
org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
        at 
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
        at 
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
        at 
org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
        at 
org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
        at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
        at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
        at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
        at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
        at 
org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
        at 
org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
        at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
        at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
        at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
        at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
        at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
        at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
        at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
        at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
        at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
        at 
org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
        at 
org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
        at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
        at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
        at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
        at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
        at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
        at 
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
        at 
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
        at 
org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
        at 
org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
        at 
com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
        at 
com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
        at 
com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
        at 
com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
        at 
com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
        at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
   Caused by: java.lang.IllegalStateException: java.lang.IllegalStateException: 
Class com.alioth.bootstrap.ExternalClass not found from classloaders 
[jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b, 
jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b]
        at 
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
 Method)
        at 
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at 
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at 
java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at 
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at 
java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
        at 
java.base/java.util.concurrent.ForkJoinTask.reportExecutionException(ForkJoinTask.java:604)
        ... 76 more
   Caused by: java.lang.IllegalStateException: Class 
com.alioth.bootstrap.ExternalClass not found from classloaders 
[jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b, 
jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b]
        at 
org.apache.fury.resolver.ClassResolver.loadClass(ClassResolver.java:1849)
        at 
org.apache.fury.resolver.ClassResolver.loadClass(ClassResolver.java:1828)
        at 
org.apache.fury.resolver.ClassResolver.populateBytesToClassInfo(ClassResolver.java:1765)
        at 
org.apache.fury.resolver.ClassResolver.loadBytesToClassInfo(ClassResolver.java:1750)
        at 
org.apache.fury.resolver.ClassResolver.readClassInfoFromBytes(ClassResolver.java:1737)
        at 
org.apache.fury.resolver.ClassResolver.readClassInfo(ClassResolver.java:1659)
        at org.apache.fury.Fury.readRef(Fury.java:860)
        at org.apache.fury.Fury.deserialize(Fury.java:792)
        at org.apache.fury.Fury.deserialize(Fury.java:714)
        at org.apache.fury.ThreadLocalFury.deserialize(ThreadLocalFury.java:127)
        at 
com.alioth.bootstrap.ExternalClassBootStrap.lambda$main$0(ExternalClassBootStrap.java:40)
        at 
java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1375)
        at 
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
        at 
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
        at 
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
        at 
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
        at 
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
   Caused by: java.lang.ClassNotFoundException: 
com.alioth.bootstrap.ExternalClass
        at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:467)
        at 
org.apache.fury.resolver.ClassResolver.loadClass(ClassResolver.java:1838)
        ... 16 more
   ```
   
   ### Anything Else?
   
   1. The ForkJoinWorkerThread in ForkJoinPool#commonPool sets the 
ThreadContextClassLoader in LTS JDK 11 JDK17 JDK21 ,however, this issue does 
not occur in JDK 8., which can cause the aforementioned issues for some common 
APIs, such as CompletableFuture when no specific thread pool is provided.
   ```java
       ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool,
                            boolean useSystemClassLoader, boolean isInnocuous) {
           super(group, null, pool.nextWorkerThreadName(), 0L);
            ...  // Omitting certain content.
           if (useSystemClassLoader) // true
               super.setContextClassLoader(ClassLoader.getSystemClassLoader()); 
// AppClassLoader
       }
   ```
   2.Why does the FuryBuilder#withClassLoader method's ClassLoader only apply 
to the Fury instance in the current thread, and not to all Fury instances under 
the ThreadSafeFury? Is this due to considerations related to GC?
   
   
   ### Are you willing to submit a PR?
   
   - [X] 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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to