Andrew Aubury
Andrew Aubury

Reputation: 113

ClassNotFoundException When using another jar file in eclipse build path (minecraft plugin)

I am trying to use a .JAR file I made as an API for my current project. This is the GitHub page for the API, and this is the code for the plugin I am working on.

I am getting these errors:

04.01 17:32:03 [Server] INFO Caused by: java.lang.NoClassDefFoundError: me/Andrew/XenforoAPI/SiteAPI
04.01 17:32:03 [Server] INFO at me.Andrew.BreezeSiteLink.APICaller.postApplication(APICaller.java:16) ~[?:?]
04.01 17:32:03 [Server] INFO at me.Andrew.BreezeSiteLink.Main.onCommand(Main.java:84) ~[?:?]
04.01 17:32:03 [Server] INFO at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[spigot.jar:git-Spigot-5391d73-0ebb9c7]
04.01 17:32:03 [Server] INFO ... 15 more
04.01 17:32:03 [Server] INFO Caused by: java.lang.ClassNotFoundException: me.Andrew.XenforoAPI.SiteAPI
04.01 17:32:03 [Server] INFO at java.net.URLClassLoader$1.run(URLClassLoader.java:359) ~[?:1.7.0_121]
04.01 17:32:03 [Server] INFO at java.net.URLClassLoader$1.run(URLClassLoader.java:348) ~[?:1.7.0_121]
04.01 17:32:03 [Server] INFO at java.security.AccessController.doPrivileged(Native Method) ~[?:1.7.0_121]
04.01 17:32:03 [Server] INFO at java.net.URLClassLoader.findClass(URLClassLoader.java:347) ~[?:1.7.0_121]
04.01 17:32:03 [Server] INFO at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:101) ~[spigot.jar:git-Spigot-5391d73-0ebb9c7]

In Eclipse, "Export as JAR file" is checked (but not "Runnable JAR file").

How can I resolve this and get the API to compile with the plugin?

Upvotes: 0

Views: 1665

Answers (2)

Frelling
Frelling

Reputation: 3507

As already discussed, the error is a result of your plugin not finding your API library. In most cases, I would recommend that you include that dependency in your plugin's JAR.

However, if this API, which itself is not a plugin, is used by more than one plugin, create a lib directory at the server root and place your API JAR therein. Any JAR files located in this directory will be loaded by Bukkit/Spigot and available to all plugins.

Edit:

As I mentioned in my comment, I have used this technique for so long, I assumed it to be a feature of Bukkit. Alas, it is not.

Adding Classpath in MANIFEST.MF

Adding the following maven-jar-plugin configuration to your POM, ensures that any dependencies having a scope of compile will be added to your plugin's classpath. The classpath is relative to the location of your plugin (the plugin directory), thus ../lib/ is the lib directory in the server root.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <archive>
            <manifestEntries>
                 <Built-By>You</Built-By>
            </manifestEntries>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>../lib/</classpathPrefix>
            </manifest>
        </archive>
     /configuration>
</plugin>

In essence, this creates an entry in your plugin's META-INF/MANIFEST.MF referencing your API library similar to the following:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: You
Class-Path: ../lib/my-api.jar
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_73

Create an Uber-JAR

The above solution has worked well for us, providing a single location for maintaining libraries used by several of our in-house plugins. Then again, we run our own server.

If your long-term plans are to publish your plugin for others to use, this solution is not ideal. While it will work, it requires additional work on the part of server operators, unless the installation of your API library is automated. Then again, installing files other than what server operators expect may not be a good idea either.

A better solution is to create an uber-JAR that includes your code and any unique dependencies, such as your API. It eliminates the need to installed your API JAR as in the above example. More importantly, it avoids potential version mismatches as newer versions of your plugin are released.

Adding the following maven-shade-plugin configuration to your POM, will create an uber-JAR that includes your plugin and API classes and interfaces in a single JAR. The example assumed that the your API has the Maven coordinates me.andy:myapi:1.0

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <minimizeJar>true</minimizeJar>
                <filters>
                    <filter>
                        <artifact>me.andy:myapi:1.0</artifact>
                        <includes>
                            <include>**</include>
                        </includes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

After you run mvn install you will find three JAR files in the target directory (filenames will obviously differ):

  • original-myplugin-1.0.jar - the original JAR as it would have been created normally.
  • myplugin-1.0-shaded.jar - the combined JAR
  • myplugin-1.0.jar - the combined JAR with reduced dependencies. This is the final plugin JAR.

You can verify what was included with any popular ZIP tool.

Upvotes: 1

Cath
Cath

Reputation: 462

Rightclick your Projct -> Java Build Path -> Libaries -> Add External Jars

You can then select the jar / api you want to use with your project, but don't forget to add it to the dependencies in the plugin.yml too:

depend: [Plugin1, Plugin2...]

Upvotes: 0

Related Questions