'Spring boot gradle project deployed to heroku using bitbucket pipeline gives error no main manifest attribute, in build/libs/app-SNAPSHOT-plain.jar
I have a Spring boot gradle project built using IntelliJIDEA with gradle.build:
plugins {
id 'org.springframework.boot' version '2.5.5'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'pk.inlab.app.web'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// Apache commons
implementation 'commons-beanutils:commons-beanutils:1.9.4'
// Jwt
implementation 'io.jsonwebtoken:jjwt:0.9.1'
// OpenAPI and Swagger
implementation 'org.springdoc:springdoc-openapi-ui:1.5.11'
implementation 'org.springdoc:springdoc-openapi-data-rest:1.5.11'
// Passy
implementation 'org.passay:passay:1.6.1'
// Thymeleaf for registration email with template
implementation 'org.thymeleaf:thymeleaf-spring5'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
// Rest Assured
testImplementation 'io.rest-assured:spring-mock-mvc:4.4.0'
// hamcrest-library
testImplementation 'org.hamcrest:hamcrest-library:2.2'
}
test {
useJUnitPlatform()
}
the project works well on local machine, when pushed to bitbucket with pipeline setting file bitbucket-pipelines.yml:
# Template Java Gradle build
# This template allows you to test and build your Java project with Gradle.
# The workflow allows running tests, code checkstyle and security scans on the default branch.
# Prerequisites: appropriate project structure should exist in the repository.
image: gradle:7.2
pipelines:
default:
- parallel:
- step:
name: Build and Test
caches:
- gradle
script:
- gradle clean build
- git archive --format=tar.gz master -o application.tar.gz
- pipe: atlassian/heroku-deploy:1.2.1
variables:
HEROKU_API_KEY: $HEROKU_API_KEY
HEROKU_APP_NAME: $HEROKU_APP_NAME
ZIP_FILE : "application.tar.gz"
after-script:
- pipe: atlassian/checkstyle-report:0.2.0
- step:
name: Security Scan
script:
# Run a security scan for sensitive data.
# See more security tools at https://bitbucket.org/product/features/pipelines/integrations?&category=security
- pipe: atlassian/git-secrets-scan:0.4.3
the build logs are all correct, it shows:
-----> Building on the Heroku-20 stack
-----> Using buildpack: heroku/gradle
-----> Gradle app detected
-----> Spring Boot detected
-----> Installing JDK 1.8... done
-----> Building Gradle app...
-----> executing ./gradlew build -x check
To honour the JVM settings for this build a single-use Daemon process will be forked. See https://docs.gradle.org/7.2/userguide/gradle_daemon.html#sec:disabling_the_daemon.
Daemon will be stopped at the end of the build
> Task :compileJava
> Task :processResources
> Task :classes
> Task :bootJarMainClassName
> Task :bootJar
> Task :jar
> Task :assemble
> Task :build
BUILD SUCCESSFUL in 20s
5 actionable tasks: 5 executed
-----> Discovering process types
Procfile declares types -> (none)
Default types for buildpack -> web
-----> Compressing...
Done: 99.4M
-----> Launching...
Released v8
https://rest-todo-work.herokuapp.com/ deployed to Heroku
after all when I visit the site its shows:
when I check heroku logs it shows:
2021-10-26T04:35:07.000000+00:00 app[api]: Build started by user [email protected]
2021-10-26T04:35:46.654664+00:00 app[api]: Release v8 created by user [email protected]
2021-10-26T04:35:46.654664+00:00 app[api]: Deploy cf272d57 by user [email protected]
2021-10-26T04:35:46.918113+00:00 heroku[web.1]: State changed from crashed to starting
2021-10-26T04:35:50.193127+00:00 heroku[web.1]: Starting process with command `java -Dserver.port=37836 $JAVA_OPTS -jar build/libs/*.jar`
2021-10-26T04:35:50.877195+00:00 app[web.1]: Create a Procfile to customize the command used to run this process: https://devcenter.heroku.com/articles/procfile
2021-10-26T04:35:50.890431+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2021-10-26T04:35:50.894017+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2021-10-26T04:35:50.954182+00:00 app[web.1]: no main manifest attribute, in build/libs/to-do-0.0.1-SNAPSHOT-plain.jar
2021-10-26T04:35:51.082759+00:00 heroku[web.1]: Process exited with status 1
2021-10-26T04:35:51.148321+00:00 heroku[web.1]: State changed from starting to crashed
2021-10-26T04:36:03.000000+00:00 app[api]: Build succeeded
2021-10-26T04:39:01.736780+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=rest-todo-work.herokuapp.com request_id=21a8013c-0771-4758-8245-a575145bc3b0 fwd="111.119.183.2" dyno= connect= service= status=503 bytes= protocol=https
2021-10-26T04:39:02.249498+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=rest-todo-work.herokuapp.com request_id=7fd63420-a032-49ef-bd81-990df93bc5d1 fwd="111.119.183.2" dyno= connect= service= status=503 bytes= protocol=https
all right when I wanted to solve no main manifest attribute, I found a SO post which suggests to add:
jar {
manifest {
attributes 'Main-Class': 'pk.inlab.app.web.todo.ToDoApplication'
}
}
in gradle file, I added and heroku logs are:
2021-10-26T04:28:04.396482+00:00 heroku[web.1]: State changed from crashed to starting
2021-10-26T04:28:07.756486+00:00 heroku[web.1]: Starting process with command `java -Dserver.port=45162 $JAVA_OPTS -jar build/libs/*.jar`
2021-10-26T04:28:09.250355+00:00 app[web.1]: Create a Procfile to customize the command used to run this process: https://devcenter.heroku.com/articles/procfile
2021-10-26T04:28:09.274928+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2021-10-26T04:28:09.278725+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2021-10-26T04:28:09.420855+00:00 app[web.1]: Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
2021-10-26T04:28:09.420930+00:00 app[web.1]: at pk.inlab.app.web.todo.ToDoApplication.main(ToDoApplication.java:12)
2021-10-26T04:28:09.420987+00:00 app[web.1]: Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
2021-10-26T04:28:09.421018+00:00 app[web.1]: at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
2021-10-26T04:28:09.421046+00:00 app[web.1]: at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
2021-10-26T04:28:09.421075+00:00 app[web.1]: at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
2021-10-26T04:28:09.421102+00:00 app[web.1]: at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
2021-10-26T04:28:09.421129+00:00 app[web.1]: ... 1 more
2021-10-26T04:28:09.609559+00:00 heroku[web.1]: Process exited with status 1
this adds a new error. Any suggestions for these issues.
Solution 1:[1]
I was facing the same issue and tried to search a legit solution, in the end I found that, all you have to do is to add :
bootJar {
archiveClassifier.set('boot')
}
jar {
archiveClassifier.set('')
}
and let the gradle handle all other things, let me paste contents of gradle.build file which worked:
plugins {
id 'org.springframework.boot' version '2.5.5'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'pk.inlab.app.web'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// Apache commons
implementation 'commons-beanutils:commons-beanutils:1.9.4'
// implementation 'org.apache.commons:commons-collections4:4.4'
// Jwt
implementation 'io.jsonwebtoken:jjwt:0.9.1'
// OpenAPI and Swagger
implementation 'org.springdoc:springdoc-openapi-ui:1.5.11'
implementation 'org.springdoc:springdoc-openapi-data-rest:1.5.11'
// Passy
implementation 'org.passay:passay:1.6.1'
// Thymeleaf for registration email with template
implementation 'org.thymeleaf:thymeleaf-spring5'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
// Rest Assured
testImplementation 'io.rest-assured:spring-mock-mvc:4.4.0'
// hamcrest-library
testImplementation 'org.hamcrest:hamcrest-library:2.2'
}
// Add these START
bootJar {
archiveClassifier.set('boot')
}
jar {
archiveClassifier.set('')
}
// Add these END
test {
useJUnitPlatform()
}
It was the solution which worked for me, hope will work for you as well.
Solution 2:[2]
It seems you're deploying/starting the wrong jar file.
2021-10-26T04:35:50.954182+00:00 app[web.1]: no main manifest attribute, in build/libs/to-do-0.0.1-SNAPSHOT-plain.jar
The Spring Boot Gradle plugin gives you two jar files when executing gradlew build:
build/libs/to-do-0.0.1-SNAPSHOT-plain.jar- Created by the defaultjartask and contains only the compiled sources and resources of the project. Even when adding theMain-Classmanifest attribute, dependencies are not present and consequentlyClassNotFoundExceptionis raised.build/libs/to-do-0.0.1-SNAPSHOT.jar- Contributed by thebootJartask and, in addition to the regularjarcontents, also includes all required dependencies to run the application as injava -jar to-do-0.0.1-SNAPSHOT.jar.
That being said, you must deploy build/libs/to-do-0.0.1-SNAPSHOT.jar rather than the -plain one.
According to the Heroku output (build/libs/*.jar) it may be that both are deployed and started:
Starting process with command
java -Dserver.port=37836 $JAVA_OPTS -jar build/libs/*.jar
Without knowing too much about Heroku, you could prevent this from happening by building the bootJar only, e.g. by skipping the jar task in you build pipeline: gradlew clean build -x jar.
Solution 3:[3]
The same problem happened to me, as heroku runs the jar with the command java -Dserver.port=$PORT $JAVA_OPTS -jar build/libs/*.jar it for some reason was running the jar with the final SNAPSHOT-plain.jar. what I did was basically remove the generation of the SNAPSHOT-plain.jar, leaving only the executable jar.
Using the plugin java:
plugins {
id("org.springframework.boot") version "2.6.3"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.6.10"
kotlin("plugin.spring") version "1.6.10"
id ("java")
}
And putting the task:
tasks.jar {
enabled = false
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | Dauto Freitas |

