This commit is contained in:
Phillip Webb 2014-03-03 16:24:02 -08:00
parent 07b88630f4
commit 468728a2c0
34 changed files with 244 additions and 164 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -24,8 +24,9 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author Dave Syer
* Test for application hierarchies created using {@link SpringApplicationBuilder}.
*
* @author Dave Syer
*/
public class SpringApplicationHierarchyTests {

View File

@ -116,4 +116,4 @@ public class AuthenticationManagerConfiguration extends
auth.parentAuthenticationManager(parent);
}
}
}
}

View File

@ -45,9 +45,11 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
@Import({ SpringBootWebSecurityConfiguration.class,
AuthenticationManagerConfiguration.class })
public class SecurityAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SecurityProperties securityProperties() {
return new SecurityProperties();
}
}
}

View File

@ -124,8 +124,8 @@ public class WebMvcAutoConfiguration {
// Defined as a nested config to ensure WebMvcConfigurerAdapter it not read when not
// on the classpath
@EnableWebMvc
@Configuration
@EnableWebMvc
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
private static Log logger = LogFactory.getLog(WebMvcConfigurerAdapter.class);

View File

@ -49,8 +49,8 @@
<spring-data-jpa.version>1.5.0.RELEASE</spring-data-jpa.version>
<spring-data-mongodb.version>1.4.0.RELEASE</spring-data-mongodb.version>
<spring-data-redis.version>1.1.1.RELEASE</spring-data-redis.version>
<spring-data-rest.version>2.0.0.RELEASE</spring-data-rest.version>
<spring-hateoas.version>0.9.0.RELEASE</spring-hateoas.version>
<spring-data-rest.version>2.0.0.RELEASE</spring-data-rest.version>
<spring-hateoas.version>0.9.0.RELEASE</spring-hateoas.version>
<spring-rabbit.version>1.2.1.RELEASE</spring-rabbit.version>
<spring-mobile.version>1.1.1.RELEASE</spring-mobile.version>
<spring-security.version>3.2.1.RELEASE</spring-security.version>
@ -494,16 +494,16 @@
<artifactId>spring-data-redis</artifactId>
<version>${spring-data-redis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>${spring-hateoas.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>${spring-data-rest.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>${spring-hateoas.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>${spring-data-rest.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -24,7 +24,7 @@ import sample.data.jpa.domain.Hotel;
@RepositoryRestResource(collectionResourceRel = "hotels", path = "hotels")
interface HotelRepository extends PagingAndSortingRepository<Hotel, Long> {
Hotel findByCityAndName(City city, String name);
}

View File

@ -1,9 +1,20 @@
package sample.data.jpa;
/*
* 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.
*/
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
package sample.data.jpa;
import org.junit.Before;
import org.junit.Test;
@ -17,6 +28,11 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration test to run the application.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.jpa.service;
import org.junit.Test;

View File

@ -16,8 +16,6 @@
package sample.secure;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -38,6 +36,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import sample.secure.SampleSecureApplicationTests.TestConfiguration;
import static org.junit.Assert.assertEquals;
/**
* Basic integration tests for demo application.
*
@ -58,9 +58,9 @@ public class SampleSecureApplicationTests {
@Before
public void init() {
AuthenticationManager authenticationManager = context
.getBean(AuthenticationManagerBuilder.class).getOrBuild();
authentication = authenticationManager
AuthenticationManager authenticationManager = this.context.getBean(
AuthenticationManagerBuilder.class).getOrBuild();
this.authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@ -71,25 +71,25 @@ public class SampleSecureApplicationTests {
@Test(expected = AuthenticationException.class)
public void secure() throws Exception {
assertEquals(service.secure(), "Hello Security");
assertEquals(this.service.secure(), "Hello Security");
}
@Test
public void authenticated() throws Exception {
SecurityContextHolder.getContext().setAuthentication(authentication);
assertEquals(service.secure(), "Hello Security");
SecurityContextHolder.getContext().setAuthentication(this.authentication);
assertEquals(this.service.secure(), "Hello Security");
}
@Test
public void preauth() throws Exception {
SecurityContextHolder.getContext().setAuthentication(authentication);
assertEquals(service.authorized(), "Hello World");
SecurityContextHolder.getContext().setAuthentication(this.authentication);
assertEquals(this.service.authorized(), "Hello World");
}
@Test(expected = AccessDeniedException.class)
public void denied() throws Exception {
SecurityContextHolder.getContext().setAuthentication(authentication);
assertEquals(service.denied(), "Goodbye World");
SecurityContextHolder.getContext().setAuthentication(this.authentication);
assertEquals(this.service.denied(), "Goodbye World");
}
@PropertySource("classpath:test.properties")

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->

View File

@ -76,26 +76,20 @@ public class SampleMethodSecurityApplication extends WebMvcConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth.inMemoryAuthentication()
.withUser("admin").password("admin").roles("ADMIN", "USER")
.and()
.withUser("user").password("user").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("admin")
.roles("ADMIN", "USER").and().withUser("user").password("user")
.roles("USER");
// @formatter:on
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.and()
.exceptionHandling().accessDeniedPage("/access?error");
http.authorizeRequests().antMatchers("/login").permitAll().anyRequest()
.fullyAuthenticated().and().formLogin().loginPage("/login")
.failureUrl("/login?error").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and()
.exceptionHandling().accessDeniedPage("/access?error");
// @formatter:on
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<!-- logger name="org.springframework.boot" level="DEBUG"/-->
<logger name="org.springframework.security" level="DEBUG"/>
</configuration>

View File

@ -16,9 +16,6 @@
package sample.ui.method;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.Callable;
@ -45,6 +42,9 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Basic integration tests for demo application.
*

View File

@ -30,12 +30,12 @@ The parent pom adds two main fetaures to your project:
* dependency management configuration, so you don't have to specify
versions or excludes with your own dependencies, as long as they are
part of the Spring Boot stack
* plugin configuration, so you don't have to configure some common
settings in the main Maven plugins used to get a project off the
ground (e.g. the
[Spring Boot Maven plugin](../spring-boot-tools/spring-boot-maven-plugin/README.md))
As an example, if you want to build a simple RESTful web service with
embedded Tomcat, you only need one dependency:

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>

View File

@ -18,13 +18,13 @@
<artifactId>spring-boot-starter-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
provides: spring-hateoas,spring-data-rest-webmvc

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
@ -308,17 +309,22 @@
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<transformer
implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${start-class}</mainClass>
</transformer>
</transformers>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -27,25 +27,26 @@ import org.springframework.util.ObjectUtils;
*/
public class ErrorPage {
private final HttpStatus status;
private final Class<? extends Throwable> exception;
private final String path;
private Class<? extends Throwable> exception = null;
private HttpStatus status = null;
public ErrorPage(String path) {
super();
this.status = null;
this.exception = null;
this.path = path;
}
public ErrorPage(HttpStatus status, String path) {
super();
this.status = status;
this.exception = null;
this.path = path;
}
public ErrorPage(Class<? extends Throwable> exception, String path) {
super();
this.status = null;
this.exception = exception;
this.path = path;
}
@ -61,15 +62,17 @@ public class ErrorPage {
}
/**
* @return the exception type (or null for a page that matches by status)
* Returns the exception type (or {@code null} for a page that matches by status)
* @return the exception type or {@code null}
*/
public Class<? extends Throwable> getException() {
return this.exception;
}
/**
* The HTTP status value that this error page matches.
* @return the status
* The HTTP status value that this error page matches (or {@code null} for a page that
* matches by exception).
* @return the status or {@code null}
*/
public HttpStatus getStatus() {
return this.status;
@ -80,7 +83,7 @@ public class ErrorPage {
* @return the status value (or 0 for a page that matches any status)
*/
public int getStatusCode() {
return this.status == null ? 0 : this.status.value();
return (this.status == null ? 0 : this.status.value());
}
/**
@ -88,15 +91,15 @@ public class ErrorPage {
* @return the exception type name (or {@code null} if there is none)
*/
public String getExceptionName() {
return this.exception == null ? null : this.exception.getName();
return (this.exception == null ? null : this.exception.getName());
}
/**
* @return is this error page a global one (matches all unmatched status and exception
* types)?
* types)
*/
public boolean isGlobal() {
return this.status == null && this.exception == null;
return (this.status == null && this.exception == null);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -51,18 +51,28 @@ import org.springframework.stereotype.Component;
* of that type in the context will be applied to this container).
*
* @author Dave Syer
*
* @author Phillip Webb
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ErrorWrapperEmbeddedServletContainerFactory extends
AbstractEmbeddedServletContainerFactory implements Filter {
// From RequestDispatcher but not referenced to remain compatible with Servlet 2.5
private static final String ERROR_EXCEPTION = "javax.servlet.error.exception";
private static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
private static final String ERROR_MESSAGE = "javax.servlet.error.message";
private static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
private String global;
private Map<Integer, String> statuses = new HashMap<Integer, String>();
private final Map<Integer, String> statuses = new HashMap<Integer, String>();
private Map<Class<? extends Throwable>, String> exceptions = new HashMap<Class<? extends Throwable>, String>();
private final Map<Class<?>, String> exceptions = new HashMap<Class<?>, String>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@ -71,65 +81,90 @@ public class ErrorWrapperEmbeddedServletContainerFactory extends
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String errorPath;
ErrorWrapperResponse wrapped = new ErrorWrapperResponse(
(HttpServletResponse) response);
if (request instanceof HttpServletRequest
&& response instanceof HttpServletResponse) {
doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
}
else {
chain.doFilter(request, response);
}
}
private void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
ErrorWrapperResponse wrapped = new ErrorWrapperResponse(response);
try {
chain.doFilter(request, wrapped);
int status = wrapped.getStatus();
if (status >= 400) {
errorPath = this.statuses.containsKey(status) ? this.statuses.get(status)
: this.global;
if (errorPath != null) {
request.setAttribute("javax.servlet.error.status_code", status);
request.setAttribute("javax.servlet.error.message",
wrapped.getMessage());
((HttpServletRequest) request).getRequestDispatcher(errorPath)
.forward(request, response);
}
else {
((HttpServletResponse) response).sendError(status,
wrapped.getMessage());
}
handleErrorStatus(request, response, status, wrapped.getMessage());
}
}
catch (Throwable e) {
Class<? extends Throwable> cls = e.getClass();
errorPath = this.exceptions.containsKey(cls) ? this.exceptions.get(cls)
: this.global;
if (errorPath != null) {
request.setAttribute("javax.servlet.error.status_code", 500);
request.setAttribute("javax.servlet.error.exception", e);
request.setAttribute("javax.servlet.error.message", e.getMessage());
wrapped.sendError(500, e.getMessage());
((HttpServletRequest) request).getRequestDispatcher(errorPath).forward(
request, response);
}
else {
rethrow(e);
}
catch (Throwable ex) {
handleException(request, response, wrapped, ex);
}
}
private void rethrow(Throwable e) throws IOException, ServletException {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
private void handleErrorStatus(HttpServletRequest request,
HttpServletResponse response, int status, String message)
throws ServletException, IOException {
String errorPath = getErrorPath(this.statuses, status);
if (errorPath == null) {
response.sendError(status, message);
return;
}
if (e instanceof Error) {
throw (Error) e;
setErrorAttributes(request, status, message);
request.getRequestDispatcher(errorPath).forward(request, response);
}
private void handleException(HttpServletRequest request,
HttpServletResponse response, ErrorWrapperResponse wrapped, Throwable ex)
throws IOException, ServletException {
String errorPath = getErrorPath(this.exceptions, ex.getClass());
if (errorPath == null) {
rethrow(ex);
return;
}
if (e instanceof IOException) {
throw (IOException) e;
setErrorAttributes(request, 500, ex.getMessage());
request.setAttribute(ERROR_EXCEPTION, ex);
request.setAttribute(ERROR_EXCEPTION_TYPE, ex.getClass().getName());
wrapped.sendError(500, ex.getMessage());
request.getRequestDispatcher(errorPath).forward(request, response);
}
private String getErrorPath(Map<?, String> map, Object key) {
if (map.containsKey(key)) {
return map.get(key);
}
if (e instanceof ServletException) {
throw (ServletException) e;
return this.global;
}
private void setErrorAttributes(ServletRequest request, int status, String message) {
request.setAttribute(ERROR_STATUS_CODE, status);
request.setAttribute(ERROR_MESSAGE, message);
}
private void rethrow(Throwable ex) throws IOException, ServletException {
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
throw new IllegalStateException("Unidentified Exception", e);
if (ex instanceof Error) {
throw (Error) ex;
}
if (ex instanceof IOException) {
throw (IOException) ex;
}
if (ex instanceof ServletException) {
throw (ServletException) ex;
}
throw new IllegalStateException(ex);
}
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
return new EmbeddedServletContainer() {
@Override
@ -145,6 +180,7 @@ public class ErrorWrapperEmbeddedServletContainerFactory extends
return -1;
}
};
}
@Override
@ -169,6 +205,7 @@ public class ErrorWrapperEmbeddedServletContainerFactory extends
private static class ErrorWrapperResponse extends HttpServletResponseWrapper {
private int status;
private String message;
public ErrorWrapperResponse(HttpServletResponse response) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -84,7 +84,7 @@ public abstract class SpringBootServletInitializer implements WebApplicationInit
servletContext));
application.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
application = configure(application);
// Ensure error pages ar registered
// Ensure error pages are registered
application.sources(ErrorWrapperEmbeddedServletContainerFactory.class);
return (WebApplicationContext) application.run();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* 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.
@ -18,6 +18,7 @@ package org.springframework.boot.context.web;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@ -31,24 +32,30 @@ import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.junit.Assert.assertEquals;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link ErrorWrapperEmbeddedServletContainerFactory}.
*
* @author Dave Syer
*/
public class ErrorWrapperEmbeddedServletContainerFactoryTests {
private ErrorWrapperEmbeddedServletContainerFactory filter = new ErrorWrapperEmbeddedServletContainerFactory();
private MockHttpServletRequest request = new MockHttpServletRequest();
private MockHttpServletResponse response = new MockHttpServletResponse();
private MockFilterChain chain = new MockFilterChain();
@Test
public void notAnError() throws Exception {
this.filter.doFilter(this.request, this.response, this.chain);
assertEquals(this.request, this.chain.getRequest());
assertEquals(this.response,
((HttpServletResponseWrapper) this.chain.getResponse()).getResponse());
assertThat(this.chain.getRequest(), equalTo((ServletRequest) this.request));
assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse(),
equalTo((ServletResponse) this.response));
}
@Test
@ -63,10 +70,12 @@ public class ErrorWrapperEmbeddedServletContainerFactoryTests {
}
};
this.filter.doFilter(this.request, this.response, this.chain);
assertEquals(400,
((HttpServletResponseWrapper) this.chain.getResponse()).getStatus());
assertEquals(400, this.request.getAttribute("javax.servlet.error.status_code"));
assertEquals("BAD", this.request.getAttribute("javax.servlet.error.message"));
assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus(),
equalTo(400));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE),
equalTo((Object) 400));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE),
equalTo((Object) "BAD"));
}
@Test
@ -81,10 +90,12 @@ public class ErrorWrapperEmbeddedServletContainerFactoryTests {
}
};
this.filter.doFilter(this.request, this.response, this.chain);
assertEquals(400,
((HttpServletResponseWrapper) this.chain.getResponse()).getStatus());
assertEquals(400, this.request.getAttribute("javax.servlet.error.status_code"));
assertEquals("BAD", this.request.getAttribute("javax.servlet.error.message"));
assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus(),
equalTo(400));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE),
equalTo((Object) 400));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE),
equalTo((Object) "BAD"));
}
@Test
@ -99,9 +110,13 @@ public class ErrorWrapperEmbeddedServletContainerFactoryTests {
}
};
this.filter.doFilter(this.request, this.response, this.chain);
assertEquals(500,
((HttpServletResponseWrapper) this.chain.getResponse()).getStatus());
assertEquals(500, this.request.getAttribute("javax.servlet.error.status_code"));
assertEquals("BAD", this.request.getAttribute("javax.servlet.error.message"));
assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus(),
equalTo(500));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE),
equalTo((Object) 500));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE),
equalTo((Object) "BAD"));
assertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE),
equalTo((Object) RuntimeException.class.getName()));
}
}

View File

@ -52,7 +52,7 @@ public class JavaLoggerSystemTests {
@Before
public void init() throws SecurityException, IOException {
defaultLocale = Locale.getDefault();
this.defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.ENGLISH);
this.logger = new Jdk14Logger(getClass().getName());
}
@ -62,7 +62,7 @@ public class JavaLoggerSystemTests {
System.clearProperty("LOG_FILE");
System.clearProperty("LOG_PATH");
System.clearProperty("PID");
Locale.setDefault(defaultLocale);
Locale.setDefault(this.defaultLocale);
}
@Test