Is there something wrong with commons-net-3.12.0.jar when I get java.lang.NoClassDefFoundError?

2 days ago 1
ARTICLE AD BOX

The stack trace unfortunately does not say which class was not found. However, looking at the source code of org.apache.commons.net.SocketClient shows us:

@SuppressWarnings("unused") // subclasses may throw IOException public void disconnect() throws IOException { IOUtils.closeQuietly(_socket_); IOUtils.closeQuietly(_input_); IOUtils.closeQuietly(_output_); _socket_ = null; _hostname_ = null; _input_ = null; _output_ = null; }

The first line of that method is line 329. That's the line that throws the exception according to the stack trace. So, org.apache.commons.io.IOUtils is probably the class that's missing. That class comes from commons-io, which is a dependency of commons-net.

According to your question, you declared a dependency on commons-net like so:

implementation files('libs/commons-net-3.12.0.jar')

That's how you declare a dependency on a local file in Gradle. You must've manually downloaded that JAR and put it in the libs directory. This is an atypical way of declaring dependencies in Java or Android projects. Not least because you just lost the automatic resolution of transitive dependencies provided by Gradle (and Maven). Which means the classes from commons-io are not being included on the class-path when building and running your application. Hence the error when trying to load IOUtils.

There are two solutions:

Manually download the appropriate commons-io JAR file, place it in your libs directory, and finally declare a dependency on it. Note you'll have to do this for any dependencies of commons-io as well, recursively.

Don't depend on a local JAR file. Declare a dependency on the artifact using Maven coordinates like normal:

implementation 'commons-net:commons-net:3.12.0'

Now Gradle will automatically resolve all transitive dependencies of commons-net. They will be downloaded from Maven Central (or another Maven repository if configured to do so) into Gradle's local cache. And Gradle will include the downloaded JARs on the class-path when building your application.

I strongly recommend the second solution.


As an aside:

@Slaw I thought it's obvious that SocketClient.disconnect() is missing?

Note that disconnect() is a method. You'd get a NoSuchMethodError if a method was missing when called. And the stack trace shows that SocketClient was found and loaded just fine. The class shows up in the top stack frame of the stack trace. Thus, the exception was thrown from code in the class, specifically its disconnect() method, which could only happen if the class was found.

Read Entire Article