1

I'm trying to generate an executable jar for the api that I've been working on. I've been able to debug locally using localhost, but when I try to run the generated jar artifact from the command line I get the error no main manifest attribute, in api.jar. I've read up on the related SO questions here and here, but the changes they've recommended seem to have no effect. My project structure is below:

project structure

When I try to select the main class while navigating through the artifact wizard I can get all the way to highlighting the main class, but the OK button is disabled.

OK button disabled

Finally, when I try to specify the main class manually in the manifest file by right clicking on the main class name and selecting Copy Reference and pasting the clipboard value in I get the error that it's an invalid main class:

Invalid main class

My actual main class is included below. Any help is appreciated.

package api

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
open class KotlinSpringJpaPostgresqlApplication

fun main(args: Array<String>) {
    SpringApplication.run(KotlinSpringJpaPostgresqlApplication::class.java, *args)
}

As a final aside, my code is available here if you want to try and run it locally.

James Jordan Taylor
  • 1,560
  • 3
  • 24
  • 38

2 Answers2

2

You need to append Kt with an upper case K to the filename that holds your main method. 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.

Note that the filename is of importance here (In your question it is api.kt). I would recommend to just create a file Main.kt and move your main function there. It will be compiled to a MainKt class, which you should reference from your Manifest.

I would expect that your manually created MANIFEST.MF file gets overwritten by the build process. Have you unzipt the final jar file and inspected that MANIFEST.MF is as you expect it to be?

Rather than writing the MANIFEST.MF yourself, let your build system handle it for you:

For Maven:

<configuration>
    <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>api.KotlinSpringJpaPostgresqlApplicationKt</mainClass>
        </manifest>
    </archive>
</configuration>

For Gradle:

jar {
     manifest {
        attributes 'Main-Class': 'api.KotlinSpringJpaPostgresqlApplicationKt'
    }
    from { 
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } 
    }
}
phisch
  • 4,571
  • 2
  • 34
  • 52
  • I specified it in the pom and compiled the .jar from the command line using maven package for good measure. I got the error `Exception in thread "main" java.lang.ClassNotFoundException: api.KotlinSpringJpaPostgresqlApplication Kt at java.net.URLClassLoader.findClass(URLClassLoader.java:381)` – James Jordan Taylor Apr 16 '18 at 12:14
  • Sorry, I am note sure where this whitespace in my answer came from. It has to be one word `api.KotlinSpringJpaPostgresqlApplicationKt` with no blank in front of `Kt` – phisch Apr 16 '18 at 12:16
  • I figured it might be a typo and tried it both ways. Same result. – James Jordan Taylor Apr 16 '18 at 12:22
  • Could you please double check that the MANIFEST.MF actually contains the correct Main Class and that the `api.KotlinSpringJpaPostgresqlApplicationKt` is indeed part of the Jar? – phisch Apr 16 '18 at 13:00
  • The MANIFEST.MF generated by the .pom contains the class `api.KotlinSpringJpaPostgresqlApplicationKt`. When examined, the jar contains the class `BOOT-INF/classes/api/KotlinSpringJpaPostgresqlApplication.class` – James Jordan Taylor Apr 16 '18 at 14:22
  • I just noticed that your file name is `api.kt` and not KotlinSpringJpaPostgresqlApplication. Do you have an `apiKt.class` ? If so, that would be your main class. – phisch Apr 16 '18 at 14:29
  • I don't. Should I refactor KotlinSpringJpaPostgresqlApplication to match the filename? – James Jordan Taylor Apr 16 '18 at 14:38
  • Yes. I would give that a try. Alternatively you could also just create a file `Main.kt` and move your mail function there. It will be compiled to a `MainKt` class – phisch Apr 16 '18 at 14:40
  • That did it! If you update your original answer to reflect our comments chain I'll upvote & mark accepted. – James Jordan Taylor Apr 16 '18 at 14:44
1

The issue is the name of the class as Kotlin will create a Java class with a Kt suffix.

This means that the Main Class in your manifest should be:

Main-Class: api.KotlinSpringJpaPostgresqlApplicationKt

hexkid
  • 574
  • 1
  • 4
  • 13
  • That just causes the error to become `Error: Could not find or load main class api.KotlinSpringJpaPostgresqlApplicationKt` – James Jordan Taylor Apr 15 '18 at 23:09
  • Can you specify the Main Class in the pom.xml rather than in IntelliJ? I did this yesterday in Gradle & your main class should definitely be the one with the 'Kt' suffix. See: https://stackoverflow.com/questions/37671510/how-do-i-specify-a-main-class-in-the-manifest-of-my-generated-jar-file – hexkid Apr 16 '18 at 08:08
  • I specified it in the pom and compiled the .jar from the command line using maven package for good measure. I got the error Exception in thread "main" java.lang.ClassNotFoundException: api.KotlinSpringJpaPostgresqlApplicationKt at java.net.URLClassLoader.findClass(URLClassLoader.java:381) – James Jordan Taylor Apr 16 '18 at 12:22