Exporting Jar file with Manifest attribute in Android Studio? - java

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.

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
}

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.

Related

Gradle Jar type task doesn't package .class files from src/main

I defined a task "exeJar" with Jar type to package an executable jar, shown as below.
task exeJar(type: Jar, group: 'build', dependsOn: classes) {
description 'Package an executable jar.'
archiveClassifier.set('exe')
manifest {
attributes 'Main-Class': mainClassName
}
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
}
}
And I make the jar task exclude the main class.
jar{
exclude 'com/example/*class'
}
jar: packages an artifactId-version.jar file containing only the resources from src/main and excluding the main class.
exeJar: packages an executable artifactId-version-exe.jar file.
But the artifactId-version-exe.jar only contains the dependencies and excludes the resources from src/main directory, shown in the picture below.
Can someone explain why this happens and give a possible solution to make artifactId-version-exe.jar contain the main class?

Duplicate zip entry when creating an obfuscated application jar using proguard with gradle

The Java application itself contains no third party library dependencies. And if I remove the obfuscate task and the line jar.finalizedBy(project.tasks.obfuscate), the standard jar builds and is runnable.
Error ..
* What went wrong:
Execution failed for task ':obfuscate'.
> java.io.IOException: Can't write [/Users/rob/git/repo/build/libs/tool.out.jar] (Can't read [/Users/rob/git/repo/build/libs/tool.jar] (Duplicate zip entry [com/example/cli/j.class == tool.jar:com/example/cli/HelperUtils$5.class]))
build.gradle ..
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "build/libs/tool.jar"
outjars "build/libs/tool.out.jar"
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
}
jar {
archiveName = "tool.jar"
from sourceSets.main.output.classesDir
include '**/cli/*.class'
manifest {
attributes 'Main-Class': 'com.example.cli.Tool'
}
}
jar.finalizedBy(project.tasks.obfuscate)
proguard.txt ..
-keep public class com.example.cli.* {*;}
The application contains 3 Java class files ..
com.example.cli.Tool (which contains the main)
com.example.cli.HelperUtils
com.example.cli.CustomEnums
Added the following to the jar task:
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
..
}

Gradle dependency issue, java.lang.NoClassDefFoundError, but compiles

new to gradle and java here and I am trying to use Android's Log method from android.util.Log. It seems I can compile and it finds what it needs, but it can not find it at runtime. I have tried using 'runtime' instead of 'compile' in the dependencies section, but not luck.
java -jar build/libs/testJavaHttp.jar
Exception in thread "main" java.lang.NoClassDefFoundError: android/util/Log
at myproject.test.HttpToFile.downloadFile(HttpToFile.java:20)
at myproject.test.Main.main(Main.java:12)
Caused by: java.lang.ClassNotFoundException: android.util.Log
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
In build.gradle
apply plugin: 'java'
dependencies {
compile files('../androidsdk/platforms/android-25/android.jar')
}
jar {
manifest {
attributes 'Main-Class': 'myproject.test.Main'
}
}
You are trying to run the jar and the jar is not packed with dependencies, use shadow jar plugin or pack required artifacts in, by extending the jar task.
jar {
archiveName = 'Name.jar'
manifest {
attributes 'Main-Class': 'myproject.test.Main',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' '),
'Implementation-Version': 1.0
}
from(configurations.myconfig.collect { it.isDirectory() ? it : zipTree(it) }) {
// in here you can exclude what you need as well if needed.
}
}
To not pull the 'entire world' into a jar you can create configuration just with libraries you require:
configurations{
myconfig // to create configuration
compile.extendsFrom(myConfig) //to include it in compile as well
}
and then use this config in the jar creation and in dependecies.
dependencies {
myconfig files('../androidsdk/platforms/android-25/android.jar')
}
But looking at your code there is not much to pull there. You need to consider packing all needed artifacts and transitives if you expect it to be a runnable jar, as you run it with 'java -jar [...]' command.
PS. Everything that is in compile is going to be included in runtime configuration as well.

Gradle - no main manifest attribute

I'm building a JAR file with Gradle. When I try to run it I get the following error
no main manifest attribute, in RxJavaDemo.jar
I tried manipulating the manifest property but I think I'm forgetting to add the dependencies or something to it. What exactly am I doing wrong?
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'demo.MainDashboard'
dependencies {
compile files ("H:/Processes/Development/libraries/hikari-cp/HikariCP-2.4.1.jar")
compile files ("H:/Processes/Development/libraries/controls-fx/controlsfx.jar")
compile files ("H:/Processes/Development/libraries/database_connections/sqlite-jdbc-3.8.6.jar")
compile files ("H:/Processes/Development/libraries/guava/guava-18.0.jar")
compile files ("H:/Processes/Development/libraries/rxjava/rxjava-1.0.12.jar")
compile files ("H:/Processes/Development/libraries/rxjava-extras/rxjava-extras-0.5.15.jar")
compile files ("H:/Processes/Development/libraries/rxjavafx/RxJavaFX-1.0.0-RC1-SNAPSHOT.jar")
compile files ("H:/Processes/Development/libraries/rxjavaguava/rxjava-guava-1.0.3.jar")
compile files ("H:/Processes/Development/libraries/rxjava-jdbc/rxjava-jdbc-0.6.3.jar")
compile files ("H:/Processes/Development/libraries/slf4j/slf4j-api-1.7.12.jar")
compile files ("H:/Processes/Development/libraries/tom-commons/tom-commons.jar")
}
sourceSets {
main.java.srcDir "src/main/java"
main.resources.srcDir "src/main/resources"
}
jar {
manifest {
attributes(
"Class-Path": configurations.compile.collect { it.getName() }.join(' '))
}
from configurations.compile.collect { entry -> zipTree(entry) }
}
Try to change your manifest attributes like:
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'hello.HelloWorld'
)
}
}
And then just change 'hello.helloWorld' to '<your packagename>.<the name of your Main class>' (where your Main class has a main method). In this case, you make in your manifest an attribute, which point to this class, then a jar is running.
To make the jar file executable (so that the java -jar command works), specify the Main-Class attribute in MANIFEST.MF.
In Gradle, you can do it by configuring the jar task.
for Groovy DSL see these answers ([1], [2])
for Kotlin DSL you can use the following code snippet:
tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.caco3.Main"
}
}
Why mainClassName does not work as expected?
Or why mainClassName does not specify the attribute in the manifest?
The mainClassName property comes from the application plugin. The plugin:
makes it easy to start the application locally during development, and to package the application as a TAR and/or ZIP including operating system specific start scripts.
So the application plugin does not aim at producing executable jars
When a mainClassName property set, then:
$ ./gradlew run will launch the main method in the class specified in the attribute
the zip/tar archive built using distZip/distTar tasks will contain a script, which will launch the main method of the specified previously class.
Here is the line of shell script setting the main class:
$ grep Main2 gradletest
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLETEST_OPTS -classpath "\"$CLASSPATH\"" com.caco3.gradletest.Main2 "$APP_ARGS"
To complement Denis Zavedeev answer, here are more ways for Kotlin DSL (build.gradle.kts):
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
}
tasks.jar {
manifest {
attributes["Main-Class"] = "com.example.MyMainClass"
}
}
Side note: to create a runnable fat JAR (also called uber JAR), see this post.
FWIW - I used the following jar task to assemble all my compile dependencies into the jar file, and used the above recommendation to get the class-path properly set
apply plugin: 'java-library'
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'your.main.class.goes.here'
)
}
// You can reference any part of the dependency configurations,
// and you can have as many from statements as you need
from configurations.compile
// I just copied them into the top of the jar, so it looks like the eclipse exported
// runnable jar, but you could designate a lib directory, and reference that in the
// classpath as "lib/$it.name" instead of it.getName()
into ''
}

Creating runnable JAR with Gradle

Until now I created runnable JAR files via the Eclipse "Export..." functionallity but now I switched to IntelliJ IDEA and Gradle for build automation.
Some articles here suggest the "application" plugin, but this does not entirely lead to the result I expected (just a JAR, no start scripts or anything like this).
How can I achieve the same result Eclipse does with the "Export..." dialog?
An executable jar file is just a jar file containing a Main-Class entry in its manifest. So you just need to configure the jar task in order to add this entry in its manifest:
jar {
manifest {
attributes 'Main-Class': 'com.foo.bar.MainClass'
}
}
You might also need to add classpath entries in the manifest, but that would be done the same way.
See http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
If you already have defined an application context, you can re-use the definition rather than duplicate it:
application {
// Define the main class for the application.
mainClass = 'com.foo.bar.MainClass'
}
jar {
manifest {
attributes 'Main-Class': application.mainClass
}
}
Both JB Nizet and Jorge_B's answers are correct.
In its simplest form, creating an executable JAR with Gradle is just a matter of adding the appropriate entries to the manifest. However, it's much more common to have dependencies that need to be included on the classpath, making this approach tricky in practice.
The application plugin provides an alternate approach; instead of creating an executable JAR, it provides:
a run task to facilitate easily running the application directly from the build
an installDist task that generates a directory structure including the built JAR, all of the JARs that it depends on, and a startup script that pulls it all together into a program you can run
distZip and distTar tasks that create archives containing a complete application distribution (startup scripts and JARs)
A third approach is to create a so-called "fat JAR" which is an executable JAR that includes not only your component's code, but also all of its dependencies. There are a few different plugins that use this approach. I've included links to a few that I'm aware of; I'm sure there are more.
shadow
one-jar
spring-boot
capsule
Least effort solution for me was to make use of the gradle-shadow-plugin
Besides applying the plugin all that needs to be done is:
Configure the jar task to put your Main class into manifest
jar {
manifest {
attributes 'Main-Class': 'com.my.app.Main'
}
}
Run the gradle task
./gradlew shadowJar
Take the app-version-all.jar from build/libs/
And finally execute it via:
java -jar app-version-all.jar
As others have noted, in order for a jar file to be executable, the application's entry point must be set in the Main-Class attribute of the manifest file. If the dependency class files are not collocated, then they need to be set in the Class-Path entry of the manifest file.
I have tried all kinds of plugin combinations and what not for the simple task of creating an executable jar and somehow someway, include the dependencies. All plugins seem to be lacking one way or another, but finally I got it like I wanted. No mysterious scripts, not a million different mini files polluting the build directory, a pretty clean build script file, and above all: not a million foreign third party class files merged into my jar archive.
The following is a copy-paste from here for your convenience..
[How-to] create a distribution zip file with dependency jars in subdirectory /lib and add all dependencies to Class-Path entry in the manifest file:
apply plugin: 'java'
apply plugin: 'java-library-distribution'
repositories {
mavenCentral()
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.3.2'
}
// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)
jar {
// Keep jar clean:
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
manifest {
attributes 'Main-Class': 'com.somepackage.MainClass',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
}
// How-to add class path:
// https://stackoverflow.com/questions/22659463/add-classpath-in-manifest-using-gradle
// https://gist.github.com/simon04/6865179
}
Hosted as a gist here.
The result can be found in build/distributions and the unzipped contents look like this:
lib/commons-lang3-3.3.2.jar
MyJarFile.jar
Contents of MyJarFile.jar#META-INF/MANIFEST.mf:
Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib/commons-lang3-3.3.2.jar
This is for Kotlin DSL (build.gradle.kts).
Method 1 (no need for application or other plugins)
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
// OR another notation
// manifest {
// attributes["Main-Class"] = "com.example.MyMainClass"
// }
}
If you use any external libraries, use below code. Copy library JARs in libs sub-directory of where you put your result JAR. Make sure your library JAR files do not contain space in their file name.
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
manifest.attributes["Class-Path"] = configurations
.runtimeClasspath
.get()
.joinToString(separator = " ") { file ->
"libs/${file.name}"
}
}
Note that Java requires us to use relative URLs for the Class-Path attribute. So, we cannot use the absolute path of Gradle dependencies (which is also prone to being changed and not available on other systems). If you want to use absolute paths, maybe this workaround will work.
Create the JAR with the following command:
./gradlew jar
The result JAR will be created in build/libs/ directory by default.
Method 2: Embedding libraries (if any) in the result JAR (fat or uber JAR)
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree) // OR .map { zipTree(it) }
from(dependencies)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Creating the JAR is exactly the same as the previous method.
Method 3: Using the Shadow plugin (to create a fat or uber JAR)
plugins {
id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these will be reflected for Shadow as well
tasks.jar {
manifest.attributes["Main-Class"] = "org.example.MainKt"
}
Create the JAR with this command:
./gradlew shadowJar
See Shadow documentations for more information about configuring the plugin.
Running the created JAR
java -jar my-artifact.jar
The above solutions were tested with:
Java 17
Gradle 7.1 (which uses Kotlin 1.4.31 for .kts build scripts)
See the official Gradle documentation for creating uber (fat) JARs.
For more information about manifests, see Oracle Java Documentation: Working with Manifest files.
Note that your resource files will be included in the JAR file automatically (assuming they were placed in /src/main/resources/ directory or any custom directory set as resources root in the build file). To access a resource file in your application, use this code (note the / at the start of names):
Kotlin
val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText()
// Alternative ways:
// val vegetables = object{}.javaClass.getResource("/vegetables.txt").readText()
// val vegetables = MyClass::class.java.getResourceAsStream("/vegetables.txt").reader().readText()
// val vegetables = object{}.javaClass.getResourceAsStream("/vegetables.txt").reader().readText()
Java
var stream = MyClass.class.getResource("/vegetables.txt").openStream();
// OR var stream = MyClass.class.getResourceAsStream("/vegetables.txt");
var reader = new BufferedReader(new InputStreamReader(stream));
var vegetables = reader.lines().collect(Collectors.joining("\n"));
You can use the SpringBoot plugin:
plugins {
id "org.springframework.boot" version "2.2.2.RELEASE"
}
Create the jar
gradle assemble
And then run it
java -jar build/libs/*.jar
Note: your project does NOT need to be a SpringBoot project to use this plugin.
Have you tried the 'installApp' task? Does it not create a full directory with a set of start scripts?
http://www.gradle.org/docs/current/userguide/application_plugin.html
Thank you Konstantin, it worked like a charm with few nuances. For some reason, specifying main class as part of jar manifest did not quite work and it wanted the mainClassName attribute instead. Here is a snippet from build.gradle that includes everything to make it work:
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
baseName = 'myapp'
}
After running gradle shadowJar you get myapp-{version}-all.jar in your build folder which can be run as java -jar myapp-{version}-all.jar.
You can define a jar artifact in the module settings (or project structure).
Right click the module > Open module settings > Artifacts > + > JAR > from modules with dependencies.
Set the main class.
Making a jar is then as easy as clicking "Build artifact..." from the Build menu. As a bonus, you can package all the dependencies into a single jar.
Tested on IntelliJ IDEA 14 Ultimate.
I checked quite some links for the solution, finally did the below mentioned steps to get it working. I am using Gradle 2.9.
Make the following changes in your build,gradle file :
Mention plugin:
apply plugin: 'eu.appsatori.fatjar'
Provide the Buildscript:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
}
}
Provide the Main Class:
fatJar {
classifier 'fat'
manifest {
attributes 'Main-Class': 'my.project.core.MyMainClass'
}
exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
}
Create the fatjar:
./gradlew clean fatjar
Run the fatjar from /build/libs/ :
java -jar MyFatJar.jar
Here is the solution I tried with Gradle 6.7
Runnable fat Jar (with all dependent libraries copied to the jar)
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.gradle.App'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
}
Runnable jar with all dependencies copied to a directory and adding the classpath to the manifest
def dependsDir = "${buildDir}/libs/dependencies/"
task copyDependencies(type: Copy) {
from configurations.compile
into "${dependsDir}"
}
task createJar(dependsOn: copyDependencies, type: Jar) {
manifest {
attributes('Main-Class': 'com.example.gradle.App',
'Class-Path': configurations.compile.collect { 'dependencies/' + it.getName() }.join(' ')
)
}
with jar
}
How to use ?
Add the above tasks to build.gradle
Execute gradle fatJar //create fatJar
Execute gradle createJar // create jar with dependencies copied.
More details : https://jafarmlp.medium.com/a-simple-java-project-with-gradle-2c323ae0e43d
Configure Main Class to your Manifest
If you are using gradle project, just add the following into your build.gradle
jar {
manifest {
attributes(
'Main-Class': 'pokerhandscorer.PokerHandScorer'
)
}
}
Where 'pokerhandscorer' is the name of the package name,
and PokerHandScorer is the main class name
This creates a jar file into your \build\libs{jarFilename}.jar
Run jar file using java -jar /{path}/{jarFileName.jar}
java -jar /{path}/{jarFileName.jar}

Categories