Spring boot executable jar can not resolve freemarker template - spring

I am learning web application building with spring boot and java. I've got my app working when I run it through Spring Tool Suite but after I build executable jar using bootRepackage and run it, It's not able to resolve the freemarker views.
I am not sure what's wrong. Any help would be appreciated.
Following is my application.properties related to freemarker,
spring.http.encoding.charset=UTF-8
spring.freemarker.cache=false
spring.freemarker.charset=utf-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.enabled=true
spring.freemarker.suffix=.html
spring.freemarker.template-loader-path=classpath:/templates/,classpath:/templates/web/
My jar structure,
BOOT-INF
classes
com
scss
static
templates
web
story.html
app
application.properties
log4j2.xml
META-INF
org
my controller,
#Controller
public class HomeController {
#Autowired
private AppLog appLogger;
#RequestMapping("/")
public ModelAndView Index(HttpServletRequest request) {
appLogger.log(Level.ERROR,AppLogSource.Web, "Reached Controller", null);
String testAttribute = request.getAttribute("com.demo.test").toString();
Map<String, String> vm = new HashMap<String, String>();
vm.put("testAttribute", testAttribute);
return new ModelAndView("/web/story", vm);
}
}
I verified that I am hitting the log step so I think issue is in resolving the view but I could be wrong and missing something else. So let me know if you need more info.
Thanks again!
Best,
Mrunal
edit
Gradle File,
buildscript {
ext {
springBootVersion = '1.4.1.RELEASE'
}
repositories {
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("com.moowork.gradle:gradle-node-plugin:1.2.0")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
apply plugin: 'com.moowork.node'
apply plugin: 'com.moowork.grunt'
jar {
baseName = 'testDemo'
version = '0.0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
node {
version = '6.11.3'
npmVersion = '3.10.10'
download = true
}
task gruntMinifyJs(type: GruntTask){
args=['minifyJs', '--debug']
}
task gruntMinifyCss(type: GruntTask){
args=['minifyCss', '--debug']
}
task buildFrontEnd(type: GruntTask) {
args = ['default', '--debug']
}
npmInstall.dependsOn(nodeSetup)
buildFrontEnd.dependsOn(npmInstall)
gruntMinifyCss.dependsOn(npmInstall)
gruntMinifyJs.dependsOn(npmInstall)
build.dependsOn(buildFrontEnd)
configurations {
all*.exclude group: 'ch.qos.logback', module:'logback-classic'
all*.exclude group: 'ch.qos.logback', module:'logback-core'
}
dependencies {
compile('org.springframework.boot:spring-boot-devtools')
compile('org.springframework.boot:spring-boot-starter-freemarker')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter:1.4.1.RELEASE'){
exclude group:'org.springframework.boot', module:'spring-boot-starter-logging'
}
compile('org.springframework.boot:spring-boot-starter-jdbc'){
exclude group:'org.apache.tomcat', module:'tomcat-jdbc'
}
compile('mysql:mysql-connector-java')
compile('com.zaxxer:HikariCP-java6:2.3.13')
compile('org.springframework.boot:spring-boot-starter-log4j2:1.4.1.RELEASE')
compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.8')
compile('com.google.zxing:core:3.3.0')
compile('org.antlr:antlr4-runtime:4.5')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
edit 3,
further updates,
So I attached remote debugger and I found that spring is using ContentNegotiatingViewResolver to resolve the view as InternalResourceView but when I execute through spring tool suite it resolves properly to FreemarkerView.
I hope this helps someone to narrow down my issue. I'll see if I can get anywhere else in mean time by stepping through debugger.

Perhaps the freemarker jar file is not specified as a dependency in your spring boot application module. Unsure if you are running maven or gradle but do make sure you have the freemarker library included in your build.
See downloads # https://mvnrepository.com/artifact/org.freemarker/freemarker

Related

Spring boot multi project with gradle generates the same jar

I'm new to gradle and I'm having trouble generating multiple jars with spring boot.
I generate two different builds, but when I run build A or build B, both are A
My project has the following structure:
root
├── facade
├─── rest-api
└─── web-api
├── dependencies
├─── services
├─── entities
└─── ...
├── settings.gradle
└── build.gradle
My intention is to have a mono repo of micro services. The micro services I will generate are the web api and rest api modules of the facade directory. These modules have dependencies of the module called dependencies as its name indicates.
As I described before, when I run the web api module, it's like I'm running rest api, even asking for its dependencies.
My settings.gradle:
rootProject.name = "root"
include ":root:facade:rest-api"
include ":root:facade:web-api"
include ":root:dependencies:entities"
include ":root:dependencies:services"
...
And my build.gradle
buildscript {
ext.kotlin_version = '1.3.61'
ext.spring_boot_version = '2.2.2.RELEASE'
ext.jjwt_version = '0.10.6'
ext.klockVersion = "1.7.3"
ext.queryDslVersion = '4.1.4'
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
group 'org.com'
version '0.1.0'
def javaProjects() {
return subprojects.findAll { new File(it.projectDir, "src").exists() }
}
subprojects {
repositories {
jcenter()
mavenCentral()
}
configure(javaProjects()) {
apply plugin: "java"
apply plugin: "java-library"
apply plugin: "org.jetbrains.kotlin.jvm"
apply plugin: 'kotlin'
apply plugin: "kotlin-spring"
apply plugin: "kotlin-jpa"
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "io.jsonwebtoken:jjwt-api:$jjwt_version"
implementation "io.jsonwebtoken:jjwt-impl:$jjwt_version"
implementation "io.jsonwebtoken:jjwt-jackson:$jjwt_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.soywiz.korlibs.klock:klock-jvm:1.7.3"
implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation "org.springframework.boot:spring-boot-starter-web"
implementation("org.springframework.boot:spring-boot-starter-security")
implementation "org.postgresql:postgresql:42.1.3"
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
implementation "khttp:khttp:1.0.0"
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude module: 'junit'
exclude module: 'mockito-core'
}
testImplementation('org.junit.jupiter:junit-jupiter:5.5.2')
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation('com.ninja-squad:springmockk:2.0.0')
}
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
}
}
}
project(":root:dependencies:services") {
bootJar {
enabled = false
}
jar {
enabled = true
}
}
project(":root:dependencies:entities") {
bootJar {
enabled = false
}
jar {
enabled = true
}
}
...
I feel that I must have something wrong with the build.gradle, but I don't understand what.
I also have omitted the build.gradle files of the modules rest api and web api since I only have the dependencies and I have not considered it relevant.
I had previously worked with maven and followed this architecture. I don't know if gradle is the right thing to do, so I'm open to any advice you can give me.
Thank you for your attention.
As I mentioned in the comments, the correct way to include subprojects is to replace the path to the subproject with : i.e. if the subproject is in (from the root project) sub/project1, then the correct way to include it is:
include ':sub:project1'
Now as for your other question in the comments regarding:
Main class name has not been configured and it could not be resolved
You can simply do:
mainClassName = 'full.cannonical.name.of.MainClass'
If all the projects have a main class, then you need to do this in each project's build.gradle

Spring Boot Test not working with Java 11

I'm trying to upgrade my existing Java 8 multi-project gradle application to Java 11. After fixing a few compilation issues, I ended up getting issues in test cases. When i run a test in Intellij, it throws the following error:
Error:java: Attempt to recreate a file for type {QueryDsl classes}
It is trying to generate the Querydsl classes but since those classes are already there, the test is throwing exception.
I'm using Java11, IntelliJ 2019, Gradle 5 to run the application.
These tests are working as expected in Java8.
I've no idea what is causing this error. Can anybody please help me in understanding this.
Code snippets are given below.
Root project build.gradle:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE)
classpath("net.ltgt.gradle:gradle-apt-plugin:0.21")
}
}
subprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
task allDependencies(type: DependencyReportTask) {}
jar {
baseName = "${parent.name}-${project.name}"
}
sourceSets {
main {
java {
srcDirs 'src/main/java', 'build/generated/sources/main/java', 'build/generated/sources/annotationProcessor/java/main'
}
}
}
}
Sub-project build.gradle:
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'net.ltgt.apt'
bootJar {
baseName = "test"
version = "1.0.0"
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa: 2.1.4.RELEASE")
compile("com.querydsl:querydsl-core:4.1.3")
compile("com.querydsl:querydsl-jpa:4.1.3")
annotationProcessor(
"com.querydsl:querydsl-apt:4.1.3:jpa",
"javax.annotation:javax.annotation-api:1.3.2"
)
annotationProcessor("org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final")
testCompile("org.springframework.boot:spring-boot-starter-test:2.1.4.RELEASE")
testCompile("com.h2database:h2:2.1.4.RELEASE")
}
Integration test
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MainClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ServiceImplTest {
#Autowired
private Service1Impl service;
#Test
public void getData() {
Data data = service.getData();
Assert.assertEquals(0, data.size());
}
}
I had the same issue and the problem was with the order of the dependencies in gradle. Somehow the java compiler in intellij can not work well.
Be sure you have this dependencies for QueryDSL
annotationProcessor group: 'com.querydsl', name: 'querydsl-apt', version: querydsl_version, classifier: 'jpa'
annotationProcessor group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: hibernate_jpa_version
annotationProcessor group: 'javax.annotation', name: 'javax.annotation-api', version: javax_annotation_version
Delete the out folder in your project just in case and rebuild with Ctrl+f9.
Note aside, executing build from gradle and test command worked fine. Check this out https://blog.jdriven.com/2018/10/using-querydsl-annotation-processor-with-gradle-and-intellij-idea/

java.lang.NoClassDefFoundError in Intellij Plugin

I'm trying to build a plugin for Intellij but I'm getting a java.lang.NoClassDefFoundError at runtime every time my code point to a class in another module or to an external library.
Everything works fine in my tests and in the sandbox via runIde.
I also managed to reproduce the error by creating a new project with just an action and a module with a class and an empty method.
root gradle:
buildscript {
ext.kotlin_version = '1.2.31'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id 'org.jetbrains.intellij' version '0.3.12'
}
group 'test'
version '1.0-SNAPSHOT'
apply plugin: 'kotlin'
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile project(':testmodule')
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
intellij {
version '2018.1.6'
}
patchPluginXml {
changeNotes """
Add change notes here.
most HTML tags may be used"""
}
action:
package action
import com.intellij.openapi.actionSystem.*
import packages.OtherModuleClass
class TestAction : AnAction() {
override fun actionPerformed(e: AnActionEvent?) {
OtherModuleClass().otherModuleMethod()
}
}
other module class:
package packages
class OtherModuleClass {
fun otherModuleMethod() {}
}
I found out what my problem was.
I was installing in my IDE the jar in build/libs instead of the zip in build/distributions.
If someone else is looking for a solution for similar problem, I fixed it by adding the java plugin in build.gradle
apply plugin "java"

Gatling is not working with SpringBoot 2.0.1.RELEASE

I'm trying to setup Gatling with Spring Boot 2.0.1.RELEASE.
I've created this api:
#RestController
#RequestMapping("/contact")
public class ContactController {
#GetMapping
public ResponseEntity get() {
return ResponseEntity.ok("Contact retrieved successfully");
}
}
And this basic simulation:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class ContactSimulation extends Simulation {
val httpConf = http.baseURL("http://localhost:8080")
val scn = scenario("GetContact")
.exec(
http("GetContact")
.get("/contact")
.check(status.is(200))
)
setUp(scn.inject(atOnceUsers(1))).protocols(httpConf)
}
The build.gradle is configured this way:
buildscript {
ext {
springBootVersion = '2.0.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'scala'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.gatling.poc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('io.gatling.highcharts:gatling-charts-highcharts:2.3.0')
}
task loadTest(type: JavaExec) {
dependsOn testClasses
description = "Load Test With Gatling"
group = "Load Test"
classpath = sourceSets.test.runtimeClasspath
jvmArgs = [
"-Dgatling.core.directory.binaries=${sourceSets.test.output.classesDir.toString()}"
]
main = "io.gatling.app.Gatling"
args = [
"--simulation", "com.gatling.poc.simulations.ContactSimulation",
"--results-folder", "${buildDir}/gatling-results",
"--binaries-folder", sourceSets.test.output.classesDir.toString(),
"--bodies-folder", sourceSets.test.resources.srcDirs.toList().first().toString() + "/gatling/bodies",
]
}
While executing the tests:
./gradlew loadTest
I'm getting the following stacktrace:
21:00:12.804 [main] WARN io.netty.util.concurrent.DefaultPromise - An exception was thrown by org.asynchttpclient.netty.request.NettyRequestSender$1.operationComplete()
java.lang.NoSuchMethodError: io.netty.channel.DefaultChannelId.newInstance()Lio/netty/channel/DefaultChannelId;
at io.netty.channel.AbstractChannel.newId(AbstractChannel.java:111)
at io.netty.channel.AbstractChannel.<init>(AbstractChannel.java:83)
at io.netty.bootstrap.FailedChannel.<init>(FailedChannel.java:33)
at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:330)
at io.netty.bootstrap.Bootstrap.doResolveAndConnect(Bootstrap.java:163)
at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:156)
at org.asynchttpclient.netty.request.NettyChannelConnector.connect0(NettyChannelConnector.java:81)
at org.asynchttpclient.netty.request.NettyChannelConnector.connect(NettyChannelConnector.java:69)
at org.asynchttpclient.netty.request.NettyRequestSender$1.onSuccess(NettyRequestSender.java:292)
at org.asynchttpclient.netty.request.NettyRequestSender$1.onSuccess(NettyRequestSender.java:285)
at org.asynchttpclient.netty.SimpleFutureListener.operationComplete(SimpleFutureListener.java:24)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
at io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:162)
at io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:33)
at org.asynchttpclient.netty.request.NettyRequestSender.sendRequestWithNewChannel(NettyRequestSender.java:285)
at org.asynchttpclient.netty.request.NettyRequestSender.sendRequestWithCertainForceConnect(NettyRequestSender.java:136)
at org.asynchttpclient.netty.request.NettyRequestSender.sendRequest(NettyRequestSender.java:107)
at org.asynchttpclient.DefaultAsyncHttpClient.execute(DefaultAsyncHttpClient.java:216)
at org.asynchttpclient.DefaultAsyncHttpClient.executeRequest(DefaultAsyncHttpClient.java:184)
at org.asynchttpclient.DefaultAsyncHttpClient.executeRequest(DefaultAsyncHttpClient.java:206)
at io.gatling.http.ahc.HttpEngine.warmpUp(HttpEngine.scala:96)
at io.gatling.http.protocol.HttpProtocol$$anon$1.$anonfun$newComponents$1(HttpProtocol.scala:62)
at io.gatling.core.protocol.ProtocolComponentsRegistry.comps$1(Protocol.scala:67)
at io.gatling.core.protocol.ProtocolComponentsRegistry.$anonfun$components$4(Protocol.scala:69)
at scala.collection.mutable.HashMap.getOrElseUpdate(HashMap.scala:82)
at io.gatling.core.protocol.ProtocolComponentsRegistry.components(Protocol.scala:69)
at io.gatling.http.action.HttpActionBuilder.lookUpHttpComponents(HttpActionBuilder.scala:25)
at io.gatling.http.action.sync.HttpRequestActionBuilder.build(HttpRequestActionBuilder.scala:33)
at io.gatling.core.structure.StructureBuilder.$anonfun$build$1(StructureBuilder.scala:34)
at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:122)
at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:118)
at scala.collection.immutable.List.foldLeft(List.scala:86)
at io.gatling.core.structure.StructureBuilder.build(StructureBuilder.scala:33)
at io.gatling.core.structure.StructureBuilder.build$(StructureBuilder.scala:32)
at io.gatling.core.structure.ScenarioBuilder.build(ScenarioBuilder.scala:38)
at io.gatling.core.structure.PopulationBuilder.build(ScenarioBuilder.scala:98)
at io.gatling.core.scenario.SimulationParams.$anonfun$scenarios$1(Simulation.scala:188)
at scala.collection.immutable.List.map(List.scala:283)
at io.gatling.core.scenario.SimulationParams.scenarios(Simulation.scala:188)
at io.gatling.app.Runner.run0(Runner.scala:95)
at io.gatling.app.Runner.run(Runner.scala:64)
at io.gatling.app.Gatling$.start(Gatling.scala:59)
at io.gatling.app.Gatling$.fromArgs(Gatling.scala:43)
at io.gatling.app.Gatling$.main(Gatling.scala:35)
at io.gatling.app.Gatling.main(Gatling.scala)
If I create the same project using SpringBoot 1.5.12.RELEASE, it works perfectly. I'm suspecting of the spring-boot-gradle-plugin since it changes according to the SpringBoot version.
If necessary I can create a project into github to demonstrate the problem. =)
I would appreciate if someone could help me!
I got fix this issue.
The problem was the version of the io.netty group used by the SpringBoot 2.0.1.RELEASE. It is using the version 4.1.23.Final which for some reason (maybe some change in scala) is not executing the gatling tests.
I did the downgrade to use the same version as SpringBoot 1.5.12.RELEASE, which is 4.0.51.Final. I had to add this configuration to the build.gradle:
{
// This build.gradle is the same that I posted above. For the sake of simplicity I just put the configuration that has been necessary to solve the problem.
// After dependencies{} section, I had to put this:
configurations.all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'io.netty') {
details.useVersion "4.0.51.Final"
}
}
}
}
}
I don't think is the best solution since I'm reverting the io.netty version to use a older version, which can have some side effect. In my case I didn't have the option of downgrading the SpringBoot version. If you have the option to revert the SpringBoot version, I would recommend to do that.

Kotlin Gradle Could not find or load main class

I tried to copy the Spring Boot Kotlin sample project https://github.com/JetBrains/kotlin-examples/tree/master/tutorials/spring-boot-restful. I Added some more dependencies and when I tried to build the executable jar and run it, I got the error:
Could not find or load main class...
Gradle build script:
buildscript {
ext.kotlin_version = '1.1.3' // Required for Kotlin integration
ext.spring_boot_version = '1.5.4.RELEASE'
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // Required for Kotlin integration
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin
classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"
}
}
/*plugins {
id 'org.springframework.boot' version '2.0.0.RELEASE'
}*/
apply plugin: 'kotlin' // Required for Kotlin integration
apply plugin: "kotlin-spring" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin
apply plugin: 'org.springframework.boot'
jar {
baseName = 'gs-rest-service'
version = '0.1.0'
from {
(configurations.runtime).collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.Applicationkt'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin/'
test.java.srcDirs += 'src/test/kotlin/'
}
repositories {
jcenter()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // Required for Kotlin integration
compile("org.springframework.boot:spring-boot-starter-web")
compile group: 'org.apache.camel', name: 'camel-quartz2', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-http4', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-docker', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-aws', version: '2.20.2'
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Change Applicationkt to ApplicationKt will work, and BTW you may upgrade Kotlin version to 1.3.50.
By Applicationkt I mean the one in this line:
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.Applicationkt'
Kotlin compiles the Application file in two different files:
one file called Application.class with the Springboot things
another file called ApplicationKt.class with the main method
In this second file is where the main function is located at, so you have to use this name in the build.gradle file.
mainClassName = 'org.jetbrains.kotlin.demo.ApplicationKt'
Update your build.gradle to
jar {
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.ApplicationKt'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
with an upper case K in ApplicationKt.
This is required because of the way Kotlin compiles to Java Bytecode. The fun main() function in Kotlin is not attached to any class, but Java always requires a class and does not support classless functions.
The Kotlin compiler has to create a Java class. Because you already defined a class Application it created one with the suffix Kt for the functions in your Kotlin file org/jetbrains/kotlin/demo/Application.kt. You have to set this class so that the JVM can find it.
BTW a Jar file is just a Zip file, you can unpack it and see for yourself if the ApplicationKt.class is there.
For me the main function needed to be outside the class body
#SpringBootApplication
#Configuration
class Application
(private val locationRepository: LocationRepository,
) : CommandLineRunner {
override fun run(vararg args: String?) {
whatever()
}
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
Indeed, Kotlin create file ApplicationKt.class in the jar if your main class file is named Application.kt. You have to add the following lines:
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = 'org.jetbrains.kotlin.demo.ApplicationKt'
If you use the classic jar plugin, you can do as below (which is described in previous responses):
jar {
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.ApplicationKt'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
However, my preference is to use bootJar plugin which is much clear and which allow me to use layered jars for example:
bootJar {
layered() // Not useful if you don't want to use layered jars
}

Resources