question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ClassLoaderHandler for Quarkus RuntimeClassLoader 1.13.3

See original GitHub issue

Hey,

I run in a problem after a quarkus update to 1.13.3. I don’t know since which version the Classloader at Runtime (fast-jar) changed, but it changed to “io.quarkus.bootstrap.runner.RunnerClassLoader”.

I tried a little bit by myself and following code worked for me. Perhaps you want to use it, otherwise feel free to close this issue.

BR Tobias

/**
 * Extract classpath entries from the Quarkus ClassLoader.
 */
class QuarkusClassLoaderHandler implements ClassLoaderHandler {
    // Classloader until Quarkus 1.2
    private static final String RUNTIME_CLASSLOADER         = "io.quarkus.runner.RuntimeClassLoader";

    // Classloader since Quarkus 1.3
    private static final String QUARKUS_CLASSLOADER         = "io.quarkus.bootstrap.classloading.QuarkusClassLoader";

    // Classloader since Quarkus 1.13
    private static final String QUARKUS_RUNTIME_CLASSLOADER = "io.quarkus.bootstrap.runner.RunnerClassLoader";

    /**
     * Class cannot be constructed.
     */
    private QuarkusClassLoaderHandler() {
    }

    /**
     * Can handle.
     *
     * @param classLoaderClass the classloader class
     * @param log              the log
     * @return true, if classLoaderClass is the Quarkus RuntimeClassloader or QuarkusClassloader
     */
    public static boolean canHandle(final Class<?> classLoaderClass, final LogNode log) {
        return RUNTIME_CLASSLOADER.equals(classLoaderClass.getName())
                || QUARKUS_CLASSLOADER.equals(classLoaderClass.getName())
                || QUARKUS_RUNTIME_CLASSLOADER.equals(classLoaderClass.getName());
    }

    /**
     * Find classloader order.
     *
     * @param classLoader      the class loader
     * @param classLoaderOrder the classloader order
     * @param log              the log
     */
    public static void findClassLoaderOrder(final ClassLoader classLoader, final ClassLoaderOrder classLoaderOrder,
            final LogNode log) {
        classLoaderOrder.delegateTo(classLoader.getParent(), /* isParent = */ true, log);
        classLoaderOrder.add(classLoader, log);
    }

    /**
     * Find the classpath entries for the associated {@link ClassLoader}.
     *
     * @param classLoader    the {@link ClassLoader} to find the classpath entries order for.
     * @param classpathOrder a {@link ClasspathOrder} object to update.
     * @param scanSpec       the {@link ScanSpec}.
     * @param log            the log.
     */
    public static void findClasspathOrder(final ClassLoader classLoader, final ClasspathOrder classpathOrder,
            final ScanSpec scanSpec, final LogNode log) {

        final String classLoaderName = classLoader.getClass().getName();
        if (RUNTIME_CLASSLOADER.equals(classLoaderName)) {
            findClasspathOrderForRuntimeClassloader(classLoader, classpathOrder, scanSpec, log);
        } else if (QUARKUS_CLASSLOADER.equals(classLoaderName)) {
            findClasspathOrderForQuarkusClassloader(classLoader, classpathOrder, scanSpec, log);
        } else if (QUARKUS_RUNTIME_CLASSLOADER.equals(classLoaderName)) {
            findClasspathOrderForQuarkusRuntimeClassloader(classLoader, classpathOrder, scanSpec, log);
        }
    }

    @SuppressWarnings("unchecked")
    private static void findClasspathOrderForQuarkusClassloader(final ClassLoader classLoader,
            final ClasspathOrder classpathOrder, final ScanSpec scanSpec, final LogNode log) {
        for (final Object element : (Collection<Object>) ReflectionUtils.getFieldVal(classLoader, "elements", false)) {
            final String elementClassName = element.getClass().getName();
            if ("io.quarkus.bootstrap.classloading.JarClassPathElement".equals(elementClassName)) {
                classpathOrder.addClasspathEntry(ReflectionUtils.getFieldVal(element, "file", false), classLoader,
                        scanSpec, log);
            } else if ("io.quarkus.bootstrap.classloading.DirectoryClassPathElement".equals(elementClassName)) {
                classpathOrder.addClasspathEntry(ReflectionUtils.getFieldVal(element, "root", false), classLoader,
                        scanSpec, log);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private static void findClasspathOrderForRuntimeClassloader(final ClassLoader classLoader,
            final ClasspathOrder classpathOrder, final ScanSpec scanSpec, final LogNode log) {
        final Collection<Path> applicationClassDirectories = (Collection<Path>) ReflectionUtils.getFieldVal(classLoader,
                "applicationClassDirectories", false);
        if (applicationClassDirectories != null) {
            for (final Path path : applicationClassDirectories) {
                classpathOrder.addClasspathEntryObject(path.toUri(), classLoader, scanSpec, log);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private static void findClasspathOrderForQuarkusRuntimeClassloader(final ClassLoader classLoader,
            final ClasspathOrder classpathOrder, final ScanSpec scanSpec, final LogNode log) {
        for (final Object[] elementArray : ((Map<String, Object[]>) ReflectionUtils.getFieldVal(classLoader,
                "resourceDirectoryMap", false)).values()) {
            for (Object element : elementArray) {
                final String elementClassName = element.getClass().getName();
                if ("io.quarkus.bootstrap.runner.JarResource".equals(elementClassName)) {
                    classpathOrder.addClasspathEntry(ReflectionUtils.getFieldVal(element, "jarPath", false), classLoader,
                            scanSpec, log);
                }
            }
        }
    }
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
lukehutchcommented, Jul 1, 2021

Added and released in version 4.8.109. Thanks for the contribution and the pull request!

1reaction
lukehutchcommented, Jul 8, 2021

I was just wondering if there were some Quarkus specific thing needed to generate the class graph.

There is nothing specific needed for Quarkus when your project is in classfile form, with the classfiles either in directories or in jarfiles, as far as I know. But if you do use GraalVM to compile to native code, you have to do the scan before that compilation step, or it won’t work. (Android has the same constraint – you have to scan before compilation to Dalvik bytecodes.)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Class Loading Reference - Quarkus
This ClassLoader is used to load the application classes and other hot deployable resources. Its parent is the base runtime ClassLoader, and it...
Read more >
release - Quarkus
We released Quarkus 2.13.0.Final which, among a lot of smaller enhancements, comes with a cross site request forgery prevention filter and a Kafka...
Read more >
Quarkus - Supersonic Subatomic Java
A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards. Now Available....
Read more >
Building applications with Maven - Quarkus
Logging Quarkus application build classpath tree. Usually, dependencies of an application (which is a Maven project) could be displayed using mvn dependency: ...
Read more >
Creating Your First Application - Quarkus
Learn how to create a Hello World Quarkus app. This guide covers: Bootstrapping an application. Creating a JAX-RS endpoint. Injecting beans.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found