Add support for customizing layers in Gradle

This commit adds configuration to the Spring Boot Gradle plugin that
allows the names and contents of layers to be customized in the build
configuration.

Fixes gh-20296
This commit is contained in:
Scott Frederick
2020-03-10 16:09:44 -07:00
parent c4a55a5fb4
commit f2dadf5a87
23 changed files with 643 additions and 59 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.boot.loader.tools;
import java.io.Serializable;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
@@ -28,7 +29,7 @@ import org.springframework.util.Assert;
* @since 2.3.0
* @see Layers
*/
public class Layer {
public class Layer implements Serializable {
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9-]+$");

View File

@@ -57,6 +57,7 @@ public class CustomLayers implements Layers {
for (ResourceStrategy strategy : this.resourceStrategies) {
Layer matchingLayer = strategy.getMatchingLayer(resourceName);
if (matchingLayer != null) {
validateLayerName(matchingLayer, "Resource '" + resourceName + "'");
return matchingLayer;
}
}
@@ -68,10 +69,18 @@ public class CustomLayers implements Layers {
for (LibraryStrategy strategy : this.libraryStrategies) {
Layer matchingLayer = strategy.getMatchingLayer(library);
if (matchingLayer != null) {
validateLayerName(matchingLayer, "Library '" + library.getName() + "'");
return matchingLayer;
}
}
throw new IllegalStateException("Library '" + library.getName() + "' did not match any layer.");
}
private void validateLayerName(Layer layer, String nameText) {
if (!this.layers.contains(layer)) {
throw new IllegalStateException(nameText + " matched a layer '" + layer
+ "' that is not included in the configured layers " + this.layers + ".");
}
}
}

View File

@@ -16,13 +16,15 @@
package org.springframework.boot.loader.tools.layer.classes;
import java.io.Serializable;
/**
* A filter that can tell if a resource has been included or excluded.
*
* @author Madhura Bhave
* @since 2.3.0
*/
public interface ResourceFilter {
public interface ResourceFilter extends Serializable {
/**
* Return true if the resource is included by the filter.

View File

@@ -16,6 +16,8 @@
package org.springframework.boot.loader.tools.layer.classes;
import java.io.Serializable;
import org.springframework.boot.loader.tools.Layer;
/**
@@ -24,7 +26,7 @@ import org.springframework.boot.loader.tools.Layer;
* @author Madhura Bhave
* @since 2.3.0
*/
public interface ResourceStrategy {
public interface ResourceStrategy extends Serializable {
/**
* Return a {@link Layer} for the given resource. If no matching layer is found,

View File

@@ -16,6 +16,8 @@
package org.springframework.boot.loader.tools.layer.library;
import java.io.Serializable;
import org.springframework.boot.loader.tools.Library;
/**
@@ -24,7 +26,7 @@ import org.springframework.boot.loader.tools.Library;
* @author Madhura Bhave
* @since 2.3.0
*/
public interface LibraryFilter {
public interface LibraryFilter extends Serializable {
/**
* Return true if the {@link Library} is included by the filter.

View File

@@ -16,6 +16,8 @@
package org.springframework.boot.loader.tools.layer.library;
import java.io.Serializable;
import org.springframework.boot.loader.tools.Layer;
import org.springframework.boot.loader.tools.Library;
@@ -25,7 +27,7 @@ import org.springframework.boot.loader.tools.Library;
* @author Madhura Bhave
* @since 2.3.0
*/
public interface LibraryStrategy {
public interface LibraryStrategy extends Serializable {
/**
* Return a {@link Layer} for the given {@link Library}. If no matching layer is

View File

@@ -73,6 +73,18 @@ class CustomLayersTests {
assertThatIllegalStateException().isThrownBy(() -> customLayers.getLayer("com/acme"));
}
@Test
void layerForResourceIsNotInListedLayers() {
FilteredResourceStrategy resourceStrategy = new FilteredResourceStrategy("test-not-listed", Collections
.singletonList(new LocationFilter(Collections.singletonList("META-INF/**"), Collections.emptyList())));
Layer targetLayer = new Layer("test");
CustomLayers customLayers = new CustomLayers(Collections.singletonList(targetLayer),
Collections.singletonList(resourceStrategy), Collections.emptyList());
assertThatIllegalStateException().isThrownBy(() -> customLayers.getLayer("META-INF/manifest.mf"))
.withMessageContaining("META-INF/manifest.mf").withMessageContaining("test-not-listed")
.withMessageContaining("[test]");
}
@Test
void layerForLibraryIsFound() {
FilteredLibraryStrategy libraryStrategy = new FilteredLibraryStrategy("test", Collections
@@ -92,9 +104,22 @@ class CustomLayersTests {
assertThatIllegalStateException().isThrownBy(() -> customLayers.getLayer(mockLibrary("org.another:test")));
}
@Test
void layerForLibraryIsNotInListedLayers() {
FilteredLibraryStrategy libraryStrategy = new FilteredLibraryStrategy("test-not-listed", Collections
.singletonList(new CoordinateFilter(Collections.singletonList("com.acme:*"), Collections.emptyList())));
Layer targetLayer = new Layer("test");
CustomLayers customLayers = new CustomLayers(Collections.singletonList(targetLayer), Collections.emptyList(),
Collections.singletonList(libraryStrategy));
assertThatIllegalStateException().isThrownBy(() -> customLayers.getLayer(mockLibrary("com.acme:test")))
.withMessageContaining("com.acme:test").withMessageContaining("test-not-listed")
.withMessageContaining("[test]");
}
private Library mockLibrary(String coordinates) {
Library library = mock(Library.class);
given(library.getCoordinates()).willReturn(new LibraryCoordinates(coordinates));
given(library.getName()).willReturn(coordinates);
return library;
}