Skip to content

Commit 2b83654

Browse files
zambrovskimhalbritter
authored andcommitted
Add ability to exclude ProjectGenerationConfiguration
See gh-1584
1 parent 0db7ed4 commit 2b83654

File tree

7 files changed

+195
-5
lines changed

7 files changed

+195
-5
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.initializr.generator.project;
18+
19+
/**
20+
* Allows to filter {@link ProjectGenerationConfiguration}.
21+
*
22+
* @author Simon Zambrovski
23+
*/
24+
public interface ProjectGenerationConfigurationTypeFilter {
25+
26+
/**
27+
* Determines if the provided class matches the filter.
28+
* @param type type to match.
29+
* @return true, if the type matches.
30+
*/
31+
boolean match(Class<?> type);
32+
33+
}

initializr-generator/src/main/java/io/spring/initializr/generator/project/ProjectGenerator.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.beans.factory.support.GenericBeanDefinition;
2525
import org.springframework.context.support.GenericApplicationContext;
2626
import org.springframework.core.io.support.SpringFactoriesLoader;
27+
import org.springframework.util.ClassUtils;
2728

2829
/**
2930
* Main entry point for project generation that processes a {@link ProjectDescription} by
@@ -116,17 +117,51 @@ public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> p
116117

117118
/**
118119
* Return the {@link ProjectGenerationConfiguration} class names that should be
119-
* considered. By default this method will load candidates using
120-
* {@link SpringFactoriesLoader} with {@link ProjectGenerationConfiguration}.
120+
* considered. By default, this method will load candidates using
121+
* {@link SpringFactoriesLoader} with {@link ProjectGenerationConfiguration} and
122+
* exclude those which are matched by the
123+
* {@link ProjectGenerationConfigurationTypeFilter}
121124
* @param description the description of the project to generate
122125
* @return a list of candidate configurations
123126
*/
124-
@SuppressWarnings("deprecation")
127+
125128
protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescription description) {
129+
List<String> candidates = getProjectGenerationConfigurationFactoryNames();
130+
ProjectGenerationConfigurationTypeFilter filter = getProjectGenerationConfigurationExclusionFilter();
131+
return candidates.stream().filter((candidate) -> {
132+
Class<?> type = this.resolveClass(candidate);
133+
return type != null && !filter.match(type);
134+
}).toList();
135+
}
136+
137+
private Class<?> resolveClass(String candidate) {
138+
try {
139+
return ClassUtils.forName(candidate, getClass().getClassLoader());
140+
}
141+
catch (ClassNotFoundException ex) {
142+
return null;
143+
}
144+
}
145+
146+
@SuppressWarnings("deprecation")
147+
List<String> getProjectGenerationConfigurationFactoryNames() {
126148
return SpringFactoriesLoader.loadFactoryNames(ProjectGenerationConfiguration.class,
127149
getClass().getClassLoader());
128150
}
129151

152+
ProjectGenerationConfigurationTypeFilter getProjectGenerationConfigurationExclusionFilter() {
153+
List<ProjectGenerationConfigurationTypeFilter> filters = SpringFactoriesLoader
154+
.loadFactories(ProjectGenerationConfigurationTypeFilter.class, getClass().getClassLoader());
155+
// Build a composite filter, combining results with a logical OR
156+
return (configurationClass) -> {
157+
boolean excluded = false;
158+
for (ProjectGenerationConfigurationTypeFilter filter : filters) {
159+
excluded = excluded || filter.match(configurationClass);
160+
}
161+
return excluded;
162+
};
163+
}
164+
130165
private void registerProjectDescription(ProjectGenerationContext context, ProjectDescription description) {
131166
context.registerBean(ProjectDescription.class, resolve(description, context));
132167
}

initializr-generator/src/test/java/io/spring/initializr/generator/project/ProjectGeneratorTests.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
import io.spring.initializr.generator.buildsystem.maven.MavenBuildSystem;
2727
import io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration;
28+
import io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration2;
29+
import org.assertj.core.util.Lists;
2830
import org.junit.jupiter.api.Test;
2931
import org.junit.jupiter.api.io.TempDir;
3032
import org.mockito.InOrder;
@@ -181,8 +183,9 @@ void generateCanBeExtendedToFilterProjectContributors(@TempDir Path projectDir)
181183
given(description.getBuildSystem()).willReturn(new MavenBuildSystem());
182184
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr()) {
183185
@Override
184-
protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescription description) {
185-
assertThat(description).isSameAs(description);
186+
protected List<String> getCandidateProjectGenerationConfigurations(
187+
ProjectDescription generatorDescription) {
188+
assertThat(description).isSameAs(generatorDescription);
186189
return Collections.singletonList(TestProjectGenerationConfiguration.class.getName());
187190
}
188191
};
@@ -195,6 +198,37 @@ protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescri
195198
verify(description).getBuildSystem();
196199
}
197200

201+
@Test
202+
void loadAndConstructProjectGenerationTypeExclusionFilter() {
203+
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr());
204+
ProjectGenerationConfigurationTypeFilter filter = generator.getProjectGenerationConfigurationExclusionFilter();
205+
assertThat(filter).isNotNull();
206+
assertThat(filter.match(TestProjectGenerationConfiguration.class)).isTrue();
207+
assertThat(filter.match(TestProjectGenerationConfiguration2.class)).isTrue();
208+
assertThat(filter.match(Integer.class)).isFalse();
209+
}
210+
211+
@Test
212+
void filterProjectContributorsCorrectly(@TempDir Path projectDir) {
213+
ProjectDescription description = mock(ProjectDescription.class);
214+
given(description.getArtifactId()).willReturn("test-custom-contributor");
215+
given(description.getBuildSystem()).willReturn(new MavenBuildSystem());
216+
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr()) {
217+
@Override
218+
List<String> getProjectGenerationConfigurationFactoryNames() {
219+
return Lists.list(TestProjectGenerationConfiguration.class.getName(),
220+
TestProjectGenerationConfiguration2.class.getName());
221+
}
222+
223+
@Override
224+
ProjectGenerationConfigurationTypeFilter getProjectGenerationConfigurationExclusionFilter() {
225+
return TestProjectGenerationConfiguration2.class::equals;
226+
}
227+
};
228+
List<String> candidates = generator.getCandidateProjectGenerationConfigurations(description);
229+
assertThat(candidates).containsOnly(TestProjectGenerationConfiguration.class.getCanonicalName());
230+
}
231+
198232
@SuppressWarnings("unchecked")
199233
private Consumer<ProjectGenerationContext> mockContextInitializr() {
200234
return mock(Consumer.class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.initializr.generator.project.contributor;
18+
19+
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
20+
21+
/**
22+
* Test contributor.
23+
*/
24+
@ProjectGenerationConfiguration
25+
public class TestProjectGenerationConfiguration2 {
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.initializr.generator.project.contributor;
18+
19+
import io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter;
20+
21+
public class TestProjectGenerationConfiguration2ExcludingTypeFilter
22+
implements ProjectGenerationConfigurationTypeFilter {
23+
24+
@Override
25+
public boolean match(Class<?> type) {
26+
return TestProjectGenerationConfiguration2.class.equals(type);
27+
}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.initializr.generator.project.contributor;
18+
19+
import io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter;
20+
21+
public class TestProjectGenerationConfigurationExcludingTypeFilter implements ProjectGenerationConfigurationTypeFilter {
22+
23+
@Override
24+
public boolean match(Class<?> type) {
25+
return TestProjectGenerationConfiguration.class.equals(type);
26+
}
27+
28+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter=\
2+
io.spring.initializr.generator.project.contributor.TestProjectGenerationConfigurationExcludingTypeFilter,\
3+
io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration2ExcludingTypeFilter
4+

0 commit comments

Comments
 (0)