Gradle Plugin Task Reflection Scans Plugin's Project Class Files Instead of Current Project Files

I’ve created a Gradle plugin which scans the class files in my project and find which ones have an annotation.

I got it to work and compiled it. Now when I run the task in my project, instead of scanning the classes of the project that I’m in and runs the task on it, it scans the class files of the plugin project itself. What am I doing wrong?

final ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
    ClassPath classpath = ClassPath.from(loader); // scans the class path used by classloader
    log.info("classPath = {}", classpath);
    for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClassesRecursive(packageName)) {
        log.info("classInfo={}", classInfo);
        Class<?> clazz = classInfo.load();
        if (clazz.isAnnotationPresent(RestController.class)) {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                doSomething(clazz, method);
            }
        }
    }
} catch (IOException | NoSuchFieldException | IllegalAccessException ex) {
    String errorMsg = new StringBuilder("Unable to generate ").append(propertiesFileName).append(" file.").toString();
    log.error(errorMsg, ex);
    throw ex;
}

Gradle tasks are loaded via Gradle’s buildscript classloader. Classes compiled during the build of your project are not loaded by the buildscript classloader.

Instead of

ClassLoader loader = Thread.currentThread().getContextClassLoader();

You should do something like

def urls = sourceSets.main.runtimeClasspath.collect { it.toURI().toURL() } 
ClassLoader loader = new URLClassLoader(urls as URL[]) 
1 Like

Thanks for the quick response!
I’m not sure how to implement this n Java…

Set<File> files = project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().getByName("main").getRuntimeClasspath().getFiles();
URL[] urls = files.stream().map(file -> file.toURI().toURL()).toArray(URL[]::new);
ClassLoader loader = new URLClassLoader(urls);

When my plugin works in Android Project, project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() rentrun an empty Set. How to write when gradle plugin is used in Android project.

Same problem here. I was able to replicate the same config in android with kotlin using android variants but not sure how to get the runtimeClassPath. You can actually reuse the same approach as Butterknife did here

project.getConvention().getPlugin(JavaPluginConvention.class)
.getSourceSets().getByName(“main”).getRuntimeClasspath().getFiles()

I use your help, when I ran this code ervery time, it always slow, likely stucked. could you check it for me, thank you very much.

<-------------> 0% EXECUTING [2m 9s]

:cango-mid-dictionary-client:generateProto > Resolve dependencies of :cango-mid-dictionary-api:runtimeClasspath