mirror of
https://gitee.com/dcren/initializr.git
synced 2025-05-09 15:18:02 +08:00
Use project name to infer the name of the app
The 'name' field can now be used to customize the name of the generated application (and its test counterpart). A default application name is used If no suitable identifier can be inferred from the specified name. Concretely, this means that the default application name is no longer `Application` but `DemoApplication` since the default name is `demo`. Closes gh-60
This commit is contained in:
parent
4ab189539e
commit
fd85022ef6
@ -297,10 +297,13 @@ class InitializrMetadata {
|
||||
}
|
||||
|
||||
static class Defaults {
|
||||
|
||||
static final String DEFAULT_NAME = 'demo'
|
||||
|
||||
String groupId = 'org.test'
|
||||
String artifactId
|
||||
String version = '0.0.1-SNAPSHOT'
|
||||
String name = 'demo'
|
||||
String name = DEFAULT_NAME
|
||||
String description = 'Demo project for Spring Boot'
|
||||
String packageName
|
||||
String type
|
||||
|
@ -84,14 +84,16 @@ class ProjectGenerator {
|
||||
new File(dir, 'pom.xml').write(pom)
|
||||
}
|
||||
|
||||
def applicationName = request.applicationName
|
||||
def language = request.language
|
||||
|
||||
def src = new File(new File(dir, "src/main/$language"), request.packageName.replace('.', '/'))
|
||||
src.mkdirs()
|
||||
write(src, "Application.$language", model)
|
||||
write(new File(src, "${applicationName}.${language}"), "Application.$language", model)
|
||||
|
||||
if (request.packaging == 'war') {
|
||||
write(src, "ServletInitializer.$language", model)
|
||||
def fileName = "ServletInitializer.$language"
|
||||
write(new File(src, fileName), fileName, model)
|
||||
}
|
||||
|
||||
def test = new File(new File(dir, "src/test/$language"), request.packageName.replace('.', '/'))
|
||||
@ -103,7 +105,7 @@ class ProjectGenerator {
|
||||
model.testAnnotations = ''
|
||||
model.testImports = ''
|
||||
}
|
||||
write(test, "ApplicationTests.$language", model)
|
||||
write(new File(test, "${applicationName}Tests.${language}"), "ApplicationTests.$language", model)
|
||||
|
||||
def resources = new File(dir, 'src/main/resources')
|
||||
resources.mkdirs()
|
||||
@ -174,10 +176,10 @@ class ProjectGenerator {
|
||||
template 'starter-build.gradle', model
|
||||
}
|
||||
|
||||
def write(File src, String name, def model) {
|
||||
def tmpl = name.endsWith('.groovy') ? name + '.tmpl' : name
|
||||
def write(File target, String templateName, def model) {
|
||||
def tmpl = templateName.endsWith('.groovy') ? templateName + '.tmpl' : templateName
|
||||
def body = template tmpl, model
|
||||
new File(src, name).write(body)
|
||||
target.write(body)
|
||||
}
|
||||
|
||||
private void addTempFile(String group, File file) {
|
||||
|
@ -33,6 +33,11 @@ class ProjectRequest {
|
||||
*/
|
||||
static final DEFAULT_STARTER = 'root_starter'
|
||||
|
||||
/**
|
||||
* The default name of the application class.
|
||||
*/
|
||||
static final String DEFAULT_APPLICATION_NAME = 'Application'
|
||||
|
||||
List<String> style = []
|
||||
List<String> dependencies = []
|
||||
String name
|
||||
@ -43,6 +48,7 @@ class ProjectRequest {
|
||||
String version
|
||||
String bootVersion
|
||||
String packaging
|
||||
String applicationName
|
||||
String language
|
||||
String packageName
|
||||
String javaVersion
|
||||
@ -88,6 +94,11 @@ class ProjectRequest {
|
||||
this.build = buildTag
|
||||
}
|
||||
}
|
||||
|
||||
if (!applicationName) {
|
||||
this.applicationName = generateApplicationName(this.name, DEFAULT_APPLICATION_NAME)
|
||||
}
|
||||
|
||||
afterResolution(metadata)
|
||||
}
|
||||
|
||||
@ -114,7 +125,6 @@ class ProjectRequest {
|
||||
root.id = DEFAULT_STARTER
|
||||
root.asSpringBootStarter('')
|
||||
resolvedDependencies << root
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,4 +141,51 @@ class ProjectRequest {
|
||||
facets.contains(facet)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a suitable application mame based on the specified name. If no suitable
|
||||
* application name can be generated from the specified {@code name}, the
|
||||
* {@code defaultApplicationName} is used instead.
|
||||
* <p>No suitable application name can be generated if the name is {@code null} or
|
||||
* if it contains an invalid character for a class identifier.
|
||||
*/
|
||||
static String generateApplicationName(String name, String defaultApplicationName) {
|
||||
if (!name) {
|
||||
return defaultApplicationName
|
||||
}
|
||||
String text = splitCamelCase(name.trim())
|
||||
String result = text.replaceAll("(_|-| |:)+([A-Za-z0-9])", { Object[] it ->
|
||||
it[2].toUpperCase()
|
||||
})
|
||||
if (!result.endsWith('Application')) {
|
||||
result += 'Application'
|
||||
}
|
||||
String candidate = result.capitalize();
|
||||
if (hasInvalidChar(candidate)) {
|
||||
return defaultApplicationName
|
||||
} else {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
private static String splitCamelCase(String text) {
|
||||
text.split('(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])').collect {
|
||||
String s = it.toLowerCase()
|
||||
s.capitalize()
|
||||
}.join("")
|
||||
}
|
||||
|
||||
private static boolean hasInvalidChar(String text) {
|
||||
if (!Character.isJavaIdentifierStart(text.charAt(0))) {
|
||||
return true
|
||||
}
|
||||
if (text.length() > 1) {
|
||||
for (int i = 1; i < text.length(); i++) {
|
||||
if (!Character.isJavaIdentifierPart(text.charAt(i))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import org.springframework.context.annotation.Configuration
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
class Application {
|
||||
class ${applicationName} {
|
||||
|
||||
static void main(String[] args) {
|
||||
SpringApplication.run Application, args
|
||||
SpringApplication.run ${applicationName}, args
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
public class Application {
|
||||
public class ${applicationName} {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
SpringApplication.run(${applicationName}.class, args);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ ${testImports}import org.springframework.boot.test.SpringApplicationConfiguratio
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner)
|
||||
@SpringApplicationConfiguration(classes = Application)
|
||||
${testAnnotations}class ApplicationTests {
|
||||
@SpringApplicationConfiguration(classes = ${applicationName})
|
||||
${testAnnotations}class ${applicationName}Tests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
|
@ -6,8 +6,8 @@ ${testImports}import org.springframework.boot.test.SpringApplicationConfiguratio
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = Application.class)
|
||||
${testAnnotations}public class ApplicationTests {
|
||||
@SpringApplicationConfiguration(classes = ${applicationName}.class)
|
||||
${testAnnotations}public class ${applicationName}Tests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
|
@ -3,11 +3,11 @@ package ${packageName}
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder
|
||||
import org.springframework.boot.context.web.SpringBootServletInitializer
|
||||
|
||||
class ServletInitializer extends SpringBootServletInitializer {
|
||||
class ServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
application.sources(Application)
|
||||
application.sources(${applicationName})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ public class ServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(Application.class);
|
||||
return application.sources(${applicationName}.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<start-class>${packageName}.Application</start-class>
|
||||
<start-class>${packageName}.${applicationName}</start-class>
|
||||
<java.version>${javaVersion}</java.version>
|
||||
</properties>
|
||||
|
||||
|
@ -51,7 +51,7 @@ class ProjectGeneratorTests {
|
||||
projectGenerator.listeners << listener
|
||||
|
||||
def request = createProjectRequest('web')
|
||||
generateMavenPom(request).hasStartClass('demo.Application')
|
||||
generateMavenPom(request).hasStartClass('demo.DemoApplication')
|
||||
.hasNoRepository().hasSpringBootStarterDependency('web')
|
||||
verify(listener, times(1)).onGeneratedProject(request)
|
||||
}
|
||||
@ -73,7 +73,7 @@ class ProjectGeneratorTests {
|
||||
|
||||
def request = createProjectRequest('web')
|
||||
generateProject(request).isJavaProject().isMavenProject().pomAssert()
|
||||
.hasStartClass('demo.Application').hasNoRepository().hasSpringBootStarterDependency('web')
|
||||
.hasStartClass('demo.DemoApplication').hasNoRepository().hasSpringBootStarterDependency('web')
|
||||
verify(listener, times(1)).onGeneratedProject(request)
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ class ProjectGeneratorTests {
|
||||
void mavenPomWithBootSnapshot() {
|
||||
def request = createProjectRequest('web')
|
||||
request.bootVersion = '1.0.1.BUILD-SNAPSHOT'
|
||||
generateMavenPom(request).hasStartClass('demo.Application')
|
||||
generateMavenPom(request).hasStartClass('demo.DemoApplication')
|
||||
.hasSnapshotRepository().hasSpringBootStarterDependency('web')
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ class ProjectGeneratorTests {
|
||||
projectGenerator.metadata = metadata
|
||||
|
||||
def request = createProjectRequest('thymeleaf')
|
||||
generateMavenPom(request).hasStartClass('demo.Application')
|
||||
generateMavenPom(request).hasStartClass('demo.DemoApplication')
|
||||
.hasDependency('org.foo', 'thymeleaf')
|
||||
.hasDependenciesCount(2)
|
||||
|
||||
@ -125,7 +125,7 @@ class ProjectGeneratorTests {
|
||||
|
||||
def request = createProjectRequest('thymeleaf')
|
||||
request.packaging = 'war'
|
||||
generateMavenPom(request).hasStartClass('demo.Application')
|
||||
generateMavenPom(request).hasStartClass('demo.DemoApplication')
|
||||
.hasSpringBootStarterDependency('tomcat')
|
||||
.hasDependency('org.foo', 'thymeleaf') // This is tagged as web facet so it brings the web one
|
||||
.hasSpringBootStarterDependency('test')
|
||||
@ -137,7 +137,7 @@ class ProjectGeneratorTests {
|
||||
void mavenWarPomWithoutWebFacet() {
|
||||
def request = createProjectRequest('data-jpa')
|
||||
request.packaging = 'war'
|
||||
generateMavenPom(request).hasStartClass('demo.Application')
|
||||
generateMavenPom(request).hasStartClass('demo.DemoApplication')
|
||||
.hasSpringBootStarterDependency('tomcat')
|
||||
.hasSpringBootStarterDependency('data-jpa')
|
||||
.hasSpringBootStarterDependency('web') // Added by war packaging
|
||||
|
@ -29,6 +29,8 @@ import static org.junit.Assert.assertNull
|
||||
*/
|
||||
class ProjectRequestTests {
|
||||
|
||||
private static final String DEFAULT_APPLICATION_NAME = 'FooBarApplication'
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@ -127,6 +129,105 @@ class ProjectRequestTests {
|
||||
request.resolve(metadata)
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveApplicationNameWithNoName() {
|
||||
def request = new ProjectRequest()
|
||||
def metadata = InitializrMetadataBuilder.withDefaults().validateAndGet()
|
||||
|
||||
request.resolve(metadata)
|
||||
assertEquals ProjectRequest.DEFAULT_APPLICATION_NAME, request.applicationName
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveApplicationName() {
|
||||
def request = new ProjectRequest()
|
||||
request.name = 'Foo2'
|
||||
def metadata = InitializrMetadataBuilder.withDefaults().validateAndGet()
|
||||
|
||||
request.resolve(metadata)
|
||||
assertEquals 'Foo2Application', request.applicationName
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveApplicationNameWithApplicationNameSet() {
|
||||
def request = new ProjectRequest()
|
||||
request.name = 'Foo2'
|
||||
request.applicationName ='MyApplicationName'
|
||||
def metadata = InitializrMetadataBuilder.withDefaults().validateAndGet()
|
||||
|
||||
request.resolve(metadata)
|
||||
assertEquals 'MyApplicationName', request.applicationName
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimple() {
|
||||
assertEquals 'DemoApplication', generateApplicationName('demo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimpleApplication() {
|
||||
assertEquals 'DemoApplication', generateApplicationName('demoApplication')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimpleCamelCase() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('myDemo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimpleUnderscore() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('my_demo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimpleColon() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('my:demo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameSimpleSpace() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('my demo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNamSsimpleDash() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('my-demo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameUpperCaseUnderscore() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('MY_DEMO')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameUpperCaseDash() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName('MY-DEMO')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameMultiSpaces() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName(' my demo ')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameMultiSpacesUpperCase() {
|
||||
assertEquals 'MyDemoApplication', generateApplicationName(' MY DEMO ')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameInvalidStartCharacter() {
|
||||
assertEquals DEFAULT_APPLICATION_NAME, generateApplicationName('1MyDemo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateApplicationNameInvalidPartCharacter() {
|
||||
assertEquals DEFAULT_APPLICATION_NAME, generateApplicationName('MyDe|mo')
|
||||
}
|
||||
|
||||
private static generateApplicationName(String text) {
|
||||
ProjectRequest.generateApplicationName(text, DEFAULT_APPLICATION_NAME)
|
||||
}
|
||||
|
||||
private static void assertBootStarter(InitializrMetadata.Dependency actual, String name) {
|
||||
def expected = new InitializrMetadata.Dependency()
|
||||
expected.asSpringBootStarter(name)
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package io.spring.initializr.support
|
||||
|
||||
import io.spring.initializr.InitializrMetadata
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
|
||||
/**
|
||||
@ -26,6 +28,8 @@ import static org.junit.Assert.assertEquals
|
||||
*/
|
||||
class ProjectAssert {
|
||||
|
||||
private static final DEFAULT_APPLICATION_NAME = generateDefaultApplicationName()
|
||||
|
||||
final File dir
|
||||
|
||||
/**
|
||||
@ -51,17 +55,25 @@ class ProjectAssert {
|
||||
hasFile('build.gradle').hasNoFile('pom.xml')
|
||||
}
|
||||
|
||||
ProjectAssert isJavaProject() {
|
||||
hasFile('src/main/java/demo/Application.java',
|
||||
'src/test/java/demo/ApplicationTests.java',
|
||||
ProjectAssert isJavaProject(String expectedApplicationName) {
|
||||
hasFile("src/main/java/demo/${expectedApplicationName}.java",
|
||||
"src/test/java/demo/${expectedApplicationName}Tests.java",
|
||||
'src/main/resources/application.properties')
|
||||
}
|
||||
|
||||
ProjectAssert isJavaWarProject() {
|
||||
isJavaProject().hasStaticAndTemplatesResources(true)
|
||||
ProjectAssert isJavaProject() {
|
||||
isJavaProject(DEFAULT_APPLICATION_NAME)
|
||||
}
|
||||
|
||||
ProjectAssert isJavaWarProject(String expectedApplicationName) {
|
||||
isJavaProject(expectedApplicationName).hasStaticAndTemplatesResources(true)
|
||||
.hasFile('src/main/java/demo/ServletInitializer.java')
|
||||
}
|
||||
|
||||
ProjectAssert isJavaWarProject() {
|
||||
isJavaWarProject(DEFAULT_APPLICATION_NAME)
|
||||
}
|
||||
|
||||
ProjectAssert hasStaticAndTemplatesResources(boolean web) {
|
||||
assertFile('src/main/resources/templates', web)
|
||||
assertFile('src/main/resources/static', web)
|
||||
@ -91,4 +103,8 @@ class ProjectAssert {
|
||||
new File(dir, localPath)
|
||||
}
|
||||
|
||||
private static generateDefaultApplicationName() {
|
||||
InitializrMetadata.Defaults.DEFAULT_NAME.capitalize() + 'Application'
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -86,7 +86,8 @@ abstract class AbstractInitializerControllerFormIntegrationTests extends Abstrac
|
||||
assertEquals 'attachment; filename="foo-bar.zip"', value
|
||||
|
||||
def projectAssert = zipProjectAssert(webResponse)
|
||||
projectAssert.isMavenProject().isJavaProject().hasStaticAndTemplatesResources(true)
|
||||
projectAssert.isMavenProject().isJavaProject('MyProjectApplication')
|
||||
.hasStaticAndTemplatesResources(true)
|
||||
|
||||
projectAssert.pomAssert().hasGroupId('com.acme').hasArtifactId('foo-bar')
|
||||
.hasName('My project').hasDescription('A description for my project')
|
||||
|
@ -20,7 +20,7 @@ class MainControllerDefaultsIntegrationTests extends AbstractInitializrControlle
|
||||
def content = restTemplate.getForObject(createUrl('/pom.xml?style=web'), String)
|
||||
def pomAssert = new PomAssert(content)
|
||||
pomAssert.hasGroupId('org.foo').hasArtifactId('foo-bar').hasVersion('1.2.4-SNAPSHOT').hasPackaging('jar')
|
||||
.hasName('FooBar').hasDescription('FooBar Project').hasStartClass('org.foo.demo.Application')
|
||||
.hasName('FooBar').hasDescription('FooBar Project').hasStartClass('org.foo.demo.FooBarApplication')
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user