diff --git a/belgif-rest-problem-it/belgif-rest-problem-codegen-it/pom.xml b/belgif-rest-problem-it/belgif-rest-problem-codegen-it/pom.xml index 495e3999..237e543e 100644 --- a/belgif-rest-problem-it/belgif-rest-problem-codegen-it/pom.xml +++ b/belgif-rest-problem-it/belgif-rest-problem-codegen-it/pom.xml @@ -148,7 +148,7 @@ io.swagger.core.v3 swagger-annotations - 2.2.25 + 2.2.26 jakarta.platform diff --git a/belgif-rest-problem-it/belgif-rest-problem-it-common/src/main/java/io/github/belgif/rest/problem/AbstractJacksonSerializationTest.java b/belgif-rest-problem-it/belgif-rest-problem-it-common/src/main/java/io/github/belgif/rest/problem/AbstractJacksonSerializationTest.java index 9883df57..5c1a08e2 100644 --- a/belgif-rest-problem-it/belgif-rest-problem-it-common/src/main/java/io/github/belgif/rest/problem/AbstractJacksonSerializationTest.java +++ b/belgif-rest-problem-it/belgif-rest-problem-it-common/src/main/java/io/github/belgif/rest/problem/AbstractJacksonSerializationTest.java @@ -224,6 +224,24 @@ void issueWithStatusAndInstance() throws JsonProcessingException { assertSerializationRoundtrip(problem); } + @Test + void issueWithNullValue() throws JsonProcessingException { + BadRequestProblem problem = new BadRequestProblem( + new InputValidationIssue(InEnum.BODY, "id", null)); + String json = mapper.writeValueAsString(problem); + assertThat(json).doesNotContain("null"); + assertSerializationRoundtrip(problem); + } + + @Test + void issueWithNullInputValue() throws JsonProcessingException { + BadRequestProblem problem = new BadRequestProblem(new InputValidationIssue() + .inputs(Input.body("a", null), Input.body("b", null))); + String json = mapper.writeValueAsString(problem); + assertThat(json).doesNotContain("null"); + assertSerializationRoundtrip(problem); + } + void assertSerializationRoundtrip(Problem problem) throws JsonProcessingException { String json = mapper.writeValueAsString(problem); print(json); diff --git a/belgif-rest-problem-it/belgif-rest-problem-jakarta-ee-it/pom.xml b/belgif-rest-problem-it/belgif-rest-problem-jakarta-ee-it/pom.xml index 3ac5c170..c8a08bb8 100644 --- a/belgif-rest-problem-it/belgif-rest-problem-jakarta-ee-it/pom.xml +++ b/belgif-rest-problem-it/belgif-rest-problem-jakarta-ee-it/pom.xml @@ -71,7 +71,7 @@ org.testcontainers junit-jupiter - 1.20.3 + 1.20.4 test diff --git a/belgif-rest-problem-it/belgif-rest-problem-java-ee-it/pom.xml b/belgif-rest-problem-it/belgif-rest-problem-java-ee-it/pom.xml index d41ab105..00cdd940 100644 --- a/belgif-rest-problem-it/belgif-rest-problem-java-ee-it/pom.xml +++ b/belgif-rest-problem-it/belgif-rest-problem-java-ee-it/pom.xml @@ -175,7 +175,7 @@ org.testcontainers junit-jupiter - 1.20.3 + 1.20.4 test diff --git a/belgif-rest-problem-spring-boot-2/pom.xml b/belgif-rest-problem-spring-boot-2/pom.xml index 789df2d1..e6fd8c47 100644 --- a/belgif-rest-problem-spring-boot-2/pom.xml +++ b/belgif-rest-problem-spring-boot-2/pom.xml @@ -71,6 +71,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-validation + test + org.junit.jupiter junit-jupiter diff --git a/belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java b/belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java new file mode 100644 index 00000000..d9bbc04e --- /dev/null +++ b/belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java @@ -0,0 +1,20 @@ +package io.github.belgif.rest.problem.spring; + +import java.util.stream.Stream; + +import org.springframework.core.ParameterNameDiscoverer; + +import io.github.belgif.rest.problem.internal.CachedAnnotationParameterNameSupport; + +/** + * ParameterNameDiscoverer that retrieves the parameter name from Spring MVC annotations (if present). + */ +public class AnnotationParameterNameDiscoverer extends CachedAnnotationParameterNameSupport + implements ParameterNameDiscoverer { + + @Override + protected String[] toResult(Stream parameterNames) { + return parameterNames.toArray(String[]::new); + } + +} diff --git a/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java b/belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java similarity index 89% rename from belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java rename to belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java index ca872c5e..5893905c 100644 --- a/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java +++ b/belgif-rest-problem-spring-boot-2/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfiguration.java @@ -3,8 +3,10 @@ import javax.validation.ConstraintViolationException; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.validation.MessageInterpolatorFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -21,6 +23,7 @@ * @see org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration */ @Configuration +@AutoConfigureBefore(ValidationAutoConfiguration.class) public class ProblemValidatorConfiguration { @Bean diff --git a/belgif-rest-problem-spring-boot-2/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java b/belgif-rest-problem-spring-boot-2/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java new file mode 100644 index 00000000..d7c995a5 --- /dev/null +++ b/belgif-rest-problem-spring-boot-2/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java @@ -0,0 +1,18 @@ +package io.github.belgif.rest.problem.spring; + +import static org.assertj.core.api.Assertions.*; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +class AnnotationParameterNameDiscovererTest { + + private final AnnotationParameterNameDiscoverer discoverer = new AnnotationParameterNameDiscoverer(); + + @Test + void toResult() { + assertThat(discoverer.toResult(Stream.of("A", "B"))).containsExactly("A", "B"); + } + +} diff --git a/belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfigurationTest.java b/belgif-rest-problem-spring-boot-2/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfigurationTest.java similarity index 100% rename from belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfigurationTest.java rename to belgif-rest-problem-spring-boot-2/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidatorConfigurationTest.java diff --git a/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProvider.java b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProvider.java new file mode 100644 index 00000000..666aaa94 --- /dev/null +++ b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProvider.java @@ -0,0 +1,22 @@ +package io.github.belgif.rest.problem.spring; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jakarta.validation.ParameterNameProvider; + +import io.github.belgif.rest.problem.internal.CachedAnnotationParameterNameSupport; + +/** + * ParameterNameProvider that retrieves the parameter name from Spring MVC annotations (if present). + */ +public class AnnotationParameterNameProvider extends CachedAnnotationParameterNameSupport> + implements ParameterNameProvider { + + @Override + protected List toResult(Stream parameterNames) { + return parameterNames.collect(Collectors.toList()); + } + +} diff --git a/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizer.java b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizer.java new file mode 100644 index 00000000..61e09e42 --- /dev/null +++ b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizer.java @@ -0,0 +1,21 @@ +package io.github.belgif.rest.problem.spring; + +import jakarta.validation.Configuration; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.validation.ValidationConfigurationCustomizer; +import org.springframework.stereotype.Component; + +/** + * ValidationConfigurationCustomizer that registers the AnnotationParameterNameProvider. + */ +@Component +@ConditionalOnClass(Configuration.class) +public class ProblemValidationConfigurationCustomizer implements ValidationConfigurationCustomizer { + + @Override + public void customize(Configuration configuration) { + configuration.parameterNameProvider(new AnnotationParameterNameProvider()); + } + +} diff --git a/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProviderTest.java b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProviderTest.java new file mode 100644 index 00000000..5781c398 --- /dev/null +++ b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameProviderTest.java @@ -0,0 +1,18 @@ +package io.github.belgif.rest.problem.spring; + +import static org.assertj.core.api.Assertions.*; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +class AnnotationParameterNameProviderTest { + + private final AnnotationParameterNameProvider provider = new AnnotationParameterNameProvider(); + + @Test + void toResult() { + assertThat(provider.toResult(Stream.of("A", "B"))).containsExactly("A", "B"); + } + +} diff --git a/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizerTest.java b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizerTest.java new file mode 100644 index 00000000..61f9ad78 --- /dev/null +++ b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemValidationConfigurationCustomizerTest.java @@ -0,0 +1,34 @@ +package io.github.belgif.rest.problem.spring; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import jakarta.validation.Configuration; +import jakarta.validation.ParameterNameProvider; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ProblemValidationConfigurationCustomizerTest { + + private final ProblemValidationConfigurationCustomizer customizer = new ProblemValidationConfigurationCustomizer(); + + @Mock + private Configuration configuration; + + @Captor + private ArgumentCaptor parameterNameProviderCaptor; + + @Test + void customize() { + when(configuration.parameterNameProvider(parameterNameProviderCaptor.capture())).thenReturn(configuration); + customizer.customize(configuration); + assertThat(parameterNameProviderCaptor.getValue()).isInstanceOf(AnnotationParameterNameProvider.class); + } + +} diff --git a/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java b/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupport.java similarity index 71% rename from belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java rename to belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupport.java index 8542bf06..7f1d5d79 100644 --- a/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscoverer.java +++ b/belgif-rest-problem-spring/src/main/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupport.java @@ -1,4 +1,4 @@ -package io.github.belgif.rest.problem.spring; +package io.github.belgif.rest.problem.internal; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; @@ -7,8 +7,9 @@ import java.lang.reflect.Parameter; import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; -import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.lang.NonNull; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.MatrixVariable; import org.springframework.web.bind.annotation.PathVariable; @@ -16,26 +17,25 @@ import org.springframework.web.bind.annotation.RequestParam; /** - * ParameterNameDiscoverer that retrieves the parameter name from Spring MVC annotations (if present). + * Helper class for cached retrieval of parameter names from Spring MVC annotations. + * + * @param the result type */ -public class AnnotationParameterNameDiscoverer implements ParameterNameDiscoverer { +public abstract class CachedAnnotationParameterNameSupport { - private final ConcurrentHashMap parameterNameCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap parameterNameCache = new ConcurrentHashMap<>(); - @Override - public String[] getParameterNames(Constructor constructor) { + public T getParameterNames(@NonNull Constructor constructor) { return parameterNameCache.computeIfAbsent(constructor, this::getParameterNames); } - @Override - public String[] getParameterNames(Method method) { + public T getParameterNames(@NonNull Method method) { return parameterNameCache.computeIfAbsent(method, this::getParameterNames); } - private String[] getParameterNames(Executable executable) { - return Arrays.stream(executable.getParameters()) - .map(this::getParameterName) - .toArray(String[]::new); + private T getParameterNames(Executable executable) { + return toResult(Arrays.stream(executable.getParameters()) + .map(this::getParameterName)); } private String getParameterName(Parameter parameter) { @@ -64,4 +64,6 @@ private String getParameterNameFromAnnotations(Parameter parameter) { return null; } + protected abstract T toResult(Stream parameterNames); + } diff --git a/belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java b/belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupportTest.java similarity index 65% rename from belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java rename to belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupportTest.java index 3c120940..3dd730e9 100644 --- a/belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/spring/AnnotationParameterNameDiscovererTest.java +++ b/belgif-rest-problem-spring/src/test/java/io/github/belgif/rest/problem/internal/CachedAnnotationParameterNameSupportTest.java @@ -1,7 +1,11 @@ -package io.github.belgif.rest.problem.spring; +package io.github.belgif.rest.problem.internal; import static org.assertj.core.api.Assertions.*; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -11,20 +15,26 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; -class AnnotationParameterNameDiscovererTest { +class CachedAnnotationParameterNameSupportTest { - private final AnnotationParameterNameDiscoverer discoverer = new AnnotationParameterNameDiscoverer(); + private final CachedAnnotationParameterNameSupport> support = + new CachedAnnotationParameterNameSupport>() { + @Override + protected List toResult(Stream parameterNames) { + return parameterNames.collect(Collectors.toList()); + } + }; @Test void getParameterNameConstructor() throws Exception { - assertThat(discoverer.getParameterNames(Tested.class.getDeclaredConstructor(String.class, Long.class))) + assertThat(support.getParameterNames(Tested.class.getDeclaredConstructor(String.class, Long.class))) .containsExactly("name", "other"); } @Test void getParameterNamesMethod() throws Exception { assertThat( - discoverer.getParameterNames(Tested.class.getDeclaredMethod("plainMethod", String.class, Long.class))) + support.getParameterNames(Tested.class.getDeclaredMethod("plainMethod", String.class, Long.class))) .containsExactly("name", "other"); } @@ -32,7 +42,7 @@ void getParameterNamesMethod() throws Exception { @ValueSource( strings = { "requestParam", "pathVariable", "requestHeader", "cookieValue", "matrixVariable", "fallback" }) void getParameterNamesMethodWithJaxRsAnnotation(String method) throws Exception { - assertThat(discoverer.getParameterNames(Tested.class.getDeclaredMethod(method, String.class))) + assertThat(support.getParameterNames(Tested.class.getDeclaredMethod(method, String.class))) .containsExactly("name"); } diff --git a/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/Input.java b/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/Input.java index 8e45388e..cf60474c 100644 --- a/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/Input.java +++ b/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/Input.java @@ -20,6 +20,7 @@ * * @param the input value type */ +@JsonInclude(value = JsonInclude.Include.NON_EMPTY) @JsonPropertyOrder({ "in", "name", "value" }) public class Input { @@ -52,7 +53,6 @@ public void setName(String name) { this.name = name; } - @JsonInclude(value = JsonInclude.Include.ALWAYS, content = JsonInclude.Include.ALWAYS) public V getValue() { return value; } diff --git a/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/InputValidationIssue.java b/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/InputValidationIssue.java index 27e84f39..459e838e 100644 --- a/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/InputValidationIssue.java +++ b/belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/InputValidationIssue.java @@ -32,7 +32,7 @@ * * @see InputValidationProblem */ -@JsonInclude(value = Include.NON_DEFAULT) +@JsonInclude(value = Include.NON_EMPTY) @JsonPropertyOrder(value = { "type", "href", "title", "detail", "in", "name", "value", "inputs" }) public class InputValidationIssue { @@ -123,7 +123,6 @@ public void setName(String name) { this.name = name; } - @JsonInclude(value = Include.NON_NULL, content = Include.ALWAYS) public Object getValue() { return value; } @@ -263,6 +262,14 @@ public InputValidationIssue in(InEnum in, String name, Object value) { return in(in).name(name).value(value); } + public InputValidationIssue in(Input input) { + if (input != null) { + return in(input.getIn(), input.getName(), input.getValue()); + } else { + return this; + } + } + public InputValidationIssue in(InEnum in) { setIn(in); return this; diff --git a/belgif-rest-problem/src/test/java/io/github/belgif/rest/problem/api/InputValidationIssueTest.java b/belgif-rest-problem/src/test/java/io/github/belgif/rest/problem/api/InputValidationIssueTest.java index 01a6218d..c1c25bd5 100644 --- a/belgif-rest-problem/src/test/java/io/github/belgif/rest/problem/api/InputValidationIssueTest.java +++ b/belgif-rest-problem/src/test/java/io/github/belgif/rest/problem/api/InputValidationIssueTest.java @@ -90,7 +90,7 @@ void in() { issue.setIn(null); assertThat(issue.getIn()).isNull(); - issue.in(null); + issue.in((InEnum) null); assertThat(issue.getIn()).isNull(); issue.setIn(InEnum.QUERY); @@ -98,6 +98,21 @@ void in() { assertThat(new InputValidationIssue().in(InEnum.QUERY).getIn()).isEqualTo(InEnum.QUERY); } + @Test + void inInput() { + InputValidationIssue issue = new InputValidationIssue(); + + issue.in((Input) null); + assertThat(issue.getIn()).isNull(); + assertThat(issue.getName()).isNull(); + assertThat(issue.getValue()).isNull(); + + issue = issue.in(Input.query("name", "value")); + assertThat(issue.getIn()).isEqualTo(InEnum.QUERY); + assertThat(issue.getName()).isEqualTo("name"); + assertThat(issue.getValue()).isEqualTo("value"); + } + @Test void name() { InputValidationIssue issue = new InputValidationIssue(); diff --git a/pom.xml b/pom.xml index 72a38bc2..6cd1495e 100644 --- a/pom.xml +++ b/pom.xml @@ -138,7 +138,7 @@ org.asciidoctor asciidoctor-maven-plugin - 3.1.0 + 3.1.1 org.codehaus.mojo @@ -158,17 +158,17 @@ org.openapitools openapi-generator-maven-plugin - 7.9.0 + 7.10.0 io.swagger.codegen.v3 swagger-codegen-maven-plugin - 3.0.63 + 3.0.64 org.sonarsource.scanner.maven sonar-maven-plugin - 4.0.0.4121 + 5.0.0.4389 org.jacoco diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index fdacf72c..d2010c4e 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -562,7 +562,6 @@ io.github.belgif.rest.problem.scan-additional-problem-packages=com.acme.custom * *RoutingExceptionsHandler:* an exception handler for RestControllers that converts routing related validation exceptions to HTTP 400 BadRequestProblem. * *ProblemResponseErrorHandler:* a RestTemplate error handler that converts problem responses to Problem exceptions. * *ProblemRestTemplateCustomizer:* a RestTemplateCustomizer that registers the ProblemResponseErrorHandler. -* *AnnotationParameterNameDiscoverer:* a bean validation ParameterNameDiscoverer that retrieves parameter names from Spring MVC annotations In general, these components make it possible to use standard java exception handling (throw and try-catch) for dealing with problems in Spring Boot REST APIs. @@ -573,6 +572,8 @@ Rather than depending on <> directly, Spring Boot 2. * *ProblemWebClientCustomizer:* a WebClientCustomizer that registers a filter that converts problem responses to Problem exceptions. This handles integration with the https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html[Reactive WebClient]. +* *AnnotationParameterNameDiscoverer:* a bean validation ParameterNameDiscoverer that retrieves parameter names from Spring MVC annotations +* *ProblemValidatorConfiguration:* registers a LocalValidatorFactoryBean with the AnnotationParameterNameDiscoverer [[belgif-rest-problem-spring-boot-3]] ==== belgif-rest-problem-spring-boot-3 @@ -583,3 +584,5 @@ Rather than depending on <> directly, Spring Boot 3. This handles integration with the https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html[Reactive WebClient]. * *NoResourceFoundExceptionHandler:* an exception handler for RestControllers that converts NoResourceFoundException to HTTP 404 ResourceNotFoundProblem. * *ProblemRestClientCustomizer:* a RestClientCustomizer that registers the ProblemResponseErrorHandler. +* *AnnotationParameterNameProvider:* a bean validation ParameterNameProvider that retrieves parameter names from Spring MVC annotations +* *ProblemValidationConfigurationCustomizer:* a ValidationConfigurationCustomizer that registers the AnnotationParameterNameProvider \ No newline at end of file diff --git a/src/main/asciidoc/release-notes.adoc b/src/main/asciidoc/release-notes.adoc index aea125a5..d3bb7f7b 100644 --- a/src/main/asciidoc/release-notes.adoc +++ b/src/main/asciidoc/release-notes.adoc @@ -12,11 +12,22 @@ // tag::recent-versions[] -== Version 0.11 +== Version 0.12 *belgif-rest-problem:* * Add internationalization support for localized detail messages based on Accept-Language HTTP request header +* Don't include null (issue) input values when serializing + +== Version 0.11 + +*belgif-rest-problem:* + +* Add in(Input) to InputValidationIssue for a fluent single input setter + +*belgif-rest-problem-spring:* + +* Fix non-deterministic configuration for retrieving parameter names from Spring MVC annotations == Version 0.10