Spring Boot Maven Plugin - No BOOT-INF directory
Asked Answered
A

6

13

Between version 1.3.8.RELEASE of the spring-boot-maven-plugin and version 1.4.0.RELEASE - there has been a change in the generated package structure (if you extract the uber jar file) 1.3.8.RELEASE com, lib, META-INF and org directories 1.4.0.RELEASE has a BOOT-INF, META-INF and org directories Basically from 1.4.0.RELEASE onwards - all the classes and libs are in the BOOT-INF directory. Due to this - when you try to run a Spring Boot project on Amazon Lambda - it says that there is a jar not found as it cannot read the new Spring Boot Uber jar structure

My question is - is it possible in the newer versions of the Spring Boot Maven Plugin to get it to generate the uber jar to be the same structure as in version 1.3.9.RELEASE?

I tried the maven-shade-plugin - but that leads to other issues

Any help is greatly appreciated

Thanks Damien

Augustin answered 30/3, 2017 at 17:41 Comment(0)
A
22

The solution was to add the MODULE layout for the plugin in the pom.xml file

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layout>MODULE</layout>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Augustin answered 30/3, 2017 at 20:29 Comment(4)
why no one has marked it as Right Answer. I had similar problem when I upgraded spring boot. Was puzzled by docs.Spring description. Adding this piece works.<configuration> <layout>MODULE</layout> </configuration>Salic
how to do this for build.gradle ? i am using below plugin classpath "org.springframework.boot:spring-boot-gradle-plugin:1.4.2.RELEASE" , because of this , my fat jar , has below structure BOOT-INF MATA-INF org.springframework.boot.loader but i want the structure like below <<some package strcutre>> META-INFMotivate
It says, Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.2.RELEASE:repackage (repackage) on project businessunit-service-businessunit: Unable to parse configuration of mojo org.springframework.boot:spring-boot-maven-plugin:2.1.2.RELEASE:repackage: Cannot convert 'MODULE' to Enum: No enum constant org.springframework.boot.maven.RepackageMojo.LayoutType.MODULE -> [Help 1]Haney
This no longer works in newer versions of Spring Boot. I'm using 2.7.5 and I get the same error as a previous commenter: " Cannot convert 'MODULE' to Enum: No enum constant org.springframework.boot.maven.AbstractPackagerMojo.LayoutType.MODULE"Transubstantiate
M
12

In my case I'm using spring boot 2.X and I declared the spring-boot-maven-plugin after the maven-dependency-plugin (which I used to unpack and create exploded app in Docker) and it must be before the unpack, makes sense, it was unpacking before the spring boot maven plugin executed. Next time I'll declare it first thing in the plugin chain, lost more than 1 hour on this. Hope it helps someone.

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>${spring.boot.mainClass}</mainClass>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>${project.artifactId}</artifactId>
                                <version>${project.version}</version>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Mantelet answered 17/12, 2019 at 16:11 Comment(1)
I also got my setup working by putting my maven-shade-plugin declaration before the spring-boot-maven-plugin declaration in pom.xml. The resulting shade jar has everything in the root as expected while the Spring boot jar has everything in BOOT-INF as expected.Aery
M
5

The answer above with

<layout>MODULE</layout>

does not work anymore, this is because layout element is deprecated in Spring Boot 2.x. I am using Spring Boot 2.0.x, I found this helpful comment on github:

Support for the module layout was removed in Spring Boot 2.0 having been deprecated in 1.5. Unfortunately, the updates to the Maven Plugin's documentation were missed so we can use this issue to sort that out. You should use a custom LayoutFactory instead.

But as I did not want to implement LayoutFactory I tried this second solution below that actually repackage and creates an extra jar with a classifier given name:

This is due to the change in layout of executable jars in Spring Boot 1.4. Application classes are now packaging in BOOT-INF/classes. Your client module depends on the repackaged, fat jar of your web module. Due to the new layout that means that the client module can no longer load the web module's classes. If you want to use your web module as a dependency, you should configure Boot's repackaging to apply a classifier to the fat jar. For example:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                    <configuration>
                        <classifier>exec</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Doing so will allow other modules to depend on the original jar that does not embed the module's dependencies and has the classes at the root of the jar.

One original jar have the same structure as I wanted like

com.my-package.foo.bar
META-INF

and the second classifier have the newer structure with BOOT-INF/ etc.

Malraux answered 27/8, 2019 at 14:50 Comment(1)
Thank you very much. It's very good answerBegley
C
1

For me, the solution was a bit more insidious....I had the spring-boot-maven-plugin nested under pluginManagement, (see below). Doh!

The nasty thing, is that when I'd run mvn spring-boot:run, spring boot comes up just fine, and runs app! It wasn't until we tried to deploy to PCF (as a spring-boot JAR), that we'd get an error that there was something wrong with format of the binary....

<build>

  <!-- 
    DON'T DO THIS!! 
  -->
  <pluginManagement>

    <plugins>             
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring.boot.version}</version>            
        <executions>
            <execution>
                <goals>
                    <goal>repackage</goal>
                    <goal>build-info</goal>
                </goals>
            </execution>
        </executions>                        
      </plugin>                                     
    </plugins>

  </pluginManagement>

  <!-- 
    DO THIS INSTEAD!! 
  -->      
<plugins>

    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>${spring.boot.version}</version>            
      <executions>
          <execution>
              <goals>
                  <goal>repackage</goal>
                  <goal>build-info</goal>
              </goals>
          </execution>
      </executions>                        
    </plugin>                         

  </plugins>

</build>

Once I removed the pluginManagement tags from the POM, I would now get the ./BOOT-INF structure. Please keep in mind that pluginManagement is typically for a parent-pom structure, where you want that plugin's config used across other modules.

Compression answered 22/8, 2019 at 14:45 Comment(0)
R
1

How can we achieve the same result using gradle ? I've switched from spring-boot-gradle-plugin 1.2.5 to 1.4.0 and now the jar structure has changed. Does this solution <layout>MODULE</layout> has an equivalent in gradle ?

Ruthful answered 27/10, 2023 at 12:54 Comment(0)
A
0

I was using Gradle, instead of Maven, and this is what I had to do:

1- In my build.gradle, I added the following properties as defined in https://spring.io/guides/gs/spring-boot-Docker/.

buildscript {
    ...
    dependencies {
        ...
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
    }
}

group = 'springio'

...
apply plugin: 'com.palantir.docker'

task unpack(type: Copy) {
    dependsOn bootJar
    from(zipTree(tasks.bootJar.outputs.files.singleFile))
    into("build/dependency")
}
docker {
    name "${project.group}/${bootJar.baseName}"
    copySpec.from(tasks.unpack.outputs).into("dependency")
    buildArgs(['DEPENDENCY': "dependency"])
}

2- My dependency folder was not being written to

ARG DEPENDENCY=target/dependency

instead, I located it in another folder, so I changed this property in the Dockerfile:

ARG DEPENDENCY=build/dependency

With this I got a successful build.

Arterio answered 23/5, 2020 at 17:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.