parent
9c7b5cb3f5
commit
61eaa9333b
|
|
@ -64,6 +64,9 @@ public interface ErrorResponse {
|
|||
*/
|
||||
ProblemDetail getBody();
|
||||
|
||||
|
||||
// MessageSource codes and arguments
|
||||
|
||||
/**
|
||||
* Return a code to use to resolve the problem "type" for this exception
|
||||
* through a {@link MessageSource}. The type resolved through the
|
||||
|
|
@ -76,6 +79,15 @@ public interface ErrorResponse {
|
|||
return getDefaultTypeMessageCode(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a code to use to resolve the problem "title" for this exception
|
||||
* through a {@link MessageSource}.
|
||||
* <p>By default this is initialized via {@link #getDefaultTitleMessageCode(Class)}.
|
||||
*/
|
||||
default String getTitleMessageCode() {
|
||||
return getDefaultTitleMessageCode(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a code to use to resolve the problem "detail" for this exception
|
||||
* through a {@link MessageSource}.
|
||||
|
|
@ -111,15 +123,6 @@ public interface ErrorResponse {
|
|||
return getDetailMessageArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a code to use to resolve the problem "title" for this exception
|
||||
* through a {@link MessageSource}.
|
||||
* <p>By default this is initialized via {@link #getDefaultTitleMessageCode(Class)}.
|
||||
*/
|
||||
default String getTitleMessageCode() {
|
||||
return getDefaultTitleMessageCode(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link MessageSource} to resolve the
|
||||
* {@link #getTypeMessageCode() type}, {@link #getTitleMessageCode() title},
|
||||
|
|
@ -159,6 +162,16 @@ public interface ErrorResponse {
|
|||
return "problemDetail.type." + exceptionType.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a message code for the "title" field, for the given exception type.
|
||||
* @param exceptionType the exception type associated with the problem
|
||||
* @return {@code "problemDetail.title."} followed by the fully qualified
|
||||
* {@link Class#getName() class name}
|
||||
*/
|
||||
static String getDefaultTitleMessageCode(Class<?> exceptionType) {
|
||||
return "problemDetail.title." + exceptionType.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a message code for the "detail" field, for the given exception type.
|
||||
* @param exceptionType the exception type associated with the problem
|
||||
|
|
@ -171,15 +184,6 @@ public interface ErrorResponse {
|
|||
return "problemDetail." + exceptionType.getName() + (suffix != null ? "." + suffix : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a message code for the "title" field, for the given exception type.
|
||||
* @param exceptionType the exception type associated with the problem
|
||||
* @return {@code "problemDetail.title."} followed by the fully qualified
|
||||
* {@link Class#getName() class name}
|
||||
*/
|
||||
static String getDefaultTitleMessageCode(Class<?> exceptionType) {
|
||||
return "problemDetail.title." + exceptionType.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to build an instance via
|
||||
|
|
@ -229,33 +233,6 @@ public interface ErrorResponse {
|
|||
*/
|
||||
Builder headers(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Set the underlying {@link ProblemDetail#setDetail(String) detail}.
|
||||
* @return the same builder instance
|
||||
*/
|
||||
Builder detail(String detail);
|
||||
|
||||
/**
|
||||
* Customize the {@link MessageSource} code for looking up the value for
|
||||
* the underlying {@link #detail(String) detail}.
|
||||
* <p>By default, this is set to
|
||||
* {@link ErrorResponse#getDefaultDetailMessageCode(Class, String)} with the
|
||||
* associated Exception type.
|
||||
* @param messageCode the message code to use
|
||||
* @return the same builder instance
|
||||
* @see ErrorResponse#getDetailMessageCode()
|
||||
*/
|
||||
Builder detailMessageCode(String messageCode);
|
||||
|
||||
/**
|
||||
* Set the arguments to provide to the {@link MessageSource} lookup for
|
||||
* {@link #detailMessageCode(String)}.
|
||||
* @param messageArguments the arguments to provide
|
||||
* @return the same builder instance
|
||||
* @see ErrorResponse#getDetailMessageArguments()
|
||||
*/
|
||||
Builder detailMessageArguments(Object... messageArguments);
|
||||
|
||||
/**
|
||||
* Set the underlying {@link ProblemDetail#setType(URI) type} field.
|
||||
* @return the same builder instance
|
||||
|
|
@ -286,6 +263,33 @@ public interface ErrorResponse {
|
|||
*/
|
||||
Builder instance(@Nullable URI instance);
|
||||
|
||||
/**
|
||||
* Set the underlying {@link ProblemDetail#setDetail(String) detail}.
|
||||
* @return the same builder instance
|
||||
*/
|
||||
Builder detail(String detail);
|
||||
|
||||
/**
|
||||
* Customize the {@link MessageSource} code for looking up the value for
|
||||
* the underlying {@link #detail(String) detail}.
|
||||
* <p>By default, this is set to
|
||||
* {@link ErrorResponse#getDefaultDetailMessageCode(Class, String)} with the
|
||||
* associated Exception type.
|
||||
* @param messageCode the message code to use
|
||||
* @return the same builder instance
|
||||
* @see ErrorResponse#getDetailMessageCode()
|
||||
*/
|
||||
Builder detailMessageCode(String messageCode);
|
||||
|
||||
/**
|
||||
* Set the arguments to provide to the {@link MessageSource} lookup for
|
||||
* {@link #detailMessageCode(String)}.
|
||||
* @param messageArguments the arguments to provide
|
||||
* @return the same builder instance
|
||||
* @see ErrorResponse#getDetailMessageArguments()
|
||||
*/
|
||||
Builder detailMessageArguments(Object... messageArguments);
|
||||
|
||||
/**
|
||||
* Set a "dynamic" {@link ProblemDetail#setProperty(String, Object)
|
||||
* property} on the underlying {@code ProblemDetail}.
|
||||
|
|
|
|||
|
|
@ -127,37 +127,35 @@ public class ResponseEntityExceptionHandlerTests {
|
|||
|
||||
@Test
|
||||
void errorResponseProblemDetailViaMessageSource() {
|
||||
|
||||
Locale locale = Locale.UK;
|
||||
LocaleContextHolder.setLocale(locale);
|
||||
|
||||
String type = "https://example.com/probs/unsupported-content";
|
||||
String title = "Media type is not valid or not supported";
|
||||
Class<UnsupportedMediaTypeStatusException> exceptionType = UnsupportedMediaTypeStatusException.class;
|
||||
|
||||
StaticMessageSource messageSource = new StaticMessageSource();
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultDetailMessageCode(UnsupportedMediaTypeStatusException.class, null), locale,
|
||||
StaticMessageSource source = new StaticMessageSource();
|
||||
source.addMessage(ErrorResponse.getDefaultTypeMessageCode(exceptionType), locale, type);
|
||||
source.addMessage(ErrorResponse.getDefaultTitleMessageCode(exceptionType), locale, title);
|
||||
source.addMessage(ErrorResponse.getDefaultDetailMessageCode(exceptionType, null), locale,
|
||||
"Content-Type {0} not supported. Supported: {1}");
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultTitleMessageCode(UnsupportedMediaTypeStatusException.class), locale, title);
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultTypeMessageCode(UnsupportedMediaTypeStatusException.class), locale, type);
|
||||
|
||||
this.exceptionHandler.setMessageSource(messageSource);
|
||||
this.exceptionHandler.setMessageSource(source);
|
||||
|
||||
Exception ex = new UnsupportedMediaTypeStatusException(MediaType.APPLICATION_JSON,
|
||||
List.of(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML));
|
||||
Exception ex = new UnsupportedMediaTypeStatusException(
|
||||
MediaType.APPLICATION_JSON, List.of(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML));
|
||||
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(
|
||||
MockServerHttpRequest.get("/").acceptLanguageAsLocales(locale).build());
|
||||
|
||||
ResponseEntity<?> responseEntity = this.exceptionHandler.handleException(ex, exchange).block();
|
||||
assertThat(responseEntity).isNotNull();
|
||||
|
||||
ProblemDetail body = (ProblemDetail) responseEntity.getBody();
|
||||
assertThat(body.getDetail()).isEqualTo(
|
||||
ProblemDetail problem = (ProblemDetail) responseEntity.getBody();
|
||||
assertThat(problem).isNotNull();
|
||||
assertThat(problem.getType()).isEqualTo(URI.create(type));
|
||||
assertThat(problem.getTitle()).isEqualTo(title);
|
||||
assertThat(problem.getDetail()).isEqualTo(
|
||||
"Content-Type application/json not supported. Supported: [application/atom+xml, application/xml]");
|
||||
assertThat(body.getTitle()).isEqualTo(title);
|
||||
assertThat(body.getType()).isEqualTo(URI.create(type));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -161,33 +161,31 @@ public class ResponseEntityExceptionHandlerTests {
|
|||
|
||||
@Test
|
||||
public void errorResponseProblemDetailViaMessageSource() {
|
||||
|
||||
Locale locale = Locale.UK;
|
||||
LocaleContextHolder.setLocale(locale);
|
||||
|
||||
String type = "https://example.com/probs/unsupported-content";
|
||||
String title = "Media type is not valid or not supported";
|
||||
|
||||
try {
|
||||
StaticMessageSource messageSource = new StaticMessageSource();
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultDetailMessageCode(HttpMediaTypeNotSupportedException.class, null), locale,
|
||||
"Content-Type {0} not supported. Supported: {1}");
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultTitleMessageCode(HttpMediaTypeNotSupportedException.class), locale, title);
|
||||
messageSource.addMessage(
|
||||
ErrorResponse.getDefaultTypeMessageCode(HttpMediaTypeNotSupportedException.class), locale, type);
|
||||
Locale locale = Locale.UK;
|
||||
LocaleContextHolder.setLocale(locale);
|
||||
|
||||
this.exceptionHandler.setMessageSource(messageSource);
|
||||
String type = "https://example.com/probs/unsupported-content";
|
||||
String title = "Media type is not valid or not supported";
|
||||
Class<HttpMediaTypeNotSupportedException> exceptionType = HttpMediaTypeNotSupportedException.class;
|
||||
|
||||
StaticMessageSource source = new StaticMessageSource();
|
||||
source.addMessage(ErrorResponse.getDefaultTypeMessageCode(exceptionType), locale, type);
|
||||
source.addMessage(ErrorResponse.getDefaultTitleMessageCode(exceptionType), locale, title);
|
||||
source.addMessage(ErrorResponse.getDefaultDetailMessageCode(exceptionType, null), locale,
|
||||
"Content-Type {0} not supported. Supported: {1}");
|
||||
|
||||
this.exceptionHandler.setMessageSource(source);
|
||||
|
||||
ResponseEntity<?> entity = testException(new HttpMediaTypeNotSupportedException(
|
||||
MediaType.APPLICATION_JSON, List.of(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML)));
|
||||
|
||||
ProblemDetail body = (ProblemDetail) entity.getBody();
|
||||
assertThat(body.getDetail()).isEqualTo(
|
||||
ProblemDetail problem = (ProblemDetail) entity.getBody();
|
||||
assertThat(problem).isNotNull();
|
||||
assertThat(problem.getType()).isEqualTo(URI.create(type));
|
||||
assertThat(problem.getTitle()).isEqualTo(title);
|
||||
assertThat(problem.getDetail()).isEqualTo(
|
||||
"Content-Type application/json not supported. Supported: [application/atom+xml, application/xml]");
|
||||
assertThat(body.getTitle()).isEqualTo(title);
|
||||
assertThat(body.getType()).isEqualTo(URI.create(type));
|
||||
}
|
||||
finally {
|
||||
LocaleContextHolder.resetLocaleContext();
|
||||
|
|
|
|||
Loading…
Reference in New Issue