[resolved] noClassDef error, apache common's math3 classfiles not present at runtime?

Hey all,
my plugin relies on the Apache Commons Math Library. I’ve edited my build.gradle file to declare these dependencies:

apply plugin: 'java'
apply plugin: 'maven'

group = 'net.kevinmendoza.geoworldlibrary'
version = '0.0.1-SNAPSHOT'
description = 'GeoWorld Library'

sourceCompatibility = 1.8
targetCompatibility = 1.8


repositories {
    mavenCentral()
    maven {
        name = 'sponge'
        url = 'http://repo.spongepowered.org/maven'
    }
     maven {
        name = 'commons-math3'
        url = 'https://mvnrepository.com/artifact/org.apache.commons/commons-math3'
    }
}

dependencies {
    compile 'org.spongepowered:spongeapi:5.0.0'
    compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
}

However, when I call the section of my code which relies on the library, I get the following noClassDefFoundError:

[17:54:31] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.util.ReportedException: Exception generating new chunk
	at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:704) ~[MinecraftServer.class:?]
	at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:387) ~[ld.class:?]
	at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:613) ~[MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:471) [MinecraftServer.class:?]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_65]
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/math3/geometry/euclidean/threed/Rotation
	at net.kevinmendoza.geoworldlibrary.proceduralgeneration.shapes.Shape.initEmptyRotation(Shape.java:37) ~[Shape.class:?]
	at net.kevinmendoza.geoworldlibrary.proceduralgeneration.shapes.Shape.<init>(Shape.java:32) ~[Shape.class:?]
	at net.kevinmendoza.geoworldlibrary.proceduralgeneration.shapes.Shape2D.<init>(Shape2D.java:24) ~[Shape2D.class:?]
	at net.kevinmendoza.geoworldlibrary.proceduralgeneration.shapes.Ellipse.<init>(Ellipse.java:20) ~[Ellipse.class:?]
	at net.kevinmendoza.geoworldlibrary.proceduralgeneration.shapes.RegionFactory.MakeEllipse(RegionFactory.java:14) ~[RegionFactory.class:?]

I’m fairly sure this is because the Rotation.class file defined in the commons math library isn’t actually around during runtime, but I don’t know enough about the runtime vs compile time side of devops to say for sure. In any case, is there something else I need to do within my build.gradle?

To shade a dependency into the final jar(fat jar):

  1. Add a shadow plugin, it also supports reloacting the dependencies which is very important.
  2. For convenience
  3. Mark the dependencies to be shaded, transitive set to false disables shadowing the dependencies of the marked dependency in the final jar too.
  4. I think this isn’t needed, I can’t recall what things happened when jar wasn’t disabled, just try without it and see.
  5. The actual configuration of the shadow plugin: Shadow the dependency marked with shadow, disable unnecessary files getting into the jar, relocate the dependencies(important, choose a package location that is definitely not used by someone else)
  6. Run the shadow task when the project is built, this is in general for convenience and sometimes needed when an external thing tries to get a jar with the build task(I use jitpack).

When :jar is enabled, it just builds a useless file and then overwrites it with :shadowJar. A wasted use of resources.

And an easy list of file additions in case you don’t want to click six different links:

plugins {
    id 'com.github.johnrengelman.shadow' version '1.2.4'
}

jar.enabled = false
build.dependsOn shadowJar

configurations {
    compile.extendsFrom shadow
}

dependencies {
    shadow group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
}

shadowJar {
    classifier = null
    configurations = [project.configurations.shadow]
    relocate('org.apache', 'net.kevinmendoza.geoworldlibrary.util.org.apache')
}
1 Like

Shading and Relocating apache commons will package it with your plugin, and change the namespace so it won’t conflict with any others.

Your other option would be to include apache commons as a library the user could leave in their mods folder, or keep in the appropriate forge library folder.

Shading is recommended, so you don’t have potential versioning conflicts with others.

I don’t think vanilla loads non-plugin jars in the mods folder.

Thanks pie_flavor,
That list of file changes did it!

If you have a proveable example of this being true, we would appreciate an issue on SpongeVanilla.