From c451de18f719f42ddb3870a80682758465af02f4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 30 May 2014 17:37:29 +0200 Subject: [PATCH 1/5] Fix resource directory location This commit fixes the main resources directory location so that it also works in a multi-projects setup. Fixes gh-993 (cherry picked from commit a69f518) --- spring-boot-starters/spring-boot-starter-parent/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-starters/spring-boot-starter-parent/pom.xml b/spring-boot-starters/spring-boot-starter-parent/pom.xml index a6c75780c4..3cf7457998 100644 --- a/spring-boot-starters/spring-boot-starter-parent/pom.xml +++ b/spring-boot-starters/spring-boot-starter-parent/pom.xml @@ -185,7 +185,7 @@ - src/main/resources + ${basedir}/src/main/resources true **/application.yml @@ -193,7 +193,7 @@ - src/main/resources + ${basedir}/src/main/resources **/application.yml **/application.properties From 355f63892dec8abe182b15b97a0ae8df4f022501 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 28 May 2014 14:19:17 +0100 Subject: [PATCH 2/5] Unify versions in POMs started by the invoker Unify the versions used in integration tests launched by the maven-invoker-plugin. Allows for already cached local copies to be used, hopefully speeding up the build. --- spring-boot-dependencies/pom.xml | 6 ++++++ spring-boot-tools/spring-boot-loader-tools/pom.xml | 5 +++++ .../spring-boot-loader/src/it/executable-dir/pom.xml | 8 ++++---- .../spring-boot-loader/src/it/executable-jar/pom.xml | 8 ++++---- .../spring-boot-loader/src/it/executable-war/pom.xml | 10 +++++----- .../spring-boot-maven-plugin/src/it/jar/pom.xml | 2 +- .../spring-boot-maven-plugin/src/it/prop/pom.xml | 2 +- .../spring-boot-maven-plugin/src/it/war/pom.xml | 2 +- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 86e9974c7d..bbab0a7acd 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -88,6 +88,7 @@ 1.1.1.RELEASE 2.0.2.RELEASE 0.9.0.RELEASE + 1.2.0.RELEASE 1.2.2.RELEASE 1.1.1.RELEASE 3.2.4.RELEASE @@ -512,6 +513,11 @@ + + org.springframework + springloaded + ${spring-loaded.version} + org.springframework.batch spring-batch-core diff --git a/spring-boot-tools/spring-boot-loader-tools/pom.xml b/spring-boot-tools/spring-boot-loader-tools/pom.xml index d60ace0213..d58ed4f0ca 100644 --- a/spring-boot-tools/spring-boot-loader-tools/pom.xml +++ b/spring-boot-tools/spring-boot-loader-tools/pom.xml @@ -36,6 +36,11 @@ zt-zip test + + org.springframework + springloaded + test + diff --git a/spring-boot-tools/spring-boot-loader/src/it/executable-dir/pom.xml b/spring-boot-tools/spring-boot-loader/src/it/executable-dir/pom.xml index 3fc16df78d..53849e2108 100644 --- a/spring-boot-tools/spring-boot-loader/src/it/executable-dir/pom.xml +++ b/spring-boot-tools/spring-boot-loader/src/it/executable-dir/pom.xml @@ -22,7 +22,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.6 + 2.8 unpack @@ -73,17 +73,17 @@ org.eclipse.jetty jetty-webapp - 8.1.8.v20121106 + 8.1.14.v20131031 org.eclipse.jetty jetty-annotations - 8.1.8.v20121106 + 8.1.14.v20131031 org.springframework spring-webmvc - 3.2.0.RELEASE + 4.0.5.RELEASE diff --git a/spring-boot-tools/spring-boot-loader/src/it/executable-jar/pom.xml b/spring-boot-tools/spring-boot-loader/src/it/executable-jar/pom.xml index 2fffa60044..a80b5fc692 100644 --- a/spring-boot-tools/spring-boot-loader/src/it/executable-jar/pom.xml +++ b/spring-boot-tools/spring-boot-loader/src/it/executable-jar/pom.xml @@ -22,7 +22,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.6 + 2.8 unpack @@ -86,17 +86,17 @@ org.eclipse.jetty jetty-webapp - 8.1.8.v20121106 + 8.1.14.v20131031 org.eclipse.jetty jetty-annotations - 8.1.8.v20121106 + 8.1.14.v20131031 org.springframework spring-webmvc - 3.2.0.RELEASE + 4.0.5.RELEASE diff --git a/spring-boot-tools/spring-boot-loader/src/it/executable-war/pom.xml b/spring-boot-tools/spring-boot-loader/src/it/executable-war/pom.xml index 193173d667..305c85e517 100644 --- a/spring-boot-tools/spring-boot-loader/src/it/executable-war/pom.xml +++ b/spring-boot-tools/spring-boot-loader/src/it/executable-war/pom.xml @@ -39,7 +39,7 @@ org.apache.maven.plugins maven-dependency-plugin - 2.6 + 2.8 unpack @@ -67,22 +67,22 @@ org.eclipse.jetty jetty-webapp - 8.1.8.v20121106 + 8.1.14.v20131031 org.eclipse.jetty jetty-plus - 8.1.8.v20121106 + 8.1.14.v20131031 org.eclipse.jetty jetty-annotations - 8.1.8.v20121106 + 8.1.14.v20131031 org.springframework spring-webmvc - 3.2.0.RELEASE + 4.0.5.RELEASE diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar/pom.xml index c851abd8c5..e9208df9d7 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar/pom.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar/pom.xml @@ -43,7 +43,7 @@ org.springframework spring-context - 3.2.3.RELEASE + 4.0.5.RELEASE javax.servlet diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml index 2bdf801298..b170f2e04e 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml @@ -43,7 +43,7 @@ org.springframework spring-context - 3.2.3.RELEASE + 4.0.5.RELEASE javax.servlet diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/war/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/war/pom.xml index b947e7b472..de38c51db7 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/war/pom.xml +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/war/pom.xml @@ -42,7 +42,7 @@ org.springframework spring-context - 3.2.3.RELEASE + 4.0.5.RELEASE javax.servlet From 790e61574131d79b801d6c7a61520e4335acd3ab Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 28 May 2014 14:41:15 +0100 Subject: [PATCH 3/5] Fix URL methods in JarURLConnection Update JarURLConnection to return correct values from `getURL()`, `getJarFileURL()` and `getEntryName()`. Fixes gh-973 --- .../boot/loader/jar/JarURLConnection.java | 35 ++++++++++--------- .../boot/loader/jar/JarFileTests.java | 23 +++++++++++- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java index 5be57a0a38..569594e6c1 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java @@ -28,7 +28,7 @@ import org.springframework.boot.loader.util.AsciiBytes; /** * {@link java.net.JarURLConnection} used to support {@link JarFile#getUrl()}. - * + * * @author Phillip Webb */ class JarURLConnection extends java.net.JarURLConnection { @@ -51,6 +51,7 @@ class JarURLConnection extends java.net.JarURLConnection { protected JarURLConnection(URL url, JarFile jarFile) throws MalformedURLException { super(new URL(buildRootUrl(jarFile))); + this.url = url; this.jarFile = jarFile; String spec = url.getFile(); @@ -59,27 +60,19 @@ class JarURLConnection extends java.net.JarURLConnection { throw new MalformedURLException("no " + SEPARATOR + " found in url spec:" + spec); } - /* - * The superclass constructor creates a jarFileUrl which is equal to the root URL - * of the containing archive (therefore not unique if we are connecting to - * multiple nested jars in the same archive). Therefore we need to make something - * sensible for #getJarFileURL(). - */ - if (separator + SEPARATOR.length() != spec.length()) { + if (separator + 2 != spec.length()) { this.jarEntryName = decode(spec.substring(separator + 2)); - this.jarFileUrl = new URL("jar:" + spec.substring(0, separator) + SEPARATOR - + this.jarEntryName); + } + + String container = spec.substring(0, separator); + if (container.indexOf(SEPARATOR) == -1) { + this.jarFileUrl = new URL(container); } else { - this.jarFileUrl = new URL("jar:" + spec.substring(0, separator)); + this.jarFileUrl = new URL("jar:" + container); } } - @Override - public URL getJarFileURL() { - return this.jarFileUrl; - } - @Override public void connect() throws IOException { if (this.jarEntryName != null) { @@ -108,12 +101,22 @@ class JarURLConnection extends java.net.JarURLConnection { return this.jarFile; } + @Override + public URL getJarFileURL() { + return this.jarFileUrl; + } + @Override public JarEntry getJarEntry() throws IOException { connect(); return (this.jarEntryData == null ? null : this.jarEntryData.asJarEntry()); } + @Override + public String getEntryName() { + return this.jarEntryName; + } + @Override public InputStream getInputStream() throws IOException { connect(); diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java index ea4ecfba5d..1cdf36c066 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java @@ -183,7 +183,7 @@ public class JarFileTests { assertThat(jarURLConnection.getContentLength(), greaterThan(1)); assertThat(jarURLConnection.getContent(), sameInstance((Object) this.jarFile)); assertThat(jarURLConnection.getContentType(), equalTo("x-java/jar")); - assertThat(jarURLConnection.getJarFileURL().toString(), equalTo("jar:file:" + assertThat(jarURLConnection.getJarFileURL().toString(), equalTo("file:" + this.rootJarFile)); } @@ -296,6 +296,27 @@ public class JarFileTests { InputStream inputStream = url.openStream(); assertThat(inputStream, notNullValue()); assertThat(inputStream.read(), equalTo(3)); + JarURLConnection connection = (JarURLConnection) url.openConnection(); + assertThat(connection.getURL().toString(), equalTo(spec)); + assertThat(connection.getJarFileURL().toString(), equalTo("jar:file:" + + this.rootJarFile.getPath() + "!/nested.jar")); + assertThat(connection.getEntryName(), equalTo("3.dat")); + } + + @Test + public void createNonNestedUrlFromString() throws Exception { + JarFile.registerUrlProtocolHandler(); + String spec = "jar:file:" + this.rootJarFile.getPath() + "!/2.dat"; + URL url = new URL(spec); + assertThat(url.toString(), equalTo(spec)); + InputStream inputStream = url.openStream(); + assertThat(inputStream, notNullValue()); + assertThat(inputStream.read(), equalTo(2)); + JarURLConnection connection = (JarURLConnection) url.openConnection(); + assertThat(connection.getURL().toString(), equalTo(spec)); + assertThat(connection.getJarFileURL().toString(), equalTo("file:" + + this.rootJarFile.getPath())); + assertThat(connection.getEntryName(), equalTo("2.dat")); } @Test From 329175b95645c1e2dfe83cd63135021bb98ea81e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 28 May 2014 14:52:21 +0100 Subject: [PATCH 4/5] Fix Jasper on Tomcat 8 Refactor Jasper initialization code to call JasperInitializer during server start. Fixes gh-962 See gh-919 --- spring-boot-samples/pom.xml | 1 + .../spring-boot-sample-tomcat8-jsp/pom.xml | 65 +++++++++++++++++++ .../jsp/SampleTomcat8JspApplication.java | 40 ++++++++++++ .../java/sample/jsp/WelcomeController.java | 39 +++++++++++ .../src/main/resources/application.properties | 3 + .../src/main/webapp/WEB-INF/jsp/welcome.jsp | 18 +++++ .../jsp/SampleWebJspApplicationTests.java | 58 +++++++++++++++++ .../tomcat/CustomSkipPatternJarScanner.java | 11 +++- .../JasperInitializerLifecycleListener.java | 58 ----------------- ...TomcatEmbeddedServletContainerFactory.java | 15 ++++- 10 files changed, 246 insertions(+), 62 deletions(-) create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/SampleTomcat8JspApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/WelcomeController.java create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/resources/application.properties create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp create mode 100644 spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/test/java/sample/jsp/SampleWebJspApplicationTests.java delete mode 100644 spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/JasperInitializerLifecycleListener.java diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 2157038440..16606ab78d 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -39,6 +39,7 @@ spring-boot-sample-simple spring-boot-sample-tomcat spring-boot-sample-tomcat-multi-connectors + spring-boot-sample-tomcat8-jsp spring-boot-sample-traditional spring-boot-sample-web-method-security spring-boot-sample-web-secure diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/pom.xml new file mode 100644 index 0000000000..e06cdddf3c --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 1.0.3.BUILD-SNAPSHOT + + spring-boot-sample-tomcat8-jsp + war + Spring Boot Tomcat 8 JSP Sample + Spring Boot Tomcat 8 JSP Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + / + 8.0.8 + 1.7 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.apache.tomcat.embed + tomcat-embed-jasper + provided + + + javax.servlet + jstl + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/SampleTomcat8JspApplication.java b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/SampleTomcat8JspApplication.java new file mode 100644 index 0000000000..6ab7e320f3 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/SampleTomcat8JspApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2013 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 sample.jsp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.web.SpringBootServletInitializer; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@ComponentScan +public class SampleTomcat8JspApplication extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(SampleTomcat8JspApplication.class); + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleTomcat8JspApplication.class, args); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/WelcomeController.java b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/WelcomeController.java new file mode 100644 index 0000000000..03d439caa3 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/java/sample/jsp/WelcomeController.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2014 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 sample.jsp; + +import java.util.Date; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class WelcomeController { + + @Value("${application.message:Hello World}") + private String message = "Hello World"; + + @RequestMapping("/") + public String welcome(Map model) { + model.put("time", new Date()); + model.put("message", this.message); + return "welcome"; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/resources/application.properties new file mode 100644 index 0000000000..f95f1d3c01 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.view.prefix: /WEB-INF/jsp/ +spring.view.suffix: .jsp +application.message: Hello Phil \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp new file mode 100644 index 0000000000..3196dac625 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp @@ -0,0 +1,18 @@ + + +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + + + + Spring URL: ${springUrl} at ${time} +
+ JSTL URL: ${url} +
+ Message: ${message} + + + diff --git a/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/test/java/sample/jsp/SampleWebJspApplicationTests.java b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/test/java/sample/jsp/SampleWebJspApplicationTests.java new file mode 100644 index 0000000000..09d557e12b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-tomcat8-jsp/src/test/java/sample/jsp/SampleWebJspApplicationTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2014 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 sample.jsp; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Basic integration tests for JSP application. + * + * @author Phillip Webb + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = SampleTomcat8JspApplication.class) +@WebAppConfiguration +@IntegrationTest("server.port:0") +@DirtiesContext +public class SampleWebJspApplicationTests { + + @Value("${local.server.port}") + private int port; + + @Test + public void testJspWithEl() throws Exception { + ResponseEntity entity = new TestRestTemplate().getForEntity( + "http://localhost:" + this.port, String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertTrue("Wrong body:\n" + entity.getBody(), + entity.getBody().contains("/resources/text.txt")); + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/CustomSkipPatternJarScanner.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/CustomSkipPatternJarScanner.java index ad083a9fc4..454ee0e787 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/CustomSkipPatternJarScanner.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/CustomSkipPatternJarScanner.java @@ -25,15 +25,18 @@ import javax.servlet.ServletContext; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; +import org.apache.tomcat.util.scan.StandardJarScanner; import org.springframework.util.Assert; /** - * {@link JarScanner} decorator allowing alternative default jar pattern matching. + * {@link JarScanner} decorator allowing alternative default jar pattern matching. This + * class extends {@link StandardJarScanner} rather than implementing the + * {@link JarScanner} due to API changes introduced in Tomcat 8. * * @author Phillip Webb * @see #apply(TomcatEmbeddedContext, String) */ -class SkipPatternJarScanner implements JarScanner { +class SkipPatternJarScanner extends StandardJarScanner { private final JarScanner jarScanner; @@ -58,7 +61,9 @@ class SkipPatternJarScanner implements JarScanner { * @param pattern the jar skip pattern or {@code null} for defaults */ public static void apply(TomcatEmbeddedContext context, String pattern) { - context.setJarScanner(new SkipPatternJarScanner(context.getJarScanner(), pattern)); + SkipPatternJarScanner scanner = new SkipPatternJarScanner( + context.getJarScanner(), pattern); + context.setJarScanner(scanner); } private static class SkipPattern { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/JasperInitializerLifecycleListener.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/JasperInitializerLifecycleListener.java deleted file mode 100644 index 6a7e107c78..0000000000 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/JasperInitializerLifecycleListener.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.springframework.boot.context.embedded.tomcat; - -import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletException; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.core.StandardContext; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Tomcat {@link LifecycleListener} to initialize Jasper by calling the - * `JasperInitializer` used in Tomcat 8. - * - * @author Phillip Webb - */ -class JasperInitializerLifecycleListener implements LifecycleListener { - - private static final String JASPER_INITIALIZER_CLASS = "org.apache.jasper.servlet.JasperInitializer"; - - private ServletContainerInitializer initializer; - - public JasperInitializerLifecycleListener() { - this.initializer = getJasperInitializer(); - } - - @Override - public void lifecycleEvent(LifecycleEvent event) { - if (this.initializer != null - && Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) { - onStartup(event); - } - } - - private void onStartup(LifecycleEvent event) { - Assert.isInstanceOf(StandardContext.class, event.getSource()); - StandardContext standardContext = (StandardContext) event.getSource(); - try { - this.initializer.onStartup(null, standardContext.getServletContext()); - } - catch (ServletException ex) { - throw new IllegalStateException(ex); - } - } - - private ServletContainerInitializer getJasperInitializer() { - try { - Class jasperClass = ClassUtils.forName(JASPER_INITIALIZER_CLASS, null); - return (ServletContainerInitializer) jasperClass.newInstance(); - } - catch (Exception ex) { - return null; - } - } - -} diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java index 2fd2463c80..089175553b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import org.apache.catalina.Context; @@ -167,6 +168,7 @@ public class TomcatEmbeddedServletContainerFactory extends && ClassUtils.isPresent(getJspServletClassName(), getClass() .getClassLoader())) { addJspServlet(context); + addJasperInitializer(context); context.addLifecycleListener(new StoreMergedWebXmlListener()); } ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); @@ -199,6 +201,18 @@ public class TomcatEmbeddedServletContainerFactory extends context.addServletMapping("*.jspx", "jsp"); } + private void addJasperInitializer(TomcatEmbeddedContext context) { + try { + ServletContainerInitializer initializer = (ServletContainerInitializer) ClassUtils + .forName("org.apache.jasper.servlet.JasperInitializer", null) + .newInstance(); + context.addServletContainerInitializer(initializer, null); + } + catch (Exception ex) { + // Probably not Tomcat 8 + } + } + // Needs to be protected so it can be used by subclasses protected void customizeConnector(Connector connector) { int port = (getPort() >= 0 ? getPort() : 0); @@ -230,7 +244,6 @@ public class TomcatEmbeddedServletContainerFactory extends ServletContextInitializer[] initializers) { context.addLifecycleListener(new ServletContextInitializerLifecycleListener( initializers)); - context.addLifecycleListener(new JasperInitializerLifecycleListener()); for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) { context.addLifecycleListener(lifecycleListener); } From abc1e5de8f43538095112ef9bb73f5aa2fdd97da Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 30 May 2014 17:21:40 +0100 Subject: [PATCH 5/5] Fix ifAnyMissingClasses to return false if no classes are missing Fixes #1003 --- .../cli/compiler/DependencyCustomizer.java | 2 +- .../compiler/DependencyCustomizerTests.java | 141 ++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/DependencyCustomizerTests.java diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyCustomizer.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyCustomizer.java index c2f4b06e90..5554f088dd 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyCustomizer.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyCustomizer.java @@ -96,7 +96,7 @@ public class DependencyCustomizer { return true; } } - return DependencyCustomizer.this.canAdd(); + return false; } }; } diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/DependencyCustomizerTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/DependencyCustomizerTests.java new file mode 100644 index 0000000000..0d9ecef2a6 --- /dev/null +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/DependencyCustomizerTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2012-2014 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.compiler; + +import groovy.lang.Grab; +import groovy.lang.GroovyClassLoader; + +import java.util.List; + +import org.codehaus.groovy.ast.AnnotationNode; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.ModuleNode; +import org.codehaus.groovy.ast.expr.ConstantExpression; +import org.codehaus.groovy.control.SourceUnit; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.cli.compiler.dependencies.ArtifactCoordinatesResolver; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link DependencyCustomizer} + * + * @author Andy Wilkinson + */ +public class DependencyCustomizerTests { + + private final ModuleNode moduleNode = new ModuleNode((SourceUnit) null); + + private final ClassNode classNode = new ClassNode(DependencyCustomizerTests.class); + + @Mock + private ArtifactCoordinatesResolver resolver; + + private DependencyCustomizer dependencyCustomizer; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(this.resolver.getGroupId("spring-boot-starter-logging")).thenReturn( + "org.springframework.boot"); + when(this.resolver.getVersion("spring-boot-starter-logging")).thenReturn("1.2.3"); + + this.moduleNode.addClass(this.classNode); + this.dependencyCustomizer = new DependencyCustomizer(new GroovyClassLoader( + getClass().getClassLoader()), this.moduleNode, this.resolver); + } + + @Test + public void basicAdd() { + this.dependencyCustomizer.add("spring-boot-starter-logging"); + List grabAnnotations = this.classNode + .getAnnotations(new ClassNode(Grab.class)); + assertEquals(1, grabAnnotations.size()); + AnnotationNode annotationNode = grabAnnotations.get(0); + assertGrabAnnotation(annotationNode, "org.springframework.boot", + "spring-boot-starter-logging", true); + } + + @Test + public void anyMissingClassesWithMissingClassesPerformsAdd() { + this.dependencyCustomizer.ifAnyMissingClasses("does.not.Exist").add( + "spring-boot-starter-logging"); + assertEquals(1, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void anyMissingClassesWithMixtureOfClassesPerformsAdd() { + this.dependencyCustomizer.ifAnyMissingClasses(getClass().getName(), + "does.not.Exist").add("spring-boot-starter-logging"); + assertEquals(1, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void anyMissingClassesWithNoMissingClassesDoesNotPerformAdd() { + this.dependencyCustomizer.ifAnyMissingClasses(getClass().getName()).add( + "spring-boot-starter-logging"); + assertEquals(0, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void allMissingClassesWithNoMissingClassesDoesNotPerformAdd() { + this.dependencyCustomizer.ifAllMissingClasses(getClass().getName()).add( + "spring-boot-starter-logging"); + assertEquals(0, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void allMissingClassesWithMixtureOfClassesDoesNotPerformAdd() { + this.dependencyCustomizer.ifAllMissingClasses(getClass().getName(), + "does.not.Exist").add("spring-boot-starter-logging"); + assertEquals(0, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void allMissingClassesWithAllClassesMissingPerformsAdd() { + this.dependencyCustomizer.ifAllMissingClasses("does.not.Exist", + "does.not.exist.Either").add("spring-boot-starter-logging"); + assertEquals(1, this.classNode.getAnnotations(new ClassNode(Grab.class)).size()); + } + + @Test + public void nonTransitiveAdd() { + this.dependencyCustomizer.add("spring-boot-starter-logging", false); + List grabAnnotations = this.classNode + .getAnnotations(new ClassNode(Grab.class)); + assertEquals(1, grabAnnotations.size()); + AnnotationNode annotationNode = grabAnnotations.get(0); + assertGrabAnnotation(annotationNode, "org.springframework.boot", + "spring-boot-starter-logging", false); + } + + private void assertGrabAnnotation(AnnotationNode annotationNode, String group, + String module, boolean transitive) { + assertEquals(group, getMemberValue(annotationNode, "group")); + assertEquals(module, getMemberValue(annotationNode, "module")); + assertEquals(transitive, getMemberValue(annotationNode, "transitive")); + } + + private Object getMemberValue(AnnotationNode annotationNode, String member) { + return ((ConstantExpression) annotationNode.getMember(member)).getValue(); + } +}