Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
450ab281
Commit
450ab281
authored
Nov 29, 2016
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '1.5.x'
parents
fe63c981
d0c3ece0
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1029 additions
and
70 deletions
+1029
-70
build-tool-plugins.adoc
spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
+37
-0
pom.xml
spring-boot-samples/pom.xml
+1
-0
pom.xml
spring-boot-samples/spring-boot-sample-custom-layout/pom.xml
+107
-0
build.gradle
...ring-boot-sample-custom-layout/src/it/custom/build.gradle
+28
-0
pom.xml
...es/spring-boot-sample-custom-layout/src/it/custom/pom.xml
+41
-0
SampleApplication.java
...c/it/custom/src/main/java/org/test/SampleApplication.java
+24
-0
verify.groovy
...ing-boot-sample-custom-layout/src/it/custom/verify.groovy
+7
-0
build.gradle
...ing-boot-sample-custom-layout/src/it/default/build.gradle
+24
-0
pom.xml
...s/spring-boot-sample-custom-layout/src/it/default/pom.xml
+36
-0
SampleApplication.java
.../it/default/src/main/java/org/test/SampleApplication.java
+24
-0
verify.groovy
...ng-boot-sample-custom-layout/src/it/default/verify.groovy
+7
-0
SampleLayout.java
...stom-layout/src/main/java/sample/layout/SampleLayout.java
+42
-0
SampleLayoutFactory.java
...yout/src/main/java/sample/layout/SampleLayoutFactory.java
+48
-0
spring.factories
...ustom-layout/src/main/resources/META-INF/spring.factories
+2
-0
GradeIT.java
...le-custom-layout/src/test/java/sample/layout/GradeIT.java
+89
-0
Verify.java
...ple-custom-layout/src/test/java/sample/layout/Verify.java
+45
-0
SpringBootPluginExtension.java
...pringframework/boot/gradle/SpringBootPluginExtension.java
+15
-0
RepackageTask.java
.../springframework/boot/gradle/repackage/RepackageTask.java
+10
-22
CustomLoaderLayout.java
...springframework/boot/loader/tools/CustomLoaderLayout.java
+37
-0
DefaultLayoutFactory.java
...ringframework/boot/loader/tools/DefaultLayoutFactory.java
+34
-0
JarWriter.java
...java/org/springframework/boot/loader/tools/JarWriter.java
+15
-2
Layout.java
...in/java/org/springframework/boot/loader/tools/Layout.java
+4
-0
LayoutFactory.java
.../org/springframework/boot/loader/tools/LayoutFactory.java
+36
-0
LoaderClassesWriter.java
...pringframework/boot/loader/tools/LoaderClassesWriter.java
+53
-0
Repackager.java
...ava/org/springframework/boot/loader/tools/Repackager.java
+109
-19
RepackagerTests.java
...rg/springframework/boot/loader/tools/RepackagerTests.java
+74
-0
RepackageMojo.java
...in/java/org/springframework/boot/maven/RepackageMojo.java
+20
-27
custom-layout.apt
...boot-maven-plugin/src/site/apt/examples/custom-layout.apt
+58
-0
index.apt
...oot-tools/spring-boot-maven-plugin/src/site/apt/index.apt
+2
-0
No files found.
spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
View file @
450ab281
...
@@ -484,6 +484,11 @@ The following configuration options are available:
...
@@ -484,6 +484,11 @@ The following configuration options are available:
(
defaults
to
a
guess
based
on
the
archive
type
).
See
(
defaults
to
a
guess
based
on
the
archive
type
).
See
<<
build
-
tool
-
plugins
-
gradle
-
configuration
-
layouts
,
available
layouts
for
more
details
>>.
<<
build
-
tool
-
plugins
-
gradle
-
configuration
-
layouts
,
available
layouts
for
more
details
>>.
|
'layoutFactory`
|A layout factory that can be used if a custom layout is required. Alternative layouts
can be provided by 3rd parties. Layout factories are only used when `layout` is not
specified.
|`requiresUnpack`
|`requiresUnpack`
|A list of dependencies (in the form "`groupId:artifactId`" that must be unpacked from
|A list of dependencies (in the form "`groupId:artifactId`" that must be unpacked from
fat jars in order to run. Items are still packaged into the fat jar, but they will be
fat jars in order to run. Items are still packaged into the fat jar, but they will be
...
@@ -530,6 +535,38 @@ loader should be included or not. The following layouts are available:
...
@@ -530,6 +535,38 @@ loader should be included or not. The following layouts are available:
+[[build-tool-plugins-gradle-configuration-custom-repackager]]
+==== Using a custom layout
If you have custom requirements for how to arrange the dependencies and loader classes
inside the repackaged jar, you can use a custom layout. Any library which defines one
or more `LayoutFactory` implementations can be added to the build script dependencies
and then the layout factory becomes available in the `springBoot` configuration.
For example:
[source,groovy,indent=0,subs="verbatim,attributes"]
----
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}")
classpath("com.example:custom-layout:1.0.0")
}
}
springBoot {
layoutFactory = new com.example.CustomLayoutFactory()
}
+----
NOTE: If there is only one custom `LayoutFactory` on the build classpath and it is
listed in `META-INF/spring.factories` then it is unnecessary to explicitly set it in the
`springBoot` configuration. Layout factories are only used when no explicit `layout` is
specified.
[[build-tool-plugins-understanding-the-gradle-plugin]]
[[build-tool-plugins-understanding-the-gradle-plugin]]
=== Understanding how the Gradle plugin works
=== Understanding how the Gradle plugin works
When `spring-boot` is applied to your Gradle project a default task named `bootRepackage`
When `spring-boot` is applied to your Gradle project a default task named `bootRepackage`
...
...
spring-boot-samples/pom.xml
View file @
450ab281
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
<module>
spring-boot-sample-atmosphere
</module>
<module>
spring-boot-sample-atmosphere
</module>
<module>
spring-boot-sample-batch
</module>
<module>
spring-boot-sample-batch
</module>
<module>
spring-boot-sample-cache
</module>
<module>
spring-boot-sample-cache
</module>
<module>
spring-boot-sample-custom-layout
</module>
<module>
spring-boot-sample-data-cassandra
</module>
<module>
spring-boot-sample-data-cassandra
</module>
<module>
spring-boot-sample-data-couchbase
</module>
<module>
spring-boot-sample-data-couchbase
</module>
<module>
spring-boot-sample-data-elasticsearch
</module>
<module>
spring-boot-sample-data-elasticsearch
</module>
...
...
spring-boot-samples/spring-boot-sample-custom-layout/pom.xml
0 → 100644
View file @
450ab281
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-samples
</artifactId>
<version>
1.5.0.BUILD-SNAPSHOT
</version>
</parent>
<artifactId>
spring-boot-sample-custom-layout
</artifactId>
<name>
Spring Boot Custom Layout Sample
</name>
<description>
Spring Boot Custom Layout Sample
</description>
<url>
http://projects.spring.io/spring-boot/
</url>
<organization>
<name>
Pivotal Software, Inc.
</name>
<url>
http://www.spring.io
</url>
</organization>
<properties>
<main.basedir>
${basedir}/../..
</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-loader-tools
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.gradle
</groupId>
<artifactId>
gradle-tooling-api
</artifactId>
<version>
${gradle.version}
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-invoker-plugin
</artifactId>
<configuration>
<cloneProjectsTo>
${project.build.directory}/it
</cloneProjectsTo>
<settingsFile>
src/it/settings.xml
</settingsFile>
<localRepositoryPath>
${project.build.directory}/local-repo
</localRepositoryPath>
<postBuildHookScript>
verify
</postBuildHookScript>
<addTestClassPath>
true
</addTestClassPath>
<skipInvocation>
${skipTests}
</skipInvocation>
<streamLogs>
true
</streamLogs>
</configuration>
<executions>
<execution>
<id>
integration-test
</id>
<goals>
<goal>
install
</goal>
<goal>
run
</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-failsafe-plugin
</artifactId>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<executions>
<execution>
<id>
copy-effective-pom
</id>
<phase>
generate-test-resources
</phase>
<goals>
<goal>
copy
</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-dependencies
</artifactId>
<version>
${project.version}
</version>
<type>
effective-pom
</type>
<overWrite>
true
</overWrite>
<outputDirectory>
${project.build.directory}
</outputDirectory>
<destFileName>
dependencies-pom.xml
</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>
gradle
</id>
<url>
http://repo.gradle.org/gradle/libs-releases-local
</url>
<releases>
<enabled>
true
</enabled>
</releases>
<snapshots>
<enabled>
false
</enabled>
</snapshots>
</repository>
</repositories>
</project>
spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/build.gradle
0 → 100644
View file @
450ab281
buildscript
{
repositories
{
flatDir
{
dirs
'../..'
}
mavenLocal
()
}
dependencies
{
classpath
"org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}"
classpath
"org.springframework.boot:spring-boot-sample-custom-layout:${project.bootVersion}"
}
}
repositories
{
mavenLocal
()
mavenCentral
()
}
apply
plugin:
'java'
apply
plugin:
'org.springframework.boot'
springBoot
{
layoutFactory
=
new
sample
.
layout
.
SampleLayoutFactory
(
'custom'
)
}
dependencies
{
compile
'org.springframework.boot:spring-boot-starter'
}
spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/pom.xml
0 → 100644
View file @
450ab281
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.springframework.boot.maven.it
</groupId>
<artifactId>
custom
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<version>
@project.version@
</version>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
<configuration>
<layoutFactory
implementation=
"sample.layout.SampleLayoutFactory"
>
<name>
custom
</name>
</layoutFactory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
</dependencies>
</project>
spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/src/main/java/org/test/SampleApplication.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
test
;
public
class
SampleApplication
{
public
static
void
main
(
String
[]
args
)
{
}
}
spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/verify.groovy
0 → 100644
View file @
450ab281
import
java.io.*
;
import
sample.layout.*
;
Verify
.
verify
(
new
File
(
basedir
,
"target/custom-0.0.1.BUILD-SNAPSHOT.jar"
),
"custom"
);
spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/build.gradle
0 → 100644
View file @
450ab281
buildscript
{
repositories
{
flatDir
{
dirs
'../..'
}
mavenLocal
()
}
dependencies
{
classpath
"org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}"
classpath
"org.springframework.boot:spring-boot-sample-custom-layout:${project.bootVersion}"
}
}
repositories
{
mavenLocal
()
mavenCentral
()
}
apply
plugin:
'java'
apply
plugin:
'org.springframework.boot'
dependencies
{
compile
'org.springframework.boot:spring-boot-starter'
}
spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/pom.xml
0 → 100644
View file @
450ab281
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.springframework.boot.maven.it
</groupId>
<artifactId>
default
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<version>
@project.version@
</version>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
</dependencies>
</project>
spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/src/main/java/org/test/SampleApplication.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
test
;
public
class
SampleApplication
{
public
static
void
main
(
String
[]
args
)
{
}
}
spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/verify.groovy
0 → 100644
View file @
450ab281
import
java.io.*
;
import
sample.layout.*
;
Verify
.
verify
(
new
File
(
basedir
,
"target/default-0.0.1.BUILD-SNAPSHOT.jar"
),
"sample"
);
spring-boot-samples/spring-boot-sample-custom-layout/src/main/java/sample/layout/SampleLayout.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
sample
.
layout
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
org.springframework.boot.loader.tools.CustomLoaderLayout
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.LoaderClassesWriter
;
/**
* @author pwebb
*/
public
class
SampleLayout
extends
Layouts
.
Jar
implements
CustomLoaderLayout
{
private
String
name
;
public
SampleLayout
(
String
name
)
{
this
.
name
=
name
;
}
@Override
public
void
writeLoadedClasses
(
LoaderClassesWriter
writer
)
throws
IOException
{
writer
.
writeEntry
(
this
.
name
,
new
ByteArrayInputStream
(
"test"
.
getBytes
()));
}
}
spring-boot-samples/spring-boot-sample-custom-layout/src/main/java/sample/layout/SampleLayoutFactory.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
sample
.
layout
;
import
java.io.File
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.LayoutFactory
;
public
class
SampleLayoutFactory
implements
LayoutFactory
{
private
String
name
=
"sample"
;
public
SampleLayoutFactory
()
{
}
public
SampleLayoutFactory
(
String
name
)
{
this
.
name
=
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
String
getName
()
{
return
this
.
name
;
}
@Override
public
Layout
getLayout
(
File
source
)
{
return
new
SampleLayout
(
this
.
name
);
}
}
spring-boot-samples/spring-boot-sample-custom-layout/src/main/resources/META-INF/spring.factories
0 → 100644
View file @
450ab281
org.springframework.boot.loader.tools.LayoutFactory=\
sample.layout.SampleLayoutFactory
spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/GradeIT.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
sample
.
layout
;
import
java.io.File
;
import
java.io.FileReader
;
import
javax.xml.xpath.XPath
;
import
javax.xml.xpath.XPathExpression
;
import
javax.xml.xpath.XPathFactory
;
import
org.gradle.tooling.GradleConnector
;
import
org.gradle.tooling.ProjectConnection
;
import
org.gradle.tooling.internal.consumer.DefaultGradleConnector
;
import
org.junit.Test
;
import
org.xml.sax.InputSource
;
import
org.springframework.util.FileCopyUtils
;
public
class
GradeIT
{
@Test
public
void
sampleDefault
()
throws
Exception
{
test
(
"default"
,
"sample"
);
}
@Test
public
void
sampleCustom
()
throws
Exception
{
test
(
"custom"
,
"custom"
);
}
private
void
test
(
String
name
,
String
expected
)
throws
Exception
{
File
projectDirectory
=
new
File
(
"target/gradleit/"
+
name
);
File
javaDirectory
=
new
File
(
"target/gradleit/"
+
name
+
"/src/main/java/org/test/"
);
projectDirectory
.
mkdirs
();
javaDirectory
.
mkdirs
();
File
script
=
new
File
(
projectDirectory
,
"build.gradle"
);
FileCopyUtils
.
copy
(
new
File
(
"src/it/"
+
name
+
"/build.gradle"
),
script
);
FileCopyUtils
.
copy
(
new
File
(
"src/it/"
+
name
+
"/src/main/java/org/test/SampleApplication.java"
),
new
File
(
javaDirectory
,
"SampleApplication.java"
));
GradleConnector
gradleConnector
=
GradleConnector
.
newConnector
();
gradleConnector
.
useGradleVersion
(
"2.9"
);
((
DefaultGradleConnector
)
gradleConnector
).
embedded
(
true
);
ProjectConnection
project
=
gradleConnector
.
forProjectDirectory
(
projectDirectory
)
.
connect
();
project
.
newBuild
().
forTasks
(
"clean"
,
"build"
)
.
withArguments
(
"-PbootVersion="
+
getBootVersion
()).
run
();
Verify
.
verify
(
new
File
(
"target/gradleit/"
+
name
+
"/build/libs/"
+
name
+
".jar"
),
expected
);
}
public
static
String
getBootVersion
()
{
return
evaluateExpression
(
"/*[local-name()='project']/*[local-name()='version']"
+
"/text()"
);
}
private
static
String
evaluateExpression
(
String
expression
)
{
try
{
XPathFactory
xPathFactory
=
XPathFactory
.
newInstance
();
XPath
xpath
=
xPathFactory
.
newXPath
();
XPathExpression
expr
=
xpath
.
compile
(
expression
);
String
version
=
expr
.
evaluate
(
new
InputSource
(
new
FileReader
(
"target/dependencies-pom.xml"
)));
return
version
;
}
catch
(
Exception
ex
)
{
throw
new
IllegalStateException
(
"Failed to evaluate expression"
,
ex
);
}
}
}
spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/Verify.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
sample
.
layout
;
import
java.io.File
;
import
java.util.Enumeration
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
public
final
class
Verify
{
private
Verify
()
{
}
public
static
void
verify
(
File
file
,
String
entry
)
throws
Exception
{
ZipFile
zipFile
=
new
ZipFile
(
file
);
try
{
Enumeration
<?
extends
ZipEntry
>
entries
=
zipFile
.
entries
();
while
(
entries
.
hasMoreElements
())
{
if
(
entries
.
nextElement
().
getName
().
equals
(
entry
))
{
return
;
}
}
throw
new
AssertionError
(
"No entry "
+
entry
);
}
finally
{
zipFile
.
close
();
}
}
}
spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java
View file @
450ab281
...
@@ -26,6 +26,7 @@ import org.gradle.api.plugins.JavaPlugin;
...
@@ -26,6 +26,7 @@ import org.gradle.api.plugins.JavaPlugin;
import
org.springframework.boot.gradle.buildinfo.BuildInfo
;
import
org.springframework.boot.gradle.buildinfo.BuildInfo
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.LayoutFactory
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.Layouts
;
/**
/**
...
@@ -90,6 +91,12 @@ public class SpringBootPluginExtension {
...
@@ -90,6 +91,12 @@ public class SpringBootPluginExtension {
*/
*/
LayoutType
layout
;
LayoutType
layout
;
/**
* The layout factory that will be used when no explicit layout is specified.
* Alternative layouts can be provided by 3rd parties.
*/
LayoutFactory
layoutFactory
;
/**
/**
* Libraries that must be unpacked from fat jars in order to run. Use Strings in the
* Libraries that must be unpacked from fat jars in order to run. Use Strings in the
* form {@literal groupId:artifactId}.
* form {@literal groupId:artifactId}.
...
@@ -196,6 +203,14 @@ public class SpringBootPluginExtension {
...
@@ -196,6 +203,14 @@ public class SpringBootPluginExtension {
this
.
layout
=
layout
;
this
.
layout
=
layout
;
}
}
public
LayoutFactory
getLayoutFactory
()
{
return
this
.
layoutFactory
;
}
public
void
setLayoutFactory
(
LayoutFactory
layoutFactory
)
{
this
.
layoutFactory
=
layoutFactory
;
}
public
Set
<
String
>
getRequiresUnpack
()
{
public
Set
<
String
>
getRequiresUnpack
()
{
return
this
.
requiresUnpack
;
return
this
.
requiresUnpack
;
}
}
...
...
spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java
View file @
450ab281
...
@@ -21,7 +21,6 @@ import java.io.IOException;
...
@@ -21,7 +21,6 @@ import java.io.IOException;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
org.gradle.api.Action
;
import
org.gradle.api.Action
;
import
org.gradle.api.DefaultTask
;
import
org.gradle.api.DefaultTask
;
...
@@ -35,6 +34,7 @@ import org.springframework.boot.gradle.SpringBootPluginExtension;
...
@@ -35,6 +34,7 @@ import org.springframework.boot.gradle.SpringBootPluginExtension;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.boot.loader.tools.Repackager.MainClassTimeoutWarningListener
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.FileCopyUtils
;
/**
/**
...
@@ -46,8 +46,6 @@ import org.springframework.util.FileCopyUtils;
...
@@ -46,8 +46,6 @@ import org.springframework.util.FileCopyUtils;
*/
*/
public
class
RepackageTask
extends
DefaultTask
{
public
class
RepackageTask
extends
DefaultTask
{
private
static
final
long
FIND_WARNING_TIMEOUT
=
TimeUnit
.
SECONDS
.
toMillis
(
10
);
private
String
customConfiguration
;
private
String
customConfiguration
;
private
Object
withJarTask
;
private
Object
withJarTask
;
...
@@ -215,7 +213,10 @@ public class RepackageTask extends DefaultTask {
...
@@ -215,7 +213,10 @@ public class RepackageTask extends DefaultTask {
copy
(
file
,
outputFile
);
copy
(
file
,
outputFile
);
file
=
outputFile
;
file
=
outputFile
;
}
}
Repackager
repackager
=
new
LoggingRepackager
(
file
);
Repackager
repackager
=
new
Repackager
(
file
,
this
.
extension
.
getLayoutFactory
());
repackager
.
addMainClassTimeoutWarningListener
(
new
LoggingMainClassTimeoutWarningListener
());
setMainClass
(
repackager
);
setMainClass
(
repackager
);
if
(
this
.
extension
.
convertLayout
()
!=
null
)
{
if
(
this
.
extension
.
convertLayout
()
!=
null
)
{
repackager
.
setLayout
(
this
.
extension
.
convertLayout
());
repackager
.
setLayout
(
this
.
extension
.
convertLayout
());
...
@@ -305,26 +306,13 @@ public class RepackageTask extends DefaultTask {
...
@@ -305,26 +306,13 @@ public class RepackageTask extends DefaultTask {
/**
/**
* {@link Repackager} that also logs when searching takes too long.
* {@link Repackager} that also logs when searching takes too long.
*/
*/
private
class
LoggingRepackager
extends
Repackager
{
private
class
LoggingMainClassTimeoutWarningListener
implements
MainClassTimeoutWarningListener
{
LoggingRepackager
(
File
source
)
{
super
(
source
);
}
@Override
@Override
protected
String
findMainMethod
(
java
.
util
.
jar
.
JarFile
source
)
throws
IOException
{
public
void
handleTimeoutWarning
(
long
duration
,
String
mainMethod
)
{
long
startTime
=
System
.
currentTimeMillis
();
getLogger
().
warn
(
"Searching for the main-class is taking "
try
{
+
"some time, consider using setting "
+
"'springBoot.mainClass'"
);
return
super
.
findMainMethod
(
source
);
}
finally
{
long
duration
=
System
.
currentTimeMillis
()
-
startTime
;
if
(
duration
>
FIND_WARNING_TIMEOUT
)
{
getLogger
().
warn
(
"Searching for the main-class is taking "
+
"some time, consider using setting "
+
"'springBoot.mainClass'"
);
}
}
}
}
}
}
...
...
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/CustomLoaderLayout.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.IOException
;
/**
* Additional interface that can be implemented by {@link Layout Layouts} that write their
* own loader classes.
*
* @author Phillip Webb
* @since 1.5.0
*/
public
interface
CustomLoaderLayout
{
/**
* Write the required loader classes into the JAR.
* @param writer the writer used to write the classes
* @throws IOException if the classes cannot be written
*/
void
writeLoadedClasses
(
LoaderClassesWriter
writer
)
throws
IOException
;
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLayoutFactory.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.File
;
/**
* Default implementation of {@link LayoutFactory}.
*
* @author Phillip Webb
* @since 1.5.0
*/
public
class
DefaultLayoutFactory
implements
LayoutFactory
{
@Override
public
Layout
getLayout
(
File
source
)
{
return
Layouts
.
forFile
(
source
);
}
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java
View file @
450ab281
...
@@ -49,7 +49,7 @@ import java.util.zip.ZipEntry;
...
@@ -49,7 +49,7 @@ import java.util.zip.ZipEntry;
* @author Phillip Webb
* @author Phillip Webb
* @author Andy Wilkinson
* @author Andy Wilkinson
*/
*/
public
class
JarWriter
{
public
class
JarWriter
implements
LoaderClassesWriter
{
private
static
final
String
NESTED_LOADER_JAR
=
"META-INF/loader/spring-boot-loader.jar"
;
private
static
final
String
NESTED_LOADER_JAR
=
"META-INF/loader/spring-boot-loader.jar"
;
...
@@ -155,6 +155,7 @@ public class JarWriter {
...
@@ -155,6 +155,7 @@ public class JarWriter {
* @param inputStream The stream from which the entry's data can be read
* @param inputStream The stream from which the entry's data can be read
* @throws IOException if the write fails
* @throws IOException if the write fails
*/
*/
@Override
public
void
writeEntry
(
String
entryName
,
InputStream
inputStream
)
throws
IOException
{
public
void
writeEntry
(
String
entryName
,
InputStream
inputStream
)
throws
IOException
{
JarEntry
entry
=
new
JarEntry
(
entryName
);
JarEntry
entry
=
new
JarEntry
(
entryName
);
writeEntry
(
entry
,
new
InputStreamEntryWriter
(
inputStream
,
true
));
writeEntry
(
entry
,
new
InputStreamEntryWriter
(
inputStream
,
true
));
...
@@ -204,8 +205,20 @@ public class JarWriter {
...
@@ -204,8 +205,20 @@ public class JarWriter {
* Write the required spring-boot-loader classes to the JAR.
* Write the required spring-boot-loader classes to the JAR.
* @throws IOException if the classes cannot be written
* @throws IOException if the classes cannot be written
*/
*/
@Override
public
void
writeLoaderClasses
()
throws
IOException
{
public
void
writeLoaderClasses
()
throws
IOException
{
URL
loaderJar
=
getClass
().
getClassLoader
().
getResource
(
NESTED_LOADER_JAR
);
writeLoaderClasses
(
NESTED_LOADER_JAR
);
}
/**
* Write the required spring-boot-loader classes to the JAR.
* @param loaderJarResourceName the name of the resource containing the loader classes
* to be written
* @throws IOException if the classes cannot be written
*/
@Override
public
void
writeLoaderClasses
(
String
loaderJarResourceName
)
throws
IOException
{
URL
loaderJar
=
getClass
().
getClassLoader
().
getResource
(
loaderJarResourceName
);
JarInputStream
inputStream
=
new
JarInputStream
(
JarInputStream
inputStream
=
new
JarInputStream
(
new
BufferedInputStream
(
loaderJar
.
openStream
()));
new
BufferedInputStream
(
loaderJar
.
openStream
()));
JarEntry
entry
;
JarEntry
entry
;
...
...
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java
View file @
450ab281
...
@@ -18,9 +18,13 @@ package org.springframework.boot.loader.tools;
...
@@ -18,9 +18,13 @@ package org.springframework.boot.loader.tools;
/**
/**
* Strategy interface used to determine the layout for a particular type of archive.
* Strategy interface used to determine the layout for a particular type of archive.
* Layouts may additionally implement {@link CustomLoaderLayout} if they wish to write
* custom loader classes.
*
*
* @author Phillip Webb
* @author Phillip Webb
* @see Layouts
* @see Layouts
* @see RepackagingLayout
* @see CustomLoaderLayout
*/
*/
public
interface
Layout
{
public
interface
Layout
{
...
...
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.File
;
/**
* Factory interface used to create a {@link Layout}.
*
* @author Dave Syer
* @author Phillip Webb
*/
public
interface
LayoutFactory
{
/**
* Return a {@link Layout} for the specified source file.
* @param source the source file
* @return the layout to use for the file
*/
Layout
getLayout
(
File
source
);
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LoaderClassesWriter.java
0 → 100644
View file @
450ab281
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.IOException
;
import
java.io.InputStream
;
/**
* Writer used by {@link CustomLoaderLayout CustomLoaderLayouts} to write classes into a
* repackaged JAR.
*
* @author Phillip Webb
* @since 1.5.0
*/
public
interface
LoaderClassesWriter
{
/**
* Write the default required spring-boot-loader classes to the JAR.
* @throws IOException if the classes cannot be written
*/
void
writeLoaderClasses
()
throws
IOException
;
/**
* Write custom required spring-boot-loader classes to the JAR.
* @param loaderJarResourceName the name of the resource containing the loader classes
* to be written
* @throws IOException if the classes cannot be written
*/
void
writeLoaderClasses
(
String
loaderJarResourceName
)
throws
IOException
;
/**
* Write a single entry to the JAR.
* @param name the name of the entry
* @param inputStream the input stream content
* @throws IOException if the entry cannot be written
*/
void
writeEntry
(
String
name
,
InputStream
inputStream
)
throws
IOException
;
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java
View file @
450ab281
...
@@ -24,11 +24,15 @@ import java.util.ArrayList;
...
@@ -24,11 +24,15 @@ import java.util.ArrayList;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarFile
;
import
java.util.jar.Manifest
;
import
java.util.jar.Manifest
;
import
org.springframework.boot.loader.tools.JarWriter.EntryTransformer
;
import
org.springframework.boot.loader.tools.JarWriter.EntryTransformer
;
import
org.springframework.core.io.support.SpringFactoriesLoader
;
import
org.springframework.util.Assert
;
import
org.springframework.util.StringUtils
;
/**
/**
* Utility class that can be used to repackage an archive so that it can be executed using
* Utility class that can be used to repackage an archive so that it can be executed using
...
@@ -52,6 +56,10 @@ public class Repackager {
...
@@ -52,6 +56,10 @@ public class Repackager {
private
static
final
byte
[]
ZIP_FILE_HEADER
=
new
byte
[]
{
'P'
,
'K'
,
3
,
4
};
private
static
final
byte
[]
ZIP_FILE_HEADER
=
new
byte
[]
{
'P'
,
'K'
,
3
,
4
};
private
static
final
long
FIND_WARNING_TIMEOUT
=
TimeUnit
.
SECONDS
.
toMillis
(
10
);
private
List
<
MainClassTimeoutWarningListener
>
mainClassTimeoutListeners
=
new
ArrayList
<
MainClassTimeoutWarningListener
>();
private
String
mainClass
;
private
String
mainClass
;
private
boolean
backupSource
=
true
;
private
boolean
backupSource
=
true
;
...
@@ -60,12 +68,28 @@ public class Repackager {
...
@@ -60,12 +68,28 @@ public class Repackager {
private
Layout
layout
;
private
Layout
layout
;
private
LayoutFactory
layoutFactory
;
public
Repackager
(
File
source
)
{
public
Repackager
(
File
source
)
{
this
(
source
,
null
);
}
public
Repackager
(
File
source
,
LayoutFactory
layoutFactory
)
{
if
(
source
==
null
||
!
source
.
exists
()
||
!
source
.
isFile
())
{
if
(
source
==
null
||
!
source
.
exists
()
||
!
source
.
isFile
())
{
throw
new
IllegalArgumentException
(
"Source must refer to an existing file"
);
throw
new
IllegalArgumentException
(
"Source must refer to an existing file"
);
}
}
this
.
source
=
source
.
getAbsoluteFile
();
this
.
source
=
source
.
getAbsoluteFile
();
this
.
layout
=
Layouts
.
forFile
(
source
);
this
.
layoutFactory
=
layoutFactory
;
}
/**
* Add a listener that will be triggered to dispaly a warning if searching for the
* main class takes too long.
* @param listener the listener to add
*/
public
void
addMainClassTimeoutWarningListener
(
MainClassTimeoutWarningListener
listener
)
{
this
.
mainClassTimeoutListeners
.
add
(
listener
);
}
}
/**
/**
...
@@ -97,6 +121,15 @@ public class Repackager {
...
@@ -97,6 +121,15 @@ public class Repackager {
this
.
layout
=
layout
;
this
.
layout
=
layout
;
}
}
/**
* Sets the layout factory for the jar. The factory can be used when no specific
* layout is specific.
* @param layoutFactory the layoutFactory to set
*/
public
void
setLayoutFactory
(
LayoutFactory
layoutFactory
)
{
this
.
layoutFactory
=
layoutFactory
;
}
/**
/**
* Repackage the source file so that it can be run using '{@literal java -jar}'.
* Repackage the source file so that it can be run using '{@literal java -jar}'.
* @param libraries the libraries required to run the archive
* @param libraries the libraries required to run the archive
...
@@ -134,6 +167,9 @@ public class Repackager {
...
@@ -134,6 +167,9 @@ public class Repackager {
if
(
libraries
==
null
)
{
if
(
libraries
==
null
)
{
throw
new
IllegalArgumentException
(
"Libraries must not be null"
);
throw
new
IllegalArgumentException
(
"Libraries must not be null"
);
}
}
if
(
this
.
layout
==
null
)
{
this
.
layout
=
getLayoutFactory
().
getLayout
(
this
.
source
);
}
if
(
alreadyRepackaged
())
{
if
(
alreadyRepackaged
())
{
return
;
return
;
}
}
...
@@ -161,6 +197,19 @@ public class Repackager {
...
@@ -161,6 +197,19 @@ public class Repackager {
}
}
}
}
private
LayoutFactory
getLayoutFactory
()
{
if
(
this
.
layoutFactory
!=
null
)
{
return
this
.
layoutFactory
;
}
List
<
LayoutFactory
>
factories
=
SpringFactoriesLoader
.
loadFactories
(
LayoutFactory
.
class
,
null
);
if
(
factories
.
isEmpty
())
{
return
new
DefaultLayoutFactory
();
}
Assert
.
state
(
factories
.
size
()
==
1
,
"No unique LayoutFactory found"
);
return
factories
.
get
(
0
);
}
/**
/**
* Return the {@link File} to use to backup the original source.
* Return the {@link File} to use to backup the original source.
* @return the file to use to backup the original source
* @return the file to use to backup the original source
...
@@ -203,21 +252,7 @@ public class Repackager {
...
@@ -203,21 +252,7 @@ public class Repackager {
}
}
});
});
writer
.
writeManifest
(
buildManifest
(
sourceJar
));
repackage
(
sourceJar
,
writer
,
unpackLibraries
,
standardLibraries
);
Set
<
String
>
seen
=
new
HashSet
<
String
>();
writeNestedLibraries
(
unpackLibraries
,
seen
,
writer
);
if
(
this
.
layout
instanceof
RepackagingLayout
)
{
writer
.
writeEntries
(
sourceJar
,
new
RenamingEntryTransformer
(((
RepackagingLayout
)
this
.
layout
)
.
getRepackagedClassesLocation
()));
}
else
{
writer
.
writeEntries
(
sourceJar
);
}
writeNestedLibraries
(
standardLibraries
,
seen
,
writer
);
if
(
this
.
layout
.
isExecutable
())
{
writer
.
writeLoaderClasses
();
}
}
}
finally
{
finally
{
try
{
try
{
...
@@ -229,6 +264,23 @@ public class Repackager {
...
@@ -229,6 +264,23 @@ public class Repackager {
}
}
}
}
private
void
repackage
(
JarFile
sourceJar
,
JarWriter
writer
,
final
List
<
Library
>
unpackLibraries
,
final
List
<
Library
>
standardLibraries
)
throws
IOException
{
writer
.
writeManifest
(
buildManifest
(
sourceJar
));
Set
<
String
>
seen
=
new
HashSet
<
String
>();
writeNestedLibraries
(
unpackLibraries
,
seen
,
writer
);
if
(
this
.
layout
instanceof
RepackagingLayout
)
{
writer
.
writeEntries
(
sourceJar
,
new
RenamingEntryTransformer
(
((
RepackagingLayout
)
this
.
layout
).
getRepackagedClassesLocation
()));
}
else
{
writer
.
writeEntries
(
sourceJar
);
}
writeNestedLibraries
(
standardLibraries
,
seen
,
writer
);
writeLoaderClasses
(
writer
);
}
private
void
writeNestedLibraries
(
List
<
Library
>
libraries
,
Set
<
String
>
alreadySeen
,
private
void
writeNestedLibraries
(
List
<
Library
>
libraries
,
Set
<
String
>
alreadySeen
,
JarWriter
writer
)
throws
IOException
{
JarWriter
writer
)
throws
IOException
{
for
(
Library
library
:
libraries
)
{
for
(
Library
library
:
libraries
)
{
...
@@ -244,6 +296,15 @@ public class Repackager {
...
@@ -244,6 +296,15 @@ public class Repackager {
}
}
}
}
private
void
writeLoaderClasses
(
JarWriter
writer
)
throws
IOException
{
if
(
this
.
layout
instanceof
CustomLoaderLayout
)
{
((
CustomLoaderLayout
)
this
.
layout
).
writeLoadedClasses
(
writer
);
}
else
if
(
this
.
layout
.
isExecutable
())
{
writer
.
writeLoaderClasses
();
}
}
private
boolean
isZip
(
File
file
)
{
private
boolean
isZip
(
File
file
)
{
try
{
try
{
FileInputStream
fileInputStream
=
new
FileInputStream
(
file
);
FileInputStream
fileInputStream
=
new
FileInputStream
(
file
);
...
@@ -280,7 +341,7 @@ public class Repackager {
...
@@ -280,7 +341,7 @@ public class Repackager {
startClass
=
manifest
.
getMainAttributes
().
getValue
(
MAIN_CLASS_ATTRIBUTE
);
startClass
=
manifest
.
getMainAttributes
().
getValue
(
MAIN_CLASS_ATTRIBUTE
);
}
}
if
(
startClass
==
null
)
{
if
(
startClass
==
null
)
{
startClass
=
findMainMethod
(
source
);
startClass
=
findMainMethod
WithTimeoutWarning
(
source
);
}
}
String
launcherClassName
=
this
.
layout
.
getLauncherClassName
();
String
launcherClassName
=
this
.
layout
.
getLauncherClassName
();
if
(
launcherClassName
!=
null
)
{
if
(
launcherClassName
!=
null
)
{
...
@@ -300,11 +361,25 @@ public class Repackager {
...
@@ -300,11 +361,25 @@ public class Repackager {
(
this
.
layout
instanceof
RepackagingLayout
)
(
this
.
layout
instanceof
RepackagingLayout
)
?
((
RepackagingLayout
)
this
.
layout
).
getRepackagedClassesLocation
()
?
((
RepackagingLayout
)
this
.
layout
).
getRepackagedClassesLocation
()
:
this
.
layout
.
getClassesLocation
());
:
this
.
layout
.
getClassesLocation
());
manifest
.
getMainAttributes
().
putValue
(
BOOT_LIB_ATTRIBUTE
,
String
lib
=
this
.
layout
.
getLibraryDestination
(
""
,
LibraryScope
.
COMPILE
);
this
.
layout
.
getLibraryDestination
(
""
,
LibraryScope
.
COMPILE
));
if
(
StringUtils
.
hasLength
(
lib
))
{
manifest
.
getMainAttributes
().
putValue
(
BOOT_LIB_ATTRIBUTE
,
lib
);
}
return
manifest
;
return
manifest
;
}
}
private
String
findMainMethodWithTimeoutWarning
(
JarFile
source
)
throws
IOException
{
long
startTime
=
System
.
currentTimeMillis
();
String
mainMethod
=
findMainMethod
(
source
);
long
duration
=
System
.
currentTimeMillis
()
-
startTime
;
if
(
duration
>
FIND_WARNING_TIMEOUT
)
{
for
(
MainClassTimeoutWarningListener
listener
:
this
.
mainClassTimeoutListeners
)
{
listener
.
handleTimeoutWarning
(
duration
,
mainMethod
);
}
}
return
mainMethod
;
}
protected
String
findMainMethod
(
JarFile
source
)
throws
IOException
{
protected
String
findMainMethod
(
JarFile
source
)
throws
IOException
{
return
MainClassFinder
.
findSingleMainClass
(
source
,
return
MainClassFinder
.
findSingleMainClass
(
source
,
this
.
layout
.
getClassesLocation
());
this
.
layout
.
getClassesLocation
());
...
@@ -323,6 +398,21 @@ public class Repackager {
...
@@ -323,6 +398,21 @@ public class Repackager {
}
}
}
}
/**
* Callback interface used to present a warning when finding the main class takes too
* long.
*/
public
interface
MainClassTimeoutWarningListener
{
/**
* Handle a timeout warning.
* @param duration the amount of time it took to find the main method
* @param mainMethod the main method that was actually found
*/
void
handleTimeoutWarning
(
long
duration
,
String
mainMethod
);
}
/**
/**
* An {@code EntryTransformer} that renames entries by applying a prefix.
* An {@code EntryTransformer} that renames entries by applying a prefix.
*/
*/
...
...
spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java
View file @
450ab281
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
org
.
springframework
.
boot
.
loader
.
tools
;
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.file.Files
;
import
java.nio.file.Files
;
...
@@ -347,14 +348,46 @@ public class RepackagerTests {
...
@@ -347,14 +348,46 @@ public class RepackagerTests {
final
LibraryScope
scope
=
mock
(
LibraryScope
.
class
);
final
LibraryScope
scope
=
mock
(
LibraryScope
.
class
);
given
(
layout
.
getLauncherClassName
()).
willReturn
(
"testLauncher"
);
given
(
layout
.
getLauncherClassName
()).
willReturn
(
"testLauncher"
);
given
(
layout
.
getLibraryDestination
(
anyString
(),
eq
(
scope
))).
willReturn
(
"test/"
);
given
(
layout
.
getLibraryDestination
(
anyString
(),
eq
(
scope
))).
willReturn
(
"test/"
);
given
(
layout
.
getLibraryDestination
(
anyString
(),
eq
(
LibraryScope
.
COMPILE
)))
.
willReturn
(
"test-lib/"
);
repackager
.
setLayout
(
layout
);
repackager
.
setLayout
(
layout
);
repackager
.
repackage
(
new
Libraries
()
{
repackager
.
repackage
(
new
Libraries
()
{
@Override
@Override
public
void
doWithLibraries
(
LibraryCallback
callback
)
throws
IOException
{
public
void
doWithLibraries
(
LibraryCallback
callback
)
throws
IOException
{
callback
.
library
(
new
Library
(
libJarFile
,
scope
));
callback
.
library
(
new
Library
(
libJarFile
,
scope
));
}
}
});
});
assertThat
(
hasEntry
(
file
,
"test/"
+
libJarFile
.
getName
())).
isTrue
();
assertThat
(
hasEntry
(
file
,
"test/"
+
libJarFile
.
getName
())).
isTrue
();
assertThat
(
getManifest
(
file
).
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
))
.
isEqualTo
(
"test-lib/"
);
assertThat
(
getManifest
(
file
).
getMainAttributes
().
getValue
(
"Main-Class"
))
.
isEqualTo
(
"testLauncher"
);
}
@Test
public
void
customLayoutNoBootLib
()
throws
Exception
{
TestJarFile
libJar
=
new
TestJarFile
(
this
.
temporaryFolder
);
libJar
.
addClass
(
"a/b/C.class"
,
ClassWithoutMainMethod
.
class
);
final
File
libJarFile
=
libJar
.
getFile
();
this
.
testJarFile
.
addClass
(
"a/b/C.class"
,
ClassWithMainMethod
.
class
);
File
file
=
this
.
testJarFile
.
getFile
();
Repackager
repackager
=
new
Repackager
(
file
);
Layout
layout
=
mock
(
Layout
.
class
);
final
LibraryScope
scope
=
mock
(
LibraryScope
.
class
);
given
(
layout
.
getLauncherClassName
()).
willReturn
(
"testLauncher"
);
repackager
.
setLayout
(
layout
);
repackager
.
repackage
(
new
Libraries
()
{
@Override
public
void
doWithLibraries
(
LibraryCallback
callback
)
throws
IOException
{
callback
.
library
(
new
Library
(
libJarFile
,
scope
));
}
});
assertThat
(
getManifest
(
file
).
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
))
.
isNull
();
assertThat
(
getManifest
(
file
).
getMainAttributes
().
getValue
(
"Main-Class"
))
assertThat
(
getManifest
(
file
).
getMainAttributes
().
getValue
(
"Main-Class"
))
.
isEqualTo
(
"testLauncher"
);
.
isEqualTo
(
"testLauncher"
);
}
}
...
@@ -536,6 +569,29 @@ public class RepackagerTests {
...
@@ -536,6 +569,29 @@ public class RepackagerTests {
}
}
}
}
@Test
public
void
customLayoutFactoryWithoutLayout
()
throws
Exception
{
this
.
testJarFile
.
addClass
(
"a/b/C.class"
,
ClassWithMainMethod
.
class
);
File
source
=
this
.
testJarFile
.
getFile
();
Repackager
repackager
=
new
Repackager
(
source
,
new
TestLayoutFactory
());
repackager
.
repackage
(
NO_LIBRARIES
);
JarFile
jarFile
=
new
JarFile
(
source
);
assertThat
(
jarFile
.
getEntry
(
"test"
)).
isNotNull
();
jarFile
.
close
();
}
@Test
public
void
customLayoutFactoryWithLayout
()
throws
Exception
{
this
.
testJarFile
.
addClass
(
"a/b/C.class"
,
ClassWithMainMethod
.
class
);
File
source
=
this
.
testJarFile
.
getFile
();
Repackager
repackager
=
new
Repackager
(
source
,
new
TestLayoutFactory
());
repackager
.
setLayout
(
new
Layouts
.
Jar
());
repackager
.
repackage
(
NO_LIBRARIES
);
JarFile
jarFile
=
new
JarFile
(
source
);
assertThat
(
jarFile
.
getEntry
(
"test"
)).
isNull
();
jarFile
.
close
();
}
private
boolean
hasLauncherClasses
(
File
file
)
throws
IOException
{
private
boolean
hasLauncherClasses
(
File
file
)
throws
IOException
{
return
hasEntry
(
file
,
"org/springframework/boot/"
)
return
hasEntry
(
file
,
"org/springframework/boot/"
)
&&
hasEntry
(
file
,
"org/springframework/boot/loader/JarLauncher.class"
);
&&
hasEntry
(
file
,
"org/springframework/boot/loader/JarLauncher.class"
);
...
@@ -580,4 +636,22 @@ public class RepackagerTests {
...
@@ -580,4 +636,22 @@ public class RepackagerTests {
}
}
public
static
class
TestLayoutFactory
implements
LayoutFactory
{
@Override
public
Layout
getLayout
(
File
source
)
{
return
new
TestLayout
();
}
}
private
static
class
TestLayout
extends
Layouts
.
Jar
implements
CustomLoaderLayout
{
@Override
public
void
writeLoadedClasses
(
LoaderClassesWriter
writer
)
throws
IOException
{
writer
.
writeEntry
(
"test"
,
new
ByteArrayInputStream
(
"test"
.
getBytes
()));
}
}
}
}
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java
View file @
450ab281
...
@@ -22,14 +22,11 @@ import java.util.ArrayList;
...
@@ -22,14 +22,11 @@ import java.util.ArrayList;
import
java.util.List
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.Properties
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
java.util.jar.JarFile
;
import
org.apache.maven.artifact.Artifact
;
import
org.apache.maven.artifact.Artifact
;
import
org.apache.maven.model.Dependency
;
import
org.apache.maven.model.Dependency
;
import
org.apache.maven.plugin.MojoExecutionException
;
import
org.apache.maven.plugin.MojoExecutionException
;
import
org.apache.maven.plugin.MojoFailureException
;
import
org.apache.maven.plugin.MojoFailureException
;
import
org.apache.maven.plugin.logging.Log
;
import
org.apache.maven.plugins.annotations.Component
;
import
org.apache.maven.plugins.annotations.Component
;
import
org.apache.maven.plugins.annotations.LifecyclePhase
;
import
org.apache.maven.plugins.annotations.LifecyclePhase
;
import
org.apache.maven.plugins.annotations.Mojo
;
import
org.apache.maven.plugins.annotations.Mojo
;
...
@@ -43,9 +40,11 @@ import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
...
@@ -43,9 +40,11 @@ import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.LayoutFactory
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.Libraries
;
import
org.springframework.boot.loader.tools.Libraries
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.boot.loader.tools.Repackager.MainClassTimeoutWarningListener
;
/**
/**
* Repackages existing JAR and WAR archives so that they can be executed from the command
* Repackages existing JAR and WAR archives so that they can be executed from the command
...
@@ -59,8 +58,6 @@ import org.springframework.boot.loader.tools.Repackager;
...
@@ -59,8 +58,6 @@ import org.springframework.boot.loader.tools.Repackager;
@Mojo
(
name
=
"repackage"
,
defaultPhase
=
LifecyclePhase
.
PACKAGE
,
requiresProject
=
true
,
threadSafe
=
true
,
requiresDependencyResolution
=
ResolutionScope
.
COMPILE_PLUS_RUNTIME
,
requiresDependencyCollection
=
ResolutionScope
.
COMPILE_PLUS_RUNTIME
)
@Mojo
(
name
=
"repackage"
,
defaultPhase
=
LifecyclePhase
.
PACKAGE
,
requiresProject
=
true
,
threadSafe
=
true
,
requiresDependencyResolution
=
ResolutionScope
.
COMPILE_PLUS_RUNTIME
,
requiresDependencyCollection
=
ResolutionScope
.
COMPILE_PLUS_RUNTIME
)
public
class
RepackageMojo
extends
AbstractDependencyFilterMojo
{
public
class
RepackageMojo
extends
AbstractDependencyFilterMojo
{
private
static
final
long
FIND_WARNING_TIMEOUT
=
TimeUnit
.
SECONDS
.
toMillis
(
10
);
/**
/**
* The Maven project.
* The Maven project.
* @since 1.0
* @since 1.0
...
@@ -133,6 +130,15 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -133,6 +130,15 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
@Parameter
@Parameter
private
LayoutType
layout
;
private
LayoutType
layout
;
/**
* The layout factory that will be used to create the executable archive if no
* explicit layout is set. Alternative layouts implementations can be provided by 3rd
* parties.
* @since 1.5
*/
@Parameter
private
LayoutFactory
layoutFactory
;
/**
/**
* A list of the libraries that must be unpacked from fat jars in order to run.
* A list of the libraries that must be unpacked from fat jars in order to run.
* Specify each library as a <code><dependency></code> with a
* Specify each library as a <code><dependency></code> with a
...
@@ -224,7 +230,9 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -224,7 +230,9 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
}
}
private
Repackager
getRepackager
(
File
source
)
{
private
Repackager
getRepackager
(
File
source
)
{
Repackager
repackager
=
new
LoggingRepackager
(
source
,
getLog
());
Repackager
repackager
=
new
Repackager
(
source
,
this
.
layoutFactory
);
repackager
.
addMainClassTimeoutWarningListener
(
new
LoggingMainClassTimeoutWarningListener
());
repackager
.
setMainClass
(
this
.
mainClass
);
repackager
.
setMainClass
(
this
.
mainClass
);
if
(
this
.
layout
!=
null
)
{
if
(
this
.
layout
!=
null
)
{
getLog
().
info
(
"Layout: "
+
this
.
layout
);
getLog
().
info
(
"Layout: "
+
this
.
layout
);
...
@@ -356,30 +364,15 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -356,30 +364,15 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
}
}
private
static
class
LoggingRepackager
extends
Repackager
{
private
class
LoggingMainClassTimeoutWarningListener
implements
MainClassTimeoutWarningListener
{
private
final
Log
log
;
LoggingRepackager
(
File
source
,
Log
log
)
{
super
(
source
);
this
.
log
=
log
;
}
@Override
@Override
protected
String
findMainMethod
(
JarFile
source
)
throws
IOException
{
public
void
handleTimeoutWarning
(
long
duration
,
String
mainMethod
)
{
long
startTime
=
System
.
currentTimeMillis
();
getLog
().
warn
(
"Searching for the main-class is taking some time, "
try
{
+
"consider using the mainClass configuration "
+
"parameter"
);
return
super
.
findMainMethod
(
source
);
}
finally
{
long
duration
=
System
.
currentTimeMillis
()
-
startTime
;
if
(
duration
>
FIND_WARNING_TIMEOUT
)
{
this
.
log
.
warn
(
"Searching for the main-class is taking some time, "
+
"consider using the mainClass configuration "
+
"parameter"
);
}
}
}
}
}
}
}
}
spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/custom-layout.apt
0 → 100644
View file @
450ab281
-----
Use a custom layout
-----
Dave Syer
-----
2016-10-30
-----
Spring Boot repackages the jar file for this project using a custom layout factory
defined in the additional jar file, provided as a dependency to the build plugin:
---
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<layoutFactory implementation="com.example.CustomLayoutFactory">
<customProperty>value</customProperty>
</layoutFactory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.example</groupid>
<artifactId>custom-layout</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
</dependencies>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
+---
The layout factory is provided as an implementation of <<<LayoutFactory>>> (from
spring-boot-loader-tools) explicitly specified in the pom. If there is only one custom
<<<LayoutFactory>>> on the plugin classpath and it is listed in
<<<META-INF/spring.factories>>> then it is unnecessary to explicitly set it in the
plugin configuration.
Layout factories are always ignored if an explicit <<layout>> is set.
spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt
View file @
450ab281
...
@@ -48,6 +48,8 @@ Spring Boot Maven Plugin
...
@@ -48,6 +48,8 @@ Spring Boot Maven Plugin
* {{{./examples/repackage-disable-attach.html}Local repackaged artifact}}
* {{{./examples/repackage-disable-attach.html}Local repackaged artifact}}
* {{{./examples/custom-layout.html}Custom layout}}
* {{{./examples/exclude-dependency.html}Exclude a dependency}}
* {{{./examples/exclude-dependency.html}Exclude a dependency}}
* {{{./examples/run-debug.html}Debug the application}}
* {{{./examples/run-debug.html}Debug the application}}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment