Instantiating .class from jar file after evaluation

I’m writing a plugin to execute some classes from my jar files.

My jar files have this structure:

├── META-INF/classes.properties
└── com
    └──example
                ├── Class1.class
                ├── Class2.class
                ├── Class3.class

In classes.properties, I specify which classes should be executed in my plugin.
For example, it looks like this:

com.example.Class1
com.example.Class2

And here is my build.gradle file:

apply plugin: 'MyPlugin'
dependencies{
  compile "com.example:example:xx"
}

So in my plugin, I need to read classes.properties and then using reflection to instantiate Class1 and Class2

 class MyPlugin implements Plugin<Project> {
        @Override
        void apply(Project project) {
            project.afterEvaluate {
                project.configurations.compile.each {
                     File it -> // read from classes.properties then instantiate classes
                 }
            }
        }

But i don’t know how to instantiate classes or read .properties file.
Thanks in advance.

Your properties file doesn’t seem to adhere to the usual name=value format for propery files. Ignoring that, you could do something like:

File jarFile = project.configurations.compile.singleFile
File propFile = project.zipTree(jarFile).matching {
   include 'META-INF/classes.properties'
}.singleFile

propFile.withReader { Reader reader ->
   Properties props = new Properties(reader)
   URL[] urls = { jarFile.toURL() }
   Classloader classloader = new URLClassloader(urls)
   props.stringPropertyNames().each { String className ->
      def instance = classloader.loadClass(className).newInstance()
      doStuff(instance)
   }
}
2 Likes

Thank you, But I got ClassNotFoundException, Is it possible to use project dependencies in gradle plugin?

Yes, you have some options. If you compiled your plugin with dependencies defined in compile configuration, they will automatically be made available on the classpath.

Otherwise if those classes in your plugin requires other classes, not on the classpath, you will have to push them there via the appropriate classloader as referred to by @Lance_Java.

The Asciidoctor task in asciidoctor-gradle plugin has examples of adding to the classpath during task execution. (I have also written about this in the Idiomatic Gradle book).

1 Like

I changed jarFile.toURL() to jarFile.toURI().toURL() and now it works. Thank you both :wink:

1 Like