Coder Social home page Coder Social logo

spring-projects-experimental / spring-boot-thin-launcher Goto Github PK

View Code? Open in Web Editor NEW
680.0 42.0 90.0 2.07 MB

Tools for building "thin" executable jars, with a focus on, but not exclusively for, Spring Boot

Home Page: https://github.com/dsyer/spring-boot-thin-launcher

License: Apache License 2.0

Java 100.00%

spring-boot-thin-launcher's Introduction

Spring Boot Thin Launcher ci.spring.io

A "thin" jar launcher for java apps. Version 1.0.31.RELEASE is in Maven Central, snapshots are in https://repo.spring.io/libs-snapshot. See spring-projects/spring-boot#1813 for more discussion and ideas.

Getting Started

The thin-launcher provides its own custom layout for the Spring Boot plugins. If this layout is used then the jar built by Spring Boot will be executable and thin.

NOTE: if you are using a snapshot version of the thin launcher you either need to build it locally or include the snapshot repository declarations. You can use https://start.spring.io to find suitable repository declarations for Maven and Gradle, or look at the samples in this project.

With Maven, build a Spring Boot application and add the layout. This means adding it to the Spring Boot plugin declaration:

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<version>${spring-boot.version}</version>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot.experimental</groupId>
			<artifactId>spring-boot-thin-layout</artifactId>
			<version>1.0.31.RELEASE</version>
		</dependency>
	</dependencies>
</plugin>

and in Gradle, you need to add the thin-launcher plugin and (preferably) a maven-publish plugin with an explicit publication definition. You can use the newer id style declaration:

plugins {
	id 'org.springframework.boot' version '3.0.1'
	id 'io.spring.dependency-management' version '1.1.0'
	id 'java'
	id 'maven-publish'
	id 'org.springframework.boot.experimental.thin-launcher' version '1.0.31.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
	mavenLocal()
	mavenCentral()
	maven { url "https://repo.spring.io/snapshot" }
	maven { url "https://repo.spring.io/milestone" }
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
}

or you can use the older apply style declaration:

buildscript {
	ext {
		springBootVersion = '2.7.6'
		wrapperVersion = '1.0.31.RELEASE'
	}
	repositories {
		mavenLocal()
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot.experimental:spring-boot-thin-gradle-plugin:${wrapperVersion}")
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}
apply plugin: 'maven-publish'
apply plugin: 'org.springframework.boot.experimental.thin-launcher'

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
}

The publication named "maven" is responsible for creating a pom.xml for your application.

For Spring Boot 2.x snapshot versions (or older releases) you also need a settings.gradle with the repository configuration for the plugin. e.g. (as generated by https://start.spring.io):

pluginManagement{
	repositories{
		maven{url'https://repo.spring.io/libs-snapshot'}
		gradlePluginPortal()
	}
	resolutionStrategy{
		eachPlugin{
			if (requested.id.id=='org.springframework.boot.experimental.thin-launcher'){
				useModule("org.springframework.boot.experimental:spring-boot-thin-gradle-plugin:${requested.version}")
			}
		}
	}
}

If you don't need snapshots you can leave it all out and rely on the defaults. If you are testing a change you made to the plugin you might want to put mavenLocal() in the repositories as well.

In Gradle you also need to generate a pom.xml or a thin.properties (unless you want to maintain it by hand). A pom.xml will be generated automatically by the "thinPom" task in the Thin Gradle plugin. It does this by calling out to the maven plugin and the dependency management plugin; the maven plugin is always present, and the dependency management plugin is present if you are using the Spring Boot plugin. To generate a pom.xml remember to apply the maven and Thin Gradle plugins.

NOTE: Gradle now has a maven-publish plugin that works with the newer "standard" configurations (e.g. runtimeOnly replaces runtime). It also works with the thin launcher plugin.

The generated pom goes in the normal maven place by default under META-INF/maven. You can configure the output directory by setting the "output" property of the "thinPom" task.

You can customize the generated pom.xml, or switch it off, by creating your own task in build.gradle and forcing the jar task to depend on it instead of "thinPom", or by simply not using the Thin Gradle plugin. Example (which just duplicates the default):

task createPom {
	doLast {
		pom {
			withXml(dependencyManagement.pomConfigurer)
		}.writeTo("build/resources/main/META-INF/maven/${project.group}/${project.name}/pom.xml")
	}
}

jar.dependsOn = [createPom]

Instead of or as well as a pom.xml you could generate a thin.properties using gradle thinProperties (the task is always registered by the Thin Gradle plugin but is not executed by default). By default it shows up in META-INF in the built resources, so you need to run it before the jar is built, either manually, or via a task dependency, e.g.

jar.dependsOn = [thinProperties]

The generated properties file is "computed" (it contains all the transitive dependencies), so if you have that, the dependencies from the pom.xml will be ignored.

If you look at the jar file produced by the build you will see that it is "thin" (a few KB), but executable with java -jar ....

How does it Work?

Inspect the app jar that you built (or one of the samples in this project) and notice that it is only a few KB. It is just a regular jar file with the app classes in it and one or two extra features. The things it needs to operate are:

  1. The ThinJarWrapper class has been added.
  2. Either a pom.xml and/or a META-INF/thin.properties which lists the dependencies of the app.

When the app runs the main method per the manifest is the ThinJarWrapper. Its job is to locate another jar file (the "launcher"). The wrapper downloads the launcher (if it needs to), or else uses the cached version in your local Maven repository.

The launcher then takes over and reads the pom.xml (if present) and the thin.properties, downloading the dependencies (and all transitives) as necessary, and setting up a new class loader with them all on the classpath. It then runs the application's own main method with that class loader. The pom.xml can be in the root of the jar or in the standard META-INF/maven location.

The app jar in the demo is built using the Spring Boot plugin and a custom Layout (so it only builds with Spring Boot 2.x and above).

Caching JARs

All jar files are cached in the local Maven repository, so if you are building and running the same app repeatedly, it should be faster after the first time, or if the local repo is already warm.

The local repository can be re-located by setting a System property "thin.root". For example to use the current directory:

$ java -Dthin.root=. -jar app/target/*.jar

This will download all the dependencies to ${thin.root}/repository, and look for Maven settings in ${thin.root}/settings.xml.

You can also do a "dry run", just to warm up the cache and not run the app, by setting a System property or command line argument "thin.dryrun" (to any value except "false"). In fact, since you don't need the application code for this (except the META-INF/thin.properties), you could run only the launcher, or the wrapper which is contained in the launcher for convenience. This is a useful trick for laying down a file system layer in a container image, for example.

NOTE: options for the ThinJarLauncher that are listed as -Dthin.* can also be provided as command line arguments (--thin.* per Spring Boot conventions), or as environment variables (THIN_* capitalized and underscored). The command line options are removed before passing down to the Boot app. The ThinJarWrapper also accepts system properties, environment variables or command line flags for its (smaller) set of optional arguments.

Build Tools

Maven

In addition to the Spring Boot layout there is an optional Maven plugin which can be used to do the dry run (download and cache the dependencies) for the current project, or for any project that has an executable thin jar in the same format. The "app" sample in this repo declares this plugin and inserts it into the "package" lifecycle:

<plugin>
	<groupId>org.springframework.boot.experimental</groupId>
	<artifactId>spring-boot-thin-maven-plugin</artifactId>
	<version>${wrapper.version}</version>
	<executions>
		<execution>
			<id>resolve</id>
			<goals>
				<goal>resolve</goal>
			</goals>
			<inherited>false</inherited>
		</execution>
	</executions>
</plugin>

After running the build, there is a deployable warm-cache and a copy of the executable jar at target/thin/root (by default):

$ cd samples/app
$ mvn package
$ cd target/thin/root
$ java -Dthin.root=. -jar app-0.0.1-SNAPSHOT.jar

The "simple" sample has the same feature, but it also downloads and warms up the cache for the "app" sample, so you could use the same build to run both apps if you felt like it.

The Maven plugin also has a properties mojo, so you can create or update thin.properties from the dependencies of the project directly. By default it creates a thin.properties in src/main/resources/META-INF, but you can change the output directory with the plugin configuration. Example:

$ cd samples/app
$ mvn spring-boot-thin:properties -Dthin.output=.

By default the thin.properties is "computed" (i.e. it contains all transitive dependencies), but you can switch to just the declared dependencies using the "compute" configuration flag in the plugin (or -Dthin.compute=false on the command line).

Gradle

The same features are available to Gradle users by adding the thin jar plugin (as described above).

The plugin creates 2 tasks for every jar task in the project, one that reolves the dependencies, and one that copies the jar into the same location to make it easy to launch. A "dry run" can be executed in Gradle by calling the "thinResolve" task defined by the plugin, e.g.

$ cd samples/simple
$ gradle thinResolve
$ cd build/thin/deploy
$ java -Dthin.root=. -jar simple-0.0.1-SNAPSHOT.jar

The default location for the cache is build/thin/root but this was changed in the build.gradle for that sample:

thinResolvePrepare {
	into new File("${buildDir}/thin/deploy")
}

NOTE: The "thinResolve" and "thinResolvePrepare" tasks are the default names for a single jar project. If your jar task is not called "jar", then the names are appended with the jar task name (capitalized), e.g. "thinResolveMyJar" for a task called "myJar"). If you have multiple jar tasks in the project, then each one has its own resolve tasks.

Deploying to Cloud Foundry (or Heroku)

The thin launcher (1.0.4 and above) adds an empty "lib" entry to the jar so that it matches the default detection algorithm for a Java application with the standard Java buildpack. As of version v4.12 of the Java buildpack the dependencies will be computed during staging (in the "compile" step of the buildpack), so you don't incur that cost on startup.

You can also save the staging cost, and resolve the dependencies locally before you push the app.

$ java -jar target/demo-0.0.1.jar --thin.dryrun --thin.root=target/thin/.m2
$ (cd target/thin; jar -xf ../demo-0.0.1,jar)
$ cf push myapp -p target/thin

(Note the use of a subdirectory .m2 to hold the local repository cache - this works because the root is the default HOME directory in a Cloud Foundry app.)

The Maven plugin has a "resolve" task with a flag unpack (or -Dthin.unpack on the command line) that creates the cache in the precise form that you need to push to Cloud Foundry. The unpack flag is false by default, so remember to set it if you want to use Maven to prepare the push.

Command Line Options

You can set a variety of options on the command line or with system properties (-D...). The thin.* properties are all removed from the command line before calling the main class, so the main class doesn't have to know how it was launched.

Option Default Description
thin.main Start-Class in MANIFEST.MF The main class to launch (for a Spring Boot app, usually the one with @SpringBootApplication)
thin.dryrun false Only resolve and download the dependencies. Don't run any main class. N.B. any value other than "false" (even empty) is true.
thin.offline false Switch to "offline" mode. All dependencies must be available locally (e.g. via a previous dry run) or there will be an exception.
thin.force false Force dependency resolution to happen, even if dependencies have been computed, and marked as "computed" in thin.properties.
thin.classpath false Only print the classpath. Don't run the main class. Two formats are supported: "path" and "properties". For backwards compatibility "true" or empty are equivalent to "path".
thin.root ${user.home}/.m2 The location of the local jar cache, laid out as a maven repository. The launcher creates a new directory here called "repository" if it doesn't exist.
thin.libs <empty> Additional classpath entries to append at runtime in the same form as you would use in java -classpath .... If this property is defined then unresolved dependencies will be ignored when the classpath is computed, possibly leading to runtime class not found exceptions.
thin.archive the same as the target archive The archive to launch. Can be used to launch a JAR file that was build with a different version of the thin launcher, for instance, or a fat jar built by Spring Boot without the thin launcher.
thin.parent <empty> A parent archive to use for dependency management and common classpath entries. If you run two apps with the same parent, they will have a classpath that is the same, reading from left to right, until they actually differ.
thin.location file:.,classpath:/ The path to directory containing thin properties files (as per thin.name), as a comma-separated list of resource locations (directories). These locations plus the same paths relative /META-INF will be searched.
thin.name "thin" The name of the properties file to search for dependency specifications and overrides.
thin.profile Comma-separated list of profiles to use to locate thin properties. E.g. if thin.profile=foo the launcher searches for files called thin.properties and thin-foo.properties.
thin.library org.springframework.boot.experimental:spring-boot-thin-launcher:1.0.31.RELEASE A locator for the launcher library. Can be Maven coordinates (with optional maven:// prefix), or a file (with optional file:// prefix).
thin.repo https://repo.spring.io/snapshot (also contains GA releases) Base URL for the thin.library if it is in Maven form (the default).
thin.launcher org.springframework.boot.thin.ThinJarLauncher The main class in the thin.library. If not specified it is discovered from the manifest Main-Class attribute.
thin.parent.first true Flag to say that the class loader is "parent first" (i.e. the system class loader will be used as the default). This is the "standard" JDK class loader strategy. Setting it to false is similar to what is normally used in web containers and application servers.
thin.parent.boot true Flag to say that the parent class loader should be the boot class loader not the "system" class loader. The boot loader normally includes the JDK classes, but not the target archive, nor any agent jars added on the command line.
thin.debug false Flag to switch on some slightly verbose logging during the dependency resolution. Can also be switched on with debug (like in Spring Boot).
thin.trace false Super verbose logging of all activity during the dependency resolution and launch process. Can also be switched on with trace.

Any other thin.properties.* properties are used by the launcher to override or supplement the ones from thin.properties, so you can add additional individual dependencies on the command line using thin.properties.dependencies.* (for instance).

Downstream Tools

The default behaviour of the ThinJarWrapper is to locate and launch the ThinJarLauncher, but it can also run any main class you like by using the thin.library and thin.launcher properties. One of the main reasons to provide this feature is to be able to support "tools" that process the application jar (or whatever), for example to generate metadata, create file system layers, etc. To create a new tool, make an executable jar (it can even be thin) with a Main-Class in its manifest, and point to it with thin.library. The launched main class will find the same command line as the launched jar, but with --thin.library removed if it was there. It will also find a system property thin.source containing the location of the launched jar, or the original thin.archive if that was provided on the command line (this is the archive that contains the data to process normally). If the tool jar is thin, i.e. if the main class is ThinJarWrapper, then the thin.archive command line argument and system property will also be removed (to prevent an infinite loop, where the wrapper just runs itself over and over).

An example of a tool jar is the spring-boot-thin-tools-converter (see below). You could use that as a prototype if you wanted to create your own.

HOWTO Guides

How to Externalize the Properties File

Example command line showing to pick up an external properties file:

$ cat config/thin.properties
dependencies.spring-boot-starter-web: org.springframework.boot:spring-boot-starter-web
$ java -jar app.jar --thin.location=file:./config

How to Create a Docker File System Layer

Precompute the dependencies:

$ java -jar app.jar --thin.root=m2 --thin.dryrun
$ java -jar app.jar --thin.classpath=properties > thin.properties

Then build a docker image using a Dockerfile based on this:

FROM openjdk:8-jdk-alpine
VOLUME /tmp

ADD m2 m2
ADD app.jar app.jar
ADD thin.properties thin.properties

ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar app.jar --thin.root=/m2" ]

EXPOSE 8080

The step to add a thin.properties is optional, as is its calculation (you could maintain a hand-written properties file inside the JAR as well).

How to Change Dependencies

You can change the runtime dependencies, by changing the thin.properties in the jar. You can also read a local thin.properties from the current working directory, or set a System property thin.name to change the local file name (defaults to thin). There is also a thin.profile (comma separated list) which is appended to thin.name, so additional libraries can be added using thin-{profile}.properties. Profile-specific properties are loaded last so they take precedence. Example to pick up an extra set of dependencies in thin-rabbit.properties:

$ java -jar myapp.jar --thin.profile=rabbit

Profile-specific thin.properties can be saved in the jar file (conventionally in META-INF), or in the current working directory by default.

NOTE: You can add or override thin.properties entries on the command line or with System properties using key names in thin.properties.* (the prefix thin.properties. is stripped).

How to Upgrade Spring Boot or Spring Cloud

If your main pom (or properties) file uses boms to manage dependency versions, you can change the version of the bom using thin.properties. E.g.

boms.spring-boot-dependencies=org.springframework.boot:spring-boot-dependencies:2.2.4.RELEASE
...

If your main pom uses properties to manage dependencies (e.g. via the Spring Boot starter parent), you can change the value of the property using thin.properties. E.g.

spring-boot.version=2.2.4.RELEASE
spring-cloud.version=Hoxton.SR1

where the pom has

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring-boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

How to Exclude a Transitive Dependency

You can exclude and remove dependencies by prepending a key in the properties file with exclusions.. E.g.

dependencies.spring-boot-starter-web=org.springframework.boot:spring-boot-starter-web
dependencies.spring-boot-starter-jetty=org.springframework.boot:spring-boot-starter-jetty
exclusions.spring-cloud-starter-tomcat=org.springframework.boot:spring-cloud-starter-tomcat

How to Convert a Thin Jar to a Fat Jar

There is a converter tool that you can use as a library in place of the launcher. It works by copying all of the libraries from a thin.root into the new jar. Example:

$ java -jar myapp.jar --thin.dryrun --thin.root=target/thin/root
$ java -jar myapp.jar --thin.library=org.springframework.boot.experimental:spring-boot-thin-tools-converter:1.0.31.RELEASE
$ java -jar myapp-exec.jar

Building

To build this project locally, use the maven wrapper in the top level

$ ./mvnw clean install

Then run the "app" jar:

$ java -jar ./app/target/*.jar

(It starts an empty Spring Boot app with Tomcat.)

You can also build the samples independently.

Classpath Computation

The launcher has some optional arguments that result in classpath computations, instead of running the Boot app. E.g.

$ java -jar myapp.jar --thin.classpath=path

prints out (on stdout) a class path in the form that can be used directly in java -cp. So this is a way to run the app from its main method (which is faster than using the launcher):

$ CLASSPATH=`java -jar myapp.jar --thin.classpath=path`
$ java -cp "$CLASSPATH:myapp.jar" demo.MyApplication

You can also compute the classpath using explicit name and profile parameters:

$ java -jar myapp.jar --thin.classpath=path --thin.name=app --thin.profile=dev

will look for app.properties and app-dev.properties to list the dependencies.

You can also specify a "parent" archive which is used to calculate a prefix for the classpath. Two apps that share a parent then have the same prefix, and can share classes using -Xshare:on. For example:

$ CP1=`java -jar myapp.jar --thin.classpath=path`
$ CP2=`java -jar otherapp.jar --thin.classpath=path --thin.parent=myapp.jar`

$ java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -Xshare:off \
  -XX:DumpLoadedClassList=app.classlist \
  -noverify -cp $CP1:myapp.jar demo.MyApplication
$ java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -Xshare:dump \
  -XX:SharedArchiveFile=app.jsa -XX:SharedClassListFile=app.classlist \
  -noverify -cp $CP1

$ java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -Xshare:on \
  -XX:SharedArchiveFile=app.jsa -noverify -cp $CP1:myapp.jar demo.MyApplication
$ java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -Xshare:on \
  -XX:SharedArchiveFile=app.jsa -noverify -cp $CP1:otherapp.jar demo.OtherApplication

the two apps at the end are sharing class data from app.jsa and will also start up faster (e.g. 6s startup goes down to 4s for a vanilla Eureka Server).

The thin launcher can be used to pre-compute its own dependency graph in the form of a properties file, which also speeds up the launch a bit, even if you still have to resolve all the jars (remotely or from the cache). To compute the dependency graph and output the result in the form of a properties file, just use the thin.classpath=properties flag on startup, e.g.

$ java -jar myapp.jar --thin.classpath=properties > thin.properties
$ java -jar myapp.jar

In this example the second startup will be slightly faster, depending on the size of the classpath, but up to a few hundred milliseconds on even a fast server, and more in a constrained environment.

It also works fine with profiles, so, for example, if myapp.jar contains a META-INF/thin-rapid.properties you could do this:

$ java -jar myapp.jar --thin.profile=rapid --thin.classpath=properties > thin-super.properties
$ java -jar myapp.jar --thin.profile=super

Note that the generated thin.properties in these examples contains the property value computed=true. This tells the dependency graph calculator that the dependencies provided do not need to have their transitive dependencies or versions computed. It is possible to combine more than one properties file if they have different values of the computed flag, but if they both also contain dependencies then only the computed ones will be used. Note that this means you can compute a profile using --thin.classpath=properties and use it as a cache, speeding up startup without affecting any other settings that might be in other thin.properties.

How to Change the Maven Local Repository

You can change the location of the local Maven repository, used to resolve and cache artifacts, using the standard Maven settings.xml file (with a top level element called <localRepository/>). You can also use a system property maven.repo.local (or maven.home which defaults to ${user.home}/.m2) when you launch the thin jar, but not a command line flag. The Maven and Gradle plugins respond to the settings.xml and also (with Maven) to -Dmaven.repo.local as a command line flag. When the launcher runs it also looks in ${thin.root}/.. for a settings.xml file and uses that in preference to any other location if it exists. (For historical reasons it also looks in ${thin.root}/.m2 but that directory is unlikely to exist.)

How to Configure a Proxy

The dependency resolution uses Maven libraries, and should respect the proxy settings in your settings.xml. The initial download of the launcher by the ThinJarWrapper uses regular JDK libraries so you need to specify the normal -D args for networking as well, unless you have the launcher already cached locally.

Using a Mirror for Maven Central

The thin launcher itself parses your local Maven settings.xml and uses the mirror settings there. To download the launcher itself, and bootstrap the process, you need to explicitly provide a thin.repo to the wrapper (the same as the mirror). You can do this on the command line when running the jar, using all the usual mechanisms. To run the build plugins resolve goals you can make the thin launcher jar a dependency of the plugin, to ensure it is cached locally before the plugin runs. E.g.

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-thin-maven-plugin</artifactId>
            <version>${wrapper.version}</version>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot.experimental</groupId>
                    <artifactId>spring-boot-thin-launcher</artifactId>
                    <classifier>exec</classifier>
                    <version>${wrapper.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</pluginManagement>

Or else you can set a project, system property or environment variable. E.g.

$ ./mvnw spring-boot-thin:resolve -Dthin.repo=http://localhost:8081/repository/maven-central

or

$ ./gradlew thinResolve -P thin.repo=http://localhost:8081/repository/maven-central

System properties (thin.repo) and environment variables (THIN_REPO) work too.

Using a Custom Repository for Dependencies

The thin launcher will use repository declarations from the pom.xml in the archive, and also from the ~/.m2/settings.xml (by default, but can be relocated using maven.home or thin.root). If you have a private repository that requires credentials to access it, the best choice is settings.xml. This also applies to the Gradle plugin because it executes the jar file, and the underlying mechanism is implemented using Maven.

NOTE: The thin.repo setting only applies to the location of the launcher jar itself. If your custom repo is not a mirror it is unlikely to be that location.

License

This project is Open Source software released under the Apache 2.0 license.

spring-boot-thin-launcher's People

Contributors

aleksimpson avatar bsideup avatar dependabot[bot] avatar dsyer avatar jjelliott avatar jlleitschuh avatar loosebazooka avatar marcingrzejszczak avatar markfisher avatar mrbitrary avatar spring-operator avatar stefanocke avatar stephlag avatar sudharakap avatar wilkinsona avatar yesid-bocanegra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-boot-thin-launcher's Issues

Spring Boot 2.0 apps cannot be launched with Spring Boot 1.x

Not really very surprising this one, and it will probably be closed as "Won't Fix". But this is what happens when you compile with 2.0 and run with 1.x (or vice versa):

Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
	at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:186)
	at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:133)
	... 6 more
Caused by: java.lang.NoSuchMethodError: org.springframework.boot.SpringApplication.run(Ljava/lang/Class;[Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext;
	at com.example.LauncherApplication.main(LauncherApplication.java:21)
	... 15 more

Running build fails at simple

Running build fails at simple:

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] tools .............................................. SUCCESS [  4.051 s]
[INFO] Thin Launcher ...................................... SUCCESS [  2.282 s]
[INFO] maven-plugin ....................................... SUCCESS [  4.943 s]
[INFO] Thin Wrapper ....................................... SUCCESS [  0.865 s]
[INFO] Thin Launcher Parent ............................... SUCCESS [  0.073 s]
[INFO] Thin Launcher Gradle ............................... SUCCESS [  0.744 s]
[INFO] capsule-app ........................................ SUCCESS [  8.304 s]
[INFO] app ................................................ SUCCESS [  5.719 s]
[INFO] simple ............................................. FAILURE [  7.676 s]
[INFO] Thin Launcher Samples .............................. SKIPPED
[INFO] Thin Launcher Sample Tests ......................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 35.774 s
[INFO] Finished at: 2017-01-19T22:11:08+00:00
[INFO] Final Memory: 99M/668M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot.experimental:spring-boot-thin-maven-plugin:0.0.1.BUILD-SNAPSHOT:resolve (resolve) on project simple: Cannot locate deployable /Users/aliostad/github/spring-boot-thin-launcher/samples/simple/target/simple-0.0.1-SNAPSHOT.jar: Could not exec java: Application finished with exit code: 1 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

And the error seems to be

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:92)
	at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:77)
Caused by: org.springframework.boot.cli.compiler.grape.DependencyResolutionFailedException: java.lang.IllegalStateException: Cannot resolve version for org.springframework.cloud:spring-cloud-starter-config:jar: ()
	at org.springframework.boot.loader.thin.AetherEngine.resolveDependencies(AetherEngine.java:236)
	at org.springframework.boot.loader.thin.AetherEngine.resolveTransitive(AetherEngine.java:245)
	at org.springframework.boot.loader.thin.AetherEngine.resolve(AetherEngine.java:186)
	at org.springframework.boot.loader.thin.ArchiveUtils$ArchiveDependencies.resolve(ArchiveUtils.java:411)
	at org.springframework.boot.loader.thin.ArchiveUtils.extract(ArchiveUtils.java:264)
	at org.springframework.boot.loader.thin.ArchiveUtils.combine(ArchiveUtils.java:709)
	at org.springframework.boot.loader.thin.ThinJarLauncher.getClassPathArchives(ThinJarLauncher.java:245)
	at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:139)
	at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:102)
	... 6 more
Caused by: java.lang.IllegalStateException: Cannot resolve version for org.springframework.cloud:spring-cloud-starter-config:jar: ()
	at org.springframework.boot.loader.thin.AetherEngine.getCollectRequest(AetherEngine.java:298)
	at org.springframework.boot.loader.thin.AetherEngine.resolveDependencies(AetherEngine.java:228)

Use maven.repo.local system property if set

The user already has the option to set maven.home (not documented but quite explicit in code), but the usual Maven command line flag of maven.repo.local doesn't work. As a courtesy, and to support standard Maven idioms in the maven plugin, we should support it in the launcher.

Proxy settings provided in settings.xml are not used during download

My settings.xml is basic :

<settings>
  <proxies>
   <proxy>
      <id>example-proxy</id>
      <active>true</active>
      <protocol>https</protocol>
      <host>172.26.132.8</host>
      <port>3128</port>
      <nonProxyHosts>www.google.com|*.example.com</nonProxyHosts>
    </proxy>
  </proxies>
</settings>

Then I run :

java -Dthin.profile=exclude_Shared -Dthin.classpath=path -Dthin.root=. -jar MyJar.jar --thin.dryrun

and I get :

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:118)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:90)
Caused by: java.lang.IllegalStateException: hidden.org.eclipse.aether.resolution.ArtifactResolutionException: The following artifacts could not be resolved: ch.qos.logback:logback-core:jar:1.1.11, ch.qos.logback:logback-classic:jar:1.1.11, com.google.code.findbugs:annotations:jar:3.0.1, org.springframework.kafka:spring-kafka:jar:1.3.0.RELEASE, org.springframework:spring-expression:jar:4.3.11.RELEASE, org.springframework:spring-context:jar:4.3.11.RELEASE, org.freemarker:freemarker:jar:2.3.26-incubating, net.jcip:jcip-annotations:jar:1.0, com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0, org.springframework.security:spring-security-core:jar:4.2.3.RELEASE, org.slf4j:jul-to-slf4j:jar:1.7.25, org.springframework:spring-tx:jar:4.3.11.RELEASE, com.fasterxml.jackson.core:jackson-databind:jar:2.8.10, org.slf4j:slf4j-api:jar:1.7.25, org.springframework:spring-web:jar:4.3.11.RELEASE, org.springframework.security:spring-security-config:jar:4.2.3.RELEASE, org.yaml:snakeyaml:jar:1.17, com.sun.mail:dsn:jar:1.5.6, javax.activation:activation:jar:1.1.1, org.springframework:spring-context-support:jar:4.3.11.RELEASE, org.springframework:spring-core:jar:4.3.11.RELEASE, org.springframework:spring-aop:jar:4.3.11.RELEASE, org.slf4j:jcl-over-slf4j:jar:1.7.25, io.jsonwebtoken:jjwt:jar:0.9.0, com.sun.mail:javax.mail:jar:1.5.6, org.springframework.boot:spring-boot-autoconfigure:jar:1.5.7.RELEASE, org.apache.kafka:kafka-clients:jar:0.11.0.1, org.springframework:spring-beans:jar:4.3.11.RELEASE, com.google.code.findbugs:jsr305:jar:3.0.2, com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.8.10, org.slf4j:log4j-over-slf4j:jar:1.7.25, org.springframework.retry:spring-retry:jar:1.2.1.RELEASE, org.jooq:jool:jar:0.9.12, org.springframework.boot:spring-boot-starter-logging:jar:1.5.7.RELEASE, org.springframework.boot:spring-boot-starter:jar:1.5.7.RELEASE, com.fasterxml.jackson.core:jackson-core:jar:2.8.10, net.jpountz.lz4:lz4:jar:1.3.0, org.springframework.security:spring-security-web:jar:4.2.3.RELEASE, org.springframework.boot:spring-boot-starter-security:jar:1.5.7.RELEASE, org.springframework:spring-messaging:jar:4.3.11.RELEASE, org.springframework.boot:spring-boot-starter-mail:jar:1.5.7.RELEASE, com.google.guava:guava:jar:20.0, org.xerial.snappy:snappy-java:jar:1.1.2.6, org.springframework.boot:spring-boot:jar:1.5.7.RELEASE, io.netty:netty-all:jar:4.1.4.Final: Could not transfer artifact ch.qos.logback:logback-core:jar:1.1.11 from/to spring-snapshots (https://repo.spring.io/libs-snapshot): connect timed out
        at org.springframework.boot.loader.thin.DependencyResolver.collectNonTransitive(DependencyResolver.java:494)
        at org.springframework.boot.loader.thin.DependencyResolver.aetherDependencies(DependencyResolver.java:234)
        at org.springframework.boot.loader.thin.DependencyResolver.dependencies(DependencyResolver.java:182)
        at org.springframework.boot.loader.thin.PathResolver.extract(PathResolver.java:182)
        at org.springframework.boot.loader.thin.PathResolver.resolve(PathResolver.java:94)
        at org.springframework.boot.loader.thin.ThinJarLauncher.getClassPathArchives(ThinJarLauncher.java:320)
        at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:169)
        at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:133)
        ... 6 more
Caused by: hidden.org.eclipse.aether.resolution.ArtifactResolutionException: The following artifacts could not be resolved: ch.qos.logback:logback-core:jar:1.1.11, ch.qos.logback:logback-classic:jar:1.1.11, com.google.code.findbugs:annotations:jar:3.0.1, org.springframework.kafka:spring-kafka:jar:1.3.0.RELEASE, org.springframework:spring-expression:jar:4.3.11.RELEASE, org.springframework:spring-context:jar:4.3.11.RELEASE, org.freemarker:freemarker:jar:2.3.26-incubating, net.jcip:jcip-annotations:jar:1.0, com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0, org.springframework.security:spring-security-core:jar:4.2.3.RELEASE, org.slf4j:jul-to-slf4j:jar:1.7.25, org.springframework:spring-tx:jar:4.3.11.RELEASE, com.fasterxml.jackson.core:jackson-databind:jar:2.8.10, org.slf4j:slf4j-api:jar:1.7.25, org.springframework:spring-web:jar:4.3.11.RELEASE, org.springframework.security:spring-security-config:jar:4.2.3.RELEASE, org.yaml:snakeyaml:jar:1.17, com.sun.mail:dsn:jar:1.5.6, javax.activation:activation:jar:1.1.1, org.springframework:spring-context-support:jar:4.3.11.RELEASE, org.springframework:spring-core:jar:4.3.11.RELEASE, org.springframework:spring-aop:jar:4.3.11.RELEASE, org.slf4j:jcl-over-slf4j:jar:1.7.25, io.jsonwebtoken:jjwt:jar:0.9.0, com.sun.mail:javax.mail:jar:1.5.6, org.springframework.boot:spring-boot-autoconfigure:jar:1.5.7.RELEASE, org.apache.kafka:kafka-clients:jar:0.11.0.1, org.springframework:spring-beans:jar:4.3.11.RELEASE, com.google.code.findbugs:jsr305:jar:3.0.2, com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.8.10, org.slf4j:log4j-over-slf4j:jar:1.7.25, org.springframework.retry:spring-retry:jar:1.2.1.RELEASE, org.jooq:jool:jar:0.9.12, org.springframework.boot:spring-boot-starter-logging:jar:1.5.7.RELEASE, org.springframework.boot:spring-boot-starter:jar:1.5.7.RELEASE, com.fasterxml.jackson.core:jackson-core:jar:2.8.10, net.jpountz.lz4:lz4:jar:1.3.0, org.springframework.security:spring-security-web:jar:4.2.3.RELEASE, org.springframework.boot:spring-boot-starter-security:jar:1.5.7.RELEASE, org.springframework:spring-messaging:jar:4.3.11.RELEASE, org.springframework.boot:spring-boot-starter-mail:jar:1.5.7.RELEASE, com.google.guava:guava:jar:20.0, org.xerial.snappy:snappy-java:jar:1.1.2.6, org.springframework.boot:spring-boot:jar:1.5.7.RELEASE, io.netty:netty-all:jar:4.1.4.Final: Could not transfer artifact ch.qos.logback:logback-core:jar:1.1.11 from/to spring-snapshots (https://repo.spring.io/libs-snapshot): connect timed out
        at hidden.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:444)
        at hidden.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:246)
        at hidden.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifacts(DefaultRepositorySystem.java:302)
        at org.springframework.boot.loader.thin.DependencyResolver.collectNonTransitive(DependencyResolver.java:490)
        ... 13 more
Caused by: hidden.org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact ch.qos.logback:logback-core:jar:1.1.11 from/to spring-snapshots (https://repo.spring.io/libs-snapshot): connect timed out
        at hidden.org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:43)
        at hidden.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:355)
        at hidden.org.eclipse.aether.util.concurrency.RunnableErrorForwarder$1.run(RunnableErrorForwarder.java:67)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketTimeoutException: connect timed out
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:542)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:414)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
        at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:326)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445)
        at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
        at org.apache.http.impl.client.DecompressingHttpClient.execute(DecompressingHttpClient.java:164)
        at hidden.org.eclipse.aether.transport.http.HttpTransporter.execute(HttpTransporter.java:287)
        at hidden.org.eclipse.aether.transport.http.HttpTransporter.implGet(HttpTransporter.java:243)
        at hidden.org.eclipse.aether.spi.connector.transport.AbstractTransporter.get(AbstractTransporter.java:59)
        at hidden.org.eclipse.aether.connector.basic.BasicRepositoryConnector$GetTaskRunner.runTask(BasicRepositoryConnector.java:447)
        at hidden.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:350)
        ... 4 more

This is my analysis :

In lines 125 & 138 of https://github.com/eclipse/aether-core/blob/4cf5f7a406b516a45d8bf15e7dfe3fb3849cb87b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java#L125
we can see httpclient proxy is configured from RemoteRepository.proxy

And from https://github.com/dsyer/spring-boot-thin-launcher/blob/561d2e4b8a17addfbba75d4bfca36f4dd3cde4f8/launcher/src/main/java/org/springframework/boot/loader/thin/DependencyResolver.java#L359
we can see builder is not invoking setProxy method (https://github.com/eclipse/aether-core/blob/4cf5f7a406b516a45d8bf15e7dfe3fb3849cb87b/aether-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java#L472)

in conjunction of https://github.com/dsyer/spring-boot-thin-launcher/blob/561d2e4b8a17addfbba75d4bfca36f4dd3cde4f8/launcher/src/main/java/org/springframework/boot/loader/thin/MavenSettings.java#L255

Thank you for taking time to see whether my analysis is good.

Maven plugin properties goal NPE - failure in thin.properties generation - Cannot calculate dependencies for: null

Hi,

Environment:
Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-24T20:49:05+01:00)
Java version: 10.0.1, vendor: Oracle Corporation
Default locale: pl_PL, platform encoding: Cp1250
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

When I try to generate the thin.properties file manually I get the NPE exception.
The plugin console log indicates strange thing that properties are calculated for null.

I kindly ask for support.

[INFO] --- spring-boot-thin-maven-plugin:1.0.12.RELEASE:properties (default-cli) @ salomon-one-pager-generator ---
[INFO] Calculating properties for: null
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.043 s
[INFO] Finished at: 2018-08-01T19:50:41+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot.experimental:spring-boot-thin-maven-plugin:1.0.12.RELEASE:properties (default-cli) on project salomon-one-pager-generator: Cannot calculate dependencies for: null: NullPointerException -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.springframework.boot.experimental:spring-boot-thin-maven-plugin:1.0.12.RELEASE:properties (default-cli) on project salomon-one-pager-generator: Cannot calculate dependencies for: null
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:213)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:194)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:564)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
Caused by: org.apache.maven.plugin.MojoExecutionException: Cannot calculate dependencies for: null
    at org.springframework.boot.experimental.maven.PropertiesMojo.execute (PropertiesMojo.java:99)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:194)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:564)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
Caused by: java.lang.NullPointerException
    at org.springframework.boot.experimental.maven.PropertiesMojo.boms (PropertiesMojo.java:115)
    at org.springframework.boot.experimental.maven.PropertiesMojo.execute (PropertiesMojo.java:84)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:194)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:564)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
[ERROR]
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Use a Gradle-generated pom rather than thin.properties

You can get Gradle to generate a pom for you as long as the maven plugin has been applied.

Here's an example that also gets the dependency management plugin to configure the generated pom with any dependency management that's been configured:

task createPom {
    doLast {
        pom {
            withXml(dependencyManagement.pomConfigurer)
        }.writeTo('build/pom.xml')
    }
}

I think this might be preferable to supporting thin.properties.

Change group ID

To avoid any confusion with existing Spring Boot modules could the groupId be changed to something like org.springframework.boot.experimental.launcher?

Ability to verify checksum (immutable approach)

As a build engineer,
I want to prove authenticity of artifacts by SHA1 (for computed list, without transitive dependencies),
so that I can give a guarantee to a release manager that the deployment binaries was not changed between stage and production environment.

Could not customize maven repositories

mavenRepositories fixes maven repositories to local, spring-snapshots and central, I could not find a way to add a new one.

The scenario is that I test spring-boot-thin in a grails project whose default repo is https://repo.grails.org/grails/core, some jars only published to that repo. When running the thin-jar, it reports the following exception:

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:112)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:81)
Caused by: java.lang.RuntimeException: Could not find artifact org.grails:grails-gsp:jar:3.3.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails:grails-gsp:jar:3.3.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails:grails-web-gsp:jar:3.3.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails:grails-web-gsp:jar:3.3.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails:grails-web-sitemesh:jar:3.3.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails:grails-web-sitemesh:jar:3.3.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails.plugins:converters:jar:3.3.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails.plugins:converters:jar:3.3.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails.plugins:cache:jar:4.0.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails.plugins:cache:jar:4.0.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails.plugins:hibernate5:jar:6.1.6 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails.plugins:hibernate5:jar:6.1.6 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails.plugins:gsp:jar:3.3.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails.plugins:gsp:jar:3.3.0 in central (https://repo1.maven.org/maven2)
Could not find artifact com.bertramlabs.plugins:asset-pipeline-grails:jar:2.14.2 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact com.bertramlabs.plugins:asset-pipeline-grails:jar:2.14.2 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails:grails-gorm-testing-support:jar:1.0.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails:grails-gorm-testing-support:jar:1.0.0 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails.plugins:geb:jar:1.1.1 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails.plugins:geb:jar:1.1.1 in central (https://repo1.maven.org/maven2)
Could not find artifact org.grails:grails-web-testing-support:jar:1.0.0 in spring-snapshots (https://repo.spring.io/libs-snapshot)
Could not find artifact org.grails:grails-web-testing-support:jar:1.0.0 in central (https://repo1.maven.org/maven2)
        at org.springframework.boot.loader.thin.DependencyResolver.dependencies(DependencyResolver.java:205)
        at org.springframework.boot.loader.thin.PathResolver.extract(PathResolver.java:182)
        at org.springframework.boot.loader.thin.PathResolver.resolve(PathResolver.java:94)
        at org.springframework.boot.loader.thin.ThinJarLauncher.getClassPathArchives(ThinJarLauncher.java:324)
        at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:186)
        at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:139)

I think thin-jar should follow the build.gradle's repositories.

Gradle build failing in shadow sample with Boot 2.0 and Gradle 4.8

The changes that were made to support Boot 2.0 appear to be broken. What was supposed to happen:

  1. For a simple one-jar project, the Spring Boot thick jar is omitted and instead a thin jar is built (like what happened in 1.5.x).
  2. For a simple project when the user explicitly configures the Spring Boot thick jar, the result is a thick and a thin executable jar (this is what happens in the "app" sample).
  3. For a project with the shadow plugin, and also applying the Spring Boot plugin, you get 2 jars, one is fat and flat (the shadow one) and the other is thin and executable (the boot one).

What actually happens: 1. and 2. work but 3. is broken (the "shadow" sample). Update the shadow sample to use Boot 2.0 and Gradle 4.8 to see it break:

diff --git a/samples/shadow/build.gradle b/samples/shadow/build.gradle
index 4b0f62c..b402e38 100644
--- a/samples/shadow/build.gradle
+++ b/samples/shadow/build.gradle
@@ -1,6 +1,6 @@
 buildscript {
        ext {
-               springBootVersion = '1.5.1.RELEASE'
+               springBootVersion = '2.0.3.RELEASE'
                wrapperVersion = '1.0.13.BUILD-SNAPSHOT'
         shadowVersion = '2.0.1'
        }
@@ -21,7 +21,8 @@ buildscript {
 apply plugin: 'java'
 apply plugin: 'maven'
 apply plugin: 'eclipse'
-apply plugin: 'spring-boot'
+apply plugin: 'io.spring.dependency-management'
+apply plugin: 'org.springframework.boot'
 apply plugin: 'com.github.johnrengelman.shadow'
 apply plugin: 'org.springframework.boot.experimental.thin-launcher'
 
@@ -30,7 +31,7 @@ version = '0.0.1-SNAPSHOT'
 sourceCompatibility = 1.8
 targetCompatibility = 1.8
 
-assemble.dependsOn = [shadowJar, bootRepackage]
+assemble.dependsOn = [shadowJar, bootJar]
 
 repositories {
        mavenLocal()
diff --git a/samples/shadow/gradle/wrapper/gradle-wrapper.properties b/samples/shadow/gradle/wrapper/gradle-wrapper.properties
index a0b2851..717f038 100644
--- a/samples/shadow/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/shadow/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip

The result is a "successful" build that does not contain a shaded jar:

$ (cd samples/shadow/; gradle clean build)
$ ls -l samples/shadow/build/libs/
total 96
-rw-rw-r-- 1 dsyer dsyer  2737 Jul  9 15:38 shadow-0.0.1-SNAPSHOT-all.jar
-rw-rw-r-- 1 dsyer dsyer 92625 Jul  9 15:38 shadow-0.0.1-SNAPSHOT.jar

The "all" jar is supposed to be a fat (flat) shaded jar, but it only contains the application classes. The other one is supposed to be an executable thin jar but actually it is a Boot "fat" jar without the BOOT-INF/lib - it is neither one thing nor the other.

The AWS sample in Spring Cloud Function is even more broken because it moans about the fact that a task called "thinJarShadowJar" does not exist. This can be fixed by simply removing the afterEvaluate that asserts its existence. I'll probably do that because it doesn't seem to help anyone.

Read repositories from active profiles in Maven settings

In my company we're configuring the internal Maven repositories via profiles in the Maven settings. Currently these settings seems to be completely ignored by the thin-launcher (1.0.3.RELEASE). It's just working if we add the internal repositories to the projects POM.

The thin-launchers Maven settings encapsulation class org.springframework.boot.loader.thin.MavenSettings holds the information about the active profiles, but we don't see any usage of it by the launcher.

Or do we just have to RTFM again :-)?

Add classpath to --thin.debug=true

The thin launcher's main responsibility is to resolve dependencies to run a Boot app. That means, the actual binary doesn't contain them in the first place. Thus it would be cool if the application could be run and the resolved dependencies were logged prior to the actual application's run.

A couple of options to see the classpath already exist, with a couple of downsides:

  • --thin.classpath โ€” doesn't run the app
  • -Ddebug โ€” switches on Boot's debug mode which actually lists the classpath but also enables verbose output for the entire app (autoconfiguration report etc.) which might be too verbose for a production run

It would be cool if -Dthin.debug included the calculated classpath (essentially what --thin.classpath outputs but maybe a single line per dependency for easier grep-ing?).

Support for multi module project

Works for single project but not on multi module project.
Is there any flag in gradle to package dependent projects instead of downloading in runtime

compile project(':library')

Tried out in https://github.com/spring-guides/gs-multi-module/tree/master/complete and got the below error

java -jar gs-multi-module-application-0.0.1-SNAPSHOT.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
...
Caused by: org.springframework.boot.cli.compiler.grape.DependencyResolutionFailedException: org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact gs-multi-module:library:jar:unspecified: in central (http://repo1.maven.org/maven2/)

Add thin.offline option

If a dry run has already been done, it should be possible to shave some time off startup by not doing any network calls to the remote repositories (e.g. DNS can be slow, even if you don't even send HTTP traffic).

Problem when jar is located in folder with spaces in the name

I created an installer with install4j which installs service:
<java mainClass="org.springframework.boot.loader.wrapper.ThinJarWrapper" mainMode="1" vmParameters="-Dthin.root=./libs" arguments="" allowVMPassthroughParameters="true" preferredVM="server" bundleRuntime="true"> <classPath> <archive location="libs/manager-server-*.jar" failOnError="true" /> </classPath> <modulePath /> <nativeLibraryDirectories /> </java>

I packed the application with its dependencies.

If I install the application in a folder which name does not contains spaces works without problem but if I install in "Program Files" the app cannot start and the log files contains following exception:

java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:125)
at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.exe4j.runtime.LauncherEngine.launch(LauncherEngine.java:65)
at com.exe4j.runtime.WinLauncher$2.run(WinLauncher.java:96)
Caused by: java.lang.IllegalArgumentException: File C:\Program%20Files%20(x86)\XXXXX\YYYYY\libs\manager-server-12.0-SNAPSHOT.jar must exist
at org.springframework.boot.loader.data.RandomAccessDataFile.(RandomAccessDataFile.java:68)
at org.springframework.boot.loader.data.RandomAccessDataFile.(RandomAccessDataFile.java:51)
at org.springframework.boot.loader.jar.JarFile.(JarFile.java:83)
at org.springframework.boot.loader.archive.JarFileArchive.(JarFileArchive.java:61)
at org.springframework.boot.loader.archive.JarFileArchive.(JarFileArchive.java:57)
at org.springframework.boot.loader.thin.ArchiveUtils.getArchive(ArchiveUtils.java:55)
at org.springframework.boot.loader.thin.ThinJarLauncher.computeArchive(ThinJarLauncher.java:413)
at org.springframework.boot.loader.thin.ThinJarLauncher.(ThinJarLauncher.java:143)
at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:139)
... 12 more

I'm pretty sure the jar file exists :(
I'm using 1.0.12.RELEASE.
Have you suffered this problem before?

Not downloading dependencies to thin.root if thin.properties is computed

Hello,

I'm writing an article on the Spring Boot Thin Launcher and thus I'm trying various configurations with Maven and Gradle. I've started from an existing Boot with Gradle project which I did not write myself, whose build.gradle is located at https://github.com/eugenp/tutorials/blob/master/spring-boot-gradle/build.gradle.

Compared to it, the file I'm working on only adds the thin launcher plugin and the Maven plugin.

If I run gradlew thinResolve, I get a build/thin/root/repository directory full of dependencies, as expected.

However, if I add the line:
bootJar.dependsOn = [thinProperties]
to the end of my build.gradle, gradlew thinResolve produces a build/thin/root/repository directory containing only the thin launcher itself and no other dependencies.

In either case, the thin jar works fine (the application starts). However, when it contains the thin.properties file, if I run the app with java -jar build/libs/demo-0.0.1-SNAPSHOT.jar --thin.root=foo, then the foo/repository directory again only contains the launcher, whereas if the jar is built without a thin.properties then the foo/repository is populated as I expect.

Is this a bug?

Very large thin/root/repository

Hello

Using this awesome thin launcher, I was able to split my 40 MB uberjar into a 100 kB thin jar and a 70 MB "thin" repository. Wondering were the additional 30 MB came from, I noticed that the launcher

  • includes test scoped dependencies in the repository and
  • spring-boot-thin-launcher-1.0.10.RELEASE-exec.jar is 10 MB fat.

Is there any way to reduce the repository size? This is a problem when iterating changes which affect the repository, because I end up updating an image layer that is larger than the original uber jar.

Command line options for debug/trace output specifically to log dependency resolution outcomes

I've just added the thin launcher to Spring Restbucks and it generally works like a charm.

However, I tried to get some insight into what the launcher is doing but failed to get any output:

java -Dthin.trace=true -jar target/restbucks-1.0.0.BUILD-SNAPSHOT.jar

Do I miss anything? Might be worth mentioning that I use a pre-populated local Maven repository so there's no downloading expected. If that's the reason for the lack of output, it'd still be cool to see which dependencies the launcher is using from where.

Add support for creating a fat-jar out of a thin-jar

In scenarios where one has access to an m2 repo or can upload co-located dependencies
it is easy to use the thin jar approach.

However in restricted environments a fatjar is more appropriate. In such cases it would be
very convenient to be able to create a fatjar from a given thin jar.

Perhaps something like this would do the trick:

java -jar thin.jar -Dthin.supersizeme=./fat.jar

Create "layered" Docker build from thin launcher

Being inspired from the discussion in spring-projects/spring-boot#1813 I would like to see the following based on thin launcher: Create a Docker build with the following properties

  • Add all dependencies as Docker layers (by separate Docker ADD commands)
  • Add the application jar as the latest Docker layer

As long as only the application changes this should result in

  • a very fast Docker build since all other layers would be already cached
  • an improved shipment of the Docker image (ship dependency layers once, then only ship final application layer on changes)

The idea was also discussed here: https://github.com/JCrete/jcrete2017/tree/master/Day3/Session2/Java-Docker-Alignment and a PR is prepared and on it's way.

Use authentication configuration for repositories declared in Maven settings via profiles

Authentication information for dedicated repositories in Maven settings seem to be ignored.

Enclosed you'll see an example of our settings:

<?xml version="1.0"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>internal-releases</id>
            <username>...</username>
            <password>MAVEN_ENCRYPTED_PASSWORD</password>
        </server>
        <server>
            <id>internal-snapshots</id>
            <username>...</username>
            <password>MAVEN_ENCRYPTED_PASSWORD</password>
        </server>
        <server>
            <id>proxy-repositories</id>
            <username>...</username>
            <password>MAVEN_ENCRYPTED_PASSWORD</password>
        </server>
    </servers>
    <mirrors>
        <mirror>
            <id>proxy-repositories</id>
            <url>https://internal-nexus-proxy-repositories/...</url>
            <mirrorOf>*,!internal-releases,!internal-snapshots</mirrorOf>
        </mirror>
    </mirrors>
    <profiles>
        <profile>
            <id>defaultprofile</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                    <id>internal-releases</id>
                    <url>https://internal-nexus-releases/...</url>
                    <snapshots>
                        <enabled>false</enabled>
                    </snapshots>
                    <releases>
                        <enabled>true</enabled>
                        <updatePolicy>never</updatePolicy>
                    </releases>
                </repository>
                <repository>
                    <id>internal-snapshots</id>
                    <url>https://internal-nexus-snapshots/...</url>
                    <snapshots>
                        <enabled>true</enabled>
                        <updatePolicy>daily</updatePolicy>
                    </snapshots>
                    <releases>
                        <enabled>false</enabled>
                    </releases>
                </repository>
            </repositories>
        </profile>
    </profiles>
</settings>

As soon as we're including some artifacts of the above mentioned internal-releases repository, that requires an authentication, following error occurs...

org.eclipse.aether.resolution.ArtifactDescriptorException: Failed to read artifact descriptor for <groupId>:<artifactId>:<packaging>:<version>
	at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.loadPom(DefaultArtifactDescriptorReader.java:282)
	at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.readArtifactDescriptor(DefaultArtifactDescriptorReader.java:198)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.resolveCachedArtifactDescriptor(DefaultDependencyCollector.java:535)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.getArtifactDescriptorResult(DefaultDependencyCollector.java:519)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:409)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:363)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.process(DefaultDependencyCollector.java:351)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.collectDependencies(DefaultDependencyCollector.java:254)
	at org.eclipse.aether.internal.impl.DefaultRepositorySystem.collectDependencies(DefaultRepositorySystem.java:316)
	at org.apache.maven.project.DefaultProjectDependenciesResolver.resolve(DefaultProjectDependenciesResolver.java:172)
	at org.apache.maven.project.DefaultProjectBuilder.resolveDependencies(DefaultProjectBuilder.java:215)
	at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:188)
	at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:126)
	at org.springframework.boot.loader.thin.DependencyResolver.dependencies(DependencyResolver.java:175)
	at org.springframework.boot.loader.thin.DependencyResolver.dependencies(DependencyResolver.java:164)
	at org.springframework.boot.loader.thin.DependencyResolverTests.petclinic(DependencyResolverTests.java:48)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact <groupId>:<artifactId>:<packaging>:<version> from/to internal-releases (https://internal-nexus-releases/...): Unauthorized (401)
	at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:444)
	at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:246)
	at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:223)
	at org.apache.maven.repository.internal.DefaultArtifactResolver.loadPom(DefaultArtifactDescriptorReader.java:267)
	... 39 more
Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact <groupId>:<artifactId>:<packaging>:<version> from/to internal-releases (https://internal-nexus-releases/...): Unauthorized (401)
	at org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:43)
	at org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:355)
	at org.eclipse.aether.util.concurrency.RunnableErrorForwarder$1.run(RunnableErrorForwarder.java:67)
	at org.eclipse.aether.connector.basic.BasicRepositoryConnector$DirectExecutor.execute(BasicRepositoryConnector.java:581)
	at org.eclipse.aether.connector.basic.BasicRepositoryConnector.get(BasicRepositoryConnector.java:249)
	at org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads(DefaultArtifactResolver.java:520)
	at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:421)
	... 42 more
Caused by: org.apache.http.client.HttpResponseException: Unauthorized (401)
	at org.eclipse.aether.transport.http.HttpTransporter.handleStatus(HttpTransporter.java:466)
	at org.eclipse.aether.transport.http.HttpTransporter.execute(HttpTransporter.java:291)
	at org.eclipse.aether.transport.http.HttpTransporter.implGet(HttpTransporter.java:243)
	at org.eclipse.aether.spi.connector.transport.AbstractTransporter.get(AbstractTransporter.java:59)
	at org.eclipse.aether.connector.basic.BasicRepositoryConnector$GetTaskRunner.runTask(BasicRepositoryConnector.java:447)
	at org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:350)
	... 47 more

Some debugging has shown that the artifact repositories doesn't hold any of the configured authentication settings. I hope the description of our problem isn't TLDR and you can reproduce the situation.

Pull request is following...

"hybrid" mode to inline some jars into thin jar

if snapshot jars are not inlined into thin jar, the app could be different after startup because of snapshot jars changed in local maven repository. it's not good for integrated testing and deployment in testing environment. could thin launcher add a configuration to inline some jars?

Gradle shadow plugin breaks thin jar plugin

I don't know if this is a bug in the thin plugin, but it probably is. It's probably not a common use case, but if you wanted to build a shaded jar in addition to a thin one (e.g. to deploy to AWS Lambda) it would be useful to be able to use the shadow plugin. Currently as soon as you apply both plugins in one project Gradle barfs before it even runs any build code:

> Failed to apply plugin [id 'org.springframework.boot.experimental.thin-launcher']
   > Cannot add task ':thinProperties' as a task with that name already exists.

Support Spring Boot 2.0 with Gradle

Spring Boot 2.0's Gradle plugin is fundamentally different to 1.x's and, as a result, the Thin Launcher doesn't work with Boot 2.0 (as of 2.0.0.M3). A couple of key differences:

  1. bootRepackage no longer exists and BootJar tasks should be considered instead
  2. Custom layouts are not (currently?) supported with Gradle in Boot 2.0

1 is relatively straightforward once we've figured out how Boot 2.0 support will be provided (alongside 1.x, in a 2.0 version of this plugin, something else?)

2 is trickier. I'm not yet convinced that supporting custom layouts in Gradle is the right thing to do, at least not in their current form. They make a lot of sense in Maven where things aren't as flexible, but in Gradle where BootJar inherits all the capabilities of Gradle's copy task there may be a more idiomatic and powerful way to do it. The downside would be that code sharing across build systems is lost.

Support for Spring Boot 2.0 build-info generation in Maven

The Maven plugin from Spring Boot works fine with the thin layout, but not if you use the "build-info" mojo from Spring Boot:

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.0.0.RELEASE:build-info (default) on project petclinic-latest: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:2.0.0.RELEASE:build-info failed: An API incompatibility was encountered while executing org.springframework.boot:spring-boot-maven-plugin:2.0.0.RELEASE:build-info: java.lang.NoSuchMethodError: org.springframework.boot.loader.tools.BuildPropertiesWriter$ProjectDetails.<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/time/Instant;Ljava/util/Map;)V

Allow thin.root to be specified in plugin configuration

When we use the resolve goal of the thin plugin it would be nice to be able to specify the thin.root so that it doesn't always point to .

The use case is this:
Suppose we have a number of microservices s1, s2, ... sn.
The libraries for this are placed in a folder called (say) service-dependencies/thin/root/repository.
The maven build puts the dependencies for each service into this service-dependencies folder. Essentially the microservices are part of a bigger system and our maven.repo.local has all other dependencies which I don't want to include with my microservice dependencies. So we end up with a separate repo which contain just the microservice dependencies.

Allowing thin.root to be overridden will allow us to make the plugin write service dependencies to a diff repo.

Support for using Spring Boot without the parent POM

When i'm using Maven's dependency management import (as described in https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html#using-boot-maven-without-a-parent), instead of including the parent POM spring-boot-starter-parent, the application launch fails with following error:

no main manifest attribute, in whatever.jar

MANIFEST.MF of a working thin jar, which is using the parent POM:

Manifest-Version: 1.0
Implementation-Title: whatever
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: whoever
Implementation-Vendor-Id: com.example
Spring-Boot-Version: null
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.wrapper.ThinJarWrapper
Start-Class: com.example.SpringBootApplication
Spring-Boot-Classes: 
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_141
Implementation-URL: http://projects.spring.io/spring-boot/whatever/

MANIFEST.MF of a broken thin jar, which is using the dependency management import:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: whoever
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_141

README out of date.

Hi, this is a wonderful idea to keep the artefact as small as possible. Unfortunately the documentation in the README seems to be not up to date. The instructions on how to configure Maven ends in a failed build. And it seems that module-layout is not supported anymore?
Furthermore a properties file 'thin.properties' is mentioned multiple times. But I cant find such a properties file generated in the jars build. Maybe this could be clarified?

Support for exploded jars in deployer

The tools should be able to identify an exploded jar with a file: URL. This is mainly relevant to the deployer, which could run an app from such a directory without having any Maven co-ordinates. If Maven co-ordinates are also available (e.g. via a pom.xml) then we might also be able to use it in a classpath of a launched app.

Cannot resolve dependency with version property

I encounter the following error

[ERROR] 'build.plugins.plugin[org.springframework.boot:spring-boot-maven-plugin].dependencies.dependency.version' for org.springframework.boot.experimental:spring-boot-thin-layout:jar must be a valid version but is '${spring-boot-thin-maven-plugin.version}'. @ org.dukecon:dukecon-server-springboot:[unknown-version], URL [jar:file:/Users/ascheman/wrk/dukecon/dukecon_server/impl/target/dukecon-server-springboot-1.4-SNAPSHOT.jar!/META-INF/maven/org.dukecon/dukecon-server-springboot/pom.xml], line 669, column 22

The POM contains the following block (lines 660 - 671)

      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <dependencies>
          <dependency>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-thin-layout</artifactId>
            <!-- For some reason spring-boot-thin-maven-plugin or the embedded artifact resolver cannot use a version property here -->
            <!--<version>1.0.7.BUILD-SNAPSHOT</version>-->
            <version>${spring-boot-thin-maven-plugin.version}</version>
          </dependency>
        </dependencies>

As you can see from the comment everything is fine if I replace the version property with a real value.

Running jdeps on the jar

I would like to run jdeps on my spring boot jar, but I assume that this must be run on the fat jar, and not on the thin jar.

Is there any option available, which will generate a fat jar, besides the thin jar? (In which case I could run jdeps on the fat, and deploy the thin.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.