Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to exclude ProjectGenerationConfigurations #1584

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2012-2024 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.initializr.generator.project;

/**
* Allows to filter {@link ProjectGenerationConfiguration}.
*
* @author Simon Zambrovski
*/
public interface ProjectGenerationConfigurationTypeFilter {

/**
* Determines if the provided class matches the filter.
* @param type type to match.
* @return true, if the type matches.
*/
boolean match(Class<?> type);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ClassUtils;

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

/**
* Return the {@link ProjectGenerationConfiguration} class names that should be
* considered. By default this method will load candidates using
* {@link SpringFactoriesLoader} with {@link ProjectGenerationConfiguration}.
* considered. By default, this method will load candidates using
* {@link SpringFactoriesLoader} with {@link ProjectGenerationConfiguration} and
* exclude those which are matched by the
* {@link ProjectGenerationConfigurationTypeFilter}
* @param description the description of the project to generate
* @return a list of candidate configurations
*/
@SuppressWarnings("deprecation")

protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescription description) {
List<String> candidates = getProjectGenerationConfigurationFactoryNames();
ProjectGenerationConfigurationTypeFilter filter = getProjectGenerationConfigurationExclusionFilter();
return candidates.stream().filter((candidate) -> {
Class<?> type = this.resolveClass(candidate);
return type != null && !filter.match(type);
}).toList();
}

private Class<?> resolveClass(String candidate) {
try {
return ClassUtils.forName(candidate, getClass().getClassLoader());
}
catch (ClassNotFoundException ex) {
return null;
}
}

@SuppressWarnings("deprecation")
List<String> getProjectGenerationConfigurationFactoryNames() {
return SpringFactoriesLoader.loadFactoryNames(ProjectGenerationConfiguration.class,
getClass().getClassLoader());
}

ProjectGenerationConfigurationTypeFilter getProjectGenerationConfigurationExclusionFilter() {
List<ProjectGenerationConfigurationTypeFilter> filters = SpringFactoriesLoader
.loadFactories(ProjectGenerationConfigurationTypeFilter.class, getClass().getClassLoader());
// Build a composite filter, combining results with a logical OR
return (configurationClass) -> {
boolean excluded = false;
for (ProjectGenerationConfigurationTypeFilter filter : filters) {
excluded = excluded || filter.match(configurationClass);
}
return excluded;
};
}

private void registerProjectDescription(ProjectGenerationContext context, ProjectDescription description) {
context.registerBean(ProjectDescription.class, resolve(description, context));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

import io.spring.initializr.generator.buildsystem.maven.MavenBuildSystem;
import io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration;
import io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration2;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.InOrder;
Expand Down Expand Up @@ -181,8 +183,9 @@ void generateCanBeExtendedToFilterProjectContributors(@TempDir Path projectDir)
given(description.getBuildSystem()).willReturn(new MavenBuildSystem());
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr()) {
@Override
protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescription description) {
assertThat(description).isSameAs(description);
protected List<String> getCandidateProjectGenerationConfigurations(
ProjectDescription generatorDescription) {
assertThat(description).isSameAs(generatorDescription);
return Collections.singletonList(TestProjectGenerationConfiguration.class.getName());
}
};
Expand All @@ -195,6 +198,37 @@ protected List<String> getCandidateProjectGenerationConfigurations(ProjectDescri
verify(description).getBuildSystem();
}

@Test
void loadAndConstructProjectGenerationTypeExclusionFilter() {
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr());
ProjectGenerationConfigurationTypeFilter filter = generator.getProjectGenerationConfigurationExclusionFilter();
assertThat(filter).isNotNull();
assertThat(filter.match(TestProjectGenerationConfiguration.class)).isTrue();
assertThat(filter.match(TestProjectGenerationConfiguration2.class)).isTrue();
assertThat(filter.match(Integer.class)).isFalse();
}

@Test
void filterProjectContributorsCorrectly(@TempDir Path projectDir) {
ProjectDescription description = mock(ProjectDescription.class);
given(description.getArtifactId()).willReturn("test-custom-contributor");
given(description.getBuildSystem()).willReturn(new MavenBuildSystem());
ProjectGenerator generator = new ProjectGenerator(mockContextInitializr()) {
@Override
List<String> getProjectGenerationConfigurationFactoryNames() {
return Lists.list(TestProjectGenerationConfiguration.class.getName(),
TestProjectGenerationConfiguration2.class.getName());
}

@Override
ProjectGenerationConfigurationTypeFilter getProjectGenerationConfigurationExclusionFilter() {
return TestProjectGenerationConfiguration2.class::equals;
}
};
List<String> candidates = generator.getCandidateProjectGenerationConfigurations(description);
assertThat(candidates).containsOnly(TestProjectGenerationConfiguration.class.getCanonicalName());
}

@SuppressWarnings("unchecked")
private Consumer<ProjectGenerationContext> mockContextInitializr() {
return mock(Consumer.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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.initializr.generator.project.contributor;

import io.spring.initializr.generator.project.ProjectGenerationConfiguration;

/**
* Test contributor.
*/
@ProjectGenerationConfiguration
public class TestProjectGenerationConfiguration2 {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.initializr.generator.project.contributor;

import io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter;

public class TestProjectGenerationConfiguration2ExcludingTypeFilter
implements ProjectGenerationConfigurationTypeFilter {

@Override
public boolean match(Class<?> type) {
return TestProjectGenerationConfiguration2.class.equals(type);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.initializr.generator.project.contributor;

import io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter;

public class TestProjectGenerationConfigurationExcludingTypeFilter implements ProjectGenerationConfigurationTypeFilter {

@Override
public boolean match(Class<?> type) {
return TestProjectGenerationConfiguration.class.equals(type);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
io.spring.initializr.generator.project.ProjectGenerationConfigurationTypeFilter=\
io.spring.initializr.generator.project.contributor.TestProjectGenerationConfigurationExcludingTypeFilter,\
io.spring.initializr.generator.project.contributor.TestProjectGenerationConfiguration2ExcludingTypeFilter