Commit 003268fb authored by Andy Wilkinson's avatar Andy Wilkinson

Add support for @WebFilter, @WebListener, @WebServlet

This commit adds a new annotation, @ServletComponentScan, that can be
used to enable scanning for @WebFilter, @WebListener, and @WebServlet
annotated classes. Registration beans will be automatically created for
any classes that are found, with the configuration derived from the
annotation.
parent 07ec9bb8
...@@ -348,15 +348,23 @@ Spring Boot. The definitive list comes from searching the source code for ...@@ -348,15 +348,23 @@ Spring Boot. The definitive list comes from searching the source code for
[[howto-add-a-servlet-filter-or-servletcontextlistener]] [[howto-add-a-servlet-filter-or-listener]]
=== Add a Servlet, Filter or ServletContextListener to an application === Add a Servlet, Filter or Listener to an application
`Servlet`, `Filter`, `ServletContextListener` and the other listeners supported by the There are two ways to add `Servlet`, `Filter`, `ServletContextListener` and the other
Servlet spec can be added to your application as `@Bean` definitions. Be very careful that listeners supported by the Servlet spec to your application. You can either provide
they don't cause eager initialization of too many other beans because they have to be Spring beans for them, or enable scanning for Servlet components.
installed in the container very early in the application lifecycle (e.g. it's not a good
idea to have them depend on your `DataSource` or JPA configuration). You can work around
restrictions like that by initializing them lazily when first used instead of on
initialization. [[howto-add-a-servlet-filter-or-listener-as-spring-bean]]
==== Add a Servlet, Filter or Listener using a Spring bean
To add a `Servlet`, `Filter`, or Servlet `*Listener` provide a `@Bean` definition for it.
This can be very useful when you want to inject configuration or dependencies. However,
you must be very careful that they don't cause eager initialization of too many other
beans because they have to be installed in the container very early in the application
lifecycle (e.g. it's not a good idea to have them depend on your `DataSource` or JPA
configuration). You can work around restrictions like that by initializing them lazily
when first used instead of on initialization.
In the case of `Filters` and `Servlets` you can also add mappings and init parameters by In the case of `Filters` and `Servlets` you can also add mappings and init parameters by
adding a `FilterRegistrationBean` or `ServletRegistrationBean` instead of or as well as adding a `FilterRegistrationBean` or `ServletRegistrationBean` instead of or as well as
...@@ -365,7 +373,7 @@ the underlying component. ...@@ -365,7 +373,7 @@ the underlying component.
[[howto-disable-registration-of-a-servlet-or-filter]] [[howto-disable-registration-of-a-servlet-or-filter]]
=== Disable registration of a Servlet or Filter ===== Disable registration of a Servlet or Filter
As <<howto-add-a-servlet-filter-or-servletcontextlistener,described above>> any `Servlet` As <<howto-add-a-servlet-filter-or-servletcontextlistener,described above>> any `Servlet`
or `Filter` beans will be registered with the servlet container automatically. To disable or `Filter` beans will be registered with the servlet container automatically. To disable
registration of a particular `Filter` or `Servlet` bean create a registration bean for it registration of a particular `Filter` or `Servlet` bean create a registration bean for it
...@@ -382,6 +390,15 @@ and mark it as disabled. For example: ...@@ -382,6 +390,15 @@ and mark it as disabled. For example:
---- ----
[[howto-add-a-servlet-filter-or-listener-using-scanning]]
==== Add Servlets, Filters, and Listeners using classpath scanning
`@WebServlet`, `@WebFilter`, and `@WebListener` annotated classes can be automatically
registered with an embedded servlet container by annotating a `@Configuration` class
with `@ServletComponentScan` and specifying the package(s) containing the components
that you want to register. By default, `@ServletComponentScan` will scan from the package
of the annotated class.
[[howto-change-the-http-port]] [[howto-change-the-http-port]]
=== Change the HTTP port === Change the HTTP port
...@@ -1215,7 +1232,7 @@ using the "logging.config" property. ...@@ -1215,7 +1232,7 @@ using the "logging.config" property.
[[howto-configure-logback-for-loggin]] [[howto-configure-logback-for-loggin]]
=== Configure Logback for logging === Configure Logback for logging
If you put a `logback.xml` in the root of your classpath it will be picked up from If you put a `logback.xml` in the root of your classpath it will be picked up from
there there
(or `logback-spring.xml` to take advantage of the templating features provided by Boot). Spring Boot provides a default base configuration that you can include if you just (or `logback-spring.xml` to take advantage of the templating features provided by Boot). Spring Boot provides a default base configuration that you can include if you just
want to set levels, e.g. want to set levels, e.g.
......
...@@ -1585,12 +1585,18 @@ instance. By default the embedded server will listen for HTTP requests on port ` ...@@ -1585,12 +1585,18 @@ instance. By default the embedded server will listen for HTTP requests on port `
[[boot-features-embedded-container-servlets-and-filters]] [[boot-features-embedded-container-servlets-filters-listeners]]
==== Servlets and Filters ==== Servlets, Filters, and listeners
When using an embedded servlet container you can register Servlets, Filters and all the When using an embedded servlet container you can register Servlets, Filters and all the
listeners from the Servlet spec (e.g. `HttpSessionListener`) directly as listeners from the Servlet spec (e.g. `HttpSessionListener`) either by using Spring beans
Spring beans. This can be particularly convenient if you want to refer to a value from or by scanning for Servlet components.
your `application.properties` during configuration.
[[boot-features-embedded-container-servlets-filters-listeners-beans]]
===== Registering Servlets, Filters, and listeners as Spring beans
Any `Servlet`, `Filter` or Servlet `*Listener` instance that is a Spring bean will be
registered with the embedded container. This can be particularly convenient if you want to
refer to a value from your `application.properties` during configuration.
By default, if the context contains only a single Servlet it will be mapped to `/`. In the By default, if the context contains only a single Servlet it will be mapped to `/`. In the
case of multiple Servlet beans the bean name will be used as a path prefix. Filters will case of multiple Servlet beans the bean name will be used as a path prefix. Filters will
...@@ -1603,6 +1609,16 @@ the `ServletContextInitializer` interface. ...@@ -1603,6 +1609,16 @@ the `ServletContextInitializer` interface.
[[boot-features-embedded-container-servlets-filters-listeners-scanning]]
===== Scanning for Servlets, Filters, and listeners
When using an embedded container, automatic registration of `@WebServlet`, `@WebFilter`,
and `@WebListener` annotated classes can be enabled using `@ServletComponentScan`.
TIP: `@ServletComponentScan` will have no effect in a standalone container, where the
container's built-in discovery mechanisms will be used instead.
[[boot-features-embedded-container-application-context]] [[boot-features-embedded-container-application-context]]
==== The EmbeddedWebApplicationContext ==== The EmbeddedWebApplicationContext
Under the hood Spring Boot uses a new type of `ApplicationContext` for embedded servlet Under the hood Spring Boot uses a new type of `ApplicationContext` for embedded servlet
......
/*
* 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.web.servlet;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
/**
* Abstract base class for handlers of Servlet components discovered via classpath
* scanning.
*
* @author Andy Wilkinson
*/
abstract class ServletComponentHandler {
private final Class<? extends Annotation> annotationType;
private final TypeFilter typeFilter;
protected ServletComponentHandler(Class<? extends Annotation> annotationType) {
this.typeFilter = new AnnotationTypeFilter(annotationType);
this.annotationType = annotationType;
}
TypeFilter getTypeFilter() {
return this.typeFilter;
}
protected String[] extractUrlPatterns(String attribute, Map<String, Object> attributes) {
String[] urlPatterns = (String[]) attributes.get("urlPatterns");
if (urlPatterns.length > 0) {
if (((String[]) attributes.get("value")).length > 0) {
throw new IllegalStateException("The urlPatterns and value attributes "
+ "are mututally exclusive");
}
return urlPatterns;
}
return (String[]) attributes.get("value");
}
protected final Map<String, String> extractInitParameters(
Map<String, Object> attributes) {
Map<String, String> initParameters = new HashMap<String, String>();
for (AnnotationAttributes initParam : (AnnotationAttributes[]) attributes
.get("initParams")) {
String name = (String) initParam.get("name");
String value = (String) initParam.get("value");
initParameters.put(name, value);
}
return initParameters;
}
void handle(ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
Map<String, Object> attributes = beanDefinition.getMetadata()
.getAnnotationAttributes(this.annotationType.getName());
if (attributes != null) {
doHandle(attributes, beanDefinition, registry);
}
}
protected abstract void doHandle(Map<String, Object> attributes,
BeanDefinition beanDefinition, BeanDefinitionRegistry registry);
}
\ No newline at end of file
/*
* 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.web.servlet;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
/**
* {@link BeanFactoryPostProcessor} that registers beans for Servlet components found via
* package scanning.
*
* @see ServletComponentScan
* @see ServletComponentScanRegistrar
* @author Andy Wilkinson
*/
class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor,
ApplicationContextAware {
private final List<ServletComponentHandler> handlers = Arrays.asList(
new WebServletHandler(), new WebFilterHandler(), new WebListenerHandler());
private final Set<String> packagesToScan;
private ApplicationContext applicationContext;
public ServletComponentRegisteringPostProcessor(Set<String> packagesToScan) {
this.packagesToScan = packagesToScan;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (isRunningInEmbeddedContainer()) {
ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
for (String packageToScan : this.packagesToScan) {
for (BeanDefinition candidate : componentProvider
.findCandidateComponents(packageToScan)) {
if (candidate instanceof ScannedGenericBeanDefinition) {
for (ServletComponentHandler handler : this.handlers) {
handler.handle(((ScannedGenericBeanDefinition) candidate),
(BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
}
}
private boolean isRunningInEmbeddedContainer() {
return this.applicationContext instanceof EmbeddedWebApplicationContext
&& ((EmbeddedWebApplicationContext) this.applicationContext)
.getServletContext() == null;
}
private ClassPathScanningCandidateComponentProvider createComponentProvider() {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
for (ServletComponentHandler handler : this.handlers) {
componentProvider.addIncludeFilter(handler.getTypeFilter());
}
return componentProvider;
}
Set<String> getPackagesToScan() {
return Collections.unmodifiableSet(this.packagesToScan);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
/*
* 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.web.servlet;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebServlet;
import org.springframework.context.annotation.Import;
/**
* Enables scanning for Servlet components ({@link WebFilter filters}, {@link WebServlet
* servlets}, and {@link WebListener listeners}). Scanning is only performed when using an
* embedded Servlet container.
* <p>
* Typically, one of {@code value}, {@code basePackages}, or {@code basePackageClasses}
* should be specified to control the packages to be scanned for components. In their
* absence, scanning will be performed from the package of the class with the annotation.
*
* @author Andy Wilkinson
* @since 1.3.0
* @see WebServlet
* @see WebFilter
* @see WebListener
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @ServletComponentScan("org.my.pkg")} instead of
* {@code @ServletComponentScan(basePackages="org.my.pkg")}.
*
* @return the base packages to scan
*/
String[] value() default {};
/**
* Base packages to scan for annotated servlet components. {@link #value()} is an
* alias for (and mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated servlet components. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default {};
}
/*
* 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.web.servlet;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* {@link ImportBeanDefinitionRegistrar} used by {@link ServletComponentScan}.
*
* @author Andy Wilkinson
*/
class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor";
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (registry.containsBeanDefinition(BEAN_NAME)) {
updatePostProcessor(registry, packagesToScan);
}
else {
addPostProcessor(registry, packagesToScan);
}
}
private void addPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
private void updatePostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
ValueHolder constructorArguments = definition.getConstructorArgumentValues()
.getGenericArgumentValue(String[].class);
@SuppressWarnings("unchecked")
Set<String> mergedPackages = new LinkedHashSet<String>(
(Set<String>) constructorArguments.getValue());
mergedPackages.addAll(packagesToScan);
constructorArguments.setValue(packagesToScan);
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(ServletComponentScan.class.getName()));
String[] value = attributes.getStringArray("value");
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
if (!ObjectUtils.isEmpty(value)) {
Assert.state(ObjectUtils.isEmpty(basePackages),
"@ServletComponentScan basePackages and value attributes are"
+ " mutually exclusive");
}
Set<String> packagesToScan = new LinkedHashSet<String>();
packagesToScan.addAll(Arrays.asList(value));
packagesToScan.addAll(Arrays.asList(basePackages));
for (Class<?> basePackageClass : basePackageClasses) {
packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
}
if (packagesToScan.isEmpty()) {
return Collections.singleton(ClassUtils.getPackageName(metadata
.getClassName()));
}
return packagesToScan;
}
}
/*
* 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.web.servlet;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.annotation.WebFilter;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.util.StringUtils;
/**
* Handler for {@link WebFilter}-annotated classes
*
* @author Andy Wilkinson
*/
class WebFilterHandler extends ServletComponentHandler {
WebFilterHandler() {
super(WebFilter.class);
}
@Override
public void doHandle(Map<String, Object> attributes, BeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(FilterRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("dispatcherTypes", extractDispatcherTypes(attributes));
builder.addPropertyValue("filter", beanDefinition);
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servletNames", attributes.get("servletNames"));
builder.addPropertyValue("urlPatterns",
extractUrlPatterns("urlPatterns", attributes));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
private EnumSet<DispatcherType> extractDispatcherTypes(Map<String, Object> attributes) {
DispatcherType[] dispatcherTypes = (DispatcherType[]) attributes
.get("dispatcherTypes");
if (dispatcherTypes.length == 0) {
return EnumSet.noneOf(DispatcherType.class);
}
if (dispatcherTypes.length == 1) {
return EnumSet.of(dispatcherTypes[0]);
}
return EnumSet.of(dispatcherTypes[0],
Arrays.copyOfRange(dispatcherTypes, 1, dispatcherTypes.length));
}
private String determineName(Map<String, Object> attributes,
BeanDefinition beanDefinition) {
return (String) (StringUtils.hasText((String) attributes.get("filterName")) ? attributes
.get("filterName") : beanDefinition.getBeanClassName());
}
}
\ No newline at end of file
/*
* 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.web.servlet;
import java.util.Map;
import javax.servlet.annotation.WebListener;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
/**
* Handler for {@link WebListener}-annotated classes
*
* @author Andy Wilkinson
*/
class WebListenerHandler extends ServletComponentHandler {
WebListenerHandler() {
super(WebListener.class);
}
@Override
protected void doHandle(Map<String, Object> attributes,
BeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(ServletListenerRegistrationBean.class);
builder.addPropertyValue("listener", beanDefinition);
registry.registerBeanDefinition(beanDefinition.getBeanClassName(),
builder.getBeanDefinition());
}
}
\ No newline at end of file
/*
* 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.web.servlet;
import java.util.Map;
import javax.servlet.annotation.WebServlet;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.util.StringUtils;
/**
* Handler for {@link WebServlet}-annotated classes
*
* @author Andy Wilkinson
*/
class WebServletHandler extends ServletComponentHandler {
WebServletHandler() {
super(WebServlet.class);
}
@Override
public void doHandle(Map<String, Object> attributes, BeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(ServletRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servlet", beanDefinition);
builder.addPropertyValue("urlMappings",
extractUrlPatterns("urlPatterns", attributes));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
private String determineName(Map<String, Object> attributes,
BeanDefinition beanDefinition) {
return (String) (StringUtils.hasText((String) attributes.get("name")) ? attributes
.get("name") : beanDefinition.getBeanClassName());
}
}
\ No newline at end of file
/*
* 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.web.servlet;
import java.util.Arrays;
import java.util.HashSet;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
/**
* Tests for {@link ServletComponentRegisteringPostProcessor}
*
* @author Andy Wilkinson
*/
public class ServletComponentRegisteringPostProcessorTests {
private final ServletComponentRegisteringPostProcessor postProcessor = new ServletComponentRegisteringPostProcessor(
new HashSet<String>(Arrays.asList(getClass().getPackage().getName())));
private final EmbeddedWebApplicationContext context = new EmbeddedWebApplicationContext();
@Before
public void before() {
this.postProcessor.setApplicationContext(this.context);
}
@Test
public void test() {
this.postProcessor.postProcessBeanFactory(this.context.getBeanFactory());
this.context.getBeanDefinition("servletWithName");
this.context.getBeanDefinition("defaultNameServlet");
}
}
/*
* 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.web.servlet;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Integration tests for {@link ServletComponentScan}
*
* @author Andy Wilkinson
*/
public class ServletComponentScanIntegrationTests {
private AnnotationConfigEmbeddedWebApplicationContext context;
@After
public void cleanUp() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void componentsAreRegistered() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
this.context.register(TestConfiguration.class);
new ServerPortInfoApplicationContextInitializer().initialize(this.context);
this.context.refresh();
String port = this.context.getEnvironment().getProperty("local.server.port");
String response = new RestTemplate().getForObject("http://localhost:" + port
+ "/test", String.class);
assertThat(response, is(equalTo("alpha bravo")));
}
@Configuration
@ServletComponentScan(basePackages = "org.springframework.boot.web.servlet.testcomponents")
static class TestConfiguration {
@Bean
public TomcatEmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(0);
}
}
}
/*
* 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.web.servlet;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link ServletComponentScanRegistrar}
*
* @author Andy Wilkinson
*/
public class ServletComponentScanRegistrarTests {
private AnnotationConfigApplicationContext context;
@Rule
public ExpectedException thrown = ExpectedException.none();
@After
public void after() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void packagesConfiguredWithValue() {
this.context = new AnnotationConfigApplicationContext(ValuePackages.class);
ServletComponentRegisteringPostProcessor postProcessor = this.context
.getBean(ServletComponentRegisteringPostProcessor.class);
assertThat(postProcessor.getPackagesToScan(),
containsInAnyOrder("com.example.foo", "com.example.bar"));
}
@Test
public void packagesConfiguredWithBackPackages() {
this.context = new AnnotationConfigApplicationContext(BasePackages.class);
ServletComponentRegisteringPostProcessor postProcessor = this.context
.getBean(ServletComponentRegisteringPostProcessor.class);
assertThat(postProcessor.getPackagesToScan(),
containsInAnyOrder("com.example.foo", "com.example.bar"));
}
@Test
public void packagesConfiguredWithBasePackageClasses() {
this.context = new AnnotationConfigApplicationContext(BasePackageClasses.class);
ServletComponentRegisteringPostProcessor postProcessor = this.context
.getBean(ServletComponentRegisteringPostProcessor.class);
assertThat(postProcessor.getPackagesToScan(), containsInAnyOrder(getClass()
.getPackage().getName()));
}
@Test
public void packagesConfiguredWithBothValueAndBasePackages() {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("@ServletComponentScan basePackages and value"
+ " attributes are mutually exclusive");
this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class);
ServletComponentRegisteringPostProcessor postProcessor = this.context
.getBean(ServletComponentRegisteringPostProcessor.class);
assertThat(postProcessor.getPackagesToScan(), containsInAnyOrder(getClass()
.getPackage().getName()));
}
@Configuration
@ServletComponentScan({ "com.example.foo", "com.example.bar" })
static class ValuePackages {
}
@Configuration
@ServletComponentScan(basePackages = { "com.example.foo", "com.example.bar" })
static class BasePackages {
}
@Configuration
@ServletComponentScan(basePackageClasses = ServletComponentScanRegistrarTests.class)
static class BasePackageClasses {
}
@Configuration
@ServletComponentScan(value = "com.example.foo", basePackages = "com.example.bar")
static class ValueAndBasePackages {
}
}
/*
* 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.web.servlet;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link WebFilterHandler}
*
* @author Andy Wilkinson
*/
public class WebFilterHandlerTests {
private final WebFilterHandler handler = new WebFilterHandler();
private final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
@Rule
public ExpectedException thrown = ExpectedException.none();
@SuppressWarnings("unchecked")
@Test
public void defaultFilterConfiguration() throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory()
.getMetadataReader(DefaultConfigurationFilter.class.getName()));
this.handler.handle(scanned, this.registry);
BeanDefinition filterRegistrationBean = this.registry
.getBeanDefinition(DefaultConfigurationFilter.class.getName());
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat(propertyValues.get("asyncSupported"), is((Object) false));
assertThat((EnumSet<DispatcherType>) propertyValues.get("dispatcherTypes"),
is(EnumSet.of(DispatcherType.REQUEST)));
assertThat(((Map<String, String>) propertyValues.get("initParameters")).size(),
is(0));
assertThat((String[]) propertyValues.get("servletNames"), is(arrayWithSize(0)));
assertThat((String[]) propertyValues.get("urlPatterns"), is(arrayWithSize(0)));
assertThat(propertyValues.get("name"),
is((Object) DefaultConfigurationFilter.class.getName()));
assertThat(propertyValues.get("filter"), is(equalTo((Object) scanned)));
}
@Test
public void filterWithCustomName() throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory()
.getMetadataReader(CustomNameFilter.class.getName()));
this.handler.handle(scanned, this.registry);
BeanDefinition filterRegistrationBean = this.registry.getBeanDefinition("custom");
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat(propertyValues.get("name"), is((Object) "custom"));
}
@Test
public void asyncSupported() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(AsyncSupportedFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat(propertyValues.get("asyncSupported"), is((Object) true));
}
@Test
public void dispatcherTypes() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(DispatcherTypesFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat(propertyValues.get("dispatcherTypes"), is((Object) EnumSet.of(
DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST)));
}
@SuppressWarnings("unchecked")
@Test
public void initParameters() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(InitParametersFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat((Map<String, String>) propertyValues.get("initParameters"),
hasEntry("a", "alpha"));
assertThat((Map<String, String>) propertyValues.get("initParameters"),
hasEntry("b", "bravo"));
}
@Test
public void servletNames() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(ServletNamesFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat((String[]) propertyValues.get("servletNames"),
is(arrayContaining("alpha", "bravo")));
}
@Test
public void urlPatterns() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(UrlPatternsFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat((String[]) propertyValues.get("urlPatterns"),
is(arrayContaining("alpha", "bravo")));
}
@Test
public void urlPatternsFromValue() throws IOException {
BeanDefinition filterRegistrationBean = getBeanDefinition(UrlPatternsFromValueFilter.class);
MutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();
assertThat((String[]) propertyValues.get("urlPatterns"),
is(arrayContaining("alpha", "bravo")));
}
@Test
public void urlPatternsDeclaredTwice() throws IOException {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("The urlPatterns and value attributes are mututally "
+ "exclusive");
getBeanDefinition(UrlPatternsDeclaredTwiceFilter.class);
}
BeanDefinition getBeanDefinition(Class<?> filterClass) throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory().getMetadataReader(filterClass.getName()));
this.handler.handle(scanned, this.registry);
return this.registry.getBeanDefinition(filterClass.getName());
}
@WebFilter
class DefaultConfigurationFilter extends BaseFilter {
}
@WebFilter(asyncSupported = true)
class AsyncSupportedFilter extends BaseFilter {
}
@WebFilter(dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD,
DispatcherType.INCLUDE })
class DispatcherTypesFilter extends BaseFilter {
}
@WebFilter(initParams = { @WebInitParam(name = "a", value = "alpha"),
@WebInitParam(name = "b", value = "bravo") })
class InitParametersFilter extends BaseFilter {
}
@WebFilter(servletNames = { "alpha", "bravo" })
class ServletNamesFilter extends BaseFilter {
}
@WebFilter(urlPatterns = { "alpha", "bravo" })
class UrlPatternsFilter extends BaseFilter {
}
@WebFilter({ "alpha", "bravo" })
class UrlPatternsFromValueFilter extends BaseFilter {
}
@WebFilter(value = { "alpha", "bravo" }, urlPatterns = { "alpha", "bravo" })
class UrlPatternsDeclaredTwiceFilter extends BaseFilter {
}
@WebFilter(filterName = "custom")
class CustomNameFilter extends BaseFilter {
}
class BaseFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
}
/*
* 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.web.servlet;
import java.io.IOException;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
import org.junit.Test;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
/**
* Tests for {@WebListenerHandler}
*
* @author Andy Wilkinson
*/
public class WebListenerHandlerTests {
private final WebListenerHandler handler = new WebListenerHandler();
private final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
@Test
public void listener() throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory().getMetadataReader(TestListener.class
.getName()));
this.handler.handle(scanned, this.registry);
this.registry.getBeanDefinition(TestListener.class.getName());
}
@WebListener
static class TestListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
}
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
}
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
}
}
}
/*
* 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.web.servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Tests for {@WebServletHandler}
*
* @author Andy Wilkinson
*/
public class WebServletHandlerTests {
private final WebServletHandler handler = new WebServletHandler();
private final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
@Rule
public ExpectedException thrown = ExpectedException.none();
@SuppressWarnings("unchecked")
@Test
public void defaultServletConfiguration() throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory()
.getMetadataReader(DefaultConfigurationServlet.class.getName()));
this.handler.handle(scanned, this.registry);
BeanDefinition servletRegistrationBean = this.registry
.getBeanDefinition(DefaultConfigurationServlet.class.getName());
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat(propertyValues.get("asyncSupported"), is((Object) false));
assertThat(((Map<String, String>) propertyValues.get("initParameters")).size(),
is(0));
assertThat((Integer) propertyValues.get("loadOnStartup"), is(-1));
assertThat(propertyValues.get("name"),
is((Object) DefaultConfigurationServlet.class.getName()));
assertThat((String[]) propertyValues.get("urlMappings"), is(arrayWithSize(0)));
assertThat(propertyValues.get("servlet"), is(equalTo((Object) scanned)));
}
@Test
public void servletWithCustomName() throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory()
.getMetadataReader(CustomNameServlet.class.getName()));
this.handler.handle(scanned, this.registry);
BeanDefinition servletRegistrationBean = this.registry
.getBeanDefinition("custom");
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat(propertyValues.get("name"), is((Object) "custom"));
}
@Test
public void asyncSupported() throws IOException {
BeanDefinition servletRegistrationBean = getBeanDefinition(AsyncSupportedServlet.class);
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat(propertyValues.get("asyncSupported"), is((Object) true));
}
@SuppressWarnings("unchecked")
@Test
public void initParameters() throws IOException {
BeanDefinition servletRegistrationBean = getBeanDefinition(InitParametersServlet.class);
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat((Map<String, String>) propertyValues.get("initParameters"),
hasEntry("a", "alpha"));
assertThat((Map<String, String>) propertyValues.get("initParameters"),
hasEntry("b", "bravo"));
}
@Test
public void urlMappings() throws IOException {
BeanDefinition servletRegistrationBean = getBeanDefinition(UrlPatternsServlet.class);
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat((String[]) propertyValues.get("urlMappings"),
is(arrayContaining("alpha", "bravo")));
}
@Test
public void urlMappingsFromValue() throws IOException {
BeanDefinition servletRegistrationBean = getBeanDefinition(UrlPatternsFromValueServlet.class);
MutablePropertyValues propertyValues = servletRegistrationBean
.getPropertyValues();
assertThat((String[]) propertyValues.get("urlMappings"),
is(arrayContaining("alpha", "bravo")));
}
@Test
public void urlPatternsDeclaredTwice() throws IOException {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("The urlPatterns and value attributes are mututally "
+ "exclusive");
getBeanDefinition(UrlPatternsDeclaredTwiceServlet.class);
}
BeanDefinition getBeanDefinition(Class<?> filterClass) throws IOException {
ScannedGenericBeanDefinition scanned = new ScannedGenericBeanDefinition(
new SimpleMetadataReaderFactory().getMetadataReader(filterClass.getName()));
this.handler.handle(scanned, this.registry);
return this.registry.getBeanDefinition(filterClass.getName());
}
@WebServlet
class DefaultConfigurationServlet extends HttpServlet {
}
@WebServlet(asyncSupported = true)
class AsyncSupportedServlet extends HttpServlet {
}
@WebServlet(initParams = { @WebInitParam(name = "a", value = "alpha"),
@WebInitParam(name = "b", value = "bravo") })
class InitParametersServlet extends HttpServlet {
}
@WebServlet(urlPatterns = { "alpha", "bravo" })
class UrlPatternsServlet extends HttpServlet {
}
@WebServlet({ "alpha", "bravo" })
class UrlPatternsFromValueServlet extends HttpServlet {
}
@WebServlet(value = { "alpha", "bravo" }, urlPatterns = { "alpha", "bravo" })
class UrlPatternsDeclaredTwiceServlet extends HttpServlet {
}
@WebServlet(name = "custom")
class CustomNameServlet extends HttpServlet {
}
}
/*
* 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.web.servlet.testcomponents;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter("/*")
class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setAttribute("filterAttribute", "bravo");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
/*
* 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.web.servlet.testcomponents;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
class TestListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("listenerAttribute", "alpha");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
/*
* 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.web.servlet.testcomponents;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().print(
((String) req.getServletContext().getAttribute("listenerAttribute"))
+ " " + req.getAttribute("filterAttribute"));
resp.getWriter().flush();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment