79. Build

79.1 Generate build information

Both the Maven and Gradle plugin allow to generate build information containing the coordinates, name and version of the project. The plugin can also be configured to add additional properties through configuration. When such file is present, Spring Boot auto-configures a BuildProperties bean.

To generate build information with Maven, add an execution for the build-info goal:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.4.0.M2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
[Tip]Tip

Check the Spring Boot Maven Plugin documentation for more details.

And to do the same with Gradle:

springBoot  {
    buildInfo()
}

Additional properties can be added using the DSL:

springBoot  {
    buildInfo {
        additionalProperties = [
            'foo': 'bar'
        ]
    }
}

79.2 Generate git information

Both Maven and Gradle allow to generate a git.properties file containing information about the state of your git source code repository when the project was built.

For Maven users the spring-boot-starter-parent POM includes a pre-configured plugin to generate a git.properties file. Simply add the following declaration to your POM:

<build>
    <plugins>
        <plugin>
            <groupId>pl.project13.maven</groupId>
            <artifactId>git-commit-id-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Gradle users can achieve the same result using the gradle-git-properties plugin

plugins {
    id "com.gorylenko.gradle-git-properties" version "1.4.6"
}

79.3 Customize dependency versions

If you use a Maven build that inherits directly or indirectly from spring-boot-dependencies (for instance spring-boot-starter-parent) but you want to override a specific third-party dependency you can add appropriate <properties> elements. Browse the spring-boot-dependencies POM for a complete list of properties. For example, to pick a different slf4j version you would add the following:

<properties>
    <slf4j.version>1.7.5<slf4j.version>
</properties>
[Note]Note

This only works if your Maven project inherits (directly or indirectly) from spring-boot-dependencies. If you have added spring-boot-dependencies in your own dependencyManagement section with <scope>import</scope> you have to redefine the artifact yourself instead of overriding the property.

[Warning]Warning

Each Spring Boot release is designed and tested against a specific set of third-party dependencies. Overriding versions may cause compatibility issues.

To override dependency versions in Gradle, you can specify a version as shown below:

ext['slf4j.version'] = '1.7.5'

For additional information, please refer to the Gradle Dependency Management Plugin documentation.

79.4 Create an executable JAR with Maven

The spring-boot-maven-plugin can be used to create an executable ‘fat’ JAR. If you are using the spring-boot-starter-parent POM you can simply declare the plugin and your jars will be repackaged:

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

If you are not using the parent POM you can still use the plugin, however, you must additionally add an <executions> section:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.4.0.M2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

See the plugin documentation for full usage details.

79.5 Create an additional executable JAR

If you want to use your project as a library jar for other projects to depend on, and in addition have an executable (e.g. demo) version of it, you will want to configure the build in a slightly different way.

For Maven the normal JAR plugin and the Spring Boot plugin both have a ‘classifier’ configuration that you can add to create an additional JAR. Example (using the Spring Boot Starter Parent to manage the plugin versions and other configuration defaults):

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

Two jars are produced, the default one, and an executable one using the Boot plugin with classifier ‘exec’.

For Gradle users the steps are similar. Example:

bootRepackage  {
    classifier = 'exec'
}

79.6 Extract specific libraries when an executable jar runs

Most nested libraries in an executable jar do not need to be unpacked in order to run, however, certain libraries can have problems. For example, JRuby includes its own nested jar support which assumes that the jruby-complete.jar is always directly available as a file in its own right.

To deal with any problematic libraries, you can flag that specific nested jars should be automatically unpacked to the ‘temp folder’ when the executable jar first runs.

For example, to indicate that JRuby should be flagged for unpack using the Maven Plugin you would add the following configuration:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <requiresUnpack>
                    <dependency>
                        <groupId>org.jruby</groupId>
                        <artifactId>jruby-complete</artifactId>
                    </dependency>
                </requiresUnpack>
            </configuration>
        </plugin>
    </plugins>
</build>

And to do that same with Gradle:

springBoot  {
    requiresUnpack = ['org.jruby:jruby-complete']
}

79.7 Create a non-executable JAR with exclusions

Often if you have an executable and a non-executable jar as build products, the executable version will have additional configuration files that are not needed in a library jar. E.g. the application.yml configuration file might excluded from the non-executable JAR.

Here’s how to do that in Maven:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
                <execution>
                    <id>exec</id>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <classifier>exec</classifier>
                    </configuration>
                </execution>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <!-- Need this to ensure application.yml is excluded -->
                        <forceCreation>true</forceCreation>
                        <excludes>
                            <exclude>application.yml</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

In Gradle you can create a new JAR archive with standard task DSL features, and then have the bootRepackage task depend on that one using its withJarTask property:

jar {
    baseName = 'spring-boot-sample-profile'
    version =  '0.0.0'
    excludes = ['**/application.yml']
}

task('execJar', type:Jar, dependsOn: 'jar') {
    baseName = 'spring-boot-sample-profile'
    version =  '0.0.0'
    classifier = 'exec'
    from sourceSets.main.output
}

bootRepackage  {
    withJarTask = tasks['execJar']
}

79.8 Remote debug a Spring Boot application started with Maven

To attach a remote debugger to a Spring Boot application started with Maven you can use the jvmArguments property of the maven plugin.

Check this example for more details.

79.9 Remote debug a Spring Boot application started with Gradle

To attach a remote debugger to a Spring Boot application started with Gradle you can use the applicationDefaultJvmArgs in build.gradle or --debug-jvm command line option.

build.gradle:

applicationDefaultJvmArgs = [
    "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
]

Command line:

$ gradle run --debug-jvm

Check Gradle Application Plugin for more details.

79.10 Build an executable archive from Ant without using spring-boot-antlib

To build with Ant you need to grab dependencies, compile and then create a jar or war archive. To make it executable you can either use the spring-boot-antlib module, or you can follow these instructions:

  1. If you are building a jar, package the application’s classes and resources in a nested BOOT-INF/classes directory. If you are building a war, package the application’s classes in a nested WEB-INF/classes directory as usual.
  2. Add the runtime dependencies in a nested BOOT-INF/lib directory for a jar or WEB-INF/lib for a war. Remember not to compress the entries in the archive.
  3. Add the provided (embedded container) dependencies in a nested BOOT-INF/lib directory for jar or WEB-INF/lib-provided for a war. Remember not to compress the entries in the archive.
  4. Add the spring-boot-loader classes at the root of the archive (so the Main-Class is available).
  5. Use the appropriate launcher, e.g. JarLauncher for a jar file, as a Main-Class attribute in the manifest and specify the other properties it needs as manifest entries, principally a Start-Class.

Example:

<target name="build" depends="compile">
    <jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
        <mappedresources>
            <fileset dir="target/classes" />
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="src/main/resources" erroronmissingdir="false"/>
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="${lib.dir}/runtime" />
            <globmapper from="*" to="BOOT-INF/lib/*"/>
        </mappedresources>
        <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
        <manifest>
            <attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
            <attribute name="Start-Class" value="${start-class}" />
        </manifest>
    </jar>
</target>

The Ant Sample has a build.xml with a manual task that should work if you run it with

$ ant -lib <folder containing ivy-2.2.jar> clean manual

after which you can run the application with

$ java -jar target/*.jar

79.11 How to use Java 6

If you want to use Spring Boot with Java 6 there are a small number of configuration changes that you will have to make. The exact changes depend on your application’s functionality.

79.11.1 Embedded servlet container compatibility

If you are using one of Boot’s embedded Servlet containers you will have to use a Java 6-compatible container. Both Tomcat 7 and Jetty 8 are Java 6 compatible. See Section 70.15, “Use Tomcat 7” and Section 70.16, “Use Jetty 8” for details.

79.11.2 JTA API compatibility

While the Java Transaction API itself doesn’t require Java 7 the official API jar contains classes that have been built to require Java 7. If you are using JTA then you will need to replace the official JTA 1.2 API jar with one that has been built to work on Java 6. To do so, exclude any transitive dependencies on javax.transaction:javax.transaction-api and replace them with a dependency on org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.0.0.Final