mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-15 14:04:30 +08:00
Add project request post processing
This commit introduces `ProjectRequestPostProcessor` as a mean to modify an incoming `ProjectRequest` before and after its resolution against the meta-data. By default, all beans of that type are invoked automatically and they are ordered against their `@Order` or `Ordered` settings. Closes gh-260
This commit is contained in:
parent
fb7b8eb5cb
commit
56210d9bf2
@ -55,6 +55,9 @@ class ProjectGenerator {
|
||||
@Autowired
|
||||
InitializrMetadataProvider metadataProvider
|
||||
|
||||
@Autowired
|
||||
ProjectRequestResolver requestResolver
|
||||
|
||||
@Autowired
|
||||
ProjectResourceLocator projectResourceLocator = new ProjectResourceLocator()
|
||||
|
||||
@ -210,12 +213,12 @@ class ProjectGenerator {
|
||||
* @param request the request to handle
|
||||
* @return a model for that request
|
||||
*/
|
||||
protected Map resolveModel(ProjectRequest request) {
|
||||
Assert.notNull request.bootVersion, 'boot version must not be null'
|
||||
protected Map resolveModel(ProjectRequest originalRequest) {
|
||||
Assert.notNull originalRequest.bootVersion, 'boot version must not be null'
|
||||
def model = [:]
|
||||
def metadata = metadataProvider.get()
|
||||
|
||||
request.resolve(metadata)
|
||||
ProjectRequest request = requestResolver.resolve(originalRequest, metadata)
|
||||
|
||||
// request resolved so we can log what has been requested
|
||||
def dependencies = request.resolvedDependencies
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
|
||||
/**
|
||||
* Project generation hook that allows for custom modification of {@link ProjectRequest}
|
||||
* instances, e.g. adding custom dependencies or forcing certain settings based on custom
|
||||
* logic.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
interface ProjectRequestPostProcessor {
|
||||
|
||||
/**
|
||||
* Apply this post processor to the given {@code ProjectRequest} <i>before</i> it
|
||||
* gets resolved against the specified {@code InitializrMetadata}.
|
||||
* <p>Consider using this hook to customize basic settings of the {@code request};
|
||||
* for more advanced logic (in particular with regards to dependencies), consider
|
||||
* using {@code postProcessAfterResolution}.
|
||||
* @param request an unresolved {@link ProjectRequest}
|
||||
* @param metadata the metadata to use to resolve this request
|
||||
* @see ProjectRequest#resolve(InitializrMetadata)
|
||||
*/
|
||||
void postProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata);
|
||||
|
||||
/**
|
||||
* Apply this post processor to the given {@code ProjectRequest} <i>after</i> it has
|
||||
* been resolved against the specified {@code InitializrMetadata}.
|
||||
* <p>Dependencies, repositories, bills of materials, default properties and others
|
||||
* aspects of the request will have been resolved prior to invocation. In particular,
|
||||
* note that no further validation checks will be performed.
|
||||
* @param request an resolved {@code ProjectRequest}
|
||||
* @param metadata the metadata that were used to resolve this request
|
||||
*/
|
||||
void postProcessAfterResolution(ProjectRequest request, InitializrMetadata metadata);
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.spring.initializr.generator
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
|
||||
/**
|
||||
* An implementation of {@link ProjectRequestPostProcessor} with empty methods allowing
|
||||
* sub-classes to override only the methods they're interested in.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ProjectRequestPostProcessorAdapter implements ProjectRequestPostProcessor {
|
||||
|
||||
@Override
|
||||
void postProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void postProcessAfterResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package io.spring.initializr.generator
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
|
||||
import org.springframework.util.Assert
|
||||
|
||||
/**
|
||||
* Resolve {@link ProjectRequest} instances, honoring callback hook points.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ProjectRequestResolver {
|
||||
|
||||
private final List<ProjectRequestPostProcessor> postProcessors
|
||||
|
||||
ProjectRequestResolver(List<ProjectRequestPostProcessor> postProcessors) {
|
||||
this.postProcessors = new ArrayList<>(postProcessors)
|
||||
}
|
||||
|
||||
ProjectRequest resolve(ProjectRequest request, InitializrMetadata metadata) {
|
||||
Assert.notNull(request, "Request must not be null")
|
||||
applyPostProcessBeforeResolution(request, metadata)
|
||||
request.resolve(metadata)
|
||||
applyPostProcessAfterResolution(request, metadata)
|
||||
request
|
||||
}
|
||||
|
||||
private void applyPostProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
for (ProjectRequestPostProcessor processor : postProcessors) {
|
||||
processor.postProcessBeforeResolution(request, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPostProcessAfterResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
for (ProjectRequestPostProcessor processor : postProcessors) {
|
||||
processor.postProcessAfterResolution(request, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -57,6 +57,7 @@ abstract class AbstractProjectGeneratorTests {
|
||||
.addDependencyGroup('test', 'security', 'data-jpa', 'aop', 'batch', 'integration').build()
|
||||
applyMetadata(metadata)
|
||||
projectGenerator.eventPublisher = eventPublisher
|
||||
projectGenerator.requestResolver = new ProjectRequestResolver([])
|
||||
projectGenerator.tmpdir = folder.newFolder().absolutePath
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package io.spring.initializr.generator
|
||||
|
||||
import io.spring.initializr.metadata.BillOfMaterials
|
||||
import io.spring.initializr.metadata.Dependency
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@ -642,6 +643,34 @@ class ProjectGeneratorTests extends AbstractProjectGeneratorTests {
|
||||
.doesNotContain('ignore.property')
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionRangeWithPostProcessor() {
|
||||
Dependency foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo')
|
||||
foo.mappings << new Dependency.Mapping(versionRange: '[1.2.0.RELEASE,1.3.0.M1)', version: '1.0.0')
|
||||
foo.mappings << new Dependency.Mapping(versionRange: '1.3.0.M1', version: '1.2.0')
|
||||
def metadata = InitializrMetadataTestBuilder.withDefaults()
|
||||
.addDependencyGroup('foo', foo).build()
|
||||
applyMetadata(metadata)
|
||||
|
||||
// First without processor, get the correct version
|
||||
def request = createProjectRequest('foo')
|
||||
request.bootVersion = '1.2.5.RELEASE'
|
||||
generateMavenPom(request).hasDependency(
|
||||
new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', version: '1.0.0'))
|
||||
|
||||
// First after processor that flips Spring Boot version
|
||||
projectGenerator.requestResolver = new ProjectRequestResolver(Collections.singletonList(
|
||||
new ProjectRequestPostProcessorAdapter() {
|
||||
@Override
|
||||
void postProcessBeforeResolution(ProjectRequest r, InitializrMetadata m) {
|
||||
r.bootVersion = '1.3.0.M2'
|
||||
}
|
||||
}
|
||||
))
|
||||
generateMavenPom(request).hasDependency(
|
||||
new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', version: '1.2.0'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidProjectTypeMavenPom() {
|
||||
def request = createProjectRequest('web')
|
||||
|
@ -0,0 +1,86 @@
|
||||
package io.spring.initializr.generator
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
|
||||
/**
|
||||
* Tests for {@link ProjectRequestResolver}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ProjectRequestResolverTests {
|
||||
|
||||
def metadata = InitializrMetadataTestBuilder.withDefaults()
|
||||
.addDependencyGroup('test', 'web', 'security', 'data-jpa')
|
||||
.build()
|
||||
|
||||
final List<ProjectRequestPostProcessor> postProcessors = []
|
||||
final GenericProjectRequestPostProcessor processor = new GenericProjectRequestPostProcessor()
|
||||
|
||||
@Before
|
||||
void setup() {
|
||||
this.postProcessors << processor
|
||||
}
|
||||
|
||||
@Test
|
||||
void beforeResolution() {
|
||||
processor.before['javaVersion'] = '1.2'
|
||||
ProjectRequest request = resolve(createMavenProjectRequest(), postProcessors)
|
||||
assertEquals '1.2', request.javaVersion
|
||||
assertEquals '1.2', request.buildProperties.versions['java.version'].call()
|
||||
}
|
||||
|
||||
@Test
|
||||
void afterResolution() {
|
||||
postProcessors << new ProjectRequestPostProcessorAdapter() {
|
||||
@Override
|
||||
void postProcessAfterResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
request.buildProperties.maven.clear()
|
||||
request.buildProperties.maven['foo'] = { 'bar' }
|
||||
}
|
||||
}
|
||||
ProjectRequest request = resolve(createMavenProjectRequest(), postProcessors)
|
||||
assertEquals 1, request.buildProperties.maven.size()
|
||||
assertEquals 'bar', request.buildProperties.maven['foo'].call()
|
||||
}
|
||||
|
||||
ProjectRequest resolve(def request, def processors) {
|
||||
new ProjectRequestResolver(processors)
|
||||
.resolve(request, metadata)
|
||||
}
|
||||
|
||||
ProjectRequest createMavenProjectRequest(String... styles) {
|
||||
def request = createProjectRequest(styles)
|
||||
request.type = 'maven-project'
|
||||
request
|
||||
}
|
||||
|
||||
ProjectRequest createProjectRequest(String... styles) {
|
||||
def request = new ProjectRequest()
|
||||
request.initialize(metadata)
|
||||
request.style.addAll Arrays.asList(styles)
|
||||
request
|
||||
}
|
||||
|
||||
static class GenericProjectRequestPostProcessor implements ProjectRequestPostProcessor {
|
||||
|
||||
final Map<String, Object> before = [:]
|
||||
final Map<String, Object> after = [:]
|
||||
|
||||
@Override
|
||||
void postProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
before.forEach { k, v -> request.setProperty(k, v) }
|
||||
}
|
||||
|
||||
@Override
|
||||
void postProcessAfterResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
after.forEach { k, v -> request.setProperty(k, v) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -20,6 +20,8 @@ import java.util.concurrent.TimeUnit
|
||||
|
||||
import com.google.common.cache.CacheBuilder
|
||||
import io.spring.initializr.generator.ProjectGenerator
|
||||
import io.spring.initializr.generator.ProjectRequestPostProcessor
|
||||
import io.spring.initializr.generator.ProjectRequestResolver
|
||||
import io.spring.initializr.generator.ProjectResourceLocator
|
||||
import io.spring.initializr.metadata.DependencyMetadataProvider
|
||||
import io.spring.initializr.metadata.InitializrMetadataBuilder
|
||||
@ -30,6 +32,7 @@ import io.spring.initializr.web.support.DefaultDependencyMetadataProvider
|
||||
import io.spring.initializr.web.support.DefaultInitializrMetadataProvider
|
||||
import io.spring.initializr.web.ui.UiController
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.cache.CacheManager
|
||||
@ -56,6 +59,9 @@ import org.springframework.context.annotation.Configuration
|
||||
@EnableConfigurationProperties(InitializrProperties)
|
||||
class InitializrAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
List<ProjectRequestPostProcessor> postProcessors = []
|
||||
|
||||
@Bean
|
||||
WebConfig webConfig() {
|
||||
new WebConfig()
|
||||
@ -79,6 +85,12 @@ class InitializrAutoConfiguration {
|
||||
new ProjectGenerator()
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ProjectRequestResolver projectRequestResolver() {
|
||||
new ProjectRequestResolver(postProcessors)
|
||||
}
|
||||
|
||||
@Bean
|
||||
ProjectResourceLocator projectResourceLocator() {
|
||||
return new ProjectResourceLocator()
|
||||
|
@ -0,0 +1,59 @@
|
||||
package io.spring.initializr.web.project
|
||||
|
||||
import io.spring.initializr.generator.ProjectRequest
|
||||
import io.spring.initializr.generator.ProjectRequestPostProcessor
|
||||
import io.spring.initializr.generator.ProjectRequestPostProcessorAdapter
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests
|
||||
import org.junit.Test
|
||||
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
|
||||
@ActiveProfiles('test-default')
|
||||
@SpringApplicationConfiguration(classes = [Config, ProjectRequestPostProcessorConfiguration])
|
||||
class ProjectGenerationPostProcessorTests extends AbstractInitializrControllerIntegrationTests {
|
||||
|
||||
|
||||
@Test
|
||||
void postProcessorsInvoked() {
|
||||
downloadZip('/starter.zip?bootVersion=1.2.4.RELEASE&javaVersion=1.6')
|
||||
.isJavaProject()
|
||||
.isMavenProject().pomAssert()
|
||||
.hasSpringBootParent('1.2.3.RELEASE')
|
||||
.hasProperty('java.version', '1.7')
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ProjectRequestPostProcessorConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(2)
|
||||
ProjectRequestPostProcessor secondPostProcessor() {
|
||||
new ProjectRequestPostProcessorAdapter() {
|
||||
@Override
|
||||
void postProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
request.javaVersion = '1.7'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
ProjectRequestPostProcessor firstPostProcessor() {
|
||||
new ProjectRequestPostProcessorAdapter() {
|
||||
@Override
|
||||
void postProcessBeforeResolution(ProjectRequest request, InitializrMetadata metadata) {
|
||||
request.javaVersion = '1.2'
|
||||
request.bootVersion = '1.2.3.RELEASE'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user