9

I know you can't change the classpath in Java 9 because I read this: Add jar to classpath at runtime under java 9

I just want to list jar files and folders currently on the Classpath so that I can build a command line argument to the Java compiler.

// Construct compile command options
// According to: http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javac.html
// The directory specified by -d is not automatically added to your
// classpath, so we'll add it manually.
String[] args = new String[] {"-d", classDir,
                              "-classpath", classPath,
                              "-encoding", "UTF-8",
                              srcFile};

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int ret = compiler.run(null, out, err, args);

To construct a classpath in Java 8 I casted to URLClassLoader which is illegal in Java 9:

ClassLoader myCl = SimpleJavaCompilerTest.class.getClassLoader();
URLClassLoader myUcl = (URLClassLoader) myCl;
for (URL url : myUcl.getURLs()) {
    System.out.println(url.toString().replace("file:", ""));
}

This produced (GOOD) output like:

/tools/idea-IU-181.4445.78/lib/idea_rt.jar
...
/tools/idea-IU-181.4445.78/plugins/junit/lib/junit5-rt.jar
/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/charsets.jar
...
/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar
/blah/myApp/target/test-classes/
/blah/myApp/target/classes/
/home/me/.m2/repository/commons-fileupload/commons-fileupload/1.3.3/commons-fileupload-1.3.3.jar
...
/home/me/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar

I tried: Scanning classpath/modulepath in runtime in Java 9 but it produced a list of ~19,000 class files that are part of openjdk, but not the jar files or class folders from my project. Like (BAD):

java/awt/desktop/ScreenSleepListener.class
...
javax/accessibility/AccessibilityProvider.class
...
jdk/dynalink/beans/AbstractJavaLinker$1.class
...
META-INF/providers/org.graalvm.compiler.code.HexCodeFileDisassemblerProvider
...
module-info.class
...
netscape/javascript/JSException.class
...
org/graalvm/compiler/api/directives/GraalDirectives.class
...
org/ietf/jgss/ChannelBinding.class
...
org/jcp/xml/dsig/internal/SignerOutputStream.class
...
org/w3c/dom/xpath/XPathResult.class
...
org/xml/sax/AttributeList.class
...
sun/applet/AppContextCreator.class
...
sun/util/spi/CalendarProvider.class
...

I need the jar files and the class folders specific to my project (which are not in the java-9 list above). How do I get that in Java 9?

GlenPeterson
  • 4,236
  • 4
  • 35
  • 45
  • 1
    This doesn't solve your problems because it doesn't account for the changes in runtime, but there's a `java.class.path` property which returns "Path used to find directories and JAR archives containing class files. Elements of the class path are separated by a platform-specific character specified in the `path.separator` property.". Doesn't help in the general case, but maybe it's enough for some people. – mszymborski Aug 10 '18 at 22:12
  • **Caution:** `url.toString().replace("file:", "")` is not guaranteed to convert a URL to a valid filename. Consider `file:/C:/Users/John%20Doe`. – VGR Aug 10 '18 at 22:47
  • 1
    Out of curiosity, why do you need to do this? I’m sensing an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/66378#66378). – VGR Aug 10 '18 at 22:49
  • @VGR you are correct. I'm trying to compile and dynamically reload java files in a certain folder that implement a certain interface. You know, like the way that JSP gets compiled on the fly, except instead of .jsp files they are just .java files. The way I'm doing it is based on this: http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html – GlenPeterson Aug 13 '18 at 19:09
  • 1
    @nullpointer I appreciate the hard work that moderators on this site do. This question has been marked as a duplicate, but I had actually spent about an hour trying the answers to that question before posting my own. I hope my new examples and additions make this clear enough to warrant reopening, or maybe you could explain what more I need to do. – GlenPeterson Aug 13 '18 at 20:15
  • @VinceEmigh I deleted my earlier comment. I was frustrated when I wrote it and it came out snarky. I'm sorry about that. I understand that there is no place for attitude like that on this site. You left a helpful comment earlier which I appreciated. I was wondering if you could reconsider your "duplicate" vote because while that other question gives a list of class files, they are from the JVM which doesn't help me. I need a list of class folders and jar files from my project. I've updated my question to be clearer about that. – GlenPeterson Aug 13 '18 at 20:20
  • @mszymborski Thanks so much - I think that might work! If this question is ever reopened and you write that as an answer, I'll gladly upvote and accept it. – GlenPeterson Aug 13 '18 at 20:41
  • @GlenPeterson: I'm happy I've been able to help. – mszymborski Aug 14 '18 at 21:30

1 Answers1

0

In Java 9+ you can get classpath URLs with a little help from reflection:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Field ucpField = BuiltinClassLoader.class.getDeclaredField("ucp");
ucpField.setAccessible(true);
URLClassPath classpath = (URLClassPath) ucpField.get(classLoader);
for (URL url : classpath.getURLs()) {
    System.out.println(url.getFile());
}

Don't forget to add:

  • requires java.base to your module-info.java file
  • --add-exports java.base/jdk.internal.loader=your_module_name compiler option
  • --add-exports java.base/jdk.internal.loader=your_module_name and --add-opens java.base/jdk.internal.loader=your_module_name VM options
Nolequen
  • 2,412
  • 6
  • 33
  • 50