Skip to content

Rewrite fails to load classpath.tsv.gz resources from additional GAVs of recipes when used as a library #6885

@cmoulliard

Description

@cmoulliard

Issue

When we execute openrewrite part of a java quarkus application where the openrewrite GAVs have been loaded part of the AppClassLoader, then we hit a problem as rewrite during the execution of some recipes cannot load the classpath.tsv.gz of by example org.openrewrite.recipe:rewrite-java-dependencies:1.51.1 if we use an URLClassloader having as parent the AppClassloader.

The problem takes place when OpenRewrite runs a recipe like org.openrewrite.java.ReplaceAnnotation where they access on the JavaParser class the method classpathFromResources(Context,String ) able to search about such a resource.

As you can see hereafter the current code uses as ClassLoader the one having loaded the JavaParser class and not at all the URLClassloader created using the Environmen Builder and Environment.Collection<? extends ResourceLoader> resourceLoaders

// org.openrewrite.java.ReplaceAnnotation
a = JavaTemplate.builder(annotationTemplateToInsert)
                        .javaParser(classpathResourceName == null ?
        JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()) :
        JavaParser.fromJavaVersion().classpathFromResources(ctx, classpathResourceName)) // HERE
...
// JavaParser class
public B classpathFromResources(ExecutionContext ctx, String... classpath) {
    this.artifactNames = emptyList();
    this.classpath = dependenciesFromResources(ctx, classpath);
    return (B) this;
}
...
static List<Path> dependenciesFromResources(ExecutionContext ctx, String... artifactNamesWithVersions) {
    if (artifactNamesWithVersions.length == 0) {
        return emptyList();
    }
    List<Path> artifacts = new ArrayList<>(artifactNamesWithVersions.length);
    Set<String> missingArtifactNames = new LinkedHashSet<>(Arrays.asList(artifactNamesWithVersions));
    List<String> availableArtifacts = new ArrayList<>();

    TypeTable typeTable = TypeTable.fromClasspath(ctx, missingArtifactNames);
    ...

// TypeTable class    
    public static @Nullable TypeTable fromClasspath(ExecutionContext ctx, Collection<String> artifactNames) {
        try {
            ClassLoader classLoader = findCaller().getClassLoader();
            // The ClassLoader we got it here is the AppClassLoader !!

FYI: I created a project showing the issue here: https://github.com/ch007m/tsv-classloading-issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions