"No main manifest attribute" when creating Kotlin jar using IntelliJ IDEA - intellij-idea

When creating a jar from my Kotlin code and running it, it says "No main manifest attribute".
When looking at the manifest.mf, it has this content:
Manifest-Version: 1.0
When looking at the file in the source, it has this content:
Manifest-Version: 1.0
Main-Class: MyMainClass
When manually copying the source manifest to the jar, it runs perfectly.
Screenshot of my artifact settings

I got this error with Gradle and Kotlin.
I had to add in my build.gradle.kts an explicit manifest attribute:
tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.example.MainKt"
}
}
From the gradle documentation, it's better to create a fatJar task to englobe all of the runtime dependencies in case you encounter java.lang.NoClassDefFoundError errors

If any of the dependent jars has a MANIFEST.MF file, it will override your custom one which defines the Main-Class.
In order to address this problem you should do the following:
Disable the alphabetical ordering
Change items ordering so that item which has META-INF/MANIFEST.MF file is the first in the list
Your custom MANIFEST.MF will be picked up by IntelliJ IDEA and displayed for the jar artifact.
See the related issue for more details.
You can also use Gradle or Maven to generate the fat jar instead.

1.Add the following task definition in the build script
tasks.jar {
manifest {
attributes["Main-Class"] = "MainKt"
}
configurations["compileClasspath"].forEach { file: File ->
from(zipTree(file.absoluteFile))
}
}
Then the jar tasks (Tasks | build | jar) again from the right hand sidebar.

For Spring boot apps:
What worked for me (gradle kotlin) in build.gradle.kts
add spring boots plugin &. apply dependency management
plugins {
id("org.springframework.boot") version "2.6.7"
}
apply(plugin = "io.spring.dependency-management")
set your main class
springBoot {
mainClass.set("com.example.Application")
}
Found this all by reading up on spring-boot docs found here

Related

Multi-project Gradle+Kotlin: How to create Jar containing all sub-projects using Kotlin DSL?

I have a Gradle project with two subprojects. The parent does not contain any code; all the Kotlin code is in the two subprojects. All Gradle build files are defined in the Kotlin DSL.
Upon building, Gradle generates two JAR files, one in the build subfolder of each subproject. I believe this is the intended default behavior of Gradle. But this is not what I want.
I want to publish the JAR file of the parent project as a Maven artifact. Therefore, I need both subprojects to be included in one JAR file. How can I achieve this?
Note: On this web page, the author seems to achieve pretty much what I would need in this code snippet:
apply plugin: "java"
subprojects.each { subproject -> evaluationDependsOn(subproject.path)}
task allJar(type: Jar, dependsOn: subprojects.jar) {
baseName = 'multiproject-test'
subprojects.each { subproject ->
from subproject.configurations.archives.allArtifacts.files.collect {
zipTree(it)
}
}
}
artifacts {
archives allJar
}
However, this is defined in Gradle's native Groovy DSL. And I find myself unable to translate it into the Kotlin DSL. I tried to put a Groovy build file (*.gradle) besides the Kotlin build file (*.gradle.kts), but this led to a strange build error. I'm not sure if mixed build file languages are supported. Besides, I would consider it bad practice too. Better only define all build files in just one language.
Also, the example above pertains to the Java programming language. But I do not expect this to be a big problem, as both Java and Kotlin produce JVM bytecode as compile output.
More clarification:
I am not talking about a "fat JAR". Dependencies and the Kotlin library are not supposed to be included in the JAR.
I do not care if the JAR files for the subprojects are still getting built or not. I'm only interested in the integrated JAR that contains both subprojects.
The main point is getting the combined JAR for the binaries. Combined JARs for the sources and JavaDoc would be a nice-to-have, but are not strictly required.
I would use the Gradle guide Creating "uber" or "fat" JARs from the Gradle documentation as a basis. What you want is essentially the same thing. It's also much better than the Groovy example you found, as it doesn't use the discouraged subprojects util, or 'simple sharing' that requires knowing how the other projects are configured.
Create a configuration for resolving other projects.
// build.gradle.kts
val mergedJar by configurations.creating<Configuration> {
// we're going to resolve this config here, in this project
isCanBeResolved = true
// this configuration will not be consumed by other projects
isCanBeConsumed = false
// don't make this visible to other projects
isVisible = false
}
Use the new configuration to add dependencies on the projects we want to add into our combined Jar
dependencies {
mergedJar(project(":my-subproject-alpha"))
mergedJar(project(":my-subproject-beta"))
}
Now copy the guide from the docs, except instead of using configurations.runtimeClasspath we can use the mergedJar configuration, which will only create the subprojects we specified.
However we need to make some modifications.
I've adjusted the example to edit the existing Jar task rather than creating a new 'fatJar' task.
for some reason, setting isTransitive = false causes Gradle to fail resolution. Instead I've added a filter (it.path.contains(rootDir.path)) to make sure the Jars we're consuming are inside the project.
tasks.jar {
dependsOn(mergedJar)
from({
mergedJar
.filter {
it.name.endsWith("jar") && it.path.contains(rootDir.path)
}
.map {
logger.lifecycle("depending on $it")
zipTree(it)
}
})
}

Annotation Processor in IntelliJ and Gradle

tl;dr: I cannot configure IntelliJ to generate the java files in the same directory as gradle
I have a small project which uses the immutables annotation processor.
It works as expected in the gradle command line build, but I cannot get IntelliJ to output the generated files to the same directory.
The full project is available on GitLab
Gradle config:
I use the folowing gradle plugins:
gradle-idea plugin which handles the idea configuration
gradle-apt-plugin which provides the apt configuration and handles the compile-class path and idea config related to annotation processing (if also the idea plugin is applied)
relevant parts of the build-script (link to the full listing):
apply plugin: 'java'
apply plugin: "net.ltgt.apt"
apply plugin: 'idea'
dependencies {
def immutablesVersion = '2.3.9'
compileOnly "org.immutables:value:$immutablesVersion:annotations"
compileOnly "org.immutables:encode:$immutablesVersion"
apt "org.immutables:value:$immutablesVersion"
}
when I start ./gradlew build everything is as expected:
The source file DataEncoding.java is processed an the generated java-file DataEncodingEnabled.java ends up in
/build/generated/source/apt/main under the expected package com.tmtron.immutables.data
and the generated file is also compiled to a .class file
In IntelliJ I activate the annotation processing as suggested by the gradle-apt-plugin docs:
Then I execute ./gradlew clean to make sure, that the previous files are gone and then I click Build - Build Project in IntelliJ.
The annotation processor is executed, but the problem is that the generated java file ends up in the wrong location:
It is in: /build/generated/source/apt/main/build/generated/source/apt/main/com.tmtron.immutables.data
the bold part is redundant.
What am I doing wrong and how can I set it up correctly, so that IntelliJ and gradle generate the files in the same directory?
Notes:
I have of course already tried to just leave the "Production sources dir" in the IntelliJ annotation configuration empty, but his does not work: then it automatically uses "generated" and I also end up with a wrong path.
IntelliJ version 2016.3.4
Now https://github.com/tbroyer/gradle-apt-plugin states:
The goal of this plugin was to eventually no longer be needed, being superseded by built-in features. This is becoming a reality with Gradle 5.2 and IntelliJ IDEA 2019.1.
So:
dependencies {
compile("com.google.dagger:dagger:2.18")
annotationProcessor("com.google.dagger:dagger-compiler:2.18")
compileOnly("com.google.auto.factory:auto-factory:1.0-beta6")
annotationProcessor("com.google.auto.factory:auto-factory:1.0-beta6")
compileOnly("org.immutables:value-annotations:2.7.1")
annotationProcessor("org.immutables:value:2.7.1")
}
compileOnly is necessary if you use annotations, compile if you use classes, annotationProcessor introduced in Gradle 4.6.
To enable processing specific compile task:
compileJava {
options.annotationProcessorPath = configurations.annotationProcessor
}
To disable:
compileTestJava {
options.compilerArgs += '-proc:none'
}
UPDATE 2.2019
since Gradle 5.2 there is an easy way to do it - see gavenkoas answer
UPDATE 5.2018
The easiest way, I know of is to use the apt-idea plugin
Just activate the plugin in the build.gradle file:
plugins {
id 'java'
id 'net.ltgt.apt-idea' version "0.15"
}
and then add the annotation processors to the annotationProcessor configuration:
final DAGGER_VER = '2.16'
dependencies {
implementation "com.google.dagger:dagger:${DAGGER_VER}"
annotationProcessor"com.google.dagger:dagger-compiler:${DAGGER_VER}"
}
Test-project on GitHub: ex.dagger
(using IntelliJ 2018.1.4, Gradle 4.7)
ORIG ANSWER
There's a simple workaround using the parent-dir which works fine in IntelliJ 2016.3.4
Production sources directory: ../main
Test sources directory: ../test
Now gradle and IntelliJ will generate the code to the same directories.
Fixed in GitLab project V0.0.2
see also: apt-gradle-plugin issue#35
Hey there everyone I had the same issue and found a clean way of solving this issue.
I am using two libraries that require annotation processing (Lombok and MapStruct).
Also my IntelliJ is 2019.1 (update yours in case it's older) and Gradle 5.2.1.
First let's configure IntelliJ:
Disable Annotaion Processing in Settings, since we're going to delegate everything to Gradle:
Delegeate IDE actions to Gradle:
Last step is to configure your dependencies correctly in Gradle.
Dependencies section in Gradle:
Now you can execute the Build and Run from both command line and IDE.
Cheers!
2019.2.x
Disable annotation processor of intellij
add, build directory in your gradle build.gradle file
then run your gradle task to generate build file classes, example gradle compileJava
File -> project structure -> Modules -> Main Folder || remove exclude and add as source
And project should find all annotation and generated source file. Hope it helps.

Using autosuggest on dependency jars that are downloaded by Gradle

I'm pretty new to Gradle and IntelliJ and I'm trying to understand how it works [cos that's what my project uses]. I created a simple java project in Intellij IDEA with a HelloWorld class and manually added the gradle.build file along with the necessary dependencies as follows:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
mainClassName = 'main.java.test.HelloWorld'
dependencies {
compile 'joda-time:joda-time:2.2'
}
repositories {
mavenLocal()
mavenCentral()
}
jar {
baseName = 'gradle-test'
manifest {
attributes 'Main-Class': 'main.java.test.HelloWorld'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2'
}
While I specified the joda-time dependency, my IntelliJ project is unaware of this library and therefore I can't use of any of the autosuggest features of IntelliJ for the joda-time library.
Could someone give me information on how I can get IntelliJ to automatically start recognizing the downloaded jars and allow me to use the auto-suggest features?
In other words,
where are the dependency jars downloaded ?
How can I have these jars to automatically be included in the
class path of the project ? [Is it ok to do so ? If not, what
would be your recommendation ?]
Thanks !
I used Peter's suggestion to run gradle idea and imported the project into IntelliJ and I was able to start using the auto-suggestion features in IntelliJ.
Thanks

Provided dependencies using Gradle (JetGradle) and Intellij Idea 13

I have a multiproject build with multiple war modules that depends on one jar module.
Both war and jar modules have dependencies over libraries like Spring, Hibernate and so on, those dependencies are defined as providedCompile on the war modules and as compile on the jar.
The problem is that when JetGradle updates the dependencies all artifacts have errors, as the dependencies from the jar module are required on the artifacts.
I would like to use any of this solutions:
Include the libraries on the lib folder of the server and have Intellij treat them as provided.
Include the libraries as project wide libraries somehow, so intellij puts them on all artifacts even after the gradle dependencies are updated.
On the other hand my approach could be completely wrong from the beginning.
The dependencies in the war modules are defined as:
providedCompile 'org.slf4j:slf4j-log4j12:1.7.5'
providedCompile 'org.slf4j:jcl-over-slf4j:1.7.5'
...
compile(project(':jarModule')) {transitive = false}
...
The dependencies in the jar module are defined as:
...
compile 'org.slf4j:slf4j-log4j12:1.7.5'
compile 'org.slf4j:jcl-over-slf4j:1.7.5'
...
The best solution I found was to set the transitive "compile" dependencies from the jar module as provided using the following code in the Gradle configuration file:
apply plugin: 'idea'
configurations {
provided
provided.extendsFrom(compile)
}
idea {
module {
scopes.PROVIDED.plus += configurations.provided
}
}
For Gradle 2.0+ modify the last bit to be like this:
idea {
module {
scopes.PROVIDED.plus += [configurations.provided]
}
}
This solution works using the Intellij Gradle plugin and also the idea task in Gradle
I got this solution working based on the info on this urls:
https://github.com/Netflix/RxJava/pull/145
http://www.gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
I hope this helps someone else
I tried the above solution but found a problem. In my scenario I had a sub-project that had the above configuration. The problem was that the transitive dependencies of the sub-project were not being exported in the IntelliJ configuration, which caused the base project to stop compiling.
I did some digging around and stumbled upon this little gem which fixed the problem.
https://github.com/gradle/gradle/blob/ccddc438ce09293d84030ebe31668d739c8a228a/gradle/providedConfiguration.gradle
/**
* Adds a configuration named 'provided'. 'Provided' dependencies
* are incoming compile dependencies that aren't outgoing
* dependencies. In other words, they have no effect on transitive
* dependency management.
*/
configurations {
provided
providedPlusCompile.extendsFrom(compile, provided)
testCompile.extendsFrom(providedPlusCompile)
}
sourceSets.main {
compileClasspath = configurations.providedPlusCompile
}
plugins.withType(IdeaPlugin) {
idea.module.scopes.PROVIDED.plus = [ configurations.provided ]
}
Adding to the answer from Adrijardi, for Gadle 2.0 + not only did I have to change
scopes.PROVIDED.plus += configurations.provided
to
scopes.PROVIDED.plus += [configurations.provided]
I also had to change
provided project(":module-name") {
transitive = false
}
to
provided (project(":module-name")) {
transitive = false
}
Note the extra set of brackets on the second code sample

Gradle script to move artifacts between Maven repos

I'm working on a Gradle script to copy an artifact from one Maven repo to another. I was trying to hack it by putting the artifact as a dependency and then us setting that as an archive.
I've tried using the configuration.files() method but I haven't been able to build a dependency object that it will accept.
dependencies {
compile group: artGroup, name: artName, version: artVersion
}
artifacts {
archives configurations.default.files(
/* I have not been able to build an argument this method accepts */
)
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: 'file:../../../repo')
}
}
}
We did this already in other environment (copying files from remote to local), and it looks like you got some misconceptions with Gradle DSL.
First the artifacts { archives {}} is used to ADD deployable artifacts to the archives configurations. You cannot use it (in term of doing something with the configurations files) in this block.
Second, you cannot upload what you resolved "as-is". Upload is for artifacts produced or manual added (they have a special type) by the build.
For us the solution was to create a new Gradle task "copyArtifacts" that actually copy all the files of resolved configuration into the local folder.
Hope this helps.