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
1245e5ee
Commit
1245e5ee
authored
Feb 01, 2021
by
Madhura Bhave
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for creating layered war files with Gradle
See gh-22195
parent
7f8ea333
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1019 additions
and
625 deletions
+1019
-625
BootWar.java
...g/springframework/boot/gradle/tasks/bundling/BootWar.java
+51
-1
LayeredSpec.java
...ringframework/boot/gradle/tasks/bundling/LayeredSpec.java
+11
-9
AbstractBootArchiveIntegrationTests.java
...e/tasks/bundling/AbstractBootArchiveIntegrationTests.java
+355
-2
AbstractBootArchiveTests.java
.../boot/gradle/tasks/bundling/AbstractBootArchiveTests.java
+281
-1
BootJarIntegrationTests.java
...k/boot/gradle/tasks/bundling/BootJarIntegrationTests.java
+8
-346
BootJarTests.java
...ingframework/boot/gradle/tasks/bundling/BootJarTests.java
+7
-263
BootWarIntegrationTests.java
...k/boot/gradle/tasks/bundling/BootWarIntegrationTests.java
+13
-2
BootWarTests.java
...ingframework/boot/gradle/tasks/bundling/BootWarTests.java
+19
-1
BootJarIntegrationTests-implicitLayers.gradle
...ks/bundling/BootJarIntegrationTests-implicitLayers.gradle
+1
-0
BootWarIntegrationTests-customLayers.gradle
...asks/bundling/BootWarIntegrationTests-customLayers.gradle
+50
-0
BootWarIntegrationTests-developmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle
...nlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle
+6
-0
BootWarIntegrationTests-developmentOnlyDependenciesCanBeIncludedInTheArchive.gradle
...velopmentOnlyDependenciesCanBeIncludedInTheArchive.gradle
+6
-0
BootWarIntegrationTests-implicitLayers.gradle
...ks/bundling/BootWarIntegrationTests-implicitLayers.gradle
+33
-0
BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle
.../BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle
+6
-0
BootWarIntegrationTests-layersWithCustomSourceSet.gradle
.../BootWarIntegrationTests-layersWithCustomSourceSet.gradle
+36
-0
BootWarIntegrationTests-multiModuleCustomLayers.gradle
...ng/BootWarIntegrationTests-multiModuleCustomLayers.gradle
+62
-0
BootWarIntegrationTests-multiModuleImplicitLayers.gradle
.../BootWarIntegrationTests-multiModuleImplicitLayers.gradle
+40
-0
BootWarIntegrationTests-notUpToDateWhenBuiltWithLayerToolsAndThenWithoutLayerTools.gradle
...ateWhenBuiltWithLayerToolsAndThenWithoutLayerTools.gradle
+12
-0
BootWarIntegrationTests-notUpToDateWhenBuiltWithoutLayersAndThenWithLayers.gradle
...notUpToDateWhenBuiltWithoutLayersAndThenWithLayers.gradle
+12
-0
BootWarIntegrationTests-upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered.gradle
...nBuiltWithDefaultLayeredAndThenWithExplicitLayered.gradle
+10
-0
No files found.
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java
View file @
1245e5ee
...
...
@@ -22,6 +22,7 @@ import java.util.function.Function;
import
org.gradle.api.Action
;
import
org.gradle.api.Project
;
import
org.gradle.api.artifacts.ResolvableDependencies
;
import
org.gradle.api.file.CopySpec
;
import
org.gradle.api.file.FileCollection
;
import
org.gradle.api.file.FileCopyDetails
;
...
...
@@ -30,6 +31,8 @@ import org.gradle.api.internal.file.copy.CopyAction;
import
org.gradle.api.provider.Property
;
import
org.gradle.api.specs.Spec
;
import
org.gradle.api.tasks.Classpath
;
import
org.gradle.api.tasks.Internal
;
import
org.gradle.api.tasks.Nested
;
import
org.gradle.api.tasks.Optional
;
import
org.gradle.api.tasks.bundling.War
;
...
...
@@ -50,12 +53,18 @@ public class BootWar extends War implements BootArchive {
private
static
final
String
LIB_DIRECTORY
=
"WEB-INF/lib/"
;
private
static
final
String
LAYERS_INDEX
=
"WEB-INF/layers.idx"
;
private
final
BootArchiveSupport
support
;
private
final
Property
<
String
>
mainClass
;
private
FileCollection
providedClasspath
;
private
final
ResolvedDependencies
resolvedDependencies
=
new
ResolvedDependencies
();
private
LayeredSpec
layered
=
new
LayeredSpec
();
/**
* Creates a new {@code BootWar} task.
*/
...
...
@@ -65,6 +74,14 @@ public class BootWar extends War implements BootArchive {
getWebInf
().
into
(
"lib-provided"
,
fromCallTo
(
this
::
getProvidedLibFiles
));
this
.
support
.
moveModuleInfoToRoot
(
getRootSpec
());
getRootSpec
().
eachFile
(
this
.
support
::
excludeNonZipLibraryFiles
);
getProject
().
getConfigurations
().
all
((
configuration
)
->
{
ResolvableDependencies
incoming
=
configuration
.
getIncoming
();
incoming
.
afterResolve
((
resolvableDependencies
)
->
{
if
(
resolvableDependencies
==
incoming
)
{
this
.
resolvedDependencies
.
processConfiguration
(
configuration
);
}
});
});
}
private
Object
getProvidedLibFiles
()
{
...
...
@@ -74,12 +91,21 @@ public class BootWar extends War implements BootArchive {
@Override
public
void
copy
()
{
this
.
support
.
configureManifest
(
getManifest
(),
getMainClass
().
get
(),
CLASSES_DIRECTORY
,
LIB_DIRECTORY
,
null
,
null
);
(
isLayeredDisabled
())
?
null
:
LAYERS_INDEX
);
super
.
copy
();
}
private
boolean
isLayeredDisabled
()
{
return
this
.
layered
!=
null
&&
!
this
.
layered
.
isEnabled
();
}
@Override
protected
CopyAction
createCopyAction
()
{
if
(!
isLayeredDisabled
())
{
LayerResolver
layerResolver
=
new
LayerResolver
(
this
.
resolvedDependencies
,
this
.
layered
,
this
::
isLibrary
);
String
layerToolsLocation
=
this
.
layered
.
isIncludeLayerTools
()
?
LIB_DIRECTORY
:
null
;
return
this
.
support
.
createCopyAction
(
this
,
layerResolver
,
layerToolsLocation
);
}
return
this
.
support
.
createCopyAction
(
this
);
}
...
...
@@ -181,6 +207,25 @@ public class BootWar extends War implements BootArchive {
return
isLibrary
(
details
)
?
ZipCompression
.
STORED
:
ZipCompression
.
DEFLATED
;
}
/**
* Returns the spec that describes the layers in a layered jar.
* @return the spec for the layers
* @since 2.5.0
*/
@Nested
public
LayeredSpec
getLayered
()
{
return
this
.
layered
;
}
/**
* Configures the war's layering using the given {@code action}.
* @param action the action to apply
* @since 2.5.0
*/
public
void
layered
(
Action
<
LayeredSpec
>
action
)
{
action
.
execute
(
this
.
layered
);
}
/**
* Return if the {@link FileCopyDetails} are for a library. By default any file in
* {@code WEB-INF/lib} or {@code WEB-INF/lib-provided} is considered to be a library.
...
...
@@ -201,6 +246,11 @@ public class BootWar extends War implements BootArchive {
return
launchScript
;
}
@Internal
ResolvedDependencies
getResolvedDependencies
()
{
return
this
.
resolvedDependencies
;
}
/**
* Syntactic sugar that makes {@link CopySpec#into} calls a little easier to read.
* @param <T> the result type
...
...
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LayeredSpec.java
View file @
1245e5ee
...
...
@@ -41,7 +41,7 @@ import org.springframework.boot.loader.tools.layer.LibraryContentFilter;
import
org.springframework.util.Assert
;
/**
* Encapsulates the configuration for a layered
jar
.
* Encapsulates the configuration for a layered
archive
.
*
* @author Madhura Bhave
* @author Scott Frederick
...
...
@@ -65,7 +65,7 @@ public class LayeredSpec {
/**
* Returns whether the layer tools should be included as a dependency in the layered
*
jar
.
*
archive
.
* @return whether the layer tools should be included
*/
@Input
...
...
@@ -74,7 +74,8 @@ public class LayeredSpec {
}
/**
* Sets whether the layer tools should be included as a dependency in the layered jar.
* Sets whether the layer tools should be included as a dependency in the layered
* archive.
* @param includeLayerTools {@code true} if the layer tools should be included,
* otherwise {@code false}
*/
...
...
@@ -83,7 +84,7 @@ public class LayeredSpec {
}
/**
* Returns whether the layers.idx should be included in the
jar
.
* Returns whether the layers.idx should be included in the
archive
.
* @return whether the layers.idx should be included
*/
@Input
...
...
@@ -92,8 +93,8 @@ public class LayeredSpec {
}
/**
* Sets whether the layers.idx should be included in the
jar
.
* @param enabled {@code true} layers.idx should be included in the
jar
, otherwise
* Sets whether the layers.idx should be included in the
archive
.
* @param enabled {@code true} layers.idx should be included in the
archive
, otherwise
* {@code false}
*/
public
void
setEnabled
(
boolean
enabled
)
{
...
...
@@ -171,7 +172,8 @@ public class LayeredSpec {
}
/**
* Returns the order of the layers in the jar from least to most frequently changing.
* Returns the order of the layers in the archive from least to most frequently
* changing.
* @return the layer order
*/
@Input
...
...
@@ -180,7 +182,7 @@ public class LayeredSpec {
}
/**
* Sets t
o order of the layers in the jar
from least to most frequently changing.
* Sets t
he order of the layers in the archive
from least to most frequently changing.
* @param layerOrder the layer order
*/
public
void
setLayerOrder
(
String
...
layerOrder
)
{
...
...
@@ -188,7 +190,7 @@ public class LayeredSpec {
}
/**
* Sets t
o order of the layers in the jar
from least to most frequently changing.
* Sets t
he order of the layers in the archive
from least to most frequently changing.
* @param layerOrder the layer order
*/
public
void
setLayerOrder
(
List
<
String
>
layerOrder
)
{
...
...
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java
View file @
1245e5ee
...
...
@@ -16,18 +16,36 @@
package
org
.
springframework
.
boot
.
gradle
.
tasks
.
bundling
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.PrintWriter
;
import
java.io.StringReader
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
java.util.function.Consumer
;
import
java.util.jar.Attributes
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarOutputStream
;
import
java.util.jar.Manifest
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
java.util.zip.ZipEntry
;
import
org.gradle.testkit.runner.BuildResult
;
import
org.gradle.testkit.runner.InvalidRunnerConfigurationException
;
import
org.gradle.testkit.runner.TaskOutcome
;
import
org.gradle.testkit.runner.UnexpectedBuildFailure
;
...
...
@@ -35,14 +53,17 @@ import org.junit.jupiter.api.TestTemplate;
import
org.springframework.boot.gradle.testkit.GradleBuild
;
import
org.springframework.boot.loader.tools.FileUtils
;
import
org.springframework.boot.loader.tools.JarModeLibrary
;
import
org.springframework.util.FileSystemUtils
;
import
org.springframework.util.StringUtils
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
/**
* Integration tests for {@link BootJar}.
* Integration tests for {@link BootJar}
and {@link BootWar}
.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
abstract
class
AbstractBootArchiveIntegrationTests
{
...
...
@@ -52,12 +73,16 @@ abstract class AbstractBootArchiveIntegrationTests {
private
final
String
classesPath
;
private
final
String
indexPath
;
GradleBuild
gradleBuild
;
protected
AbstractBootArchiveIntegrationTests
(
String
taskName
,
String
libPath
,
String
classesPath
)
{
protected
AbstractBootArchiveIntegrationTests
(
String
taskName
,
String
libPath
,
String
classesPath
,
String
indexPath
)
{
this
.
taskName
=
taskName
;
this
.
libPath
=
libPath
;
this
.
classesPath
=
classesPath
;
this
.
indexPath
=
indexPath
;
}
@TestTemplate
...
...
@@ -204,6 +229,235 @@ abstract class AbstractBootArchiveIntegrationTests {
.
isEqualTo
(
TaskOutcome
.
UP_TO_DATE
);
}
@TestTemplate
void
upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layered"
,
""
).
build
(
""
+
this
.
taskName
).
task
(
":"
+
this
.
taskName
)
.
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layered"
,
"layered {}"
).
build
(
""
+
this
.
taskName
)
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
UP_TO_DATE
);
}
@TestTemplate
void
notUpToDateWhenBuiltWithoutLayersAndThenWithLayers
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerEnablement"
,
"enabled = false"
).
build
(
this
.
taskName
)
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerEnablement"
,
"enabled = true"
).
build
(
this
.
taskName
)
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
notUpToDateWhenBuiltWithLayerToolsAndThenWithoutLayerTools
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerTools"
,
""
).
build
(
this
.
taskName
).
task
(
":"
+
this
.
taskName
)
.
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerTools"
,
"includeLayerTools = false"
).
build
(
this
.
taskName
)
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
layersWithCustomSourceSet
()
throws
IOException
{
assertThat
(
this
.
gradleBuild
.
build
(
this
.
taskName
).
task
(
":"
+
this
.
taskName
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
implicitLayers
()
throws
IOException
{
writeMainClass
();
writeResource
();
assertThat
(
this
.
gradleBuild
.
build
(
this
.
taskName
).
task
(
":"
+
this
.
taskName
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"static/file.txt"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
this
.
libPath
+
"commons-lang3-3.9.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"jul-to-slf4j-1.7.28.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"log4j-api-2.12.1.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"log4j-to-slf4j-2.12.1.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"logback-classic-1.2.3.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"logback-core-1.2.3.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"slf4j-api-1.7.28.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-boot-starter-logging-2.2.0.RELEASE.jar"
);
Set
<
String
>
expectedSnapshotDependencies
=
new
TreeSet
<>();
expectedSnapshotDependencies
.
add
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"spring-boot-loader"
)).
containsExactly
(
"org/"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"application"
))
.
containsExactly
(
getExpectedApplicationLayerContents
(
this
.
classesPath
));
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
abstract
String
[]
getExpectedApplicationLayerContents
(
String
...
additionalFiles
);
@TestTemplate
void
multiModuleImplicitLayers
()
throws
IOException
{
writeSettingsGradle
();
writeMainClass
();
writeResource
();
assertThat
(
this
.
gradleBuild
.
build
(
this
.
taskName
).
task
(
":"
+
this
.
taskName
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"alpha-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"bravo-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"static/file.txt"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
this
.
libPath
+
"commons-lang3-3.9.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
);
Set
<
String
>
expectedSnapshotDependencies
=
new
TreeSet
<>();
expectedSnapshotDependencies
.
add
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"spring-boot-loader"
)).
containsExactly
(
"org/"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"application"
)).
containsExactly
(
getExpectedApplicationLayerContents
(
this
.
classesPath
,
this
.
libPath
+
"alpha-1.2.3.jar"
,
this
.
libPath
+
"bravo-1.2.3.jar"
));
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
@TestTemplate
void
customLayers
()
throws
IOException
{
writeMainClass
();
writeResource
();
BuildResult
build
=
this
.
gradleBuild
.
build
(
this
.
taskName
);
assertThat
(
build
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"static/file.txt"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
indexPath
+
"layers.idx"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"static"
,
"app"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
);
List
<
String
>
expectedSnapshotDependencies
=
new
ArrayList
<>();
expectedSnapshotDependencies
.
add
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"commons-dependencies"
)).
containsExactly
(
this
.
libPath
+
"commons-lang3-3.9.jar"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"static"
)).
containsExactly
(
this
.
classesPath
+
"static/"
);
List
<
String
>
appLayer
=
new
ArrayList
<>(
indexedLayers
.
get
(
"app"
));
String
[]
appLayerContents
=
getExpectedApplicationLayerContents
(
this
.
classesPath
+
"example/"
);
assertThat
(
appLayer
).
containsSubsequence
(
appLayerContents
);
appLayer
.
removeAll
(
Arrays
.
asList
(
appLayerContents
));
assertThat
(
appLayer
).
containsExactly
(
"org/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
@TestTemplate
void
multiModuleCustomLayers
()
throws
IOException
{
writeSettingsGradle
();
writeMainClass
();
writeResource
();
BuildResult
build
=
this
.
gradleBuild
.
build
(
this
.
taskName
);
assertThat
(
build
.
task
(
":"
+
this
.
taskName
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"alpha-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"bravo-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
classesPath
+
"static/file.txt"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
this
.
indexPath
+
"layers.idx"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"subproject-dependencies"
,
"static"
,
"app"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedSubprojectDependencies
=
new
TreeSet
<>();
expectedSubprojectDependencies
.
add
(
this
.
libPath
+
"alpha-1.2.3.jar"
);
expectedSubprojectDependencies
.
add
(
this
.
libPath
+
"bravo-1.2.3.jar"
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
this
.
libPath
+
"spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
this
.
libPath
+
"spring-jcl-5.2.5.RELEASE.jar"
);
List
<
String
>
expectedSnapshotDependencies
=
new
ArrayList
<>();
expectedSnapshotDependencies
.
add
(
this
.
libPath
+
"library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"subproject-dependencies"
))
.
containsExactlyElementsOf
(
expectedSubprojectDependencies
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"commons-dependencies"
)).
containsExactly
(
this
.
libPath
+
"commons-lang3-3.9.jar"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"static"
)).
containsExactly
(
this
.
classesPath
+
"static/"
);
List
<
String
>
appLayer
=
new
ArrayList
<>(
indexedLayers
.
get
(
"app"
));
String
[]
appLayerContents
=
getExpectedApplicationLayerContents
(
this
.
classesPath
+
"example/"
);
assertThat
(
appLayer
).
containsSubsequence
(
appLayerContents
);
appLayer
.
removeAll
(
Arrays
.
asList
(
appLayerContents
));
assertThat
(
appLayer
).
containsExactly
(
"org/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
private
void
copyMainClassApplication
()
throws
IOException
{
copyApplication
(
"main"
);
}
...
...
@@ -235,4 +489,103 @@ abstract class AbstractBootArchiveIntegrationTests {
new
JarOutputStream
(
new
FileOutputStream
(
location
),
manifest
).
close
();
}
private
void
writeSettingsGradle
()
{
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"settings.gradle"
))))
{
writer
.
println
(
"include 'alpha', 'bravo'"
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
void
writeMainClass
()
{
File
examplePackage
=
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"src/main/java/example"
);
examplePackage
.
mkdirs
();
File
main
=
new
File
(
examplePackage
,
"Main.java"
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
main
)))
{
writer
.
println
(
"package example;"
);
writer
.
println
();
writer
.
println
(
"import java.io.IOException;"
);
writer
.
println
();
writer
.
println
(
"public class Main {"
);
writer
.
println
();
writer
.
println
(
" public static void main(String[] args) {"
);
writer
.
println
(
" }"
);
writer
.
println
();
writer
.
println
(
"}"
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
void
writeResource
()
{
try
{
Path
path
=
this
.
gradleBuild
.
getProjectDir
().
toPath
()
.
resolve
(
Paths
.
get
(
"src"
,
"main"
,
"resources"
,
"static"
,
"file.txt"
));
Files
.
createDirectories
(
path
.
getParent
());
Files
.
createFile
(
path
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
Map
<
String
,
List
<
String
>>
readLayerIndex
(
JarFile
jarFile
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
index
=
new
LinkedHashMap
<>();
ZipEntry
indexEntry
=
jarFile
.
getEntry
(
this
.
indexPath
+
"layers.idx"
);
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
jarFile
.
getInputStream
(
indexEntry
))))
{
String
line
=
reader
.
readLine
();
String
layer
=
null
;
while
(
line
!=
null
)
{
if
(
line
.
startsWith
(
"- "
))
{
layer
=
line
.
substring
(
3
,
line
.
length
()
-
2
);
}
else
if
(
line
.
startsWith
(
" - "
))
{
index
.
computeIfAbsent
(
layer
,
(
key
)
->
new
ArrayList
<>()).
add
(
line
.
substring
(
5
,
line
.
length
()
-
1
));
}
line
=
reader
.
readLine
();
}
return
index
;
}
}
private
Map
<
String
,
List
<
String
>>
readExtractedLayers
(
File
root
,
List
<
String
>
layerNames
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
extractedLayers
=
new
LinkedHashMap
<>();
for
(
String
layerName
:
layerNames
)
{
File
layer
=
new
File
(
root
,
layerName
);
assertThat
(
layer
).
isDirectory
();
extractedLayers
.
put
(
layerName
,
Files
.
walk
(
layer
.
toPath
()).
filter
((
path
)
->
path
.
toFile
().
isFile
()).
map
(
layer
.
toPath
()::
relativize
)
.
map
(
Path:
:
toString
).
map
(
StringUtils:
:
cleanPath
).
collect
(
Collectors
.
toList
()));
}
return
extractedLayers
;
}
private
void
assertExtractedLayers
(
List
<
String
>
layerNames
,
Map
<
String
,
List
<
String
>>
indexedLayers
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
extractedLayers
=
readExtractedLayers
(
this
.
gradleBuild
.
getProjectDir
(),
layerNames
);
assertThat
(
extractedLayers
.
keySet
()).
isEqualTo
(
indexedLayers
.
keySet
());
extractedLayers
.
forEach
((
name
,
contents
)
->
{
List
<
String
>
index
=
indexedLayers
.
get
(
name
);
List
<
String
>
unexpected
=
new
ArrayList
<>();
for
(
String
file
:
contents
)
{
if
(!
isInIndex
(
index
,
file
))
{
unexpected
.
add
(
name
);
}
}
assertThat
(
unexpected
).
isEmpty
();
});
}
private
boolean
isInIndex
(
List
<
String
>
index
,
String
file
)
{
for
(
String
candidate
:
index
)
{
if
(
file
.
equals
(
candidate
)
||
candidate
.
endsWith
(
"/"
)
&&
file
.
startsWith
(
candidate
))
{
return
true
;
}
}
return
false
;
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java
View file @
1245e5ee
...
...
@@ -16,10 +16,12 @@
package
org
.
springframework
.
boot
.
gradle
.
tasks
.
bundling
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.nio.file.Files
;
import
java.nio.file.StandardOpenOption
;
import
java.nio.file.attribute.PosixFilePermission
;
...
...
@@ -27,19 +29,35 @@ import java.util.ArrayList;
import
java.util.Arrays
;
import
java.util.Enumeration
;
import
java.util.HashMap
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarOutputStream
;
import
java.util.jar.Manifest
;
import
java.util.stream.Collectors
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
import
org.apache.commons.compress.archivers.zip.ZipArchiveEntry
;
import
org.apache.commons.compress.archivers.zip.ZipFile
;
import
org.gradle.api.Action
;
import
org.gradle.api.DomainObjectSet
;
import
org.gradle.api.Project
;
import
org.gradle.api.artifacts.Configuration
;
import
org.gradle.api.artifacts.DependencySet
;
import
org.gradle.api.artifacts.ModuleVersionIdentifier
;
import
org.gradle.api.artifacts.ProjectDependency
;
import
org.gradle.api.artifacts.ResolvableDependencies
;
import
org.gradle.api.artifacts.ResolvedArtifact
;
import
org.gradle.api.artifacts.ResolvedConfiguration
;
import
org.gradle.api.artifacts.ResolvedModuleVersion
;
import
org.gradle.api.artifacts.component.ComponentArtifactIdentifier
;
import
org.gradle.api.artifacts.component.ModuleComponentIdentifier
;
import
org.gradle.api.artifacts.component.ProjectComponentIdentifier
;
import
org.gradle.api.internal.file.archive.ZipCopyAction
;
import
org.gradle.api.tasks.bundling.AbstractArchiveTask
;
import
org.gradle.api.tasks.bundling.Jar
;
...
...
@@ -49,8 +67,13 @@ import org.junit.jupiter.api.Test;
import
org.junit.jupiter.api.io.TempDir
;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.JarModeLibrary
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
BDDMockito
.
willAnswer
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
* Abstract base class for testing {@link BootArchive} implementations.
...
...
@@ -72,15 +95,19 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
private
final
String
classesPath
;
private
final
String
indexPath
;
private
Project
project
;
private
T
task
;
protected
AbstractBootArchiveTests
(
Class
<
T
>
taskClass
,
String
launcherClass
,
String
libPath
,
String
classesPath
)
{
protected
AbstractBootArchiveTests
(
Class
<
T
>
taskClass
,
String
launcherClass
,
String
libPath
,
String
classesPath
,
String
indexPath
)
{
this
.
taskClass
=
taskClass
;
this
.
launcherClass
=
launcherClass
;
this
.
libPath
=
libPath
;
this
.
classesPath
=
classesPath
;
this
.
indexPath
=
indexPath
;
}
@BeforeEach
...
...
@@ -407,6 +434,145 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
this
.
libPath
+
"third-library.jar"
);
}
@Test
void
archiveShouldBeLayeredByDefault
()
throws
IOException
{
addContent
();
executeTask
();
try
(
JarFile
jarFile
=
new
JarFile
(
this
.
task
.
getArchiveFile
().
get
().
getAsFile
()))
{
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classes"
))
.
isEqualTo
(
this
.
classesPath
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
)).
isEqualTo
(
this
.
libPath
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Layers-Index"
))
.
isEqualTo
(
this
.
indexPath
+
"layers.idx"
);
assertThat
(
getEntryNames
(
jarFile
)).
contains
(
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
());
}
}
@Test
void
jarWhenLayersDisabledShouldNotContainLayersIndex
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
((
configuration
)
->
configuration
.
setEnabled
(
false
)));
assertThat
(
entryNames
).
doesNotContain
(
this
.
indexPath
+
"layers.idx"
);
}
@Test
void
whenJarIsLayeredThenManifestContainsEntryForLayersIndexInPlaceOfClassesAndLib
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createLayeredJar
()))
{
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classes"
))
.
isEqualTo
(
this
.
classesPath
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
)).
isEqualTo
(
this
.
libPath
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Layers-Index"
))
.
isEqualTo
(
this
.
indexPath
+
"layers.idx"
);
}
}
@Test
void
whenJarIsLayeredThenLayersIndexIsPresentAndCorrect
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createLayeredJar
()))
{
List
<
String
>
entryNames
=
getEntryNames
(
jarFile
);
assertThat
(
entryNames
).
contains
(
this
.
libPath
+
"first-library.jar"
,
this
.
libPath
+
"second-library.jar"
,
this
.
libPath
+
"third-library-SNAPSHOT.jar"
,
this
.
libPath
+
"first-project-library.jar"
,
this
.
libPath
+
"second-project-library-SNAPSHOT.jar"
,
this
.
classesPath
+
"com/example/Application.class"
,
this
.
classesPath
+
"application.properties"
,
this
.
classesPath
+
"static/test.css"
);
List
<
String
>
index
=
entryLines
(
jarFile
,
this
.
indexPath
+
"layers.idx"
);
assertThat
(
getLayerNames
(
index
)).
containsExactly
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
List
<
String
>
expected
=
new
ArrayList
<>();
expected
.
add
(
"- \"dependencies\":"
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"first-library.jar\""
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"first-project-library.jar\""
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"second-library.jar\""
);
if
(!
layerToolsJar
.
contains
(
"SNAPSHOT"
))
{
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
}
expected
.
add
(
"- \"spring-boot-loader\":"
);
expected
.
add
(
" - \"org/\""
);
expected
.
add
(
"- \"snapshot-dependencies\":"
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"second-project-library-SNAPSHOT.jar\""
);
if
(
layerToolsJar
.
contains
(
"SNAPSHOT"
))
{
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
}
expected
.
add
(
" - \""
+
this
.
libPath
+
"third-library-SNAPSHOT.jar\""
);
expected
.
add
(
"- \"application\":"
);
Set
<
String
>
applicationContents
=
new
TreeSet
<>();
applicationContents
.
add
(
" - \""
+
this
.
classesPath
+
"\""
);
if
(
archiveHasClasspathIndex
())
{
applicationContents
.
add
(
" - \""
+
this
.
indexPath
+
"classpath.idx\""
);
}
applicationContents
.
add
(
" - \""
+
this
.
indexPath
+
"layers.idx\""
);
applicationContents
.
add
(
" - \"META-INF/\""
);
expected
.
addAll
(
applicationContents
);
assertThat
(
index
).
containsExactlyElementsOf
(
expected
);
}
}
@Test
void
whenJarIsLayeredWithCustomStrategiesThenLayersIndexIsPresentAndCorrect
()
throws
IOException
{
File
jar
=
createLayeredJar
((
layered
)
->
{
layered
.
application
((
application
)
->
{
application
.
intoLayer
(
"resources"
,
(
spec
)
->
spec
.
include
(
"static/**"
));
application
.
intoLayer
(
"application"
);
});
layered
.
dependencies
((
dependencies
)
->
{
dependencies
.
intoLayer
(
"my-snapshot-deps"
,
(
spec
)
->
spec
.
include
(
"com.example:*:*.SNAPSHOT"
));
dependencies
.
intoLayer
(
"my-internal-deps"
,
(
spec
)
->
spec
.
include
(
"com.example:*:*"
));
dependencies
.
intoLayer
(
"my-deps"
);
});
layered
.
setLayerOrder
(
"my-deps"
,
"my-internal-deps"
,
"my-snapshot-deps"
,
"resources"
,
"application"
);
});
try
(
JarFile
jarFile
=
new
JarFile
(
jar
))
{
List
<
String
>
entryNames
=
getEntryNames
(
jar
);
assertThat
(
entryNames
).
contains
(
this
.
libPath
+
"first-library.jar"
,
this
.
libPath
+
"second-library.jar"
,
this
.
libPath
+
"third-library-SNAPSHOT.jar"
,
this
.
libPath
+
"first-project-library.jar"
,
this
.
libPath
+
"second-project-library-SNAPSHOT.jar"
,
this
.
classesPath
+
"com/example/Application.class"
,
this
.
classesPath
+
"application.properties"
,
this
.
classesPath
+
"static/test.css"
);
List
<
String
>
index
=
entryLines
(
jarFile
,
this
.
indexPath
+
"layers.idx"
);
assertThat
(
getLayerNames
(
index
)).
containsExactly
(
"my-deps"
,
"my-internal-deps"
,
"my-snapshot-deps"
,
"resources"
,
"application"
);
String
layerToolsJar
=
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
List
<
String
>
expected
=
new
ArrayList
<>();
expected
.
add
(
"- \"my-deps\":"
);
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
expected
.
add
(
"- \"my-internal-deps\":"
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"first-library.jar\""
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"first-project-library.jar\""
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"second-library.jar\""
);
expected
.
add
(
"- \"my-snapshot-deps\":"
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"second-project-library-SNAPSHOT.jar\""
);
expected
.
add
(
" - \""
+
this
.
libPath
+
"third-library-SNAPSHOT.jar\""
);
expected
.
add
(
"- \"resources\":"
);
expected
.
add
(
" - \""
+
this
.
classesPath
+
"static/\""
);
expected
.
add
(
"- \"application\":"
);
Set
<
String
>
applicationContents
=
new
TreeSet
<>();
applicationContents
.
add
(
" - \""
+
this
.
classesPath
+
"application.properties\""
);
applicationContents
.
add
(
" - \""
+
this
.
classesPath
+
"com/\""
);
if
(
archiveHasClasspathIndex
())
{
applicationContents
.
add
(
" - \""
+
this
.
indexPath
+
"classpath.idx\""
);
}
applicationContents
.
add
(
" - \""
+
this
.
indexPath
+
"layers.idx\""
);
applicationContents
.
add
(
" - \"META-INF/\""
);
applicationContents
.
add
(
" - \"org/\""
);
expected
.
addAll
(
applicationContents
);
assertThat
(
index
).
containsExactlyElementsOf
(
expected
);
}
}
@Test
void
whenArchiveIsLayeredThenLayerToolsAreAddedToTheJar
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
());
assertThat
(
entryNames
).
contains
(
this
.
libPath
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
());
}
@Test
void
whenArchiveIsLayeredAndIncludeLayerToolsIsFalseThenLayerToolsAreNotAddedToTheJar
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
((
configuration
)
->
configuration
.
setIncludeLayerTools
(
false
)));
assertThat
(
entryNames
)
.
doesNotContain
(
this
.
indexPath
+
"layers/dependencies/lib/spring-boot-jarmode-layertools.jar"
);
}
protected
File
jarFile
(
String
name
)
throws
IOException
{
File
file
=
newFile
(
name
);
try
(
JarOutputStream
jar
=
new
JarOutputStream
(
new
FileOutputStream
(
file
)))
{
...
...
@@ -453,4 +619,118 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
return
file
;
}
File
createLayeredJar
()
throws
IOException
{
return
createLayeredJar
((
spec
)
->
{
});
}
File
createLayeredJar
(
Action
<
LayeredSpec
>
action
)
throws
IOException
{
applyLayered
(
action
);
addContent
();
executeTask
();
return
getTask
().
getArchiveFile
().
get
().
getAsFile
();
}
abstract
void
applyLayered
(
Action
<
LayeredSpec
>
action
);
boolean
archiveHasClasspathIndex
()
{
return
true
;
}
@SuppressWarnings
(
"unchecked"
)
void
addContent
()
throws
IOException
{
this
.
task
.
getMainClass
().
set
(
"com.example.Main"
);
File
classesJavaMain
=
new
File
(
this
.
temp
,
"classes/java/main"
);
File
applicationClass
=
new
File
(
classesJavaMain
,
"com/example/Application.class"
);
applicationClass
.
getParentFile
().
mkdirs
();
applicationClass
.
createNewFile
();
File
resourcesMain
=
new
File
(
this
.
temp
,
"resources/main"
);
File
applicationProperties
=
new
File
(
resourcesMain
,
"application.properties"
);
applicationProperties
.
getParentFile
().
mkdirs
();
applicationProperties
.
createNewFile
();
File
staticResources
=
new
File
(
resourcesMain
,
"static"
);
staticResources
.
mkdir
();
File
css
=
new
File
(
staticResources
,
"test.css"
);
css
.
createNewFile
();
this
.
task
.
classpath
(
classesJavaMain
,
resourcesMain
,
jarFile
(
"first-library.jar"
),
jarFile
(
"second-library.jar"
),
jarFile
(
"third-library-SNAPSHOT.jar"
),
jarFile
(
"first-project-library.jar"
),
jarFile
(
"second-project-library-SNAPSHOT.jar"
));
Set
<
ResolvedArtifact
>
artifacts
=
new
LinkedHashSet
<>();
artifacts
.
add
(
mockLibraryArtifact
(
"first-library.jar"
,
"com.example"
,
"first-library"
,
"1.0.0"
));
artifacts
.
add
(
mockLibraryArtifact
(
"second-library.jar"
,
"com.example"
,
"second-library"
,
"1.0.0"
));
artifacts
.
add
(
mockLibraryArtifact
(
"third-library-SNAPSHOT.jar"
,
"com.example"
,
"third-library"
,
"1.0.0.SNAPSHOT"
));
artifacts
.
add
(
mockProjectArtifact
(
"first-project-library.jar"
,
"com.example"
,
"first-project-library"
,
"1.0.0"
));
artifacts
.
add
(
mockProjectArtifact
(
"second-project-library-SNAPSHOT.jar"
,
"com.example"
,
"second-project-library"
,
"1.0.0.SNAPSHOT"
));
ResolvedConfiguration
resolvedConfiguration
=
mock
(
ResolvedConfiguration
.
class
);
given
(
resolvedConfiguration
.
getResolvedArtifacts
()).
willReturn
(
artifacts
);
Configuration
configuration
=
mock
(
Configuration
.
class
);
given
(
configuration
.
getResolvedConfiguration
()).
willReturn
(
resolvedConfiguration
);
ResolvableDependencies
resolvableDependencies
=
mock
(
ResolvableDependencies
.
class
);
given
(
configuration
.
getIncoming
()).
willReturn
(
resolvableDependencies
);
DependencySet
dependencies
=
mock
(
DependencySet
.
class
);
DomainObjectSet
<
ProjectDependency
>
projectDependencies
=
mock
(
DomainObjectSet
.
class
);
given
(
dependencies
.
withType
(
ProjectDependency
.
class
)).
willReturn
(
projectDependencies
);
given
(
configuration
.
getAllDependencies
()).
willReturn
(
dependencies
);
willAnswer
((
invocation
)
->
{
invocation
.
getArgument
(
0
,
Action
.
class
).
execute
(
resolvableDependencies
);
return
null
;
}).
given
(
resolvableDependencies
).
afterResolve
(
any
(
Action
.
class
));
given
(
configuration
.
getIncoming
()).
willReturn
(
resolvableDependencies
);
populateResolvedDependencies
(
configuration
);
}
abstract
void
populateResolvedDependencies
(
Configuration
configuration
);
private
ResolvedArtifact
mockLibraryArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ModuleComponentIdentifier
moduleComponentIdentifier
=
mock
(
ModuleComponentIdentifier
.
class
);
ComponentArtifactIdentifier
libraryArtifactId
=
mock
(
ComponentArtifactIdentifier
.
class
);
given
(
libraryArtifactId
.
getComponentIdentifier
()).
willReturn
(
moduleComponentIdentifier
);
ResolvedArtifact
libraryArtifact
=
mockArtifact
(
fileName
,
group
,
module
,
version
);
given
(
libraryArtifact
.
getId
()).
willReturn
(
libraryArtifactId
);
return
libraryArtifact
;
}
private
ResolvedArtifact
mockProjectArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ProjectComponentIdentifier
projectComponentIdentifier
=
mock
(
ProjectComponentIdentifier
.
class
);
ComponentArtifactIdentifier
projectArtifactId
=
mock
(
ComponentArtifactIdentifier
.
class
);
given
(
projectArtifactId
.
getComponentIdentifier
()).
willReturn
(
projectComponentIdentifier
);
ResolvedArtifact
projectArtifact
=
mockArtifact
(
fileName
,
group
,
module
,
version
);
given
(
projectArtifact
.
getId
()).
willReturn
(
projectArtifactId
);
return
projectArtifact
;
}
private
ResolvedArtifact
mockArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ModuleVersionIdentifier
moduleVersionIdentifier
=
mock
(
ModuleVersionIdentifier
.
class
);
given
(
moduleVersionIdentifier
.
getGroup
()).
willReturn
(
group
);
given
(
moduleVersionIdentifier
.
getName
()).
willReturn
(
module
);
given
(
moduleVersionIdentifier
.
getVersion
()).
willReturn
(
version
);
ResolvedModuleVersion
moduleVersion
=
mock
(
ResolvedModuleVersion
.
class
);
given
(
moduleVersion
.
getId
()).
willReturn
(
moduleVersionIdentifier
);
ResolvedArtifact
libraryArtifact
=
mock
(
ResolvedArtifact
.
class
);
File
file
=
new
File
(
this
.
temp
,
fileName
).
getAbsoluteFile
();
given
(
libraryArtifact
.
getFile
()).
willReturn
(
file
);
given
(
libraryArtifact
.
getModuleVersion
()).
willReturn
(
moduleVersion
);
return
libraryArtifact
;
}
List
<
String
>
entryLines
(
JarFile
jarFile
,
String
entryName
)
throws
IOException
{
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
jarFile
.
getInputStream
(
jarFile
.
getEntry
(
entryName
)))))
{
return
reader
.
lines
().
collect
(
Collectors
.
toList
());
}
}
private
Set
<
String
>
getLayerNames
(
List
<
String
>
index
)
{
Set
<
String
>
layerNames
=
new
LinkedHashSet
<>();
for
(
String
line
:
index
)
{
if
(
line
.
startsWith
(
"- "
))
{
layerNames
.
add
(
line
.
substring
(
3
,
line
.
length
()
-
2
));
}
}
return
layerNames
;
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java
View file @
1245e5ee
...
...
@@ -16,36 +16,16 @@
package
org
.
springframework
.
boot
.
gradle
.
tasks
.
bundling
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.PrintWriter
;
import
java.io.StringReader
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
java.util.jar.JarFile
;
import
java.util.stream.Collectors
;
import
java.util.zip.ZipEntry
;
import
org.gradle.testkit.runner.BuildResult
;
import
org.gradle.testkit.runner.InvalidRunnerConfigurationException
;
import
org.gradle.testkit.runner.TaskOutcome
;
import
org.gradle.testkit.runner.UnexpectedBuildFailure
;
import
org.junit.jupiter.api.TestTemplate
;
import
org.springframework.boot.gradle.junit.GradleCompatibility
;
import
org.springframework.boot.loader.tools.JarModeLibrary
;
import
org.springframework.util.StringUtils
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
...
@@ -60,233 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class
BootJarIntegrationTests
extends
AbstractBootArchiveIntegrationTests
{
BootJarIntegrationTests
()
{
super
(
"bootJar"
,
"BOOT-INF/lib/"
,
"BOOT-INF/classes/"
);
}
@TestTemplate
void
upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layered"
,
""
).
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layered"
,
"layered {}"
).
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
UP_TO_DATE
);
}
@TestTemplate
void
notUpToDateWhenBuiltWithoutLayersAndThenWithLayers
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerEnablement"
,
"enabled = false"
).
build
(
"bootJar"
)
.
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerEnablement"
,
"enabled = true"
).
build
(
"bootJar"
)
.
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
notUpToDateWhenBuiltWithLayerToolsAndThenWithoutLayerTools
()
throws
InvalidRunnerConfigurationException
,
UnexpectedBuildFailure
{
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerTools"
,
""
).
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
())
.
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertThat
(
this
.
gradleBuild
.
scriptProperty
(
"layerTools"
,
"includeLayerTools = false"
).
build
(
"bootJar"
)
.
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
layersWithCustomSourceSet
()
throws
IOException
{
assertThat
(
this
.
gradleBuild
.
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
}
@TestTemplate
void
implicitLayers
()
throws
IOException
{
writeMainClass
();
writeResource
();
assertThat
(
this
.
gradleBuild
.
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/static/file.txt"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
);
Set
<
String
>
expectedSnapshotDependencies
=
new
TreeSet
<>();
expectedSnapshotDependencies
.
add
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"spring-boot-loader"
)).
containsExactly
(
"org/"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"application"
)).
containsExactly
(
"BOOT-INF/classes/"
,
"BOOT-INF/classpath.idx"
,
"BOOT-INF/layers.idx"
,
"META-INF/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
@TestTemplate
void
multiModuleImplicitLayers
()
throws
IOException
{
writeSettingsGradle
();
writeMainClass
();
writeResource
();
assertThat
(
this
.
gradleBuild
.
build
(
"bootJar"
).
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/alpha-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/bravo-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/static/file.txt"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
);
Set
<
String
>
expectedSnapshotDependencies
=
new
TreeSet
<>();
expectedSnapshotDependencies
.
add
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"spring-boot-loader"
)).
containsExactly
(
"org/"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"application"
)).
containsExactly
(
"BOOT-INF/classes/"
,
"BOOT-INF/classpath.idx"
,
"BOOT-INF/layers.idx"
,
"BOOT-INF/lib/alpha-1.2.3.jar"
,
"BOOT-INF/lib/bravo-1.2.3.jar"
,
"META-INF/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
@TestTemplate
void
customLayers
()
throws
IOException
{
writeMainClass
();
writeResource
();
BuildResult
build
=
this
.
gradleBuild
.
build
(
"bootJar"
);
assertThat
(
build
.
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/static/file.txt"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/layers.idx"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"static"
,
"app"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
);
List
<
String
>
expectedSnapshotDependencies
=
new
ArrayList
<>();
expectedSnapshotDependencies
.
add
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"commons-dependencies"
)).
containsExactly
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"static"
)).
containsExactly
(
"BOOT-INF/classes/static/"
);
List
<
String
>
appLayer
=
new
ArrayList
<>(
indexedLayers
.
get
(
"app"
));
Set
<
String
>
nonLoaderEntries
=
new
TreeSet
<>();
nonLoaderEntries
.
add
(
"BOOT-INF/classes/example/"
);
nonLoaderEntries
.
add
(
"BOOT-INF/classpath.idx"
);
nonLoaderEntries
.
add
(
"BOOT-INF/layers.idx"
);
nonLoaderEntries
.
add
(
"META-INF/"
);
assertThat
(
appLayer
).
containsSubsequence
(
nonLoaderEntries
);
appLayer
.
removeAll
(
nonLoaderEntries
);
assertThat
(
appLayer
).
containsExactly
(
"org/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
}
@TestTemplate
void
multiModuleCustomLayers
()
throws
IOException
{
writeSettingsGradle
();
writeMainClass
();
writeResource
();
BuildResult
build
=
this
.
gradleBuild
.
build
(
"bootJar"
);
assertThat
(
build
.
task
(
":bootJar"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
Map
<
String
,
List
<
String
>>
indexedLayers
;
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
try
(
JarFile
jarFile
=
new
JarFile
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"build/libs"
).
listFiles
()[
0
]))
{
assertThat
(
jarFile
.
getEntry
(
layerToolsJar
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/alpha-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/bravo-1.2.3.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/example/Main.class"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/classes/static/file.txt"
)).
isNotNull
();
assertThat
(
jarFile
.
getEntry
(
"BOOT-INF/layers.idx"
)).
isNotNull
();
indexedLayers
=
readLayerIndex
(
jarFile
);
}
List
<
String
>
layerNames
=
Arrays
.
asList
(
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"subproject-dependencies"
,
"static"
,
"app"
);
assertThat
(
indexedLayers
.
keySet
()).
containsExactlyElementsOf
(
layerNames
);
Set
<
String
>
expectedSubprojectDependencies
=
new
TreeSet
<>();
expectedSubprojectDependencies
.
add
(
"BOOT-INF/lib/alpha-1.2.3.jar"
);
expectedSubprojectDependencies
.
add
(
"BOOT-INF/lib/bravo-1.2.3.jar"
);
Set
<
String
>
expectedDependencies
=
new
TreeSet
<>();
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-core-5.2.5.RELEASE.jar"
);
expectedDependencies
.
add
(
"BOOT-INF/lib/spring-jcl-5.2.5.RELEASE.jar"
);
List
<
String
>
expectedSnapshotDependencies
=
new
ArrayList
<>();
expectedSnapshotDependencies
.
add
(
"BOOT-INF/lib/library-1.0-SNAPSHOT.jar"
);
(
layerToolsJar
.
contains
(
"SNAPSHOT"
)
?
expectedSnapshotDependencies
:
expectedDependencies
).
add
(
layerToolsJar
);
assertThat
(
indexedLayers
.
get
(
"subproject-dependencies"
))
.
containsExactlyElementsOf
(
expectedSubprojectDependencies
);
assertThat
(
indexedLayers
.
get
(
"dependencies"
)).
containsExactlyElementsOf
(
expectedDependencies
);
assertThat
(
indexedLayers
.
get
(
"commons-dependencies"
)).
containsExactly
(
"BOOT-INF/lib/commons-lang3-3.9.jar"
);
assertThat
(
indexedLayers
.
get
(
"snapshot-dependencies"
)).
containsExactlyElementsOf
(
expectedSnapshotDependencies
);
assertThat
(
indexedLayers
.
get
(
"static"
)).
containsExactly
(
"BOOT-INF/classes/static/"
);
List
<
String
>
appLayer
=
new
ArrayList
<>(
indexedLayers
.
get
(
"app"
));
Set
<
String
>
nonLoaderEntries
=
new
TreeSet
<>();
nonLoaderEntries
.
add
(
"BOOT-INF/classes/example/"
);
nonLoaderEntries
.
add
(
"BOOT-INF/classpath.idx"
);
nonLoaderEntries
.
add
(
"BOOT-INF/layers.idx"
);
nonLoaderEntries
.
add
(
"META-INF/"
);
assertThat
(
appLayer
).
containsSubsequence
(
nonLoaderEntries
);
appLayer
.
removeAll
(
nonLoaderEntries
);
assertThat
(
appLayer
).
containsExactly
(
"org/"
);
BuildResult
listLayers
=
this
.
gradleBuild
.
build
(
"listLayers"
);
assertThat
(
listLayers
.
task
(
":listLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
String
listLayersOutput
=
listLayers
.
getOutput
();
assertThat
(
new
BufferedReader
(
new
StringReader
(
listLayersOutput
)).
lines
()).
containsSequence
(
layerNames
);
BuildResult
extractLayers
=
this
.
gradleBuild
.
build
(
"extractLayers"
);
assertThat
(
extractLayers
.
task
(
":extractLayers"
).
getOutcome
()).
isEqualTo
(
TaskOutcome
.
SUCCESS
);
assertExtractedLayers
(
layerNames
,
indexedLayers
);
super
(
"bootJar"
,
"BOOT-INF/lib/"
,
"BOOT-INF/classes/"
,
"BOOT-INF/"
);
}
@TestTemplate
...
...
@@ -320,107 +74,15 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
assertThat
(
output
).
doesNotContain
(
"5. "
);
}
private
void
assertExtractedLayers
(
List
<
String
>
layerNames
,
Map
<
String
,
List
<
String
>>
indexedLayers
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
extractedLayers
=
readExtractedLayers
(
this
.
gradleBuild
.
getProjectDir
(),
layerNames
);
assertThat
(
extractedLayers
.
keySet
()).
isEqualTo
(
indexedLayers
.
keySet
());
extractedLayers
.
forEach
((
name
,
contents
)
->
{
List
<
String
>
index
=
indexedLayers
.
get
(
name
);
List
<
String
>
unexpected
=
new
ArrayList
<>();
for
(
String
file
:
contents
)
{
if
(!
isInIndex
(
index
,
file
))
{
unexpected
.
add
(
name
);
}
}
assertThat
(
unexpected
).
isEmpty
();
});
}
private
boolean
isInIndex
(
List
<
String
>
index
,
String
file
)
{
for
(
String
candidate
:
index
)
{
if
(
file
.
equals
(
candidate
)
||
candidate
.
endsWith
(
"/"
)
&&
file
.
startsWith
(
candidate
))
{
return
true
;
}
}
return
false
;
}
private
void
writeSettingsGradle
()
{
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"settings.gradle"
))))
{
writer
.
println
(
"include 'alpha', 'bravo'"
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
void
writeMainClass
()
{
File
examplePackage
=
new
File
(
this
.
gradleBuild
.
getProjectDir
(),
"src/main/java/example"
);
examplePackage
.
mkdirs
();
File
main
=
new
File
(
examplePackage
,
"Main.java"
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
main
)))
{
writer
.
println
(
"package example;"
);
writer
.
println
();
writer
.
println
(
"import java.io.IOException;"
);
writer
.
println
();
writer
.
println
(
"public class Main {"
);
writer
.
println
();
writer
.
println
(
" public static void main(String[] args) {"
);
writer
.
println
(
" }"
);
writer
.
println
();
writer
.
println
(
"}"
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
void
writeResource
()
{
try
{
Path
path
=
this
.
gradleBuild
.
getProjectDir
().
toPath
()
.
resolve
(
Paths
.
get
(
"src"
,
"main"
,
"resources"
,
"static"
,
"file.txt"
));
Files
.
createDirectories
(
path
.
getParent
());
Files
.
createFile
(
path
);
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
Map
<
String
,
List
<
String
>>
readLayerIndex
(
JarFile
jarFile
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
index
=
new
LinkedHashMap
<>();
ZipEntry
indexEntry
=
jarFile
.
getEntry
(
"BOOT-INF/layers.idx"
);
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
jarFile
.
getInputStream
(
indexEntry
))))
{
String
line
=
reader
.
readLine
();
String
layer
=
null
;
while
(
line
!=
null
)
{
if
(
line
.
startsWith
(
"- "
))
{
layer
=
line
.
substring
(
3
,
line
.
length
()
-
2
);
}
else
if
(
line
.
startsWith
(
" - "
))
{
index
.
computeIfAbsent
(
layer
,
(
key
)
->
new
ArrayList
<>()).
add
(
line
.
substring
(
5
,
line
.
length
()
-
1
));
}
line
=
reader
.
readLine
();
}
return
index
;
}
}
private
Map
<
String
,
List
<
String
>>
readExtractedLayers
(
File
root
,
List
<
String
>
layerNames
)
throws
IOException
{
Map
<
String
,
List
<
String
>>
extractedLayers
=
new
LinkedHashMap
<>();
for
(
String
layerName
:
layerNames
)
{
File
layer
=
new
File
(
root
,
layerName
);
assertThat
(
layer
).
isDirectory
();
extractedLayers
.
put
(
layerName
,
Files
.
walk
(
layer
.
toPath
()).
filter
((
path
)
->
path
.
toFile
().
isFile
()).
map
(
layer
.
toPath
()::
relativize
)
.
map
(
Path:
:
toString
).
map
(
StringUtils:
:
cleanPath
).
collect
(
Collectors
.
toList
()));
}
return
extractedLayers
;
}
private
void
copyClasspathApplication
()
throws
IOException
{
copyApplication
(
"classpath"
);
}
@Override
String
[]
getExpectedApplicationLayerContents
(
String
...
additionalFiles
)
{
Set
<
String
>
contents
=
new
TreeSet
<>(
Arrays
.
asList
(
additionalFiles
));
contents
.
addAll
(
Arrays
.
asList
(
"BOOT-INF/classpath.idx"
,
"BOOT-INF/layers.idx"
,
"META-INF/"
));
return
contents
.
toArray
(
new
String
[
0
]);
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java
View file @
1245e5ee
...
...
@@ -16,41 +16,18 @@
package
org
.
springframework
.
boot
.
gradle
.
tasks
.
bundling
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.util.ArrayList
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.jar.JarFile
;
import
java.util.stream.Collectors
;
import
java.util.zip.ZipEntry
;
import
org.gradle.api.Action
;
import
org.gradle.api.DomainObjectSet
;
import
org.gradle.api.artifacts.Configuration
;
import
org.gradle.api.artifacts.DependencySet
;
import
org.gradle.api.artifacts.ModuleVersionIdentifier
;
import
org.gradle.api.artifacts.ProjectDependency
;
import
org.gradle.api.artifacts.ResolvableDependencies
;
import
org.gradle.api.artifacts.ResolvedArtifact
;
import
org.gradle.api.artifacts.ResolvedConfiguration
;
import
org.gradle.api.artifacts.ResolvedModuleVersion
;
import
org.gradle.api.artifacts.component.ComponentArtifactIdentifier
;
import
org.gradle.api.artifacts.component.ModuleComponentIdentifier
;
import
org.gradle.api.artifacts.component.ProjectComponentIdentifier
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.boot.loader.tools.JarModeLibrary
;
import
org.springframework.boot.testsupport.classpath.ClassPathExclusions
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
BDDMockito
.
willAnswer
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
* Tests for {@link BootJar}.
...
...
@@ -64,7 +41,8 @@ import static org.mockito.Mockito.mock;
class
BootJarTests
extends
AbstractBootArchiveTests
<
BootJar
>
{
BootJarTests
()
{
super
(
BootJar
.
class
,
"org.springframework.boot.loader.JarLauncher"
,
"BOOT-INF/lib/"
,
"BOOT-INF/classes/"
);
super
(
BootJar
.
class
,
"org.springframework.boot.loader.JarLauncher"
,
"BOOT-INF/lib/"
,
"BOOT-INF/classes/"
,
"BOOT-INF/"
);
}
@Test
...
...
@@ -89,130 +67,6 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
}
}
@Test
void
jarShouldBeLayeredByDefault
()
throws
IOException
{
addContent
();
executeTask
();
BootJar
bootJar
=
getTask
();
try
(
JarFile
jarFile
=
new
JarFile
(
bootJar
.
getArchiveFile
().
get
().
getAsFile
()))
{
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classes"
))
.
isEqualTo
(
"BOOT-INF/classes/"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
))
.
isEqualTo
(
"BOOT-INF/lib/"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classpath-Index"
))
.
isEqualTo
(
"BOOT-INF/classpath.idx"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Layers-Index"
))
.
isEqualTo
(
"BOOT-INF/layers.idx"
);
assertThat
(
getEntryNames
(
jarFile
)).
contains
(
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
());
}
}
@Test
void
jarWhenLayersDisabledShouldNotContainLayersIndex
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
((
configuration
)
->
configuration
.
setEnabled
(
false
)));
assertThat
(
entryNames
).
doesNotContain
(
"BOOT-INF/layers.idx"
);
}
@Test
void
whenJarIsLayeredThenManifestContainsEntryForLayersIndexInPlaceOfClassesAndLib
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createLayeredJar
()))
{
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classes"
))
.
isEqualTo
(
"BOOT-INF/classes/"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Lib"
))
.
isEqualTo
(
"BOOT-INF/lib/"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Classpath-Index"
))
.
isEqualTo
(
"BOOT-INF/classpath.idx"
);
assertThat
(
jarFile
.
getManifest
().
getMainAttributes
().
getValue
(
"Spring-Boot-Layers-Index"
))
.
isEqualTo
(
"BOOT-INF/layers.idx"
);
}
}
@Test
void
whenJarIsLayeredThenLayersIndexIsPresentAndCorrect
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createLayeredJar
()))
{
List
<
String
>
entryNames
=
getEntryNames
(
jarFile
);
assertThat
(
entryNames
).
contains
(
"BOOT-INF/lib/first-library.jar"
,
"BOOT-INF/lib/second-library.jar"
,
"BOOT-INF/lib/third-library-SNAPSHOT.jar"
,
"BOOT-INF/lib/first-project-library.jar"
,
"BOOT-INF/lib/second-project-library-SNAPSHOT.jar"
,
"BOOT-INF/classes/com/example/Application.class"
,
"BOOT-INF/classes/application.properties"
,
"BOOT-INF/classes/static/test.css"
);
List
<
String
>
index
=
entryLines
(
jarFile
,
"BOOT-INF/layers.idx"
);
assertThat
(
getLayerNames
(
index
)).
containsExactly
(
"dependencies"
,
"spring-boot-loader"
,
"snapshot-dependencies"
,
"application"
);
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
List
<
String
>
expected
=
new
ArrayList
<>();
expected
.
add
(
"- \"dependencies\":"
);
expected
.
add
(
" - \"BOOT-INF/lib/first-library.jar\""
);
expected
.
add
(
" - \"BOOT-INF/lib/first-project-library.jar\""
);
expected
.
add
(
" - \"BOOT-INF/lib/second-library.jar\""
);
if
(!
layerToolsJar
.
contains
(
"SNAPSHOT"
))
{
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
}
expected
.
add
(
"- \"spring-boot-loader\":"
);
expected
.
add
(
" - \"org/\""
);
expected
.
add
(
"- \"snapshot-dependencies\":"
);
expected
.
add
(
" - \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\""
);
if
(
layerToolsJar
.
contains
(
"SNAPSHOT"
))
{
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
}
expected
.
add
(
" - \"BOOT-INF/lib/third-library-SNAPSHOT.jar\""
);
expected
.
add
(
"- \"application\":"
);
expected
.
add
(
" - \"BOOT-INF/classes/\""
);
expected
.
add
(
" - \"BOOT-INF/classpath.idx\""
);
expected
.
add
(
" - \"BOOT-INF/layers.idx\""
);
expected
.
add
(
" - \"META-INF/\""
);
assertThat
(
index
).
containsExactlyElementsOf
(
expected
);
}
}
@Test
void
whenJarIsLayeredWithCustomStrategiesThenLayersIndexIsPresentAndCorrect
()
throws
IOException
{
File
jar
=
createLayeredJar
((
layered
)
->
{
layered
.
application
((
application
)
->
{
application
.
intoLayer
(
"resources"
,
(
spec
)
->
spec
.
include
(
"static/**"
));
application
.
intoLayer
(
"application"
);
});
layered
.
dependencies
((
dependencies
)
->
{
dependencies
.
intoLayer
(
"my-snapshot-deps"
,
(
spec
)
->
spec
.
include
(
"com.example:*:*.SNAPSHOT"
));
dependencies
.
intoLayer
(
"my-internal-deps"
,
(
spec
)
->
spec
.
include
(
"com.example:*:*"
));
dependencies
.
intoLayer
(
"my-deps"
);
});
layered
.
setLayerOrder
(
"my-deps"
,
"my-internal-deps"
,
"my-snapshot-deps"
,
"resources"
,
"application"
);
});
try
(
JarFile
jarFile
=
new
JarFile
(
jar
))
{
List
<
String
>
entryNames
=
getEntryNames
(
jar
);
assertThat
(
entryNames
).
contains
(
"BOOT-INF/lib/first-library.jar"
,
"BOOT-INF/lib/second-library.jar"
,
"BOOT-INF/lib/third-library-SNAPSHOT.jar"
,
"BOOT-INF/lib/first-project-library.jar"
,
"BOOT-INF/lib/second-project-library-SNAPSHOT.jar"
,
"BOOT-INF/classes/com/example/Application.class"
,
"BOOT-INF/classes/application.properties"
,
"BOOT-INF/classes/static/test.css"
);
List
<
String
>
index
=
entryLines
(
jarFile
,
"BOOT-INF/layers.idx"
);
assertThat
(
getLayerNames
(
index
)).
containsExactly
(
"my-deps"
,
"my-internal-deps"
,
"my-snapshot-deps"
,
"resources"
,
"application"
);
String
layerToolsJar
=
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
();
List
<
String
>
expected
=
new
ArrayList
<>();
expected
.
add
(
"- \"my-deps\":"
);
expected
.
add
(
" - \""
+
layerToolsJar
+
"\""
);
expected
.
add
(
"- \"my-internal-deps\":"
);
expected
.
add
(
" - \"BOOT-INF/lib/first-library.jar\""
);
expected
.
add
(
" - \"BOOT-INF/lib/first-project-library.jar\""
);
expected
.
add
(
" - \"BOOT-INF/lib/second-library.jar\""
);
expected
.
add
(
"- \"my-snapshot-deps\":"
);
expected
.
add
(
" - \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\""
);
expected
.
add
(
" - \"BOOT-INF/lib/third-library-SNAPSHOT.jar\""
);
expected
.
add
(
"- \"resources\":"
);
expected
.
add
(
" - \"BOOT-INF/classes/static/\""
);
expected
.
add
(
"- \"application\":"
);
expected
.
add
(
" - \"BOOT-INF/classes/application.properties\""
);
expected
.
add
(
" - \"BOOT-INF/classes/com/\""
);
expected
.
add
(
" - \"BOOT-INF/classpath.idx\""
);
expected
.
add
(
" - \"BOOT-INF/layers.idx\""
);
expected
.
add
(
" - \"META-INF/\""
);
expected
.
add
(
" - \"org/\""
);
assertThat
(
index
).
containsExactlyElementsOf
(
expected
);
}
}
@Test
void
jarsInLibAreStored
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createLayeredJar
()))
{
...
...
@@ -237,19 +91,6 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
}
}
@Test
void
whenJarIsLayeredThenLayerToolsAreAddedToTheJar
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
());
assertThat
(
entryNames
).
contains
(
"BOOT-INF/lib/"
+
JarModeLibrary
.
LAYER_TOOLS
.
getName
());
}
@Test
void
whenJarIsLayeredAndIncludeLayerToolsIsFalseThenLayerToolsAreNotAddedToTheJar
()
throws
IOException
{
List
<
String
>
entryNames
=
getEntryNames
(
createLayeredJar
((
configuration
)
->
configuration
.
setIncludeLayerTools
(
false
)));
assertThat
(
entryNames
).
doesNotContain
(
"BOOT-INF/layers/dependencies/lib/spring-boot-jarmode-layertools.jar"
);
}
@Test
void
classpathIndexPointsToBootInfLibs
()
throws
IOException
{
try
(
JarFile
jarFile
=
new
JarFile
(
createPopulatedJar
()))
{
...
...
@@ -268,111 +109,14 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
return
getTask
().
getArchiveFile
().
get
().
getAsFile
();
}
private
File
createLayeredJar
()
throws
IOException
{
return
createLayeredJar
((
spec
)
->
{
});
}
private
File
createLayeredJar
(
Action
<
LayeredSpec
>
action
)
throws
IOException
{
@Override
void
applyLayered
(
Action
<
LayeredSpec
>
action
)
{
getTask
().
layered
(
action
);
addContent
();
executeTask
();
return
getTask
().
getArchiveFile
().
get
().
getAsFile
();
}
@SuppressWarnings
(
"unchecked"
)
private
void
addContent
()
throws
IOException
{
BootJar
bootJar
=
getTask
();
bootJar
.
getMainClass
().
set
(
"com.example.Main"
);
File
classesJavaMain
=
new
File
(
this
.
temp
,
"classes/java/main"
);
File
applicationClass
=
new
File
(
classesJavaMain
,
"com/example/Application.class"
);
applicationClass
.
getParentFile
().
mkdirs
();
applicationClass
.
createNewFile
();
File
resourcesMain
=
new
File
(
this
.
temp
,
"resources/main"
);
File
applicationProperties
=
new
File
(
resourcesMain
,
"application.properties"
);
applicationProperties
.
getParentFile
().
mkdirs
();
applicationProperties
.
createNewFile
();
File
staticResources
=
new
File
(
resourcesMain
,
"static"
);
staticResources
.
mkdir
();
File
css
=
new
File
(
staticResources
,
"test.css"
);
css
.
createNewFile
();
bootJar
.
classpath
(
classesJavaMain
,
resourcesMain
,
jarFile
(
"first-library.jar"
),
jarFile
(
"second-library.jar"
),
jarFile
(
"third-library-SNAPSHOT.jar"
),
jarFile
(
"first-project-library.jar"
),
jarFile
(
"second-project-library-SNAPSHOT.jar"
));
Set
<
ResolvedArtifact
>
artifacts
=
new
LinkedHashSet
<>();
artifacts
.
add
(
mockLibraryArtifact
(
"first-library.jar"
,
"com.example"
,
"first-library"
,
"1.0.0"
));
artifacts
.
add
(
mockLibraryArtifact
(
"second-library.jar"
,
"com.example"
,
"second-library"
,
"1.0.0"
));
artifacts
.
add
(
mockLibraryArtifact
(
"third-library-SNAPSHOT.jar"
,
"com.example"
,
"third-library"
,
"1.0.0.SNAPSHOT"
));
artifacts
.
add
(
mockProjectArtifact
(
"first-project-library.jar"
,
"com.example"
,
"first-project-library"
,
"1.0.0"
));
artifacts
.
add
(
mockProjectArtifact
(
"second-project-library-SNAPSHOT.jar"
,
"com.example"
,
"second-project-library"
,
"1.0.0.SNAPSHOT"
));
ResolvedConfiguration
resolvedConfiguration
=
mock
(
ResolvedConfiguration
.
class
);
given
(
resolvedConfiguration
.
getResolvedArtifacts
()).
willReturn
(
artifacts
);
Configuration
configuration
=
mock
(
Configuration
.
class
);
given
(
configuration
.
getResolvedConfiguration
()).
willReturn
(
resolvedConfiguration
);
ResolvableDependencies
resolvableDependencies
=
mock
(
ResolvableDependencies
.
class
);
given
(
configuration
.
getIncoming
()).
willReturn
(
resolvableDependencies
);
DependencySet
dependencies
=
mock
(
DependencySet
.
class
);
DomainObjectSet
<
ProjectDependency
>
projectDependencies
=
mock
(
DomainObjectSet
.
class
);
given
(
dependencies
.
withType
(
ProjectDependency
.
class
)).
willReturn
(
projectDependencies
);
given
(
configuration
.
getAllDependencies
()).
willReturn
(
dependencies
);
willAnswer
((
invocation
)
->
{
invocation
.
getArgument
(
0
,
Action
.
class
).
execute
(
resolvableDependencies
);
return
null
;
}).
given
(
resolvableDependencies
).
afterResolve
(
any
(
Action
.
class
));
given
(
configuration
.
getIncoming
()).
willReturn
(
resolvableDependencies
);
bootJar
.
getResolvedDependencies
().
processConfiguration
(
configuration
);
}
private
ResolvedArtifact
mockLibraryArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ModuleComponentIdentifier
moduleComponentIdentifier
=
mock
(
ModuleComponentIdentifier
.
class
);
ComponentArtifactIdentifier
libraryArtifactId
=
mock
(
ComponentArtifactIdentifier
.
class
);
given
(
libraryArtifactId
.
getComponentIdentifier
()).
willReturn
(
moduleComponentIdentifier
);
ResolvedArtifact
libraryArtifact
=
mockArtifact
(
fileName
,
group
,
module
,
version
);
given
(
libraryArtifact
.
getId
()).
willReturn
(
libraryArtifactId
);
return
libraryArtifact
;
}
private
ResolvedArtifact
mockProjectArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ProjectComponentIdentifier
projectComponentIdentifier
=
mock
(
ProjectComponentIdentifier
.
class
);
ComponentArtifactIdentifier
projectArtifactId
=
mock
(
ComponentArtifactIdentifier
.
class
);
given
(
projectArtifactId
.
getComponentIdentifier
()).
willReturn
(
projectComponentIdentifier
);
ResolvedArtifact
projectArtifact
=
mockArtifact
(
fileName
,
group
,
module
,
version
);
given
(
projectArtifact
.
getId
()).
willReturn
(
projectArtifactId
);
return
projectArtifact
;
}
private
ResolvedArtifact
mockArtifact
(
String
fileName
,
String
group
,
String
module
,
String
version
)
{
ModuleVersionIdentifier
moduleVersionIdentifier
=
mock
(
ModuleVersionIdentifier
.
class
);
given
(
moduleVersionIdentifier
.
getGroup
()).
willReturn
(
group
);
given
(
moduleVersionIdentifier
.
getName
()).
willReturn
(
module
);
given
(
moduleVersionIdentifier
.
getVersion
()).
willReturn
(
version
);
ResolvedModuleVersion
moduleVersion
=
mock
(
ResolvedModuleVersion
.
class
);
given
(
moduleVersion
.
getId
()).
willReturn
(
moduleVersionIdentifier
);
ResolvedArtifact
libraryArtifact
=
mock
(
ResolvedArtifact
.
class
);
File
file
=
new
File
(
this
.
temp
,
fileName
).
getAbsoluteFile
();
given
(
libraryArtifact
.
getFile
()).
willReturn
(
file
);
given
(
libraryArtifact
.
getModuleVersion
()).
willReturn
(
moduleVersion
);
return
libraryArtifact
;
}
private
List
<
String
>
entryLines
(
JarFile
jarFile
,
String
entryName
)
throws
IOException
{
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
jarFile
.
getInputStream
(
jarFile
.
getEntry
(
entryName
)))))
{
return
reader
.
lines
().
collect
(
Collectors
.
toList
());
}
}
private
Set
<
String
>
getLayerNames
(
List
<
String
>
index
)
{
Set
<
String
>
layerNames
=
new
LinkedHashSet
<>();
for
(
String
line
:
index
)
{
if
(
line
.
startsWith
(
"- "
))
{
layerNames
.
add
(
line
.
substring
(
3
,
line
.
length
()
-
2
));
}
}
return
layerNames
;
@Override
void
populateResolvedDependencies
(
Configuration
configuration
)
{
getTask
().
getResolvedDependencies
().
processConfiguration
(
configuration
);
}
@Override
...
...
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.java
View file @
1245e5ee
...
...
@@ -16,10 +16,14 @@
package
org
.
springframework
.
boot
.
gradle
.
tasks
.
bundling
;
import
java.util.Arrays
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
org.springframework.boot.gradle.junit.GradleCompatibility
;
/**
* Integration tests for {@link Boot
J
ar}.
* Integration tests for {@link Boot
W
ar}.
*
* @author Andy Wilkinson
*/
...
...
@@ -27,7 +31,14 @@ import org.springframework.boot.gradle.junit.GradleCompatibility;
class
BootWarIntegrationTests
extends
AbstractBootArchiveIntegrationTests
{
BootWarIntegrationTests
()
{
super
(
"bootWar"
,
"WEB-INF/lib/"
,
"WEB-INF/classes/"
);
super
(
"bootWar"
,
"WEB-INF/lib/"
,
"WEB-INF/classes/"
,
"WEB-INF/"
);
}
@Override
String
[]
getExpectedApplicationLayerContents
(
String
...
additionalFiles
)
{
Set
<
String
>
contents
=
new
TreeSet
<>(
Arrays
.
asList
(
additionalFiles
));
contents
.
addAll
(
Arrays
.
asList
(
"WEB-INF/layers.idx"
,
"META-INF/"
));
return
contents
.
toArray
(
new
String
[
0
]);
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarTests.java
View file @
1245e5ee
...
...
@@ -20,6 +20,8 @@ import java.io.File;
import
java.io.IOException
;
import
java.util.jar.JarFile
;
import
org.gradle.api.Action
;
import
org.gradle.api.artifacts.Configuration
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
...
@@ -32,7 +34,8 @@ import static org.assertj.core.api.Assertions.assertThat;
class
BootWarTests
extends
AbstractBootArchiveTests
<
BootWar
>
{
BootWarTests
()
{
super
(
BootWar
.
class
,
"org.springframework.boot.loader.WarLauncher"
,
"WEB-INF/lib/"
,
"WEB-INF/classes/"
);
super
(
BootWar
.
class
,
"org.springframework.boot.loader.WarLauncher"
,
"WEB-INF/lib/"
,
"WEB-INF/classes/"
,
"WEB-INF/"
);
}
@Test
...
...
@@ -111,4 +114,19 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
getTask
().
copy
();
}
@Override
void
populateResolvedDependencies
(
Configuration
configuration
)
{
getTask
().
getResolvedDependencies
().
processConfiguration
(
configuration
);
}
@Override
void
applyLayered
(
Action
<
LayeredSpec
>
action
)
{
getTask
().
layered
(
action
);
}
@Override
boolean
archiveHasClasspathIndex
()
{
return
false
;
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-implicitLayers.gradle
View file @
1245e5ee
...
...
@@ -16,6 +16,7 @@ dependencies {
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
implementation
(
"org.springframework.boot:spring-boot-starter-logging:2.2.0.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
...
...
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-customLayers.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
bootWar
{
mainClass
=
'com.example.Application'
layered
{
application
{
intoLayer
(
"static"
)
{
include
"META-INF/resources/**"
,
"resources/**"
,
"static/**"
,
"public/**"
}
intoLayer
(
"app"
)
}
dependencies
{
intoLayer
(
"snapshot-dependencies"
)
{
include
"*:*:*SNAPSHOT"
}
intoLayer
(
"commons-dependencies"
)
{
include
"org.apache.commons:*"
}
intoLayer
(
"dependencies"
)
}
layerOrder
=
[
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"static"
,
"app"
]
}
}
repositories
{
mavenCentral
()
maven
{
url
"file:repository"
}
}
dependencies
{
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"list"
}
task
extractLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"extract"
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-developmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle
View file @
1245e5ee
...
...
@@ -16,3 +16,9 @@ dependencies {
developmentOnly
(
"commons-io:commons-io:2.6"
)
implementation
(
"commons-io:commons-io:2.6"
)
}
bootWar
{
layered
{
enabled
=
false
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-developmentOnlyDependenciesCanBeIncludedInTheArchive.gradle
View file @
1245e5ee
...
...
@@ -19,3 +19,9 @@ dependencies {
bootWar
{
classpath
configurations
.
developmentOnly
}
bootWar
{
layered
{
enabled
=
false
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-implicitLayers.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
bootWar
{
mainClass
=
'com.example.Application'
}
repositories
{
mavenCentral
()
maven
{
url
"file:repository"
}
}
dependencies
{
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
implementation
(
"org.springframework.boot:spring-boot-starter-logging:2.2.0.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"list"
}
task
extractLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"extract"
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle
View file @
1245e5ee
...
...
@@ -17,3 +17,9 @@ dependencies {
implementation
(
name:
"standard"
)
implementation
(
name:
"starter"
)
}
bootWar
{
layered
{
enabled
=
false
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-layersWithCustomSourceSet.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
sourceSets
{
custom
}
bootWar
{
mainClass
=
'com.example.Application'
}
repositories
{
mavenCentral
()
maven
{
url
"file:repository"
}
}
dependencies
{
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"list"
}
task
extractLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"extract"
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-multiModuleCustomLayers.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
subprojects
{
apply
plugin:
'java'
group
=
'org.example.projects'
version
=
'1.2.3'
}
bootWar
{
mainClass
=
'com.example.Application'
layered
{
application
{
intoLayer
(
"static"
)
{
include
"META-INF/resources/**"
,
"resources/**"
,
"static/**"
,
"public/**"
}
intoLayer
(
"app"
)
}
dependencies
{
intoLayer
(
"snapshot-dependencies"
)
{
include
"*:*:*SNAPSHOT"
excludeProjectDependencies
()
}
intoLayer
(
"subproject-dependencies"
)
{
includeProjectDependencies
()
}
intoLayer
(
"commons-dependencies"
)
{
include
"org.apache.commons:*"
}
intoLayer
(
"dependencies"
)
}
layerOrder
=
[
"dependencies"
,
"commons-dependencies"
,
"snapshot-dependencies"
,
"subproject-dependencies"
,
"static"
,
"app"
]
}
}
repositories
{
mavenCentral
()
maven
{
url
"file:repository"
}
}
dependencies
{
implementation
(
project
(
':alpha'
))
implementation
(
project
(
':bravo'
))
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"list"
}
task
extractLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"extract"
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-multiModuleImplicitLayers.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
subprojects
{
apply
plugin:
'java'
group
=
'org.example.projects'
version
=
'1.2.3'
}
bootWar
{
mainClass
=
'com.example.Application'
}
repositories
{
mavenCentral
()
maven
{
url
"file:repository"
}
}
dependencies
{
implementation
(
project
(
':alpha'
))
implementation
(
project
(
':bravo'
))
implementation
(
"com.example:library:1.0-SNAPSHOT"
)
implementation
(
"org.apache.commons:commons-lang3:3.9"
)
implementation
(
"org.springframework:spring-core:5.2.5.RELEASE"
)
}
task
listLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"list"
}
task
extractLayers
(
type:
JavaExec
)
{
classpath
=
bootWar
.
outputs
.
files
systemProperties
=
[
"jarmode"
:
"layertools"
]
args
"extract"
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-notUpToDateWhenBuiltWithLayerToolsAndThenWithoutLayerTools.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
bootWar
{
mainClass
=
'com.example.Application'
layered
{
{
layerTools
}
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-notUpToDateWhenBuiltWithoutLayersAndThenWithLayers.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
bootWar
{
mainClass
=
'com.example.Application'
layered
{
{
layerEnablement
}
}
}
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered.gradle
0 → 100644
View file @
1245e5ee
plugins
{
id
'java'
id
'org.springframework.boot'
version
'{version}'
id
'war'
}
bootWar
{
mainClass
=
'com.example.Application'
{
layered
}
}
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