Add `ClientHttpRequestInitializer` interface that can be used with any
`HttpAccessor` to initialize each `ClientHttpRequest` before it's used.
This provides a useful alternative to `ClientHttpRequestInterceptor`
when users need to configure things like `HttpHeaders`.
Closes gh-22002
On a Servlet container a completion notification may come at any time
even in the UNSUBSCRIBED state, i.e. before the write Publisher has
called onSubscribe.
See: gh-23553
Prior to this commit, a lot of work had been done to prevent improper
use of testing Framework APIs throughout the codebase; however, there
were still some loopholes.
This commit addresses these loopholes by introducing additional
Checkstyle rules (and modifying existing rules) to prevent improper use
of testing framework APIs in production code as well as in test code.
- Checkstyle rules for banned imports have been refactored into
multiple rules specific to JUnit 3, JUnit 4, JUnit Jupiter, and
TestNG.
- Accidental usage of org.junit.Assume has been switched to
org.junit.jupiter.api.Assumptions.
- All test classes now reside under org.springframework packages.
- All test classes (including abstract test classes) now conform to the
`*Tests` naming convention.
- As an added bonus, tests in the renamed
ScenariosForSpringSecurityExpressionTests are now included in the
build.
- Dead JUnit 4 parameterized code has been removed from
DefaultServerWebExchangeCheckNotModifiedTests.
Closes gh-22962
Prior to this commit, the Spring Framework build would partially use the
dependency management plugin to import and enforce BOMs.
This commit applies the dependency management plugin to all Java
projects and regroups all version management declaration in the root
`build.gradle` file (versions and exclusions).
Some versions are overridden in specific modules for
backwards-compatibility reasons or extended support.
This commit also adds the Gradle versions plugin that checks for
dependency upgrades in artifact repositories and produces a report; you
can use the following:
./gradlew dependencyUpdates
Prior to this commit, the entry set of read-only HttpHeaders lost the
original headers' ordering.
The changes in commit ce7278aaf4 introduced a regression in the read-only
HttpHeaders support. Specifically, the implementation of entrySet() in
the internal ReadOnlyHttpHeaders class converted the original entry set
to an immutable, non-ordered set of immutable entries.
This commit fixes this issue by converting the original entry set to an
immutable, ordered set of immutable entries.
Closes gh-23551
This commit prepends "[{index}] " to all custom display names
configured via @ParameterizedTest.
This provides better diagnostics between the "technical names" reported
on the CI server vs. the "display names" reported within a developer's
IDE.
See gh-23451
Prior to this commit, there was no way to replace the Set-Cookie header
via MockHttpServletResponse. Specifically, an invocation of setHeader()
for the Set-Cookie header resulted in an additional Set-Cookie header
instead of replacing the existing one, which is in violation of the
contract for javax.servlet.http.HttpServletResponse.setHeader(...).
This commit refactors the internals of MockHttpServletResponse to ensure
that an existing Set-Cookie header is overwritten when set via an
invocation of setHeader(). This commit also verifies the expected
behavior for addHeader() and addCookie() with regard to multiple cookies.
Closes gh-23512
Due to a bug (or "unintentional feature") in JUnit 4, overridden test
and lifecycle methods not annotated with @Test, @Before, @After, etc.
are still executed as test methods and lifecycle methods; however,
JUnit Jupiter does not support that. Thus, prior to this commit, some
overridden test and lifecycle methods were no longer executed after the
migration from JUnit 4 to JUnit Jupiter.
This commit addresses this issue for such known use cases, but there
are likely other such use cases within Spring's test suite.
See gh-23451
The use of LinkedCaseInsensitiveMap, going back to 3.0, makes it
unnecessary to iterate over keys which can cause
ConcurrentModificationException.
Closes gh-23460
This commit reorganizes tasks and scripts in the build to only apply
them where they're needed. We're considering here 3 "types" of projects
in our build:
* the root project, handling documentation, publishing, etc
* framework modules (a project that's published as a spring artifact)
* internal modules, such as the BOM, our coroutines support and our
integration-tests
With this change, we're strealining the project configuration for all
spring modules and only applying plugins when needed (typically our
kotlin support).
See gh-23282
This commit removes the JUnit 4 dependency from all modules except
spring-test which provides explicit JUnit 4 support.
This commit also includes the following.
- migration from JUnit 4 assertions to JUnit Jupiter assertions in all
Kotlin tests
- migration from JUnit 4 assumptions in Spring's TestGroup support to
JUnit Jupiter assumptions, based on org.opentest4j.TestAbortedException
- introduction of a new TestGroups utility class than can be used from
existing JUnit 4 tests in the spring-test module in order to perform
assumptions using JUnit 4's Assume class
See gh-23451
This commit migrates parameterized tests in spring-core using the
"composed @ParameterizedTest" approach. This approach is reused in
follow-up commits for the migration of the remaining modules.
For a concrete example, see AbstractDataBufferAllocatingTests and its
subclasses (e.g., DataBufferTests).
Specifically, AbstractDataBufferAllocatingTests declares a custom
@ParameterizedDataBufferAllocatingTest annotation that is
meta-annotated with @ParameterizedTest and
@MethodSource("org.springframework.core.io.buffer.AbstractDataBufferAllocatingTests#dataBufferFactories()").
Individual methods in concrete subclasses are then annotated with
@ParameterizedDataBufferAllocatingTest instead of @ParameterizedTest or
@Test.
The approach makes the migration from JUnit 4 to JUnit Jupiter rather
straightforward; however, there is one major downside. The arguments
for a @ParameterizedTest test method can only be accessed by the test
method itself. It is not possible to access them in an @BeforeEach
method (see https://github.com/junit-team/junit5/issues/944).
Consequently, we are forced to declare the parameters in each such
method and delegate to a custom "setup" method. Although this is a bit
cumbersome, I feel it is currently the best way to achieve fine grained
parameterized tests within our test suite without implementing a custom
TestTemplateInvocationContextProvider for each specific use case.
Once https://github.com/junit-team/junit5/issues/878 is resolved, we
should consider migrating to parameterized test classes.
See gh-23451
Deprecate all mutation methods in `MethodParameter` in favor of factory
methods that return a new instance. Existing code that previously relied
on mutation has been updated to use the replacement methods.
Closes gh-23385
Added support for status codes that do not occur in HttpStatus in
DefaultClientResponseBuilder and made ClientResponse::statusCode
ClientHttpResponse::getStatusCode @Nullable.
Closed gh-23366
The isJavaIdentifier check is not really required, but also seems
intuitive for variables to be Java identifier-like. This commit relaxes
the constraint a bit by also allowing "-".
Closes gh-23101
Prior to this commit, the `header(String, String)` method in the
ServerHttpRequest.Builder API actually added a header value instead of
setting or overriding a header value. Since this conflicted with the
stated behavior in the Javadoc as well as the original intention of the
method, we have decided to introduce an overloaded variant
`header(String, String...)` which accepts a var-args list of header
values to set or override.
In addition, this commit deprecates the existing `header(String, String)`
method for removal in Spring Framework 5.2.
In order not to be a breaking change for custom implementations of the
builder API, this commit implements the new `header(String, String...)`
method as an interface `default` method, with the intent to remove the
default implementation in Spring Framework 5.2
closes gh-23333
Prior to this commit, the `header(String, String)` method in the
ServerHttpRequest.Builder API actually added a header value instead of
setting or overriding a header value. Since this conflicted with the
stated behavior in the Javadoc as well as the original intention of the
method, we have decided to introduce an overloaded variant
`header(String, String...)` which accepts a var-args list of header
values to set or override.
In addition, this commit deprecates the existing `header(String, String)`
method for removal in Spring Framework 5.2.
In order not to be a breaking change for custom implementations of the
builder API, this commit implements the new `header(String, String...)`
method as an interface `default` method, with the intent to remove the
default implementation in Spring Framework 5.2
closes gh-23333
To make the switching of separators complete, it is also important to
know whether the decoding of path segment values and the parsing of
path param should be done as those are applied transparently.
This commit replaces the recently added separator argument to
PathContainer.parsePath with an Options type with two predefined
constants. One for HTTP URLs with automatic decoding and parsing of
path params, and another for "." separated message routes without
decoding except for encoded sequences of the separator itself.
See gh-23310
Replace docs on using MultipartBodyBuilder for the RestTemplate with
examples that show MultiValueMap. Originally the idea was to make
MultipartBodyBuilder accessible to the RestTemplate too, but with
support for async parts that's no longer a good fit.
Closes gh-23295
OncePerRequestFilter now has a doFilter method that allows separate
processing of nested ERROR dispatches. This is useful for filters
that wrap the request and response.
Closes gh-23196
The DefaultMultipartMessageReader has been removed for 5.2 and will be
part of a future release. This commit switches back to the
SynchronossPartHttpMessageReader.
gh-21659
The new annotation helps to differentiate the handling of connection
level frames (SETUP and METADATA_PUSH) from the 4 stream requests.
Closes gh-23177
The commit deprecates syncBody(Object) in favor of body(Object)
which has the same behavior in ServerResponse, WebClient and
WebTestClient. It also adds body(Object, Class) and
body(Object, ParameterizedTypeReference) methods in order to support
any reactive type that can be adapted to a Publisher via
ReactiveAdapterRegistry. Related BodyInserters#fromProducer
methods are provided as well.
Shadowed Kotlin body<T>() extensions are deprecated in favor of
bodyWithType<T>() ones, including dedicated Publisher<T> and
Flow<T> variants. Coroutines extensions are adapted as well, and
body(Object) can now be used with suspending functions.
Closes gh-23212
Prior to Spring Framework 5.1.3, MimeTypeUtils.parseMimeTypes() and
MediaType.parseMediaTypes() ignored empty entries, but 5.1.3 introduced
a regression in that an empty entry -- for example, due to a trailing
comma in the list of media types in an HTTP Accept header -- would result
in a "406 Not Acceptable" response status.
This commit fixes this by filtering out empty entries before parsing
them into MimeType and MediaType instances. Empty entries are therefore
effectively ignored.
Fixes gh-23241
Improve the performance of `FormContentFilter` by checking directly if
`contentType` is empty. This saves the need for an exception to thrown
then immediately caught.
Closes gh-23216
Commit 5008423408 added support for
multipart/* media types in FormHttpMessageConverter, but users still had
to manually register multipart/mixed as a supported media type in order
to POST multipart data with that content type.
This commit removes the need to manually register multipart/mixed as a
supported media type by registering it automatically in
FormHttpMessageConverter. In addition, this commit introduces
MULTIPART_MIXED and MULTIPART_MIXED_VALUE constants in MediaType.
Closes gh-23209
Prior to this commit, the Basic Authentication credentials were encoded
for each request.
This commit addresses this minor performance issue by caching the
encoded credentials in BasicAuthenticationInterceptor.
In addition, this commit introduces new encodeBasicAuth() and
setBasicAuth(String encodedCredentials) methods in HttpHeaders to
support this feature.
Closes gh-23204
Prior to this commit, RestTemplate posted multipart with Content-Type
"multipart/form-data" even if the FormHttpMessageConverter configured
in the RestTemplate had been configured to support additional multipart
subtypes. This made it impossible to POST form data using a content
type such as "multipart/mixed" or "multipart/related".
This commit addresses this issue by updating FormHttpMessageConverter
to support custom multipart subtypes for writing form data.
For example, the following use case is now supported.
MediaType multipartMixed = new MediaType("multipart", "mixed");
restTemplate.getMessageConverters().stream()
.filter(FormHttpMessageConverter.class::isInstance)
.map(FormHttpMessageConverter.class::cast)
.findFirst()
.orElseThrow(() ->
new IllegalStateException("Failed to find FormHttpMessageConverter"))
.addSupportedMediaTypes(multipartMixed);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("field 1", "value 1");
parts.add("file", new ClassPathResource("myFile.jpg"));
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(multipartMixed);
HttpEntity<MultiValueMap<String, Object>> requestEntity =
new HttpEntity<>(parts, requestHeaders);
restTemplate.postForLocation("https://example.com/myFileUpload", requestEntity);
Closes gh-23159
This commit changes the new addSupportedMediaType(MediaType) method
to addSupportedMediaTypes(MediaType...), in order to allow registration
of multiple supported media types simultaneously.
See gh-23203
Prior to this commit, all clients of
ControllerAdviceBean.findAnnotatedBeans() sorted the returned list
manually. In addition, clients within the core Spring Framework
unnecessarily used AnnotationAwareOrderComparator instead of
OrderComparator to sort the list.
This commit presorts the ControllerAdviceBean list using OrderComparator
directly within ControllerAdviceBean.findAnnotatedBeans().
Closes gh-23188
Prior to this commit, the resolveBean() method in ControllerAdviceBean
looked up the @ControllerAdvice bean instance in the ApplicationContext
by name for every web request that involved lookups for global methods
annotated with @ExceptionHandler, @InitBinder, and @ModelAttribute.
This commit avoids the need for such repeated lookups in the
ApplicationContext by caching the resolved @ControllerAdvice bean
instance within ControllerAdviceBean once it has been resolved.
This commit introduces unit tests for the status quo in
ControllerAdviceBeanTests to serve as regression tests for future
changes to ControllerAdviceBean.
Prior to this commit, `PathPattern::extractPathWithinMapping`
would always use the default path pattern separator `/` when extracting
the path within the pattern of a matched route.
This commit ensures that `PathPattern` uses the configured separator
when extracting the path within the matched mapping.
Fixes gh-23168
Prior to this commit, the `PathPatternRouteMatcher` would always use the
default path pattern separator when parsing incoming route strings to
`RouteMatcher.Route` instances.
When the `PathPatternRouteMatcher` is configured with a
`PathPatternParser` that has a custom separator (e.g., `.`), then the
matching algorithm can't match routes against parsed patterns.
This commit ensures that the route matcher uses the configured separator
at all times.
Fixes gh-23167