diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java index 85711944e0..c98c97e672 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.concurrent.Callable; import java.util.function.Supplier; +import org.gradle.api.InvalidUserDataException; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; @@ -66,7 +67,8 @@ final class MainClassConvention implements Callable { private String resolveMainClass() { return this.classpathSupplier.get().filter(File::isDirectory).getFiles().stream() .map(this::findMainClass).filter(Objects::nonNull).findFirst() - .orElse(null); + .orElseThrow(() -> new InvalidUserDataException( + "Main class name has not been configured and it could not be resolved")); } private String findMainClass(File file) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java index 69bfe894af..96d7362874 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java @@ -39,7 +39,6 @@ public interface BootArchive extends Task { * @return the main class name */ @Input - @Optional String getMainClassName(); /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java index da15b24780..e63e83dd25 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -42,10 +42,10 @@ public class BootJar extends Jar implements BootArchive { private final CopySpec bootInf; - private FileCollection classpath; - private String mainClassName; + private FileCollection classpath; + /** * Creates a new {@code BootJar} task. */ @@ -76,6 +76,13 @@ public class BootJar extends Jar implements BootArchive { @Override public String getMainClassName() { + if (this.mainClassName == null) { + String manifestStartClass = (String) getManifest().getAttributes() + .get("Start-Class"); + if (manifestStartClass != null) { + setMainClassName(manifestStartClass); + } + } return this.mainClassName; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java index 36c1a61852..e6be12492f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java @@ -68,6 +68,13 @@ public class BootWar extends War implements BootArchive { @Override public String getMainClassName() { + if (this.mainClassName == null) { + String manifestStartClass = (String) getManifest().getAttributes() + .get("Start-Class"); + if (manifestStartClass != null) { + setMainClassName(manifestStartClass); + } + } return this.mainClassName; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java index 753e18cbef..d69b6ae046 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -104,6 +104,14 @@ public class JavaPluginActionIntegrationTests { assertThat(result.task(":jar").getOutcome()).isEqualTo(TaskOutcome.SKIPPED); } + @Test + public void errorMessageIsHelpfulWhenMainClassCannotBeResolved() { + BuildResult result = this.gradleBuild.buildAndFail("build", "-PapplyJavaPlugin"); + assertThat(result.task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.FAILED); + assertThat(result.getOutput()).contains( + "Main class name has not been configured and it could not be resolved"); + } + @Test public void jarAndBootJarCanBothBeBuilt() { BuildResult result = this.gradleBuild.build("assemble"); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java index 0f3f4c6434..7392860e57 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -72,4 +72,12 @@ public class WarPluginActionIntegrationTests { this.gradleBuild.getProjectDir().getName() + "-boot.war")); } + @Test + public void errorMessageIsHelpfulWhenMainClassCannotBeResolved() { + BuildResult result = this.gradleBuild.buildAndFail("build", "-PapplyWarPlugin"); + assertThat(result.task(":bootWar").getOutcome()).isEqualTo(TaskOutcome.FAILED); + assertThat(result.getOutput()).contains( + "Main class name has not been configured and it could not be resolved"); + } + }