3

I have a Gradle project (say, MyProject) that has a main method that I only want to use to run a small Java app. Say, the script is in a class and package as follows:

MyScript.Java

package com.car.ant;

import com.3rdparty.library.LibraryException;

public class MyScript {
    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

I build the project with $ ./gradlew clean build, no problem. I am trying to run this via command line, but when I do, I get an Exception when trying to run:

$ pwd
~/workspace/MyProject/build/classes/java/main
$ java com.car.ant.MyScript
Exception in thread "main" java.lang.NoClassDefFoundError: com/3rdparty/library/exception/LibraryException
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
        at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
        ... 7 more

This script is not the main part of the app, but I just want it in there to run every once in a while, and I'd like to figure out how to run it by itself command line. Is there a way to do this without importing anymore libraries? I've seen this done with one-jar, but I thought I could do this without one-jar.

UPDATE:

Tried to add a classpath after reading this, but now I'm getting a different error:

$ java -cp com/3rdparty/library/exception/LibraryException com.car.ant.MyScript
Error: Could not find or load main class com.car.ant.MyScript
aCarella
  • 2,369
  • 11
  • 52
  • 85
  • If you’re using gradle I would recommend the `application` plugin, all you have to do is specify the fully qualified main class name. It also handles all of your libraries, so you don’t have to specify a classpath. – vandench Sep 18 '18 at 18:32
  • Your use of the word `script` is rather confusing as the program you are attempting to run seems to be a Java program. These are not normally referred to as scripts. Scripts rather usually refers to programs written in "scripting" languages such as shell, groovy or python. – Jolta Sep 19 '18 at 12:00

2 Answers2

5

You can read about how to do this at the Gradle Docs.

apply plugin: 'application'
mainClassName = "com.mycompany.myapplication.MyScript"
applicationDefaultJvmArgs = [
    "-Djava.util.logging.config.file=src/main/resources/logging.properties"
]

Then simply use gradlew run to run your application.

As an added benefit, this plugin helps you to package your app for distribution. Use the gradle distZip command for that.

Jolta
  • 2,620
  • 1
  • 29
  • 42
  • My code is not really the focus of the application it's living in though. The app as a whole is a service that's running on Vert.x. The code that I'm referencing above is something that needs to be run every now and then on demand (probably manually) to do a little bit of cleaning of data. It's related to the web app, but not central to it. With the web app, we build it using `gradlew clean build`. Will your solution above have any affect on this? What if I put another piece of code with a main method? How would that play into all of this? – aCarella Sep 20 '18 at 15:25
  • Of course, you should read the documentation I linked before implementing this solution to a commercial project. If you are not authorized to make the change yourself, I would advise bringing it up with your build master. My intuition is that adding the `application` plugin should not the behavior of the `clean` or `build` tasks, but don't take my word for it. – Jolta Sep 21 '18 at 14:55
  • 1
    BTW, if you're always doing "clean" when you build your project, that's an anti-pattern. Usually it is done by former Maven users who suffered that tool's poor handling of stale output files, which often leads to broken artifacts. Gradle is much better at this, and guarantees that it will always produce a correct artifact (unless you misconfigured it in some exotic way). Remove the `clean` from `clean build` and gradle will save you a lot of time by reusing outputs that were already built, in a completely safe way. – Jolta Sep 21 '18 at 14:59
1

Try this.

    plugins {
    id 'java-library'
    id 'application'
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
/*
sourceCompatibility is "Java version compatibility to use when compiling Java source." 
targetCompatibility is "Java version to generate classes for."
*/
repositories {
    jcenter()
}
dependencies {
}


//To run the class name from command line using gradle run
mainClassName = 'com.sam.home.HelloWorld'

//To create a runnable jar  in GradleJavaProject\build\libs then java -jar GradleJavaProject.jar
jar {
    manifest {
        attributes 'Main-Class': 'com.sam.home.HelloWorld'
    }
}
//Beyond this line evertyhing is optional
//Alternatively you can run it as a task too gradle -q  runWithJavaExec
task runWithJavaExec(type: JavaExec) {
    group = "Execution"
    description = "Run the main class with JavaExecTask"
    classpath = sourceSets.main.runtimeClasspath
    main = 'com.sam.home.HelloWorld'
}
wrapper {
gradleVersion = '5.5'
distributionType = Wrapper.DistributionType.BIN
}

In command line type either gradle run or gradle -q runWithJavaExec

Sameera De Silva
  • 1,722
  • 1
  • 22
  • 41