private static <T> ObjectAndClassLoader<T> createObjectFromNewClassLoader(
      String testClassName, Class<T> testClass, String source) {
    final Path classDirPath =
        new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()).toPath();

    URLClassLoader classLoader = null;
    try {
      Files.createDirectories(classDirPath);
      classLoader = compileAndLoadJava(classDirPath.toFile(), testClassName, source);

      final Class<?> clazz = classLoader.loadClass(testClassName);
      final T object = clazz.asSubclass(testClass).getDeclaredConstructor().newInstance();

      return new ObjectAndClassLoader<>(object, classLoader);
    } catch (Exception e) {
      throw new RuntimeException("Cannot create test class outside system class path", e);
    } finally {
      // we clean up eagerly, because it is fine to delete the class file once the class is
      // loaded
      // and we have no later life cycle hook here to do the cleanup
      tryClose(classLoader);
      tryDeleteDirectoryRecursively(classDirPath);
    }
  }
Creates a new ClassLoader and a new {@link Exception} class inside that ClassLoader. This is
useful when unit testing the class loading behavior of code, and needing a class that is
outside the system class path.

<p>NOTE: Even though this method may throw IOExceptions, we do not declare those and rather
wrap them in Runtime Exceptions. While this is generally discouraged, we do this here because
it is merely a test utility and not production code, and it makes it easier to use this method
during the initialization of variables and especially static variables.
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/java/org/apache/amoro/flink/util/ClassLoaderUtils.java