4

I am trying to run a jar from Android studio. After a long Workaround, the jar file run perfectly.

Now i need to export the jar file from the android studio. I got the Jar file from the build/libs folder.

But the problem is that the jar file shows a error.

no main manifest attribute, in "app.jar"

So i found this solution. Can't execute jar- file: "no main manifest attribute"

Then i read about MANIFEST.MF & added the mail class to that file.

jar {
    manifest.attributes(
            'Main-Class': "com.Remo.server.RemoServerApp"
    )
}

After adding those in my gradle. My MANIFEST.MF contains the MainClass.

But im still getting the same error? How can i solve this ?

Note: The objective is that I want to Export a Runnable Jar file from the project.

UPDATE:

After Adding the MainClass in MANIFEST.MF. I got stuck with the below error.

Exception in thread "main" java.lang.NoClassDefFoundError: com/Remo/protocol/RemoConnection
    at com.Remo.server.RemoServerApp.<init>(RemoServerApp.java:33)
    at com.Remo.server.RemoServerApp.main(RemoServerApp.java:97)
Caused by: java.lang.ClassNotFoundException: com.Remo.protocol.RemoConnection
    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)
    ... 2 more

MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.Remo.server.RemoServerApp

UPDATE 2

From your solution what i understood is that we need to copy the remoprotocol jar file to the remoserver.

remoserver project gradle file

apply plugin: 'java'

sourceSets {
    main {
        resources.srcDirs = ['src/main/resources']
    }
}

dependencies {
    compile project(':remoprotocol')
    compile files('libs/bluecove-2.1.1.jar')
}

jar {
    manifest.attributes(
            'Main-Class': "com.remo.server.remoServerApp"
    )
    manifest.attributes(
            'Class-Path': configurations.runtime.files.collect { it.getName() }.join(' '))
}

task copyRTDependenciesToLib(type: Copy) {
    into "$buildDir/output/lib"
    from configurations.runtime
}

After running the gradle task also i am getting the same error.

Community
  • 1
  • 1
Arulnadhan
  • 923
  • 4
  • 17
  • 46
  • Sounds like you need to add classpath as well to your manifest. Can you post your full manifest.mf? – RaGe Jan 04 '16 at 15:14
  • is the class `com/Remo/protocol/RemoConnection` contained in this jar? or are there any external dependency jars? – RaGe Jan 04 '16 at 15:15
  • @RaGe I have referenced the protocol module in the build.gradle file as a dependency. But they are not contained in my jar File. How can i add them ? – Arulnadhan Jan 04 '16 at 18:25
  • You don't have to bundle the protocol module inside your jar. You can just place the protocol jar in the same folder as your runnable jar, as long as your have a class-path entry in your runnable jar manifest.mf – RaGe Jan 04 '16 at 18:35

2 Answers2

4

First you want to copy all your runtime dependencies into the builddir/libs folder (or a different distribution folder if you so choose). Here is a custom task that would achieve this:

task copyRTDependenciesToLib(type: Copy) {
    into "$buildDir/libs"
    from configurations.runtime
}

Add your runtime dependency jars as a Class-Path attribute in your manifest file. The jars need to be in the same directory as your runnable jar - which the copy task above achieves. (alternatively, you can provide full relative path for your dependency jar location)

jar {
    manifest {
        attributes(
           "Main-Class": "com.Remo.server.RemoServerApp",
           "Class-Path": configurations.runtime.files.collect { it.getName() }.join(' '))
         )
    }
}

Some more things to consider:

  • The application plugin does the same thing; it adds a task installDist that produces a runnable set of jars along with any dependencies, any readme's, documentation you want to include.

  • If you want to produce a single runnable jar without having to bundle dependencies along with it, you should look into creating a "fatjar", for example:

    task fatJar(type: Jar) {
        manifest {
            attributes 'Implementation-Title': 'Gradle Jar File Example',  
                'Implementation-Version': version,
                'Main-Class': "com.Remo.server.RemoServerApp"
        }
        baseName = project.name
    
        //collect all dependencies
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
        with jar
    }
    
RaGe
  • 22,696
  • 11
  • 72
  • 104
  • Are these subprojects under a parent project? Or independent projects? – RaGe Jan 05 '16 at 12:22
  • In either case, and also because there may be other external dependencies, it probably is the simplest to create a custom copy task to copy all runtime dependencies into the build/lib folder of your runnable jar project. – RaGe Jan 05 '16 at 12:23
  • You probably also want to collect all dependency jars in the same folder as the runnable jar. Made changes in my answer to reflect this. – RaGe Jan 05 '16 at 14:20
  • did you run task `copyRTDependenciesToLib` before attempting to execute jar? – RaGe Jan 05 '16 at 17:03
  • just saw your project structure again, looks like the copy path should be `$buildDir/libs` – RaGe Jan 05 '16 at 18:47
  • Thanks a lot. fatJar was very useful. – Arulnadhan Jan 06 '16 at 03:46
-1

I have no experience with Android Studio (or Gradle), but I have with Java. Aren't you trying to set main class instead?

Therefore I suggest changing Class-Path attribute to Main-Class as the manifest should contain Main-Class to be able to invoke something when "running" JAR.

Miro Hudak
  • 2,155
  • 2
  • 21
  • 29
  • This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question, or deleted altogether. – Jared Rummler Jan 03 '16 at 10:47
  • With all due respect, if you read my response properly, you can see a suggestion there, which may lead (or may well be) an answer. So I will rephrase it and remove the question mark then. – Miro Hudak Jan 03 '16 at 21:31