diff --git a/spring-boot-cli/pom.xml b/spring-boot-cli/pom.xml index e11de7fffe8..d5e383a827a 100644 --- a/spring-boot-cli/pom.xml +++ b/spring-boot-cli/pom.xml @@ -122,6 +122,21 @@ groovy-templates provided + + org.springframework.boot + spring-boot + provided + + + org.springframework + spring-web + provided + + + javax.servlet + javax.servlet-api + provided + junit junit diff --git a/spring-boot-cli/src/it/java/org/springframework/boot/cli/CommandLineIT.java b/spring-boot-cli/src/it/java/org/springframework/boot/cli/CommandLineIT.java index 0a6e14fe440..e19a85e0e73 100644 --- a/spring-boot-cli/src/it/java/org/springframework/boot/cli/CommandLineIT.java +++ b/spring-boot-cli/src/it/java/org/springframework/boot/cli/CommandLineIT.java @@ -44,7 +44,7 @@ public class CommandLineIT { assertThat(cli.await(), equalTo(0)); assertThat("Unexpected error: \n" + cli.getErrorOutput(), cli.getErrorOutput().length(), equalTo(0)); - assertThat(cli.getStandardOutputLines().size(), equalTo(10)); + assertThat(cli.getStandardOutputLines().size(), equalTo(11)); } @Test diff --git a/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java b/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java index 62494e157e2..c59e8fb37f2 100644 --- a/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java +++ b/spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java @@ -19,7 +19,7 @@ package org.springframework.boot.cli; import java.io.File; import org.junit.Test; -import org.springframework.boot.cli.command.jar.JarCommand; +import org.springframework.boot.cli.command.archive.JarCommand; import org.springframework.boot.cli.infrastructure.CommandLineInvoker; import org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation; import org.springframework.boot.loader.tools.JavaExecutable; diff --git a/spring-boot-cli/src/it/java/org/springframework/boot/cli/WarCommandIT.java b/spring-boot-cli/src/it/java/org/springframework/boot/cli/WarCommandIT.java new file mode 100644 index 00000000000..4af85a41e3a --- /dev/null +++ b/spring-boot-cli/src/it/java/org/springframework/boot/cli/WarCommandIT.java @@ -0,0 +1,64 @@ +/* + * 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 org.springframework.boot.cli; + +import java.io.File; + +import org.junit.Test; +import org.springframework.boot.cli.command.archive.WarCommand; +import org.springframework.boot.cli.infrastructure.CommandLineInvoker; +import org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation; +import org.springframework.boot.loader.tools.JavaExecutable; +import org.springframework.util.SocketUtils; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * Integration test for {@link WarCommand}. + * + * @author Andrey Stolyarov + */ +public class WarCommandIT { + + private final CommandLineInvoker cli = new CommandLineInvoker( + new File("src/it/resources/war-command")); + + @Test + public void warCreation() throws Exception { + int port = SocketUtils.findAvailableTcpPort(); + File war = new File("target/test-app.war"); + Invocation invocation = this.cli.invoke("war", war.getAbsolutePath(), + "war.groovy"); + invocation.await(); + assertTrue(war.exists()); + Process process = new JavaExecutable() + .processBuilder("-jar", war.getAbsolutePath(), "--server.port=" + port) + .start(); + invocation = new Invocation(process); + invocation.await(); + assertThat(invocation.getErrorOutput(), containsString("onStart error")); + assertThat(invocation.getStandardOutput(), containsString("Tomcat started")); + assertThat(invocation.getStandardOutput(), + containsString("/WEB-INF/lib-provided/tomcat-embed-core")); + assertThat(invocation.getStandardOutput(), + containsString("/WEB-INF/lib-provided/tomcat-embed-core")); + process.destroy(); + } + +} diff --git a/spring-boot-cli/src/it/resources/war-command/war.groovy b/spring-boot-cli/src/it/resources/war-command/war.groovy new file mode 100644 index 00000000000..1a8ca70ecad --- /dev/null +++ b/spring-boot-cli/src/it/resources/war-command/war.groovy @@ -0,0 +1,16 @@ +package org.test + +@RestController +class WarExample implements CommandLineRunner { + + @RequestMapping("/") + public String hello() { + return "Hello" + } + + void run(String... args) { + println getClass().getResource('/org/apache/tomcat/InstanceManager.class') + throw new RuntimeException("onStart error") + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/DefaultCommandFactory.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/DefaultCommandFactory.java index c13a6c7b899..b809c9d56ec 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/DefaultCommandFactory.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/DefaultCommandFactory.java @@ -22,12 +22,13 @@ import java.util.List; import org.springframework.boot.cli.command.Command; import org.springframework.boot.cli.command.CommandFactory; +import org.springframework.boot.cli.command.archive.JarCommand; +import org.springframework.boot.cli.command.archive.WarCommand; import org.springframework.boot.cli.command.core.VersionCommand; import org.springframework.boot.cli.command.grab.GrabCommand; import org.springframework.boot.cli.command.init.InitCommand; import org.springframework.boot.cli.command.install.InstallCommand; import org.springframework.boot.cli.command.install.UninstallCommand; -import org.springframework.boot.cli.command.jar.JarCommand; import org.springframework.boot.cli.command.run.RunCommand; import org.springframework.boot.cli.command.test.TestCommand; @@ -40,7 +41,7 @@ public class DefaultCommandFactory implements CommandFactory { private static final List DEFAULT_COMMANDS = Arrays.asList( new VersionCommand(), new RunCommand(), new TestCommand(), new GrabCommand(), - new JarCommand(), new InstallCommand(), new UninstallCommand(), + new JarCommand(), new WarCommand(), new InstallCommand(), new UninstallCommand(), new InitCommand()); @Override diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationWebApplicationInitializer.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationWebApplicationInitializer.java new file mode 100644 index 00000000000..80023f0f47f --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/app/SpringApplicationWebApplicationInitializer.java @@ -0,0 +1,87 @@ +/* + * 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 org.springframework.boot.cli.app; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Manifest; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.web.SpringBootServletInitializer; + +/** + * {@link SpringBootServletInitializer} for CLI packaged WAR files. + * + * @author Phillip Webb + * @since 1.3.0 + */ +public class SpringApplicationWebApplicationInitializer + extends SpringBootServletInitializer { + + /** + * The entry containing the source class. + */ + public static final String SOURCE_ENTRY = "Spring-Application-Source-Classes"; + + private String[] sources; + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + try { + this.sources = getSources(servletContext); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + super.onStartup(servletContext); + } + + private String[] getSources(ServletContext servletContext) throws IOException { + Manifest manifest = getManifest(servletContext); + if (manifest == null) { + throw new IllegalStateException("Unable to read manifest"); + } + String sources = manifest.getMainAttributes().getValue(SOURCE_ENTRY); + return sources.split(","); + } + + private Manifest getManifest(ServletContext servletContext) throws IOException { + InputStream stream = servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"); + Manifest manifest = (stream == null ? null : new Manifest(stream)); + return manifest; + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Class[] sourceClasses = new Class[this.sources.length]; + for (int i = 0; i < this.sources.length; i++) { + sourceClasses[i] = classLoader.loadClass(this.sources[i]); + } + return builder.sources(sourceClasses) + .properties("spring.groovy.template.check-template-location=false"); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java similarity index 98% rename from spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java rename to spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java index 36dce8e53ec..e05c6d12c9a 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.cli.jar; +package org.springframework.boot.cli.archive; import java.net.URL; import java.net.URLClassLoader; diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/package-info.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/package-info.java similarity index 86% rename from spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/package-info.java rename to spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/package-info.java index fddeefa35b3..3824714ed5d 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/package-info.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/package-info.java @@ -16,6 +16,6 @@ /** * Class that are packaged as part of CLI generated JARs. - * @see org.springframework.boot.cli.command.jar.JarCommand + * @see org.springframework.boot.cli.command.archive.JarCommand */ -package org.springframework.boot.cli.jar; +package org.springframework.boot.cli.archive; diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ArchiveCommand.java similarity index 80% rename from spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java rename to spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ArchiveCommand.java index 91702fe8cb7..090ec456778 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ArchiveCommand.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.cli.command.jar; +package org.springframework.boot.cli.command.archive; import java.io.File; import java.io.FileInputStream; @@ -38,10 +38,12 @@ import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.transform.ASTTransformation; import org.springframework.boot.cli.app.SpringApplicationLauncher; +import org.springframework.boot.cli.archive.PackagedSpringApplicationLauncher; import org.springframework.boot.cli.command.Command; import org.springframework.boot.cli.command.OptionParsingCommand; -import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource; +import org.springframework.boot.cli.command.archive.ResourceMatcher.MatchedResource; import org.springframework.boot.cli.command.options.CompilerOptionHandler; +import org.springframework.boot.cli.command.options.OptionHandler; import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration; import org.springframework.boot.cli.command.options.SourceOptions; import org.springframework.boot.cli.command.status.ExitStatus; @@ -49,8 +51,8 @@ import org.springframework.boot.cli.compiler.GroovyCompiler; import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration; import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory; import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; -import org.springframework.boot.cli.jar.PackagedSpringApplicationLauncher; import org.springframework.boot.loader.tools.JarWriter; +import org.springframework.boot.loader.tools.Layout; import org.springframework.boot.loader.tools.Libraries; import org.springframework.boot.loader.tools.Library; import org.springframework.boot.loader.tools.LibraryCallback; @@ -65,51 +67,66 @@ import joptsimple.OptionSet; import joptsimple.OptionSpec; /** - * {@link Command} to create a self-contained executable jar file from a CLI application. + * Abstract {@link Command} to create a self-contained executable archive file from a CLI + * application. * * @author Andy Wilkinson * @author Phillip Webb + * @author Andrey Stolyarov */ -public class JarCommand extends OptionParsingCommand { +abstract class ArchiveCommand extends OptionParsingCommand { - public JarCommand() { - super("jar", - "Create a self-contained " - + "executable jar file from a Spring Groovy script", - new JarOptionHandler()); + protected ArchiveCommand(String name, String description, + OptionHandler optionHandler) { + super(name, description, optionHandler); } @Override public String getUsageHelp() { - return "[options] "; + return "[options] <" + getName() + "-name> "; } - private static final class JarOptionHandler extends CompilerOptionHandler { + /** + * Abstract base {@link CompilerOptionHandler} for archive commands. + */ + protected abstract static class ArchiveOptionHandler extends CompilerOptionHandler { + + private final String type; + + private final Layout layout; private OptionSpec includeOption; private OptionSpec excludeOption; + public ArchiveOptionHandler(String type, Layout layout) { + this.type = type; + this.layout = layout; + } + @Override protected void doOptions() { this.includeOption = option("include", - "Pattern applied to directories on the classpath to find files to include in the resulting jar") - .withRequiredArg().withValuesSeparatedBy(",").defaultsTo(""); + "Pattern applied to directories on the classpath to find files to " + + "include in the resulting ").withRequiredArg() + .withValuesSeparatedBy(",").defaultsTo(""); this.excludeOption = option("exclude", - "Pattern applied to directories on the classpath to find files to exclude from the resulting jar") - .withRequiredArg().withValuesSeparatedBy(",").defaultsTo(""); + "Pattern applied to directories on the classpath to find files to " + + "exclude from the resulting " + this.type).withRequiredArg() + .withValuesSeparatedBy(",").defaultsTo(""); } @Override protected ExitStatus run(OptionSet options) throws Exception { List nonOptionArguments = new ArrayList( options.nonOptionArguments()); - Assert.isTrue(nonOptionArguments.size() >= 2, - "The name of the resulting jar and at least one source file must be specified"); + Assert.isTrue(nonOptionArguments.size() >= 2, "The name of the resulting " + + this.type + " and at least one source file must be specified"); File output = new File((String) nonOptionArguments.remove(0)); - Assert.isTrue(output.getName().toLowerCase().endsWith(".jar"), - "The output '" + output + "' is not a JAR file."); + Assert.isTrue(output.getName().toLowerCase().endsWith("." + this.type), + "The output '" + output + "' is not a " + this.type.toUpperCase() + + " file."); deleteIfExists(output); GroovyCompiler compiler = createCompiler(options); @@ -196,7 +213,7 @@ public class JarCommand extends OptionParsingCommand { List libraries = new ArrayList(); for (URL dependency : dependencies) { File file = new File(dependency.toURI()); - libraries.add(new Library(file, LibraryScope.COMPILE)); + libraries.add(new Library(file, getLibraryScope(file))); } return libraries; } @@ -220,7 +237,7 @@ public class JarCommand extends OptionParsingCommand { return builder.toString(); } - private void addCliClasses(JarWriter writer) throws IOException { + protected void addCliClasses(JarWriter writer) throws IOException { addClass(writer, PackagedSpringApplicationLauncher.class); addClass(writer, SpringApplicationLauncher.class); Resource[] resources = new PathMatchingResourcePatternResolver() @@ -232,10 +249,19 @@ public class JarCommand extends OptionParsingCommand { } } - private void addClass(JarWriter writer, Class sourceClass) throws IOException { - String name = sourceClass.getName().replace(".", "/") + ".class"; - InputStream stream = sourceClass.getResourceAsStream("/" + name); - writer.writeEntry(name, stream); + protected final void addClass(JarWriter writer, Class sourceClass) + throws IOException { + addClass(writer, sourceClass.getClassLoader(), sourceClass.getName()); + } + + protected final void addClass(JarWriter writer, ClassLoader classLoader, + String sourceClass) throws IOException { + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } + String name = sourceClass.replace(".", "/") + ".class"; + InputStream stream = classLoader.getResourceAsStream(name); + writer.writeEntry(this.layout.getClassesLocation() + name, stream); } private void addResource(JarWriter writer, Resource resource, String name) @@ -259,6 +285,8 @@ public class JarCommand extends OptionParsingCommand { return libraries; } + protected abstract LibraryScope getLibraryScope(File file); + } /** diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/JarCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/JarCommand.java new file mode 100644 index 00000000000..179e9c92989 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/JarCommand.java @@ -0,0 +1,51 @@ +/* + * 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 org.springframework.boot.cli.command.archive; + +import java.io.File; + +import org.springframework.boot.cli.command.Command; +import org.springframework.boot.loader.tools.Layouts; +import org.springframework.boot.loader.tools.LibraryScope; + +/** + * {@link Command} to create a self-contained executable jar file from a CLI application. + * + * @author Andy Wilkinson + * @author Phillip Webb + */ +public class JarCommand extends ArchiveCommand { + + public JarCommand() { + super("jar", "Create a self-contained executable jar " + + "file from a Spring Groovy script", new JarOptionHandler()); + } + + private static final class JarOptionHandler extends ArchiveOptionHandler { + + JarOptionHandler() { + super("jar", new Layouts.Jar()); + } + + @Override + protected LibraryScope getLibraryScope(File file) { + return LibraryScope.COMPILE; + } + + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/ResourceMatcher.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ResourceMatcher.java similarity index 98% rename from spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/ResourceMatcher.java rename to spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ResourceMatcher.java index da08216c016..da162bed9b1 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/ResourceMatcher.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ResourceMatcher.java @@ -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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.cli.command.jar; +package org.springframework.boot.cli.command.archive; import java.io.File; import java.io.IOException; diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/WarCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/WarCommand.java new file mode 100644 index 00000000000..80f0de42d69 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/WarCommand.java @@ -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 org.springframework.boot.cli.command.archive; + +import java.io.File; +import java.io.IOException; + +import org.springframework.boot.cli.command.Command; +import org.springframework.boot.loader.tools.JarWriter; +import org.springframework.boot.loader.tools.Layouts; +import org.springframework.boot.loader.tools.LibraryScope; + +/** + * {@link Command} to create a self-contained executable jar file from a CLI application. + * + * @author Andrey Stolyarov + * @author Phillip Webb + * @since 1.3.0 + */ +public class WarCommand extends ArchiveCommand { + + public WarCommand() { + super("war", "Create a self-contained executable war " + + "file from a Spring Groovy script", new WarOptionHandler()); + } + + private static final class WarOptionHandler extends ArchiveOptionHandler { + + WarOptionHandler() { + super("war", new Layouts.War()); + } + + @Override + protected LibraryScope getLibraryScope(File file) { + String fileName = file.getName(); + if (fileName.contains("tomcat-embed") + || fileName.contains("spring-boot-starter-tomcat")) { + return LibraryScope.PROVIDED; + } + return LibraryScope.COMPILE; + } + + @Override + protected void addCliClasses(JarWriter writer) throws IOException { + addClass(writer, null, "org.springframework.boot." + + "cli.app.SpringApplicationWebApplicationInitializer"); + super.addCliClasses(writer); + } + + } + +} diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java index 08bfc88527c..e5cded16bd5 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java @@ -36,8 +36,8 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.springframework.boot.cli.command.AbstractCommand; import org.springframework.boot.cli.command.OptionParsingCommand; +import org.springframework.boot.cli.command.archive.JarCommand; import org.springframework.boot.cli.command.grab.GrabCommand; -import org.springframework.boot.cli.command.jar.JarCommand; import org.springframework.boot.cli.command.run.RunCommand; import org.springframework.boot.cli.command.test.TestCommand; import org.springframework.boot.cli.util.OutputCapture; diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/app/SpringApplicationLauncherTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/app/SpringApplicationLauncherTests.java index 2b60165fac3..95bbf004d92 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/app/SpringApplicationLauncherTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/app/SpringApplicationLauncherTests.java @@ -16,10 +16,10 @@ package org.springframework.boot.cli.app; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.junit.After; import org.junit.Test; @@ -90,27 +90,34 @@ public class SpringApplicationLauncherTests { equalTo("false")); } - private List launch() { + private Set launch() { TestClassLoader classLoader = new TestClassLoader(getClass().getClassLoader()); try { new TestSpringApplicationLauncher(classLoader).launch(new Object[0], new String[0]); } - catch (Exception e) { - // SpringApplication isn't on the classpath, but we can still check that - // the launcher tried to use the right class + catch (Exception ex) { + // Launch will fail, but we can still check that the launcher tried to use + // the right class } return classLoader.classes; } private static class TestClassLoader extends ClassLoader { - private List classes = new ArrayList(); + private Set classes = new HashSet(); TestClassLoader(ClassLoader parent) { super(parent); } + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + this.classes.add(name); + return super.loadClass(name, resolve); + } + @Override protected Class findClass(String name) throws ClassNotFoundException { this.classes.add(name); diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/jar/ResourceMatcherTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/archive/ResourceMatcherTests.java similarity index 97% rename from spring-boot-cli/src/test/java/org/springframework/boot/cli/command/jar/ResourceMatcherTests.java rename to spring-boot-cli/src/test/java/org/springframework/boot/cli/command/archive/ResourceMatcherTests.java index dad9c8f66ee..a90e557263c 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/jar/ResourceMatcherTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/archive/ResourceMatcherTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.cli.command.jar; +package org.springframework.boot.cli.command.archive; import java.io.File; import java.io.IOException; @@ -26,7 +26,7 @@ import java.util.List; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.Test; -import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource; +import org.springframework.boot.cli.command.archive.ResourceMatcher.MatchedResource; import org.springframework.test.util.ReflectionTestUtils; import static org.hamcrest.Matchers.hasItem;