Polish
This commit is contained in:
@@ -38,9 +38,7 @@ public class WebEndpointProperties {
|
||||
}
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,12 +57,12 @@ public class WebMvcEndpointManagementContextConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(
|
||||
EndpointProvider<WebEndpointOperation> provider,
|
||||
EndpointMediaTypes endpointMediaTypes,
|
||||
CorsEndpointProperties corsProperties,
|
||||
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
|
||||
WebEndpointProperties webEndpointProperties) {
|
||||
WebMvcEndpointHandlerMapping handlerMapping = new WebMvcEndpointHandlerMapping(
|
||||
new EndpointMapping(webEndpointProperties.getBasePath()),
|
||||
provider.getEndpoints(), endpointMediaTypes, getCorsConfiguration(corsProperties));
|
||||
provider.getEndpoints(), endpointMediaTypes,
|
||||
getCorsConfiguration(corsProperties));
|
||||
return handlerMapping;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,17 +43,18 @@ import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the management context. If the
|
||||
* {@code management.server.port} is the same as the {@code server.port} the management context
|
||||
* will be the same as the main application context. If the {@code management.server.port} is
|
||||
* different to the {@code server.port} the management context will be a separate context
|
||||
* that has the main application context as its parent.
|
||||
* {@code management.server.port} is the same as the {@code server.port} the management
|
||||
* context will be the same as the main application context. If the
|
||||
* {@code management.server.port} is different to the {@code server.port} the management
|
||||
* context will be a separate context that has the main application context as its parent.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
|
||||
@EnableConfigurationProperties({ WebEndpointProperties.class, ManagementServerProperties.class })
|
||||
@EnableConfigurationProperties({ WebEndpointProperties.class,
|
||||
ManagementServerProperties.class })
|
||||
public class ManagementContextAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@@ -77,8 +78,8 @@ public class ManagementContextAutoConfiguration {
|
||||
}
|
||||
|
||||
private void verifySslConfiguration() {
|
||||
Boolean enabled = this.environment.getProperty("management.server.ssl.enabled",
|
||||
Boolean.class, false);
|
||||
Boolean enabled = this.environment
|
||||
.getProperty("management.server.ssl.enabled", Boolean.class, false);
|
||||
Assert.state(!enabled,
|
||||
"Management-specific SSL cannot be configured as the management "
|
||||
+ "server is not listening on a separate port");
|
||||
|
||||
@@ -34,4 +34,3 @@ public class WebEndpointPropertiesTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,7 @@ public class WebMvcEndpointIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointsAreSecureWithActuatorRoleWithCustomBasePath()
|
||||
throws Exception {
|
||||
public void endpointsAreSecureWithActuatorRoleWithCustomBasePath() throws Exception {
|
||||
TestSecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "N/A", "ROLE_ACTUATOR"));
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
|
||||
@@ -74,8 +74,8 @@ public class ShutdownEndpointTests {
|
||||
EmptyConfig.class).child(EndpointConfig.class)
|
||||
.web(WebApplicationType.NONE).run();
|
||||
CountDownLatch latch = context.getBean(EndpointConfig.class).latch;
|
||||
assertThat(context.getBean(ShutdownEndpoint.class).shutdown()
|
||||
.get("message")).startsWith("Shutting down");
|
||||
assertThat(context.getBean(ShutdownEndpoint.class).shutdown().get("message"))
|
||||
.startsWith("Shutting down");
|
||||
assertThat(context.isActive()).isTrue();
|
||||
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
@@ -87,8 +87,8 @@ public class ShutdownEndpointTests {
|
||||
.web(WebApplicationType.NONE).run();
|
||||
CountDownLatch parentLatch = context.getBean(EndpointConfig.class).latch;
|
||||
CountDownLatch childLatch = context.getBean(EmptyConfig.class).latch;
|
||||
assertThat(context.getBean(ShutdownEndpoint.class).shutdown()
|
||||
.get("message")).startsWith("Shutting down");
|
||||
assertThat(context.getBean(ShutdownEndpoint.class).shutdown().get("message"))
|
||||
.startsWith("Shutting down");
|
||||
assertThat(context.isActive()).isTrue();
|
||||
assertThat(parentLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(childLatch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
|
||||
@@ -138,7 +138,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private void configureProviderDisablesAutocommit(Map<String, Object> vendorProperties) {
|
||||
private void configureProviderDisablesAutocommit(
|
||||
Map<String, Object> vendorProperties) {
|
||||
if (isDataSourceAutoCommitDisabled() && !isJta()) {
|
||||
vendorProperties.put(PROVIDER_DISABLES_AUTOCOMMIT, "true");
|
||||
}
|
||||
|
||||
@@ -145,8 +145,7 @@ public class OAuth2ClientProperties {
|
||||
return this.clientAuthenticationMethod;
|
||||
}
|
||||
|
||||
public void setClientAuthenticationMethod(
|
||||
String clientAuthenticationMethod) {
|
||||
public void setClientAuthenticationMethod(String clientAuthenticationMethod) {
|
||||
this.clientAuthenticationMethod = clientAuthenticationMethod;
|
||||
}
|
||||
|
||||
@@ -154,8 +153,7 @@ public class OAuth2ClientProperties {
|
||||
return this.authorizationGrantType;
|
||||
}
|
||||
|
||||
public void setAuthorizationGrantType(
|
||||
String authorizationGrantType) {
|
||||
public void setAuthorizationGrantType(String authorizationGrantType) {
|
||||
this.authorizationGrantType = authorizationGrantType;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,8 @@ final class OAuth2ClientPropertiesRegistrationAdapter {
|
||||
public static Map<String, ClientRegistration> getClientRegistrations(
|
||||
OAuth2ClientProperties properties) {
|
||||
Map<String, ClientRegistration> clientRegistrations = new HashMap<>();
|
||||
properties.getRegistration().forEach((key, value) -> {
|
||||
clientRegistrations.put(key,
|
||||
getClientRegistration(key, value, properties.getProvider()));
|
||||
});
|
||||
properties.getRegistration().forEach((key, value) -> clientRegistrations.put(key,
|
||||
getClientRegistration(key, value, properties.getProvider())));
|
||||
return clientRegistrations;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @since 2.0.0
|
||||
* @see ErrorAttributes
|
||||
*/
|
||||
public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExceptionHandler, InitializingBean {
|
||||
public abstract class AbstractErrorWebExceptionHandler
|
||||
implements ErrorWebExceptionHandler, InitializingBean {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@@ -71,7 +72,8 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
this.errorAttributes = errorAttributes;
|
||||
this.resourceProperties = resourceProperties;
|
||||
this.applicationContext = applicationContext;
|
||||
this.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);
|
||||
this.templateAvailabilityProviders = new TemplateAvailabilityProviders(
|
||||
applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,13 +103,14 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the error attributes from the current request, to be used
|
||||
* to populate error views or JSON payloads.
|
||||
* Extract the error attributes from the current request, to be used to populate error
|
||||
* views or JSON payloads.
|
||||
* @param request the source request
|
||||
* @param includeStackTrace whether to include the error stacktrace information
|
||||
* @return the error attributes as a Map.
|
||||
*/
|
||||
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
|
||||
protected Map<String, Object> getErrorAttributes(ServerRequest request,
|
||||
boolean includeStackTrace) {
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace);
|
||||
}
|
||||
|
||||
@@ -117,16 +120,16 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the given error data as a view, using a template view if available
|
||||
* or a static HTML file if available otherwise. This will return an empty
|
||||
* Render the given error data as a view, using a template view if available or a
|
||||
* static HTML file if available otherwise. This will return an empty
|
||||
* {@code Publisher} if none of the above are available.
|
||||
* @param viewName the view name
|
||||
* @param responseBody the error response being built
|
||||
* @param error the error data as a map
|
||||
* @return a Publisher of the {@link ServerResponse}
|
||||
*/
|
||||
protected Mono<ServerResponse> renderErrorView(String viewName, ServerResponse.BodyBuilder responseBody,
|
||||
Map<String, Object> error) {
|
||||
protected Mono<ServerResponse> renderErrorView(String viewName,
|
||||
ServerResponse.BodyBuilder responseBody, Map<String, Object> error) {
|
||||
if (isTemplateAvailable(viewName)) {
|
||||
return responseBody.render(viewName, error);
|
||||
}
|
||||
@@ -138,7 +141,8 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
}
|
||||
|
||||
private boolean isTemplateAvailable(String viewName) {
|
||||
return this.templateAvailabilityProviders.getProvider(viewName, this.applicationContext) != null;
|
||||
return this.templateAvailabilityProviders.getProvider(viewName,
|
||||
this.applicationContext) != null;
|
||||
}
|
||||
|
||||
private Resource resolveResource(String viewName) {
|
||||
@@ -158,23 +162,23 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
|
||||
/**
|
||||
* Render a default HTML "Whitelabel Error Page".
|
||||
* <p>Useful when no other error view is available in the application.
|
||||
* <p>
|
||||
* Useful when no other error view is available in the application.
|
||||
* @param responseBody the error response being built
|
||||
* @param error the error data as a map
|
||||
* @return a Publisher of the {@link ServerResponse}
|
||||
*/
|
||||
protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,
|
||||
Map<String, Object> error) {
|
||||
protected Mono<ServerResponse> renderDefaultErrorView(
|
||||
ServerResponse.BodyBuilder responseBody, Map<String, Object> error) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Date timestamp = (Date) error.get("timestamp");
|
||||
builder.append("<html><body><h1>Whitelabel Error Page</h1>")
|
||||
.append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>")
|
||||
.append("<div id='created'>").append(timestamp.toString()).append("</div>")
|
||||
.append("<div>There was an unexpected error (type=")
|
||||
.append(error.get("error")).append(", status=").append(error.get("status"))
|
||||
.append(").</div>")
|
||||
.append("<div>").append(error.get("message")).append("</div>")
|
||||
.append("</body></html>");
|
||||
.append("<div id='created'>").append(timestamp.toString())
|
||||
.append("</div>").append("<div>There was an unexpected error (type=")
|
||||
.append(error.get("error")).append(", status=")
|
||||
.append(error.get("status")).append(").</div>").append("<div>")
|
||||
.append(error.get("message")).append("</div>").append("</body></html>");
|
||||
return responseBody.syncBody(builder.toString());
|
||||
}
|
||||
|
||||
@@ -188,27 +192,31 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
/**
|
||||
* Create a {@link RouterFunction} that can route and handle errors as JSON responses
|
||||
* or HTML views.
|
||||
* <p>If the returned {@link RouterFunction} doesn't route to a {@code HandlerFunction},
|
||||
* <p>
|
||||
* If the returned {@link RouterFunction} doesn't route to a {@code HandlerFunction},
|
||||
* the original exception is propagated in the pipeline and can be processed by other
|
||||
* {@link org.springframework.web.server.WebExceptionHandler}s.
|
||||
* @param errorAttributes the {@code ErrorAttributes} instance to use to extract error information
|
||||
* @param errorAttributes the {@code ErrorAttributes} instance to use to extract error
|
||||
* information
|
||||
* @return a {@link RouterFunction} that routes and handles errors
|
||||
*/
|
||||
protected abstract RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes);
|
||||
protected abstract RouterFunction<ServerResponse> getRoutingFunction(
|
||||
ErrorAttributes errorAttributes);
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
|
||||
|
||||
this.errorAttributes.storeErrorInformation(throwable, exchange);
|
||||
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
|
||||
return getRoutingFunction(this.errorAttributes)
|
||||
.route(request)
|
||||
return getRoutingFunction(this.errorAttributes).route(request)
|
||||
.switchIfEmpty(Mono.error(throwable))
|
||||
.flatMap(handler -> handler.handle(request))
|
||||
.flatMap(response -> {
|
||||
// force content-type since writeTo won't overwrite response header values
|
||||
exchange.getResponse().getHeaders().setContentType(response.headers().getContentType());
|
||||
.flatMap((handler) -> handler.handle(request)).flatMap((response) -> {
|
||||
// force content-type since writeTo won't overwrite response header
|
||||
// values
|
||||
exchange.getResponse().getHeaders()
|
||||
.setContentType(response.headers().getContentType());
|
||||
return response.writeTo(exchange, new ServerResponse.Context() {
|
||||
|
||||
@Override
|
||||
public List<HttpMessageWriter<?>> messageWriters() {
|
||||
return AbstractErrorWebExceptionHandler.this.messageWriters;
|
||||
@@ -218,7 +226,9 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
public List<ViewResolver> viewResolvers() {
|
||||
return AbstractErrorWebExceptionHandler.this.viewResolvers;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request,
|
||||
boolean includeStackTrace) {
|
||||
Map<String, Object> errorAttributes = new LinkedHashMap<>();
|
||||
errorAttributes.put("timestamp", new Date());
|
||||
errorAttributes.put("path", request.path());
|
||||
@@ -90,7 +91,8 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
||||
}
|
||||
else {
|
||||
errorAttributes.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
errorAttributes.put("error", HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
|
||||
errorAttributes.put("error",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
|
||||
}
|
||||
return errorAttributes;
|
||||
}
|
||||
@@ -115,7 +117,8 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
||||
@Override
|
||||
public Throwable getError(ServerRequest request) {
|
||||
return (Throwable) request.attribute(ERROR_ATTRIBUTE)
|
||||
.orElseThrow(() -> new IllegalStateException("Missing exception attribute in ServerWebExchange"));
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
"Missing exception attribute in ServerWebExchange"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,20 +37,20 @@ import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Basic global {@link org.springframework.web.server.WebExceptionHandler},
|
||||
* rendering {@link ErrorAttributes}.
|
||||
* Basic global {@link org.springframework.web.server.WebExceptionHandler}, rendering
|
||||
* {@link ErrorAttributes}.
|
||||
*
|
||||
* <p>More specific errors can be handled either using Spring WebFlux abstractions
|
||||
* (e.g. {@code @ExceptionHandler} with the annotation model) or by adding
|
||||
* <p>
|
||||
* More specific errors can be handled either using Spring WebFlux abstractions (e.g.
|
||||
* {@code @ExceptionHandler} with the annotation model) or by adding
|
||||
* {@link RouterFunction} to the chain.
|
||||
*
|
||||
* <p>This implementation will render error as HTML views if the client explicitly
|
||||
* supports that media type. It attempts to resolve error views
|
||||
* using well known conventions. Will search for templates and static assets under
|
||||
* {@code '/error'} using the {@link HttpStatus status code} and the
|
||||
* {@link HttpStatus#series() status series}.
|
||||
* <p>
|
||||
* This implementation will render error as HTML views if the client explicitly supports
|
||||
* that media type. It attempts to resolve error views using well known conventions. Will
|
||||
* search for templates and static assets under {@code '/error'} using the
|
||||
* {@link HttpStatus status code} and the {@link HttpStatus#series() status series}.
|
||||
* <p>
|
||||
* For example, an {@code HTTP 404} will search (in the specific order):
|
||||
* <ul>
|
||||
@@ -62,10 +62,12 @@ import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
* <li>{@code '/<static>/error/error.html'}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If none found, a default "Whitelabel Error" HTML view will be rendered.
|
||||
* <p>
|
||||
* If none found, a default "Whitelabel Error" HTML view will be rendered.
|
||||
*
|
||||
* <p>If the client doesn't support HTML, the error information will be rendered
|
||||
* as a JSON payload.
|
||||
* <p>
|
||||
* If the client doesn't support HTML, the error information will be rendered as a JSON
|
||||
* payload.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 2.0.0
|
||||
@@ -99,10 +101,10 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
|
||||
protected RouterFunction<ServerResponse> getRoutingFunction(
|
||||
ErrorAttributes errorAttributes) {
|
||||
|
||||
return RouterFunctions
|
||||
.route(acceptsTextHtml(), this::renderErrorView)
|
||||
return RouterFunctions.route(acceptsTextHtml(), this::renderErrorView)
|
||||
.andRoute(RequestPredicates.all(), this::renderErrorResponse);
|
||||
}
|
||||
|
||||
@@ -119,12 +121,11 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
ServerResponse.BodyBuilder response = ServerResponse.status(errorStatus)
|
||||
.contentType(MediaType.TEXT_HTML);
|
||||
|
||||
return Flux.just("error/" + errorStatus.toString(),
|
||||
"error/" + SERIES_VIEWS.get(errorStatus.series()),
|
||||
"error/error")
|
||||
.flatMap(viewName -> renderErrorView(viewName, response, error))
|
||||
.switchIfEmpty(renderDefaultErrorView(response, error))
|
||||
.next();
|
||||
return Flux
|
||||
.just("error/" + errorStatus.toString(),
|
||||
"error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error")
|
||||
.flatMap((viewName) -> renderErrorView(viewName, response, error))
|
||||
.switchIfEmpty(renderDefaultErrorView(response, error)).next();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,9 +147,9 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the stacktrace attribute should be included
|
||||
*/
|
||||
protected boolean isIncludeStackTrace(ServerRequest request,
|
||||
MediaType produces) {
|
||||
ErrorProperties.IncludeStacktrace include = this.errorProperties.getIncludeStacktrace();
|
||||
protected boolean isIncludeStackTrace(ServerRequest request, MediaType produces) {
|
||||
ErrorProperties.IncludeStacktrace include = this.errorProperties
|
||||
.getIncludeStacktrace();
|
||||
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
|
||||
return true;
|
||||
}
|
||||
@@ -169,17 +170,19 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate that checks whether the current request
|
||||
* explicitly support {@code "text/html"} media type.
|
||||
* <p>The "match-all" media type is not considered here.
|
||||
* Predicate that checks whether the current request explicitly support
|
||||
* {@code "text/html"} media type.
|
||||
* <p>
|
||||
* The "match-all" media type is not considered here.
|
||||
* @return the request predicate
|
||||
*/
|
||||
protected RequestPredicate acceptsTextHtml() {
|
||||
return serverRequest -> {
|
||||
return (serverRequest) -> {
|
||||
List<MediaType> acceptedMediaTypes = serverRequest.headers().accept();
|
||||
acceptedMediaTypes.remove(MediaType.ALL);
|
||||
MediaType.sortBySpecificityAndQuality(acceptedMediaTypes);
|
||||
return acceptedMediaTypes.stream().anyMatch(MediaType.TEXT_HTML::isCompatibleWith);
|
||||
return acceptedMediaTypes.stream()
|
||||
.anyMatch(MediaType.TEXT_HTML::isCompatibleWith);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,12 @@ public interface ErrorAttributes {
|
||||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @return a map of error attributes
|
||||
*/
|
||||
Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace);
|
||||
Map<String, Object> getErrorAttributes(ServerRequest request,
|
||||
boolean includeStackTrace);
|
||||
|
||||
/**
|
||||
* Return the underlying cause of the error or {@code null} if the error
|
||||
* cannot be extracted.
|
||||
* Return the underlying cause of the error or {@code null} if the error cannot be
|
||||
* extracted.
|
||||
* @param request the source ServerRequest
|
||||
* @return the {@link Exception} that caused the error or {@code null}
|
||||
*/
|
||||
|
||||
@@ -19,12 +19,13 @@ package org.springframework.boot.autoconfigure.web.reactive.error;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
|
||||
/**
|
||||
* Marker interface that indicates that a {@link WebExceptionHandler}
|
||||
* is used to render errors.
|
||||
* Marker interface that indicates that a {@link WebExceptionHandler} is used to render
|
||||
* errors.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ErrorWebExceptionHandler extends WebExceptionHandler {
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to render errors via a
|
||||
* WebFlux {@link org.springframework.web.server.WebExceptionHandler}.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to render errors via a WebFlux
|
||||
* {@link org.springframework.web.server.WebExceptionHandler}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 2.0.0
|
||||
@@ -49,7 +49,7 @@ import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
@ConditionalOnClass(WebFluxConfigurer.class)
|
||||
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
|
||||
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
|
||||
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class })
|
||||
public class ErrorWebFluxAutoConfiguration {
|
||||
|
||||
private final ServerProperties serverProperties;
|
||||
@@ -70,17 +70,19 @@ public class ErrorWebFluxAutoConfiguration {
|
||||
this.serverProperties = serverProperties;
|
||||
this.applicationContext = applicationContext;
|
||||
this.resourceProperties = resourceProperties;
|
||||
this.viewResolvers = viewResolversProvider.getIfAvailable(() -> Collections.emptyList());
|
||||
this.viewResolvers = viewResolversProvider
|
||||
.getIfAvailable(() -> Collections.emptyList());
|
||||
this.serverCodecConfigurer = serverCodecConfigurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
|
||||
@Order(-1)
|
||||
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
|
||||
DefaultErrorWebExceptionHandler exceptionHandler =
|
||||
new DefaultErrorWebExceptionHandler(errorAttributes, this.resourceProperties,
|
||||
this.serverProperties.getError(), this.applicationContext);
|
||||
public ErrorWebExceptionHandler errorWebExceptionHandler(
|
||||
ErrorAttributes errorAttributes) {
|
||||
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(
|
||||
errorAttributes, this.resourceProperties,
|
||||
this.serverProperties.getError(), this.applicationContext);
|
||||
exceptionHandler.setViewResolvers(this.viewResolvers);
|
||||
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
|
||||
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
|
||||
@@ -90,7 +92,8 @@ public class ErrorWebFluxAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
|
||||
public DefaultErrorAttributes errorAttributes() {
|
||||
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
|
||||
return new DefaultErrorAttributes(
|
||||
this.serverProperties.getError().isIncludeException());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for for Spring WebFlux error handling.
|
||||
* Auto-configuration for Spring WebFlux error handling.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.web.reactive.error;
|
||||
|
||||
@@ -166,7 +166,7 @@ public class DataSourceInitializerInvokerTests {
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableApplicationContext> assertInitializationIsDisabled() {
|
||||
return context -> {
|
||||
return (context) -> {
|
||||
assertThat(context).hasSingleBean(DataSource.class);
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
context.publishEvent(new DataSourceSchemaCreatedEvent(dataSource));
|
||||
|
||||
@@ -77,12 +77,12 @@ public class HibernateJpaAutoConfigurationTests
|
||||
contextRunner().withPropertyValues("spring.datasource.data:classpath:/city.sql",
|
||||
// Missing:
|
||||
"spring.datasource.schema:classpath:/ddl.sql").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context.getStartupFailure())
|
||||
.hasMessageContaining("ddl.sql");
|
||||
assertThat(context.getStartupFailure())
|
||||
.hasMessageContaining("spring.datasource.schema");
|
||||
});
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context.getStartupFailure())
|
||||
.hasMessageContaining("ddl.sql");
|
||||
assertThat(context.getStartupFailure())
|
||||
.hasMessageContaining("spring.datasource.schema");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,7 +107,7 @@ public class HibernateJpaAutoConfigurationTests
|
||||
"spring.datasource.data:classpath:/city.sql")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(TestInitializedJpaConfiguration.class).called)
|
||||
.isTrue());
|
||||
.isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,7 +166,7 @@ public class HibernateJpaAutoConfigurationTests
|
||||
.getJpaPropertyMap();
|
||||
assertThat((String) jpaPropertyMap
|
||||
.get("hibernate.transaction.jta.platform"))
|
||||
.isEqualTo(TestJtaPlatform.class.getName());
|
||||
.isEqualTo(TestJtaPlatform.class.getName());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,12 +201,12 @@ public class HibernateJpaAutoConfigurationTests
|
||||
contextRunner().withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.auto-commit:false").run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).contains(entry(
|
||||
"hibernate.connection.provider_disables_autocommit", "true"));
|
||||
});
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).contains(entry(
|
||||
"hibernate.connection.provider_disables_autocommit", "true"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -214,27 +214,29 @@ public class HibernateJpaAutoConfigurationTests
|
||||
contextRunner().withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.auto-commit:true").run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKeys(
|
||||
"hibernate.connection.provider_disables_autocommit");
|
||||
});
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKeys(
|
||||
"hibernate.connection.provider_disables_autocommit");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerDisablesAutoCommitIsNotConfiguredIfPropertyIsSet() {
|
||||
contextRunner().withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.auto-commit:false",
|
||||
"spring.jpa.properties.hibernate.connection.provider_disables_autocommit=false"
|
||||
).run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).contains(entry(
|
||||
"hibernate.connection.provider_disables_autocommit", "false"));
|
||||
});
|
||||
contextRunner()
|
||||
.withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.auto-commit:false",
|
||||
"spring.jpa.properties.hibernate.connection.provider_disables_autocommit=false")
|
||||
.run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).contains(
|
||||
entry("hibernate.connection.provider_disables_autocommit",
|
||||
"false"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -243,13 +245,14 @@ public class HibernateJpaAutoConfigurationTests
|
||||
.withConfiguration(AutoConfigurations.of(JtaAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.datasource.type:" + HikariDataSource.class.getName(),
|
||||
"spring.datasource.hikari.auto-commit:false").run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKeys(
|
||||
"hibernate.connection.provider_disables_autocommit");
|
||||
});
|
||||
"spring.datasource.hikari.auto-commit:false")
|
||||
.run((context) -> {
|
||||
Map<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKeys(
|
||||
"hibernate.connection.provider_disables_autocommit");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -41,7 +41,7 @@ public class OAuth2ClientRegistrationRepositoryConfigurationTests {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(
|
||||
OAuth2ClientRegistrationRepositoryConfiguration.class)
|
||||
.run(context -> assertThat(context)
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ClientRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class OAuth2ClientRegistrationRepositoryConfigurationTests {
|
||||
.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd",
|
||||
REGISTRATION_PREFIX + ".foo.client-secret=secret",
|
||||
REGISTRATION_PREFIX + ".foo.provider=github")
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
ClientRegistrationRepository repository = context
|
||||
.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistration registration = repository
|
||||
|
||||
@@ -54,8 +54,7 @@ public class SessionAutoConfigurationJdbcTests
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class,
|
||||
JdbcTemplateAutoConfiguration.class,
|
||||
SessionAutoConfiguration.class))
|
||||
JdbcTemplateAutoConfiguration.class, SessionAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||
|
||||
@Test
|
||||
|
||||
@@ -49,20 +49,23 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class DefaultErrorAttributesTests {
|
||||
|
||||
private static final ResponseStatusException NOT_FOUND = new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||
private static final ResponseStatusException NOT_FOUND = new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND);
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes();
|
||||
|
||||
private List<HttpMessageReader<?>> readers = ServerCodecConfigurer.create().getReaders();
|
||||
private List<HttpMessageReader<?>> readers = ServerCodecConfigurer.create()
|
||||
.getReaders();
|
||||
|
||||
@Test
|
||||
public void missingExceptionAttribute() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Missing exception attribute in ServerWebExchange");
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test").build());
|
||||
MockServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/test").build());
|
||||
ServerRequest request = ServerRequest.create(exchange, this.readers);
|
||||
this.errorAttributes.getErrorAttributes(request, false);
|
||||
}
|
||||
@@ -117,7 +120,8 @@ public class DefaultErrorAttributesTests {
|
||||
Map<String, Object> attributes = this.errorAttributes
|
||||
.getErrorAttributes(serverRequest, false);
|
||||
assertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);
|
||||
assertThat(attributes.get("exception")).isEqualTo(RuntimeException.class.getName());
|
||||
assertThat(attributes.get("exception"))
|
||||
.isEqualTo(RuntimeException.class.getName());
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
}
|
||||
|
||||
@@ -160,14 +164,15 @@ public class DefaultErrorAttributesTests {
|
||||
Map<String, Object> attributes = this.errorAttributes
|
||||
.getErrorAttributes(buildServerRequest(request, ex), false);
|
||||
|
||||
assertThat(attributes.get("message"))
|
||||
.asString().startsWith("Validation failed for argument at index 0 in method: " +
|
||||
"public int org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorAttributesTests" +
|
||||
".method(java.lang.String), with 1 error(s)");
|
||||
assertThat(attributes.get("message")).asString()
|
||||
.startsWith("Validation failed for argument at index 0 in method: "
|
||||
+ "public int org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorAttributesTests"
|
||||
+ ".method(java.lang.String), with 1 error(s)");
|
||||
assertThat(attributes.get("errors")).isEqualTo(bindingResult.getAllErrors());
|
||||
}
|
||||
|
||||
private ServerRequest buildServerRequest(MockServerHttpRequest request, Throwable error) {
|
||||
private ServerRequest buildServerRequest(MockServerHttpRequest request,
|
||||
Throwable error) {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||
this.errorAttributes.storeErrorInformation(error, exchange);
|
||||
return ServerRequest.create(exchange, this.readers);
|
||||
|
||||
@@ -74,51 +74,45 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
@Test
|
||||
public void jsonError() throws Exception {
|
||||
load();
|
||||
this.webTestClient.get().uri("/").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectBody().jsonPath("status").isEqualTo("500")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
.jsonPath("path").isEqualTo(("/"))
|
||||
.jsonPath("message").isEqualTo("Expected!")
|
||||
.jsonPath("exception").doesNotExist()
|
||||
this.webTestClient.get().uri("/").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody()
|
||||
.jsonPath("status").isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
.jsonPath("path").isEqualTo(("/")).jsonPath("message")
|
||||
.isEqualTo("Expected!").jsonPath("exception").doesNotExist()
|
||||
.jsonPath("trace").doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFound() throws Exception {
|
||||
load();
|
||||
this.webTestClient.get().uri("/notFound").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.NOT_FOUND)
|
||||
.expectBody().jsonPath("status").isEqualTo("404")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase())
|
||||
.jsonPath("path").isEqualTo(("/notFound"))
|
||||
.jsonPath("exception").doesNotExist();
|
||||
this.webTestClient.get().uri("/notFound").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.NOT_FOUND).expectBody().jsonPath("status")
|
||||
.isEqualTo("404").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase()).jsonPath("path")
|
||||
.isEqualTo(("/notFound")).jsonPath("exception").doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void htmlError() throws Exception {
|
||||
load();
|
||||
String body = this.webTestClient.get().uri("/").accept(MediaType.TEXT_HTML).exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectHeader().contentType(MediaType.TEXT_HTML)
|
||||
.expectBody(String.class).returnResult().getResponseBody();
|
||||
String body = this.webTestClient.get().uri("/").accept(MediaType.TEXT_HTML)
|
||||
.exchange().expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectHeader().contentType(MediaType.TEXT_HTML).expectBody(String.class)
|
||||
.returnResult().getResponseBody();
|
||||
assertThat(body).contains("status: 500").contains("message: Expected!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindingResultError() throws Exception {
|
||||
load();
|
||||
this.webTestClient.post().uri("/bind")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.syncBody("{}")
|
||||
.exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.BAD_REQUEST)
|
||||
.expectBody().jsonPath("status").isEqualTo("400")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())
|
||||
.jsonPath("path").isEqualTo(("/bind"))
|
||||
.jsonPath("exception").doesNotExist()
|
||||
.jsonPath("errors").isArray()
|
||||
.jsonPath("message").isNotEmpty();
|
||||
this.webTestClient.post().uri("/bind").contentType(MediaType.APPLICATION_JSON)
|
||||
.syncBody("{}").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST).expectBody().jsonPath("status")
|
||||
.isEqualTo("400").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("path")
|
||||
.isEqualTo(("/bind")).jsonPath("exception").doesNotExist()
|
||||
.jsonPath("errors").isArray().jsonPath("message").isNotEmpty();
|
||||
|
||||
}
|
||||
|
||||
@@ -126,10 +120,10 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
public void includeStackTraceOnParam() throws Exception {
|
||||
load("--server.error.include-exception=true",
|
||||
"--server.error.include-stacktrace=on-trace-param");
|
||||
this.webTestClient.get().uri("/?trace=true").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectBody().jsonPath("status").isEqualTo("500")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
this.webTestClient.get().uri("/?trace=true").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody()
|
||||
.jsonPath("status").isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
.jsonPath("exception").isEqualTo(IllegalStateException.class.getName())
|
||||
.jsonPath("trace").exists();
|
||||
}
|
||||
@@ -138,10 +132,10 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
public void alwaysIncludeStackTrace() throws Exception {
|
||||
load("--server.error.include-exception=true",
|
||||
"--server.error.include-stacktrace=always");
|
||||
this.webTestClient.get().uri("/?trace=false").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectBody().jsonPath("status").isEqualTo("500")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
this.webTestClient.get().uri("/?trace=false").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody()
|
||||
.jsonPath("status").isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
.jsonPath("exception").isEqualTo(IllegalStateException.class.getName())
|
||||
.jsonPath("trace").exists();
|
||||
}
|
||||
@@ -150,10 +144,10 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
public void neverIncludeStackTrace() throws Exception {
|
||||
load("--server.error.include-exception=true",
|
||||
"--server.error.include-stacktrace=never");
|
||||
this.webTestClient.get().uri("/?trace=true").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectBody().jsonPath("status").isEqualTo("500")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
this.webTestClient.get().uri("/?trace=true").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody()
|
||||
.jsonPath("status").isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
|
||||
.jsonPath("exception").isEqualTo(IllegalStateException.class.getName())
|
||||
.jsonPath("trace").doesNotExist();
|
||||
}
|
||||
@@ -161,21 +155,22 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
@Test
|
||||
public void statusException() throws Exception {
|
||||
load("--server.error.include-exception=true");
|
||||
this.webTestClient.get().uri("/badRequest").exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.BAD_REQUEST)
|
||||
.expectBody().jsonPath("status").isEqualTo("400")
|
||||
.jsonPath("error").isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())
|
||||
.jsonPath("exception").isEqualTo(ResponseStatusException.class.getName());
|
||||
this.webTestClient.get().uri("/badRequest").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST).expectBody().jsonPath("status")
|
||||
.isEqualTo("400").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("exception")
|
||||
.isEqualTo(ResponseStatusException.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultErrorView() throws Exception {
|
||||
load("--spring.mustache.prefix=classpath:/unknown/");
|
||||
String body = this.webTestClient.get().uri("/").accept(MediaType.TEXT_HTML).exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectHeader().contentType(MediaType.TEXT_HTML)
|
||||
.expectBody(String.class).returnResult().getResponseBody();
|
||||
assertThat(body).contains("Whitelabel Error Page").contains("<div>Expected!</div>");
|
||||
String body = this.webTestClient.get().uri("/").accept(MediaType.TEXT_HTML)
|
||||
.exchange().expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.expectHeader().contentType(MediaType.TEXT_HTML).expectBody(String.class)
|
||||
.returnResult().getResponseBody();
|
||||
assertThat(body).contains("Whitelabel Error Page")
|
||||
.contains("<div>Expected!</div>");
|
||||
}
|
||||
|
||||
private void load(String... arguments) {
|
||||
@@ -193,9 +188,10 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ReactiveWebServerAutoConfiguration.class, HttpHandlerAutoConfiguration.class,
|
||||
WebFluxAutoConfiguration.class, ErrorWebFluxAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class})
|
||||
@Import({ ReactiveWebServerAutoConfiguration.class,
|
||||
HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||
ErrorWebFluxAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
private @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -51,15 +51,14 @@ public class TestDatabaseAutoConfigurationNoEmbeddedTests {
|
||||
|
||||
@Test
|
||||
public void applyAnyReplace() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).getFailure().isInstanceOf(BeanCreationException.class)
|
||||
.hasMessageContaining(
|
||||
"Failed to replace DataSource with an embedded database for tests.")
|
||||
.hasMessageContaining(
|
||||
"If you want an embedded database please put a supported one on the classpath")
|
||||
.hasMessageContaining(
|
||||
"or tune the replace attribute of @AutoconfigureTestDatabase.");
|
||||
});
|
||||
this.contextRunner.run((context) -> assertThat(context).getFailure()
|
||||
.isInstanceOf(BeanCreationException.class)
|
||||
.hasMessageContaining(
|
||||
"Failed to replace DataSource with an embedded database for tests.")
|
||||
.hasMessageContaining(
|
||||
"If you want an embedded database please put a supported one on the classpath")
|
||||
.hasMessageContaining(
|
||||
"or tune the replace attribute of @AutoconfigureTestDatabase."));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -72,9 +72,9 @@ public interface DataSourcePoolMetadata {
|
||||
String getValidationQuery();
|
||||
|
||||
/**
|
||||
* The default auto-commit state of connections created by this pool.
|
||||
* If not set ({@code null}), default is JDBC driver default
|
||||
* (If set to null then the java.sql.Connection.setAutoCommit(boolean) method will not be called.)
|
||||
* The default auto-commit state of connections created by this pool. If not set
|
||||
* ({@code null}), default is JDBC driver default (If set to null then the
|
||||
* java.sql.Connection.setAutoCommit(boolean) method will not be called.)
|
||||
* @return the default auto-commit state or {@code null}
|
||||
*/
|
||||
Boolean getDefaultAutoCommit();
|
||||
|
||||
@@ -85,8 +85,9 @@ public class CommonsDbcp2DataSourcePoolMetadataTests
|
||||
public void getDefaultAutoCommit() {
|
||||
BasicDataSource dataSource = createDataSource();
|
||||
dataSource.setDefaultAutoCommit(false);
|
||||
assertThat(new CommonsDbcp2DataSourcePoolMetadata(dataSource)
|
||||
.getDefaultAutoCommit()).isFalse();
|
||||
assertThat(
|
||||
new CommonsDbcp2DataSourcePoolMetadata(dataSource).getDefaultAutoCommit())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
private CommonsDbcp2DataSourcePoolMetadata createDataSourceMetadata(int minSize,
|
||||
|
||||
@@ -51,7 +51,8 @@ public class MustacheViewTests {
|
||||
|
||||
@Test
|
||||
public void viewResolvesHandlebars() throws Exception {
|
||||
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test").build());
|
||||
this.exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/test").build());
|
||||
MustacheView view = new MustacheView();
|
||||
view.setCompiler(Mustache.compiler());
|
||||
view.setUrl(this.templateUrl);
|
||||
|
||||
Reference in New Issue
Block a user