0

In my java application, I read a jar file (packaged with Maven shade plugin) into a bytestream. In the jar there is a entrypoint class defined in POM.xml

<build>
  ...
  <plugins>
    ...
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>com.mycompany.TheEntryPoint</mainClass>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

How do I load such class into my java app dynamically?

Update:

  • The jar is loaded as byte stream and does not reside in the file system or URL
quarks
  • 33,478
  • 73
  • 290
  • 513

1 Answers1

3

The easiest way to do this is to use a URLClassLoader instead of trying to do this from scratch from a byte stream. You can always write the .jar out to a temporary file and create a URL to that.

The code would look something like:

URLClassLoader loader = new URLClassLoader(
    new URL[] {new URL("file://...")},
    Thread.currentThread().getContextClassLoader());

loader.loadClass("com.mycompany.TheEntryPoint");

You can also detect the main class name (or invoke it) automatically using JarURLConnection. (Oracle also has a tutorial on using this class.)

millimoose
  • 39,073
  • 9
  • 82
  • 134
  • Your JarURLConnection links to java.lang.Thread. You might want to consider it linking to http://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html. – Ryan Amos Nov 22 '12 at 00:42
  • @RyanAmos Whoops, clipboard content confusion struck there. Thanks for picking up on it. – millimoose Nov 22 '12 at 00:54
  • @millimoose I really don't have much of a choice but to read from bytestream, the jar is not located in a file directory or URL – quarks Nov 22 '12 at 12:13
  • @xybrek As I said, you could write the byte stream out to a temporary file, and use the URL to that. Unless for some reason you're not allowed to use temporary files, but that seems unlikely. – millimoose Nov 22 '12 at 14:26
  • @xybrek Well, to get around that fairly inane restriction, you'll probably have to do things "from scratch". Subclass `ClassLoader`, override `findClass()` (see [the docs for `ClassLoader`](http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html)), and consult [the source for `URLClassLoader`](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/net/URLClassLoader.java?av=f) to see how it reads JAR files - you should be able to reuse or copy some of that. – millimoose Nov 23 '12 at 01:47
  • @xybrek (Out of curiosity, what's the reason why you can't write out temporary files? Seems like a rather inane restriction to me.) – millimoose Nov 23 '12 at 01:48
  • @millimoose I'm using Google AppEngine (GAE) so I can write files due to its restricted there (mainly due to the fact that apps built for it are distributed in nature) – quarks Nov 23 '12 at 06:16
  • @millimoose Anyway, I am trying out the code in a normal JVM environment first, but I'm getting ClassNotFoundException, although I checked the jar and the class is there. Is there a way to list which classes from the URLClassLoader? – quarks Nov 23 '12 at 07:10
  • @xybrek I don't think so. A class path `ClassLoader` should work by going through the classpath entries in order, and trying to find the class in each one - i.e. they don't necessarily analyse their contents before hand. If `URLClassLoader` does that (it'd be a valid optimisation), there definitely isn't any `API` to look at its index of known classes. – millimoose Nov 23 '12 at 11:27
  • @xybrek If you're getting a `ClassNotFoundException`, check if you can open the JAR file and class file manually using /the URLs that `URLClassLoader` is using. It's entirely possible I made a mistake you're not supposed to use `file://` URLs to point to .jars. You could verify this by looking at the `URLClassLoader` that Java uses as the "default" one - if you fire up a debugger you should be able to see the list of URLs it uses. (The [`URLClassPath ucp` field](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/net/URLClassLoader.java#URLClassLoader.0ucp) – millimoose Nov 23 '12 at 11:31