0

I'm trying to create and run an executable jar through gradle. This is what my current gradle looks like:

task jarTask(type: Jar) {
    baseName = 'my-main-class'
    from 'build/classes/main'
}

task createJarWithDependencies(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'Sample Jar',
                   'Implementation-Version': 1,
               'Main-Class':'com.example.MyMainClass'
    }
    baseName = "my-main-class-with-dependencies"
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jarTask
}

configurations {
    jarConfiguration
}

artifacts {
    jarConfiguration jarTask
}

// This is the task that I call with ./gradlew to execute my jar
task runMyJar(type: JavaExec) {
    classpath files('build/libs/my-main-class-with-dependencies.jar')
    main 'com.example.MyMainClass'
    args = ["param1","param2"]
    outputs.upToDateWhen { false }
}

runMyJar.dependsOn(createJarWithDependencies, build)

I got these approach from the following stack overflow answers/references below: Android Studio export jar with dependencies Android studio - How to use an executable jar file from gradle

However when I run ./gradlew clean runMyJar (or even just ./gradlew runMyJar, I get the following error message:

Error: Could not find or load main class com.example.MyMainClass

Can anyone point out the reason why my executable jar is not finding the main method inside my class? Is there anything I'm missing?

spring.ace
  • 141
  • 1
  • 9
  • Can you add your Main class? – OneCricketeer Aug 26 '17 at 19:45
  • Possible duplicate of [Gradle- no main manifest attribute](https://stackoverflow.com/questions/32567167/gradle-no-main-manifest-attribute) – jrtapsell Aug 26 '17 at 23:19
  • Not exactly an answer to your question, but look at https://docs.gradle.org/current/userguide/application_plugin.html – Mark Rotteveel Aug 27 '17 at 07:25
  • @cricket_007, the `Main` class is pretty straightforward (but too verbose to cut/paste here), but the simplest case is it calls methods defined from another class not part of my module, and that module references classes from yet another module. If it helps I can add my `dependencies` module here, but the `Main` method is fairly straightforward. Is there something specific you'd like to see what I"m doing in the `Main` class? `dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':common-util') }` – spring.ace Aug 27 '17 at 08:53
  • @JamesTapsell, thanks I looked into that link you referenced, but I tried defining the class path and main class in my manifest as well with no luck (I even placed it inside `jarTask`) Some additional info: My question was originally targeted for the Android Studio IntelliJ IDE, so the `jar` definition referenced in that link won't work for me. It doesn't like it unless I define `apply plugin: 'java'`, which isn't compatible when `apply plugin: 'com.android.library'` is defined, which is what I need. – spring.ace Aug 27 '17 at 08:57
  • @MarkRotteveel, I tried that approach as well but it seems like `apply plugin: 'com.android.library'` doesn't like defining the `mainClassName` in the gradle file, nor `apply plugin: 'application'`. Android Studio reports an error stating `The 'java' plugin has been applied, but it is not compatible with the Android plugin`. I need the Android plugin because my dependencies point to an android module, and some references those from `android.util` as well. – spring.ace Aug 27 '17 at 09:15

1 Answers1

0

Since I haven't had much luck with this solution, I managed to get around this problem by doing the following instead:

task deleteJar(type: Delete) {
    delete 'libs/my-main-class.jar'
}

task createJar(type: Copy) {
    from('build/intermediates/bundles/debug/')
    into('libs/')
    include('classes.jar')
    rename('classes.jar', 'my-main-class.jar')
}

// This is the task that I call with ./gradlew to execute my jar
task runMyJar(type: JavaExec) {
    classpath files('libs/my-main-class.jar')
    classpath files('libs/common-util.jar')
    main 'com.example.MyMainClass'
    args = ["param1","param2"]
    outputs.upToDateWhen { false }
}

createJar.dependsOn(deleteJar, build)
runMyJar.dependsOn(createJar, build)

This is not the solution that I want though, since this approach doesn't pull in the dependencies from other modules referenced by this module, which is what I was trying to solve. In order to do that, what I end up doing is copy/paste this same approach on those "other" modules and generate a lib for that module, and then copy that lib over to the libs folder of this module. OR I can move those dependent code in this same module so I don't have to deal with it. For a simple application that's not too bad (which, luckily, is my situation), but for a complex one, I'm not sure how to go about that.

As an added reference here is my dependencies section:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':common-util')
    // common-util is an Android module, which references other Android
    // methods such as Log.d, android.util class methods, etc.
}

By the way, I'm using the Android Studio IntelliJ IDE for this (which was the original motivation of my post). My hope was to not have to create separate jars from other modules to include it to this module but instead do it all in one go ...

spring.ace
  • 141
  • 1
  • 9