diff --git a/start-site/src/main/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizer.java new file mode 100644 index 0000000000..1632637fc0 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizer.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.start.site.extension.build.maven; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import io.spring.initializr.generator.buildsystem.maven.MavenBuild; +import io.spring.initializr.generator.spring.build.BuildCustomizer; +import io.spring.initializr.generator.version.Version; +import io.spring.initializr.generator.version.VersionParser; +import io.spring.initializr.generator.version.VersionRange; +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.metadata.InitializrMetadata; + +/** + * A {@link BuildCustomizer} that automatically excludes annotation processors from the + * repackaged archive if necessary. + * + * @author Stephane Nicoll + */ +class AnnotationProcessorExclusionBuildCustomizer implements BuildCustomizer { + + private static final VersionRange SPRING_BOOT_2_4_0_M3_0R_LATER = VersionParser.DEFAULT.parseRange("2.4.0-M3"); + + private static final List KNOWN_ANNOTATION_PROCESSORS = Collections + .singletonList("configuration-processor"); + + private final InitializrMetadata metadata; + + private final boolean hasSmartExclude; + + AnnotationProcessorExclusionBuildCustomizer(InitializrMetadata metadata, Version platformVersion) { + this.metadata = metadata; + this.hasSmartExclude = SPRING_BOOT_2_4_0_M3_0R_LATER.match(platformVersion); + } + + @Override + public void customize(MavenBuild build) { + if (!build.plugins().has("org.springframework.boot", "spring-boot-maven-plugin")) { + return; + } + List dependencies = build.dependencies().ids() + .filter(this::isAnnotationProcessor) + .filter((id) -> !this.hasSmartExclude || !KNOWN_ANNOTATION_PROCESSORS.contains(id)) + .map((id) -> build.dependencies().get(id)).collect(Collectors.toList()); + if (!dependencies.isEmpty()) { + build.plugins().add("org.springframework.boot", "spring-boot-maven-plugin", (plugin) -> plugin + .configuration((configuration) -> configuration.configure("excludes", (excludes) -> { + for (io.spring.initializr.generator.buildsystem.Dependency dependency : dependencies) { + excludes.add("exclude", (exclude) -> { + exclude.add("groupId", dependency.getGroupId()); + exclude.add("artifactId", dependency.getArtifactId()); + }); + } + }))); + } + } + + @Override + public int getOrder() { + return 5; + } + + private boolean isAnnotationProcessor(String id) { + Dependency dependency = this.metadata.getDependencies().get(id); + return (dependency != null) && Dependency.SCOPE_ANNOTATION_PROCESSOR.equals(dependency.getScope()); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/build/maven/MavenProjectGenerationConfiguration.java b/start-site/src/main/java/io/spring/start/site/extension/build/maven/MavenProjectGenerationConfiguration.java index 8e983f2d59..2393bf794f 100644 --- a/start-site/src/main/java/io/spring/start/site/extension/build/maven/MavenProjectGenerationConfiguration.java +++ b/start-site/src/main/java/io/spring/start/site/extension/build/maven/MavenProjectGenerationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import io.spring.initializr.generator.condition.ConditionalOnBuildSystem; import io.spring.initializr.generator.project.ProjectDescription; import io.spring.initializr.generator.project.ProjectGenerationConfiguration; +import io.spring.initializr.metadata.InitializrMetadata; import org.springframework.context.annotation.Bean; @@ -37,4 +38,10 @@ MavenBuildSystemHelpDocumentCustomizer mavenBuildSystemHelpDocumentCustomizer(Pr return new MavenBuildSystemHelpDocumentCustomizer(description); } + @Bean + AnnotationProcessorExclusionBuildCustomizer annotationProcessorExclusionBuildCustomizer(InitializrMetadata metadata, + ProjectDescription description) { + return new AnnotationProcessorExclusionBuildCustomizer(metadata, description.getPlatformVersion()); + } + } diff --git a/start-site/src/test/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizerTest.java b/start-site/src/test/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizerTest.java new file mode 100644 index 0000000000..b4863928d0 --- /dev/null +++ b/start-site/src/test/java/io/spring/start/site/extension/build/maven/AnnotationProcessorExclusionBuildCustomizerTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.start.site.extension.build.maven; + +import io.spring.initializr.web.project.ProjectRequest; +import io.spring.start.site.extension.AbstractExtensionTests; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link AnnotationProcessorExclusionBuildCustomizer}. + * + * @author Stephane Nicoll + */ +class AnnotationProcessorExclusionBuildCustomizerTest extends AbstractExtensionTests { + + @Test + void annotationProcessorsAreExcludedWithoutMetadata() { + ProjectRequest request = createProjectRequest("lombok", "configuration-processor"); + request.setBootVersion("2.3.0.RELEASE"); + assertThat(mavenPom(request)).lines().containsSequence(" ", + " ", " org.projectlombok", + " lombok", " ", + " ", + " org.springframework.boot", + " spring-boot-configuration-processor", + " ", " "); + + } + + @Test + void annotationProcessorsAreExcludedOnlyIfTheyAreNotHandledWithMetadata() { + ProjectRequest request = createProjectRequest("lombok", "configuration-processor"); + request.setBootVersion("2.4.0"); + assertThat(mavenPom(request)).lines().containsSequence(" ", + " ", " org.projectlombok", + " lombok", " ", + " "); + + } + + @Test + void nonAnnotationProcessorsAreIgnored() { + ProjectRequest request = createProjectRequest("web"); + request.setBootVersion("2.4.0"); + assertThat(mavenPom(request)).lines().doesNotContainSequence(" ", + " org.springframework.boot", + " spring-boot-starter-web", + " "); + + } + +}