Gradle NoClassDefFoundError when running jar


I'm trying to set up a Gradle project with some Velocity functions in it.

So far I have the following files:

src/main/java/com/veltes/velotest.java:

package com.veltes;

import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.*;

public class velotest {
    public static void main(String[] args) {

        try {
            VelocityEngine ve = new VelocityEngine();
            ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
            ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
            ve.init();
            VelocityContext context = new VelocityContext();
            context.put("name", "World");
            Template t = ve.getTemplate("com/veltes/velotest.vm");
            StringWriter writer = new StringWriter();
            t.merge(context, writer);
            System.out.println(writer.toString());

            File logFile = new File("C:/users/xxxx/Desktop/velotest.html");

            try {
                writeFile(logFile, t, context);
            }
            catch (IOException io) {
            }
        } catch (Exception e) {
        }

    }

    private static void writeFile(File logFile, Template t, VelocityContext context) throws IOException {
        Writer logWriter;

        logWriter = new BufferedWriter(new FileWriter(logFile));
        try {
            t.merge(context, logWriter);
        }
        catch (ResourceNotFoundException rnfe) {
        }
        catch (ParseErrorException pee) {
        }
        catch (MethodInvocationException mie) {
        }
        catch (Exception e) {
        }
        logWriter.flush();
        logWriter.close();
    }

}

build.gradle:

group 'velocitytest'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.5

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.3.11'
    testCompile group: 'junit', name: 'junit', version: '4.11'

    compile 'velocity:velocity:1.4'
}


Now, when I run gradle assemble and gradle build everything is fine, but when I try to run the project (same for running the built jar in build/libs/ and for running the velotest class in IntelliJ), I get the following error:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/collections/ExtendedProperties
at org.apache.velocity.runtime.RuntimeInstance.< init >(RuntimeInstance.java:183)
at org.apache.velocity.app.VelocityEngine.(VelocityEngine.java:60) at com.veltes.velotest.main(velotest.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.ExtendedProperties
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 8 more

It's a bit strange that there is no jar in build/tmp/

Does anyone of you knows a solution?


Solution 1:

You need to create a runnable jar if you want to be able to run it.

You can use shadojar plugin or extend the jar task to pack the runtime deps into an artifact.

jar {
    archiveName = 'Name.jar'

    manifest {
        attributes 'Main-Class': 'your.main.class',
                'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' '),
                'Implementation-Version': project.version
    }

    from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {}
}

For intelliJ problem:

apply plugin: 'idea'

Then run gradle idea task, this will refresh .iws .ipr .iml files in your project and sync the classpaths. Or if you use intelliJ support (which is not yet ideal) try to refresh it there. I think in version 2017.1.3 the gradle integration is a bit better.