-
-
Notifications
You must be signed in to change notification settings - Fork 808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Gradle: Classpath elements not on classpath during plugin execution #1726
Comments
You mean this configuration? There are multiple ways to configure the Gradle plugin. You can specify a name and then the plugin will be resolved from within the plugin's class path, or you can configure the plugin and its dependencies directly. How did you approach this? |
Judging from the name, I expected the classpath property to allow arbitrary classes to be supplied and accessed in the plugin. buildscript {
dependencies {
classpath 'net.bytebuddy:byte-buddy-gradle-plugin:1.15.0'
classpath 'net.bytebuddy:byte-buddy:1.15.0'
}
}
configurations {
myCustomClasspath
}
dependencies {
myCustomClasspath 'my:special:jar' // containing my.special.jar.MySpecialClass
}
import net.bytebuddy.build.Plugin
import net.bytebuddy.build.gradle.ByteBuddyJarTask
import net.bytebuddy.description.type.TypeDescription
import net.bytebuddy.dynamic.ClassFileLocator
import net.bytebuddy.dynamic.DynamicType
class SimplePlugin implements Plugin {
@Override
void close() throws IOException {
}
@Override
DynamicType.Builder<?> apply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassFileLocator classFileLocator) {
Class.forName("my.special.jar.MySpecialClass") // fails since the myCustomClasspath configuration is not resolved/available
return builder
}
@Override
boolean matches(TypeDescription typeDefinitions) {
return true
}
}
tasks.register("myByteBuddyTask", ByteBuddyJarsTask) {
source = files("libs")
target = file("transformedLibs")
classPath = project.getConfigurations().getByName("myCustomClasspath")
transformation {
plugin = SimplePlugin
}
} The Right now I have to include 'my:special:jar' in the buildscript classpath to be available in the SimplePlugin. buildscript {
dependencies {
classpath 'net.bytebuddy:byte-buddy-gradle-plugin:1.15.0'
classpath 'net.bytebuddy:byte-buddy:1.15.0'
classpath 'my:special:jar'
}
}
However I try to avoid that since those classes are not needed outside of the custom byte-buddy plugin. As far as I understand, that is exactly the purpose of the classpath property in gradle tasks like |
I tried creating a custom classloader that reads the byte[] from the class file locator. But I always get Does the class file locator do anything special with the class files or are my classes the issue? |
You can also configure dependencies in the |
How? I don't see a property in the |
This would be done via the extension in the discovery set: https://github.com/raphw/byte-buddy/blob/master/byte-buddy-gradle-plugin/src/main/java/net/bytebuddy/build/gradle/ByteBuddyTaskExtension.java#L45 The class path is meant for plugins that want to discover transformers automatically via a service loader file. |
I set both discoverySet and classpath to my gradle configuration: task.setDiscoverySet(myConfiguration);
task.setClassPath(myConfiguration);
task.doFirst(t -> myConfiguration.getFiles().forEach(System.out::println)); The System.out shows all jar files as expected. However if I use a tool like ClassGraph to scan the classpath from my custom byte-buddy plugin, I only see all the gradle jars and the jar with my plugin class. I still am unable to see the jars from I also tried again with the ClassLoader implementation, but I always get the ClassFormatError with the byte[] from the ClassFileLocator. |
You can look up the class file, but get a |
I think my custom ClassLoader works fine after all. It does find classes inside the set classpath given the class name: public class ClassFileLoader extends ClassLoader {
private final ClassFileLocator locator;
public ClassFileLoader(ClassFileLocator locator) {
this.locator = locator;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
ClassFileLocator.Resolution resolution = locator.locate(name);
if (resolution.isResolved()) {
byte[] bytes = resolution.resolve();
return this.defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} However it is impossible to locate classes without explicitly providing the name e.g. by using scanners like ClassGraph, since - again - the source URIs of the ClassFileLocator are not part of the actual classpath. And there is no way to access the URLs the ClassFileLocator is reading from. What about a new method in ClassFileLocator to expose the source URIs? public interface ClassFileLocator extends Closeable {
//...
/** Returns the sources this ClassFileLocator tries to locate classes in */
List<URI> getSources() throws IOException;
} Or is there any way to access the classpath property of the gradle task extension ( interface WithClasspath extends Plugin {
/** Implement this in your custom plugin to get ahold of the classpath property */
void processClasspathProperty(Iterable<File> classpath);
} |
I can add |
The |
I do not think a new method is the right approach. The class path might not even be available, and if it is available, it should be provided through construction. I agree that injecting the project should be a last resort, but we could provide a |
I added a change to master. Would that work for your needs? |
So a custom plugin with a constructor parameter Is it still possible to use more parameters additionally to |
I am missing the gradle plugin marker in my local maven repository when I build and install locally, so I can't test the plugin with gradle right now. Am I missing something? |
Yes, a File[] would now represent the class path. What do you mean by plugin marker? |
Multiple byte-buddy gradle tasks annotate an input property as classpath but the input is not actually used as the classpath for execution.
I tried to load some classes in my custom plugin, expecting to find them on the classpath, however they are never available, unless they are also part of an origin or used for discovery.
I understand that byte-buddy does not actually need any other classpath elements that are not part of an origin, so I am not sure if it would be smart to load more, however the use of the annotation makes this a bit misleading.
Would it be possible to load all classes that are configured as classpath? Or idk run the plugins in a custom classloader that queries the ClassFileLocator?
The text was updated successfully, but these errors were encountered: