mirror of
https://gitee.com/dcren/initializr.git
synced 2025-05-11 08:08:05 +08:00
Use SpringBootApplication when available
If Spring Boot 1.2 or later is used, the generated project uses the new SpringBootApplication annotation as a replacement for what used to be configured by Configuration, ComponentScan and EnableAutoConfiguration. Also add an infrastructure to parse and compare versions. Closes gh-46
This commit is contained in:
parent
b8e26a2d3a
commit
d35482a61b
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@ -17,6 +17,7 @@
|
||||
package io.spring.initializr
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.support.Version
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
@ -34,6 +35,8 @@ import static io.spring.initializr.support.GroovyTemplate.template
|
||||
@Slf4j
|
||||
class ProjectGenerator {
|
||||
|
||||
private static final VERSION_1_2_0_RC1 = Version.parse('1.2.0.RC1')
|
||||
|
||||
@Autowired
|
||||
InitializrMetadata metadata
|
||||
|
||||
@ -164,6 +167,10 @@ class ProjectGenerator {
|
||||
log.info("Processing request{type=$request.type, dependencies=$dependencies}")
|
||||
|
||||
request.properties.each { model[it.key] = it.value }
|
||||
|
||||
// @SpringBootApplication available as from 1.2.0.RC1
|
||||
model['useSpringBootApplication'] = VERSION_1_2_0_RC1
|
||||
.compareTo(Version.safeParse(request.bootVersion)) <= 0
|
||||
model
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.support
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.ToString
|
||||
|
||||
/**
|
||||
* Define the version number of a module. A typical version is represented
|
||||
* as {@code MAJOR.MINOR.PATCH.QUALIFER} where the qualifier can have an
|
||||
* extra version.
|
||||
* <p>
|
||||
* For example: {@code 1.2.0.RC1} is the first release candidate of 1.2.0
|
||||
* and {@code 1.5.0.M4} is the fourth milestone of 1.5.0. The special
|
||||
* {@code RELEASE} qualifier indicates a final release (a.k.a. GA)
|
||||
* <p>
|
||||
* The main purpose of parsing a version is to compare it with another
|
||||
* version, see {@link Comparable}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
class Version implements Comparable<Version> {
|
||||
|
||||
private static final String VERSION_REGEX = '^(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.([^0-9]+)(\\d+)?)?$'
|
||||
|
||||
private static final VersionQualifierComparator qualifierComparator = new VersionQualifierComparator()
|
||||
|
||||
Integer major
|
||||
Integer minor
|
||||
Integer patch
|
||||
Qualifier qualifier
|
||||
|
||||
/**
|
||||
* Parse the string representation of a {@link Version}. Throws an
|
||||
* {@link IllegalArgumentException} if the version could not be parsed.
|
||||
* @param text the version text
|
||||
* @return a Version instance for the specified version text
|
||||
* @throws IllegalArgumentException if the version text could not be parsed
|
||||
* @see #safeParse(java.lang.String)
|
||||
*/
|
||||
static Version parse(String text) {
|
||||
def matcher = (text =~ VERSION_REGEX)
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("Could not determine version based on $text")
|
||||
}
|
||||
Version version = new Version()
|
||||
version.major = Integer.valueOf(matcher[0][1])
|
||||
version.minor = Integer.valueOf(matcher[0][2])
|
||||
version.patch = Integer.valueOf(matcher[0][3])
|
||||
String qualifierId = matcher[0][4]
|
||||
if (qualifierId) {
|
||||
Qualifier qualifier = new Qualifier(qualifier: qualifierId)
|
||||
String o = matcher[0][5]
|
||||
if (o != null) {
|
||||
qualifier.version = Integer.valueOf(o)
|
||||
}
|
||||
version.qualifier = qualifier
|
||||
}
|
||||
version
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse safely the specified string representation of a {@link Version}.
|
||||
* <p>
|
||||
* Return {@code null} if the text represents an invalid version.
|
||||
* @param text the version text
|
||||
* @return a Version instance for the specified version text
|
||||
* @see #parse(java.lang.String)
|
||||
*/
|
||||
static safeParse(String text) {
|
||||
try {
|
||||
return parse(text)
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(Version other) {
|
||||
if (other == null) {
|
||||
return 1
|
||||
}
|
||||
int majorDiff = safeCompare(this.major, other.major)
|
||||
if (majorDiff != 0) {
|
||||
return majorDiff
|
||||
}
|
||||
int minorDiff = safeCompare(this.minor, other.minor)
|
||||
if (minorDiff != 0) {
|
||||
return minorDiff
|
||||
}
|
||||
int patch = safeCompare(this.patch, other.patch)
|
||||
if (patch != 0) {
|
||||
return patch
|
||||
}
|
||||
qualifierComparator.compare(this.qualifier, other.qualifier)
|
||||
}
|
||||
|
||||
private static int safeCompare(Integer first, Integer second) {
|
||||
int firstIndex = first ?: 0
|
||||
int secondIndex = second ?: 0
|
||||
return firstIndex.compareTo(secondIndex)
|
||||
}
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
public static class Qualifier {
|
||||
String qualifier
|
||||
Integer version
|
||||
}
|
||||
|
||||
|
||||
private static class VersionQualifierComparator implements Comparator<Qualifier> {
|
||||
|
||||
static final String RELEASE = 'RELEASE'
|
||||
static final String SNAPSHOT = 'BUILD-SNAPSHOT'
|
||||
static final String MILESTONE = 'M'
|
||||
static final String RC = 'RC'
|
||||
|
||||
static final List<String> KNOWN_QUALIFIERS = Arrays.asList(MILESTONE, RC, SNAPSHOT, RELEASE)
|
||||
|
||||
@Override
|
||||
int compare(Qualifier o1, Qualifier o2) {
|
||||
Qualifier first = o1 ?: new Qualifier(qualifier: RELEASE)
|
||||
Qualifier second = o2 ?: new Qualifier(qualifier: RELEASE)
|
||||
|
||||
int qualifier = compareQualifier(first, second)
|
||||
qualifier ? qualifier : compareQualifierVersion(first, second)
|
||||
}
|
||||
|
||||
private static int compareQualifierVersion(Qualifier first, Qualifier second) {
|
||||
int firstVersion = first.getVersion() ?: 0
|
||||
int secondVersion = second.getVersion() ?: 0
|
||||
firstVersion.compareTo(secondVersion)
|
||||
}
|
||||
|
||||
private static int compareQualifier(Qualifier first, Qualifier second) {
|
||||
int firstIndex = getQualifierIndex(first.qualifier)
|
||||
int secondIndex = getQualifierIndex(second.qualifier)
|
||||
|
||||
if (firstIndex == -1 && secondIndex == -1) { // Unknown qualifier, alphabetic ordering
|
||||
return first.qualifier.compareTo(second.qualifier)
|
||||
} else {
|
||||
return firstIndex.compareTo(secondIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private static int getQualifierIndex(String qualifier) {
|
||||
qualifier ? KNOWN_QUALIFIERS.indexOf(qualifier) : RELEASE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
package ${packageName}
|
||||
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.SpringApplication<% if (useSpringBootApplication) { %>
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication<% } else { %>
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
import org.springframework.context.annotation.Configuration<% } %>
|
||||
<% if (useSpringBootApplication) { %>
|
||||
@SpringBootApplication<% } else { %>
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
@EnableAutoConfiguration <% } %>
|
||||
class ${applicationName} {
|
||||
|
||||
static void main(String[] args) {
|
||||
|
@ -1,13 +1,15 @@
|
||||
package ${packageName};
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringApplication;<% if (useSpringBootApplication) { %>
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;<% } else { %>
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;<% } %>
|
||||
<% if (useSpringBootApplication) { %>
|
||||
@SpringBootApplication<% } else { %>
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
@EnableAutoConfiguration <% } %>
|
||||
public class ${applicationName} {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -25,6 +25,11 @@ import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
import static org.mockito.Mockito.*
|
||||
|
||||
/**
|
||||
@ -146,6 +151,60 @@ class ProjectGeneratorTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBoot11UseEnableAutoConfigurationJava() {
|
||||
def request = createProjectRequest('web')
|
||||
request.bootVersion = '1.1.9.RELEASE'
|
||||
request.name = 'MyDemo'
|
||||
request.packageName = 'foo'
|
||||
generateProject(request).sourceCodeAssert('src/main/java/foo/MyDemoApplication.java')
|
||||
.hasImports(EnableAutoConfiguration.class.name, ComponentScan.class.name, Configuration.class.name)
|
||||
.doesNotHaveImports(SpringBootApplication.class.name)
|
||||
.contains('@EnableAutoConfiguration', '@Configuration', '@ComponentScan')
|
||||
.doesNotContain('@SpringBootApplication')
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBootUseSpringBootApplicationJava() {
|
||||
def request = createProjectRequest('web')
|
||||
request.bootVersion = '1.2.0.RC1'
|
||||
request.name = 'MyDemo'
|
||||
request.packageName = 'foo'
|
||||
generateProject(request).sourceCodeAssert('src/main/java/foo/MyDemoApplication.java')
|
||||
.hasImports(SpringBootApplication.class.name)
|
||||
.doesNotHaveImports(EnableAutoConfiguration.class.name, ComponentScan.class.name, Configuration.class.name)
|
||||
.contains('@SpringBootApplication')
|
||||
.doesNotContain('@EnableAutoConfiguration', '@Configuration', '@ComponentScan')
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBoot11UseEnableAutoConfigurationGroovy() {
|
||||
def request = createProjectRequest('web')
|
||||
request.language = 'groovy'
|
||||
request.bootVersion = '1.1.9.RELEASE'
|
||||
request.name = 'MyDemo'
|
||||
request.packageName = 'foo'
|
||||
generateProject(request).sourceCodeAssert('src/main/groovy/foo/MyDemoApplication.groovy')
|
||||
.hasImports(EnableAutoConfiguration.class.name, ComponentScan.class.name, Configuration.class.name)
|
||||
.doesNotHaveImports(SpringBootApplication.class.name)
|
||||
.contains('@EnableAutoConfiguration', '@Configuration', '@ComponentScan')
|
||||
.doesNotContain('@SpringBootApplication')
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBootUseSpringBootApplicationGroovy() {
|
||||
def request = createProjectRequest('web')
|
||||
request.language = 'groovy'
|
||||
request.bootVersion = '1.2.0.RC1'
|
||||
request.name = 'MyDemo'
|
||||
request.packageName = 'foo'
|
||||
generateProject(request).sourceCodeAssert('src/main/groovy/foo/MyDemoApplication.groovy')
|
||||
.hasImports(SpringBootApplication.class.name)
|
||||
.doesNotHaveImports(EnableAutoConfiguration.class.name, ComponentScan.class.name, Configuration.class.name)
|
||||
.contains('@SpringBootApplication')
|
||||
.doesNotContain('@EnableAutoConfiguration', '@Configuration', '@ComponentScan')
|
||||
}
|
||||
|
||||
PomAssert generateMavenPom(ProjectRequest request) {
|
||||
def content = new String(projectGenerator.generateMavenPom(request))
|
||||
new PomAssert(content).validateProjectRequest(request)
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.support
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
import static io.spring.initializr.support.Version.parse
|
||||
import static io.spring.initializr.support.Version.safeParse
|
||||
import static org.hamcrest.MatcherAssert.assertThat
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertNull
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class VersionTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Test
|
||||
void equalNoQualifier() {
|
||||
def first = parse('1.2.0')
|
||||
def second = parse('1.2.0')
|
||||
assertThat(first, comparesEqualTo(second))
|
||||
assertThat(first, equalTo(second))
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalQualifierNoVersion() {
|
||||
def first = parse('1.2.0.RELEASE')
|
||||
def second = parse('1.2.0.RELEASE')
|
||||
assertThat(first, comparesEqualTo(second))
|
||||
assertThat(first, equalTo(second))
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalQualifierVersion() {
|
||||
def first = parse('1.2.0.RC1')
|
||||
def second = parse('1.2.0.RC1')
|
||||
assertThat(first, comparesEqualTo(second))
|
||||
assertThat(first, equalTo(second))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareMajorOnly() {
|
||||
assertThat(parse('2.2.0'), greaterThan(parse('1.8.0')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareMinorOnly() {
|
||||
assertThat(parse('2.2.0'), greaterThan(parse('2.1.9')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void comparePatchOnly() {
|
||||
assertThat(parse('2.2.4'), greaterThan(parse('2.2.3')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareHigherVersion() {
|
||||
assertThat(parse('1.2.0.RELEASE'), greaterThan(parse('1.1.9.RELEASE')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareHigherQualifier() {
|
||||
assertThat(parse('1.2.0.RC1'), greaterThan(parse('1.2.0.M1')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareHigherQualifierVersion() {
|
||||
assertThat(parse('1.2.0.RC2'), greaterThan(parse('1.2.0.RC1')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareLowerVersion() {
|
||||
assertThat(parse('1.0.5.RELEASE'), lessThan(parse('1.1.9.RELEASE')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareLowerQualifier() {
|
||||
assertThat(parse('1.2.0.RC1'), lessThan(parse('1.2.0.RELEASE')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareLessQualifierVersion() {
|
||||
assertThat(parse('1.2.0.RC2'), lessThan(parse('1.2.0.RC3')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareWithNull() {
|
||||
assertThat(parse('1.2.0.RC2'), greaterThan(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareUnknownQualifier() {
|
||||
assertThat(parse('1.2.0.Beta'), lessThan(parse('1.2.0.CR')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void compareUnknownQualifierVersion() {
|
||||
assertThat(parse('1.2.0.Beta1'), lessThan(parse('1.2.0.Beta2')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void snapshotGreaterThanRC() {
|
||||
assertThat(parse('1.2.0.BUILD-SNAPSHOT'), greaterThan(parse('1.2.0.RC1')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void snapshotLowerThanRelease() {
|
||||
assertThat(parse('1.2.0.BUILD-SNAPSHOT'), lessThan(parse('1.2.0.RELEASE')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseInvalidVersion() {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
parse('foo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void safeParseInvalidVersion() {
|
||||
assertNull safeParse('foo')
|
||||
}
|
||||
|
||||
}
|
@ -47,6 +47,14 @@ class ProjectAssert {
|
||||
new PomAssert(file('pom.xml').text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link SourceCodeAssert} for the specified source code.
|
||||
*/
|
||||
SourceCodeAssert sourceCodeAssert(String sourceCodePath) {
|
||||
hasFile(sourceCodePath)
|
||||
new SourceCodeAssert(sourceCodePath, file(sourceCodePath).text)
|
||||
}
|
||||
|
||||
ProjectAssert isMavenProject() {
|
||||
hasFile('pom.xml').hasNoFile('build.gradle')
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.test
|
||||
|
||||
import static org.junit.Assert.assertFalse
|
||||
import static org.junit.Assert.assertTrue
|
||||
|
||||
/**
|
||||
* Source code assertions.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
class SourceCodeAssert {
|
||||
|
||||
private final String name
|
||||
private final String content
|
||||
|
||||
SourceCodeAssert(String name, String content) {
|
||||
this.name = name
|
||||
this.content = content
|
||||
}
|
||||
|
||||
SourceCodeAssert hasImports(String... classNames) {
|
||||
for (String className : classNames) {
|
||||
contains("import $className")
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
SourceCodeAssert doesNotHaveImports(String... classNames) {
|
||||
for (String className : classNames) {
|
||||
doesNotContain("import $className")
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
SourceCodeAssert contains(String... expressions) {
|
||||
for (String expression : expressions) {
|
||||
assertTrue "$expression has not been found in source code '$name'", content.contains(expression)
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
SourceCodeAssert doesNotContain(String... expressions) {
|
||||
for (String expression : expressions) {
|
||||
assertFalse "$expression should not have been found in source code '$name'", content.contains(expression)
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user