Home > Back-end >  Java get project file system location from another project
Java get project file system location from another project

Time:03-27

I'm working on a multi project build where i need to get all .class files within a project and then load of all those through reflection by its file system location, given this project structure:

multi-project
|_ /app/
|   |_ src/
|_ /notification/
|   |_ /src/
|_ settings.gradle

In this multi project build my app project is dependent on notification project like this

dependencies {
    implementation project(":notification")
    // other dependencies
}

Although it may look like a gradle related question at this point, it's not, it's build tool agnostic.

Currently I'm working on app project, but i need to dynamically load all the classes located on notification project, i usually do this by inspecting the file location of a project, but i need to get the location of notification project from a class that's located in app project

I load all the classes of app project by using ClassLoader.getResources() in order to capture the path, but this class loader can not capture the path of the notification project

CodePudding user response:

You can't. The classpath abstraction fundamentally doesn't have the "list resources" concept. It's just "get me resource X", that's all it has.

Hence, "I want to get a list of all classes so I can load them via reflection" is not possible without hackery.

Fortunately, there is an actual solution. resource-listing. Generally, by using the SPI (Service Provider Interface) system.

During compilation (during which, the compiler/build tool certainly does have a complete list of everything it is compiling), a text file is created. It contains the fully qualified class name of each and every relevant class, one such name per line. This text file is then included in the jar files. Now you can build up the process of 'give me an instance of each class of project X' just fine using just the API exposed by java's ClassLoader:

  • Load resource "/meta-inf/services/com.foo.YourInterface" and read it line by line.
  • Per line, run Class.loadClass(thatLine).getConstructor().newInstance(), cast it to com.foo.YourInterface and add it to a list.
  • return the list.

Voila. No 'list' directive (which doesn't exist) required. This is exactly how java itself works when finding e.g. SQL drivers, charset encoding drivers, implementations of crypto, etcetera.

The basics for how to do this depends on your buildsystem. The compilation step ("create a text file with all implementations") is build-dependent; you could write it by hand, or you can write your own build plugin, or you can use existing annotation processors that scan for an annotation and generate it automatically.

The runtime component (using the text file that is on the classpath, i.e. in the jar where the class files also are, load each and every class listed there, instantiate them, and return it to me as a list of instances) is baked into java itself: ServiceLoader.

CodePudding user response:

I think i was not very clear as it was my first question, I just needed the file system path to the other project, I could find what i was looking for by using System.getProperty("java.class.path")

It contains the path to the compiled jar of the project i need, it's not the path i needed, but i can still get the entries of that file which is as much as useful as the path itself

  •  Tags:  
  • java
  • Related