1


The question has been edited, look ahead for the Updated sections and all the different ways I approached it in order to find a solution.


Initial question

I tried to create an executable jar file for my project but I run to the error when trying to run it no main manifest attribute, in kerkinibackend.jar.

The project is a Spring Boot application and I am using IntelliJ as an IDE.

I tried to find the most common scenarios when this could happen from similar questions but I couldn't make it work any way.

The steps I took were :

  1. Opened IntelliJ.
  2. Opened the project's Structure on the top right icon.
  3. Navigated to the Artifact.
  4. Pressed the plus to add new artifact.
  5. JAR -> from modules with dependencies. (also tried it using the blank option while having a MANIFEST.MF file, which was automatically generated from the first time I tried it).
  6. Opened the folder for the Main class in the pop-up dialog and specified it. (also tried leaving the Main class empty as I read somewhere and left it connect with it through the Manifest).
  7. Left the rest as default. (this way IntelliJ also creates the needed Manifest, in case you have it already deleting the file will allow to generate it again)
  8. Then, I pressed Build -> Build Artifacts -> Build.
  9. The is created with a size of 57Mbs. I tried running it as an executable but I saw it wasn't working. Then I opened the cmd and ran java -jar kerkinibackend.jar and then the error message comes out. The thing is that the MANIFEST.MF file is actually getting created in src/main/java/META-INF
Manifest-Version: 1.0
Main-Class: com.teicm.kerkinibackend.KerkinibackendApplication

I also do have the needed dependency in pom.xml

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>





UPDATE

I fixed the problem by changing the default generation of the manifest to be in the resources instead.

Now it the Jar runs but then I get and error from Spring No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.









Farther UPDATE

I tried to add an extra file the spring.factories (as a read in another answer Relevant question-answer) inside the META-INF folder in the resource folder in order to fix the previous problem. Now it didn't show the same error but a different one

00:24:26.230 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:767)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1308)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1154)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:391)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:853)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
        at com.teicm.kerkinibackend.KerkinibackendApplication.main(KerkinibackendApplication.java:11)

But I don't know if this brings me a step closer or a step farther. And why wouldn't the MySQL data source be recognized. When I use the project locally everything works, it connects to MySQL, it has communication with the front end.





Trying a different build method using maven-assembly-plugin

I also tried using a different way to build the executable jar, through @Zsolt Tolvarys approach (you can find more about it at link). This approach uses in the pom.xml another plugin called maven-assembly-plugin.

Unfortunately doing the suggested steps does generate a jar file but when I try to run the generated jar that exists now in the /target folder, then I get an error message of Error: Could not find or load main class com.teicm.kerkinibackend.KerkinibackendApplication having changed of course in the plugin the name of the Main class :

<build>
        <plugins>
            <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <finalName>KerkiniBackEnd</finalName>
                    <appendAssemblyId>false</appendAssemblyId>
                    <archive>
                        <manifest>
                            <mainClass>com.teicm.kerkinibackend.KerkinibackendApplication</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>





For anyone having some spare time feel free to suggest me a solution or even try it him-her self. I really need to generate it, it's the last part of finishing my thesis...

The link for the Github repository is Github Repository

Thank you for your time and effort

  • The project can built without any issue `mvn clean package -DskipTests`. The unit and integration tests are failing cause some things which are needed are not there...apart from that the configuration for integration tests should be located into `src/test/resources` instead of `src/main/resources`...and I don't understand your question about the main class? – khmarbaise Feb 23 '19 at 19:55
  • What I am trying to do is create the executable 'fat jar'. Other than that the project is running normally. If I understood correctly you are talking about the general build and run of the project, right? If not, I misunderstood. – Alexandros Markovits Feb 23 '19 at 21:19
  • I apologize for not understanding in the first place. You were correct I just didn't expect it would be that simple (while also a bit skeptical and scared not to mess up maven). Still in the learning phase :) Thank you for spending time trying to help me! Have a great day! – Alexandros Markovits Feb 24 '19 at 04:02

1 Answers1

9

The answer given above by @khmarbaise is correct and is the essential key to getting your Spring Boot bootable jar created successfully.

I'm responding only to offer additional information to hopefully further clarify some key related things for you. (I would have put this in comments, but since this is my first publication to SO, I have 0 of the 50 reputation points required to post comments - on the other hand I'm free to post answers - a "boot-up" issue of my own :-)

First, the initial IntelliJ steps you listed aren't necessary. Nor is the usage of the assembly plugin (a little more on that below).

As long as you have the spring-boot-maven-plugin defined in your pom.xml (assuming you also have the target "packaging" defined as "jar" - both of which you already do), then Maven's interaction with Spring will result in a bootable jar file when running the Maven package command: mvn clean package

As @khmarbaise also noted, for the moment you need to instruct Maven to skip test execution since your tests are failing, which will prevent the "packaging" of your bootable jar from completing successfully: mvn clean package -DskipTests

By the way, IntelliJ includes a convenient Maven "tool window" which allows you to run Maven commands like these from the IDE. If it isn't showing go to View -> Tool Windows and select "Maven."

Spring Boot applications themselves are "assembled" as "main method" jar files. This is why trying to build a Spring Boot app/jar with the maven-assembly-plugin doesn't make sense (or work, since Spring Boot creates a different internal structure inside the jar which Spring Boot requires to run).

If packaging completes successfully you should see the following pair of jar files underneath your "compiler output" directory (this is usually located at [PROJECT_ROOT_DIR]/target):

kerkinibackend-0.0.1-SNAPSHOT.jar
kerkinibackend-0.0.1-SNAPSHOT.jar.original

Peeking into the MANIFEST.MF file of kerkinibackend-0.0.1-SNAPSHOT.jar you'll see a couple key entries:

Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.teicm.kerkinibackend.KerkinibackendApplication

How this works: When the JVM is invoked with the -jar flag, it will search MANIFEST.MF for the Main-Class entry. In this case it will find Spring's JarLauncher class as the class whose main method it should invoke to launch the app. JarLauncher will then in turn look for the manifest's Start-Class entry, which has been populated with the fully qualified path to your @SpringBootApplication class: (com.teicm.kerkinibackend.KerkinibackendApplication) and will in turn eventually call main on KerkinibackendApplication:

    public static void main(String[] args) {
        SpringApplication.run(KerkinibackendApplication.class, args);
    }

Hope this information helps clarify some things. If not, let me know. Good luck and congrats on being (almost) done with your thesis!

mouselabs
  • 284
  • 2
  • 7
  • So I did indeed missunderstand the @khmarbaise comment, my bad. I will definitely look into this approach, thank you so much for the detailed answer, I will specify it as the correct answer as soon as I see it working :D thank you again for your kind words and congratulation on your first points! :) – Alexandros Markovits Feb 24 '19 at 02:39
  • No problem let me know how it goes :) – mouselabs Feb 24 '19 at 02:50
  • Sorry for taking me a while, I was away from my laptop. It worked fluently! It's actually a very clean way of building the executable, I am impressed. (sorry for not grasping things fast, I am still learning) I am so thankful of both of your detailed answer and the initial comment by @khmarbaise, hope I could help you somehow as well since you lifted a kind of big burden from my shoulders. Hoping the best for you and a great start in here, you are awesome :) – Alexandros Markovits Feb 24 '19 at 03:49
  • Btw, I do have some questions for farther clarification on the topic : 1) You both said that it was having errors running the tests so I had to bypass them, the only thing I could think of having a problem at the tests is that a couple are being left using a custom Repository method which is now annotated as `@deprecated` (annotated by me), could that be it? 2) So the appropriate way to make the executables is this by the documentation? (I am surprised I didn't find it anywhere while searching) Just to know if the first approach could work somehow to have it as a plan-b for the future . :D – Alexandros Markovits Feb 24 '19 at 03:58
  • Thanks for your kind words - right back at ya! This is typical way to create a _Spring Boot_ application "artifact" (in this case the artifact is the bootable jar ```kerkinibackend-0.0.1-SNAPSHOT.jar```. A Spring Boot executable jar is internally structured in a Spring Boot-specific way that is expected by Spring itself - so if you tried to create it using the "assembly" method it would probably fail because Spring wouldn't find what it needs where it expects to find them. – mouselabs Feb 24 '19 at 21:46
  • 1
    Using ```maven-assembly-plugin``` is appropriate (for lack of better words) more "traditional" or "vanilla" java applications - where you would supply a "plain old" main method in some class as the "entry point", and _that_ class would be the one that is populated into the ```Main-Class``` attribute in ```MANIFEST.MF``` (instead of ```JarLauncher``` as in the Spring Boot case) – mouselabs Feb 24 '19 at 21:49
  • 1
    Finally - to the tests. I didn't dig into the errors but I recall seeing database connection related errors. My guess is that the tests are "integration" tests - which in most cases means they are going to be run in an actual instance of the application. This in turn means that certain application "dependencies" (like a database) might be required in order for the tests to succeed. I'm out of time for the moment but when I return I'll run the tests again and give you a more specific answer. – mouselabs Feb 24 '19 at 21:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188969/discussion-between-mouselabs-and-alexandros-markovits). – mouselabs Feb 25 '19 at 00:39