Historically, @Configuration classes that did not declare @Bean
methods were allowed to be abstract. However, the changes made in
76a6b9ea79 introduced a regression that prevents such classes from
being abstract, resulting in a BeanInstantiationException. This change
in behavior is caused by the fact that such a @Configuration class is
no longer replaced by a concrete subclass created dynamically by CGLIB.
This commit restores support for abstract @Configuration classes
without @Bean methods by modifying the "no enhancement required" check
in ConfigurationClassParser.
See gh-34486
Closes gh-34663
(cherry picked from commit 044258f085)
This commit updates the tests of property values code generated to
invoke the generated code from a `static` context. This ensures that
the test fails if that's not the case.
This commit also updated LinkedHashMap handling that did suffer from
that problem.
Closes gh-34661
Prior to this commit, `MockHttpServletResponse` would only support
adding a `Content-Language` once. Adding multiple header values would
always replace the content-language property in the response and the
entire header value.
This commit ensures that this behavior is supported.
Fixes gh-34491
Prior to this commit, calling `setHeader` on the response wrapper would
have a separate code path for the "Content-Length" header. This did not
support calls with `null` values and would result in an exception.
This commit ensures that the cached content length value is reset in
this case and that the call is forwarded properly to the superclass.
Fixes gh-34465
Prior to this commit, `MockHttpServletResponse#setHeader` would not
remove the header entry when given a `null` value, as documented in the
Servlet API.
This commit ensures that this behavior is enforced.
Fixes gh-34466
Prior to this commit, if a String 'value' attribute of an annotation
was annotated with @AliasFor and explicitly configured to alias an
attribute other than @Component.value, the value was still used as the
@Component name, but the warning message that was logged stated that
the 'value' attribute should be annotated with
@AliasFor(annotation=Component.class). However, it is not possible to
annotate an annotation attribute twice with @AliasFor.
To address that, this commit revises the logic in
AnnotationBeanNameGenerator so that it issues a log message similar to
the following in such scenarios.
WARN o.s.c.a.AnnotationBeanNameGenerator - Although the 'value'
attribute in @example.MyStereotype declares @AliasFor for an
attribute other than @Component's 'value' attribute, the value is
still used as the @Component name based on convention. As of Spring
Framework 7.0, such a 'value' attribute will no longer be used as the
@Component name.
See gh-34346
Closes gh-34317
(cherry picked from commit 17a94fb110)
Prior to this commit, `CronExpression` would support Quartz-style
expressions with "Nth occurence of a dayOfWeek" semantics by using the
`TemporalAdjusters.dayOfWeekInMonth` JDK support. This method will
return the Nth occurence starting with the month of the given temporal,
but in some cases will overflow to the next or previous month.
This behavior is not expected for our cron expression support.
This commit ensures that when an overflow happens (meaning, the
resulting date is not in the same month as the input temporal), we
should instead have another attempt at finding a valid month for this
expression.
Fixes gh-34377
Due to changes in gh-19118, classes that contain @Lookup methods are
no longer required to be concrete classes for use with component
scanning; however, the reference documentation still states that such
classes must not be abstract.
This commit therefore removes the outdated reference documentation and
updates the corresponding Javadoc.
See gh-19118
Closes gh-34367
(cherry picked from commit 819a7c86c1)
This test was already ignored as of Java 21 because of a Java behavior
change, and now it started failing as of 17.0.14.
This commit removes the test entirely.
The changes in commit c20a2e4763 introduced a regression with regard to
binding to a Map property when the Map also happens to implement
Iterable.
Although that is perhaps not a very common scenario, this commit
reorders the if-blocks in AbstractNestablePropertyAccessor's
getPropertyValue(PropertyTokenHolder) method so that a Map is
considered before an Iterable, thereby allowing an Iterable-Map to be
accessed as a Map.
See gh-907
Closes gh-34332
(cherry picked from commit b9e43d05bd)
We now look for the target exception types in cause chain as well,
but return false if we encounter a RestClient or WebClient
exception in the chain.
Closes gh-34264
On connection loss, in a race between application thread and onError
callback trying to set the DeferredResult and dispatch, the onError
callback must not exit until dispatch completes. Currently, it may do
so because the DeferredResult has checks to bypasses locking or even
trying to dispatch if result is already set.
Closes gh-34192
There is no need to set the DeferredResult from WebAsyncManager in an
onError notification because it is already done from the Lifecycle
interceptor in DeferredResult.
See gh-34192
Prior to this commit, if a MethodHandle was registered as a custom
function in the Spring Expression Language (SpEL) for a static method
that accepted only a variable argument list (for example,
`static String func(String... args)`), attempting to invoke the
registered function within a SpEL expression resulted in a
ClassCastException because the varargs array was unnecessarily wrapped
in an Object[].
This commit modifies the logic in FunctionReference's internal
executeFunctionViaMethodHandle() method to address that.
Closes gh-34109
Prior to this commit, the MVC namespace for the XML Spring configuration
model would use the `PathMatcher` bean instance when provided like this:
```
<bean id="pathMatcher" class="org.springframework.util.AntPathMatcher"/>
<mvc:annotation-driven>
<mvc:path-matching path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<mvc:resources mapping="/resources/**" location="classpath:/static/"/>
```
With this configuration, the handler mapping for annotated controller
would use the given `AntPathMatcher` instance but the handler mapping
for resources would still use the default, which is `PathPatternParser`
since 6.0.
This commit ensures that when a custom `path-matcher` is defined, it's
consistently used for all MVC handler mappings as an alias to the
well-known bean name. This allows to use `AntPathMatcher` consistently
while working on a migration path to `PathPatternParser`
This commit also adds a new XML attribute to the path matching
configuration that makes it possible to use a custom `PathPatternParser`
instance:
```
<bean id="patternParser" class="org.springframework.web.util.pattern.PathPatternParser"/>
<mvc:annotation-driven>
<mvc:path-matching pattern-parser="patternParser"/>
</mvc:annotation-driven>
```
Closes gh-34102
See gh-34064
Prior to this commit, information was logged when a bean definition
overrode an existing bean definition, but nothing was logged when the
registration of a bean definition resulted in the removal of an alias.
With this commit, an INFO message is now logged whenever an alias is
removed in DefaultListableBeanFactory.
Closes gh-34070
(cherry picked from commit 41d9f21ab9)
This ensures that the reactive handling of the request is dispatched
from the Undertow IO thread, marking the exchange as async rather than
ending it once the Undertow `handleRequest` method returns.
See gh-33885
Closes gh-33969
Since Joda-Time support was removed in Spring Framework 6.0, this commit
removes obsolete mentions of Joda-Time in the reference guide and Javadoc.
See gh-27426
Closes gh-33881
Prior to this commit, a client sending a request to
"https://example.org" would record the wrong URI tag as
"/https://example.org".
This commit ensures that the scheme+host part is matched correctly in
the default client observation conventions.
See gh-33867
* pr/33850:
Polish "Prefer modified resources over the originals in TestCompiler"
Prefer modified resources over the originals in TestCompiler
Closes gh-33850
Previously, when the test compiler had been seeded with a resource
file, any modifications to this resource performed during
compilation would be lost as this original content would always
be returned.
This commit updates the DynamicJavaFileManager to always store
the dynamic resource in the dynamicResourceFiles map, irrespective
of whether it's being created afresh or from some existing resource
content. This ensures that any modifications made to the resource
can be retrieved later on.
Similarly, DynamicClassLoader has been updated to prefer dynamic
resource files over any original resource files. This ensures that
the resource that it finds reflects any modifications that have
been made to it.
See gh-33850
The `HttpHeaders#headerSet` method is intended as a drop-in replacement
for `entrySet` that guarantees a single casing for all header names
reported during the iteration, as the cost of some overhead but with
support for iterator removal and entry value-setting.
The `formatHeaders` static method is also altered to do a similar
deduplication of casing variants, but now additionally mentions
"with native header names [native name set]" if the native name set
contains casing variants.
Closes gh-33823
Prior to this commit, the `HttpHeaders.writeableHttpHeaders` would only
consider headers read-only instances that were wrapped once by
`HttpHeaders.readOnlyHttpHeaders`. This does not work when other
`HttpHeaders` wrappers are involved in the chain.
This commit ensures that `writeableHttpHeaders` unwraps all headers
instances down to the actual multivalue map and create a new headers
instance out of it.
Fixes gh-33789
A workaround was added for the Resin Servlet container in gh-13937.
This avoids attempting to delete parts that are not named, because the
`part.delete()` call would fail for non-file entries. This can be
problematic for files that are unnamed as they might not be removed by
the Framework.
This commit removes this workaround as Resin is not supported anymore.
Fixes gh-33511
Prior to this commit, the SpEL Tokenizer threw an IllegalStateException
when an unsupported character was detected in a SpEL expression;
however, the Javadoc for ExpressionParser.parseExpression() states that
it throws a ParseException if an exception occurred during parsing.
This commit addresses that issue by throwing a SpelParseException for
an unsupported character in a SpEL expression, using a new
UNSUPPORTED_CHARACTER enum constant in SpelMessage.
Closes gh-33767
This commit fixes the issue where the regex pattern in the reference documentation
was not rendering correctly for the `/projects/{project:[a-z]+}/versions` mapping.
Closes gh-33766
Prior to this commit, the instrumentation of the processing of JMS
messages would happen a different levels of the hierarchy, accounting
for alli known implementations, `SimpleMessageListenerContainer` and
`DefaultMessageListenerContainer` as well as various use cases and
`MessageListener` variants.
Unfortunately, this instrumentation could lead to observing JMS
processing twice in some cases, and would not be consistent about the
scope of what's observed.
This commit moves the instrumentation basics into the
`AbstractMessageListenerContainer` but leaves the actual observation
calls to the public implementations.
Fixes gh-33758
This commit updates our Date/Time formatting/printing tests to
demonstrate that the use of fallback patterns can help mitigate
locale-based parsing/formatting issues beginning with JDK 20.
The documentation within the tests is intentionally rather thorough for
two reasons:
1. We need to understand exactly what it is we are testing and why the
tests are written that way.
2. We may re-use parts of the documentation and examples in forthcoming
documentation that we will provide to users.
See gh-33151
Prior to this commit, DefaultListableBeanFactory's
determineHighestPriorityCandidate() method sometimes failed to
determine the highest priority candidate if duplicate priority
candidates were detected whose priority was not the highest priority in
the candidate set. In addition, the bean registration order affected
the outcome of the algorithm: if the highest priority was detected
before other duplicate priorities were detected, the algorithm
succeeded in determining the highest priority candidate.
This commit addresses those shortcomings by ignoring duplicate
@Priority values unless the duplication is for the highest priority
encountered, in which case a NoUniqueBeanDefinitionException is still
thrown to signal that multiple beans were found with the same "highest
priority".
Closes gh-33733
Prior to this commit, the `DefaultServerRequestObservationConvention`
for Servlet failed when the HTTP response status was invalid (for
example, set to "0").
This commit catches `IllegalArgumentException` thrown for such invalid
HTTP status and instead returns an unknown outcome for the observation.
Fixes gh-33725
This commit adds a WebFlux integration test with a request
body and a delayed response in order to test a use case
where we found a regression with Undertow 2.3.18.Final.
For now, Undertow 2.3.17.Final is still used.
Closes gh-33739
Prior to this commit, the Jackson2 decoders (JSON, Smile, CBOR) could
leak buffers in case the decoding operation times out or is cancelled
and some buffers are still in flight.
This commit ensures that buffers are released on cancel signals.
Fixes gh-33731
Rather than leaving it to the Resource implementation, and
potentially normalizing twice, we apply it once as part of the
initial processPath checks.
Closes gh-33689
Prior to this commit, the JMS connection factories would proxy various
interfaces. This typically requires runtime hints for GraalVM native
applications and spring-jms is missing those.
This commit adds a new `ConnectionFactoriesRuntimeHints` that
contributes such hints with type conditions.
Fixes gh-33590
When assessing if a request is a CORS request, both mvc and reactive
`DefaultCorsProcessor` now catch `IllegalArgumentException` and turn
this into a 403 rejection rather than letting the exception propagate
into a 500 response.
Closes gh-33688
In a Cacheable reactive method, if an exception is propagated from
both the method and the caching infrastructure, an NPE could previously
surface due to the `CacheAspectSupport` attempting to perform an
`onErrorResume` with a `null`. This change ensures that in such a case
the user-level exception from the method is propagated instead.
Closes gh-33492
Prior to this commit, the `DefaultWebClient` would execute the configured
`ExchangeFilterFunction` as the reactive pipeline is assembled during
subscription. This means that if imperative code is executed in a filter
function, it won't be aware of the current observation through the local
scope.
For example, when automatic context propagation is enabled for Reactor
operators, the logger MDC will not know about the current
traceId/spanId.
This commit ensures that client filter functions execution is deferred
during the actual client exchange.
Fixes gh-33559
Prior to this commit, the HttpComponents implementation for the
`WebClient` would only consider the max-age attribute of response
cookies when parsing the response. This is not aligned with other client
implementations that consider the max-age attribute first, and then the
expires if the former was not present. The expires date is then
translated into a max-age duration. This behavior is done naturally by
several implementations.
This commit updates the `HttpComponentsClientHttpResponse` to do the
same.
Fixes gh-33157
Prior to this commit, `MimeMessageHelper` would accept `Resource`
instances as inline attachments in multipart MIME messages. If the
provided `Resource` implementation returns `null` for `getFileName()`,
the `addInLine` method would fail with a `NullPointerException` as
Jakarta activation fails to detect the content type for a null filename.
This commit falls back on "application/octet-stream" when the filename
is not known for the given resource instead of failing with an
exception.
Fixes gh-33527
Prior to this commit, the URL handler mapping would expose the matching
pattern, the path within mapping and matching URI variables as request
attributes. This was the case when the mapping would use the
`AntPathMatcher` as matching infrastructure, but not when using the
`PathPattern` variant. In this case, the map of URI variables would be
`null`. This could throw `IllegalArgumentException` when `RedirectView`
instances were relying on the presence of specific variables.
This commit ensures that URI variables are also extracted when the
`PathPatternParser` is used.
Fixes gh-33422
The previous pointcut attempted to match against a local lambda type;
however, that pointcut was unreliable and failed sporadically.
This commit therefore changes the pointcut so that it specifically
targets the get() method of a subtype of Supplier, which seems to result
in reliable pointcut matching.
Prior to this commit, the `ServerHttpObservationFilter` was fixed to
re-enable instrumentation for async dispatches. This fix involves using
an AsyncListener to be notified of exchange completion.
This change was incomplete, as this would not work in some cases.
If another filter starts the async mode and initiates an ASYNC dispatch,
before async handling at the controller level, the async listener is not
registered against subsequent async starts.
This commit not only ensures that the async listener registers
against new async starts, but also ensure that the initial creation and
registration only happens during the initial REQUEST dispatch.
Fixes gh-33451
This commit updates the Evaluation chapter to reflect the following.
- SimpleEvaluationContext no longer has a create() method. Instead it
has forPropertyAccessors(), forReadOnlyDataBinding(), and
forReadWriteDataBinding() factory methods.
- SpEL cannot automatically create missing array elements or grow the
size of an array like it can for a collection.
Closes gh-33456
Prior to this commit, the main() method attempted to retrieve a
TransferService bean from the context, but no such bean had been
configured in the context.
This commit addresses that by configuring a TransferService bean in the
context.
Closes gh-33446
Prior to this commit, the `RestClient` instrumentation would create and
close observations for HTTP requests, but would not open an observation
scope for the lifetime of the exchange.
This means that custom `ClientHttpRequestInterceptor` and
`ResponseErrorHandler` would not get access to the current observation
scope in case of tracing, possibly leading to missing trace ids in logs.
This commit ensures that an observation scope is managed for the
lifetime of the HTTP exchange.
Fixes gh-33397
This commit applies the same kind of processing for
Void.class element type in the ParameterizedTypeReference
variant of WebTestClient.ResponseSpec#returnResult than
in the Class variant.
Closes gh-33389
Prior to this commit if the return type is a CompletableFuture but a
cache get returns null, the execution falls through to the
reactiveCachingHandler.
This commit ensures that evaluation instead continues onto the next
cache (if any).
Closes gh-33371
This commit revises QualifierAnnotationAutowireCandidateResolver to
reinstate "qualifier" support for the legacy JSR-330
@javax.inject.Named annotation.
See gh-31090
Closes gh-33345
When ScheduledAnnotationReactiveSupport adds the Observation to the
context, Reactor opens a scope through the Context Propagation API.
This happens before TrackingSubscriber would start the Observation and
opening a scope without starting an Observation is invalid.
This change moves the Observation start before the scope opening.
Closes gh-33349
Before UnknownContentTypeException is thrown, it is added to the current
Observation but since UnknownContentTypeException is a
RestClientException, the exception is added again in one of the
catch blocks later on.
Closes gh-33347
ClientHttpResponse implements Closeable and the close method of
DefaultConvertibleClientHttpResponse also stops the current Observation.
Before this change exiting the try-with-resource block stopped the
Observation since it called close on ClientHttpResponse.
After this, there were multiple error and stop calls on the Observation
in the catch blocks after the Observation was already stopped
which is invalid.
This change reorders the flow by stopping the Observation in the
finally block (closing ClientHttpResponse) and not stopping
the Observation in any of the catch blocks.
Closes gh-33346
Prior to this commit, the Gradle build output the following warning
multiple times.
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Since we don't need CDS enabled for our tests, I've added `-Xshare:off`
as a JVM argument for our tests to disable CDS.
(cherry picked from commit 27985b1439)
Since the me.champeau.mrjar stores Java 21 main and test sources in
non-standard locations, and since we can only use a single JDK within
Eclipse, this commit updates `ide.gradle` to remove `java21` classpath
entries in Eclipse projects.
This commit implements modifyContextPath in ServletRequestPath and
apply the same logic of concatenating the servlet path with the
context path.
Closes gh-33251
This changes the criteria for simplified task rejection logging from
to be that the executor is in the shutdown phase, not fully terminated.
See gh-33334
Closes gh-33336
SimpleEvaluationContext.forReadOnlyDataBinding() documents that it
creates a SimpleEvaluationContext for read-only access to public
properties; however, prior to this commit write access was not disabled
for indexed structures when using the assignment operator, the
increment operator, or the decrement operator.
In order to better align with the documented contract for
forReadOnlyDataBinding(), this commit makes it possible to disable
assignment in general in order to enforce read-only semantics for
SpEL's SimpleEvaluationContext when created via the
forReadOnlyDataBinding() factory method. Specifically:
- This commit introduces a new isAssignmentEnabled() "default" method
in the EvaluationContext API, which returns true by default.
- SimpleEvaluationContext overrides isAssignmentEnabled(), returning
false if the context was created via the forReadOnlyDataBinding()
factory method.
- The Assign, OpDec, and OpInc AST nodes -- representing the assignment
(=), increment (++), and decrement (--) operators, respectively --
now throw a SpelEvaluationException if assignment is disabled for the
current EvaluationContext.
Closes gh-33319
The changes made in conjunction with gh-33013 resulted in a regression
for varargs support in SpEL expressions. Specifically, before gh-33013
one could supply a list -- for example, an "inline list" -- as the
varargs array when invoking a varargs constructor, method, or function
within a SpEL expression. However, after gh-33013 an inline list (or
collection in general) is no longer converted to an array for varargs
invocations. Instead, the list is supplied as a single argument of the
resulting varargs array which breaks applications that depend on the
previous behavior.
Although it was never intended that one could supply a collection as
the set of varargs, we concede that this is a regression in existing
behavior, and this commit therefore restores support for supplying a
java.util.List as the varargs "array".
In addition, this commit introduces the same "list to array" conversion
support for MethodHandle-based functions that accept varargs.
Note, however, that this commit does not restore support for converting
arbitrary single objects to an array for varargs invocations if the
single object is already an instance of the varargs array's component
type.
See gh-33013
Closes gh-33315
Prior to this commit, the Indexer in the Spring Expression Language
(SpEL) silently ignored a failure to set a property via the indexed
property syntax (['<property name>'] = <new value>) – for example, if
property write access was disabled in the EvaluationContext.
This commit addresses this issue by properly throwing a
SpelEvaluationException in PropertyIndexingValueRef.setValue(Object) if
the property could not be set.
Closes gh-33310
Prior to this commit, SpEL incorrectly wrapped a primitive array in an
Object[] array when invoking Object[] varargs methods and constructors.
This commit addresses this by updating the convertArguments(...) method
in ReflectionHelper as follows when the user supplies the varargs
already packaged in a primitive array.
- When deciding whether to convert a single element passed as varargs,
we now check if the argument is an array that is assignable to the
varargs array type.
- When converting an array supplied as the varargs, we convert that
array to the varargs array type.
Closes gh-33317
Prior to this commit, the ConversionService failed to convert a primitive
array (such as int[]) to an Object[] due to an error in the logic in
ArrayToArrayConverter.
This commit addresses this by augmenting the "can bypass conversion"
check in ArrayToArrayConverter to ensure that the supplied source object
is an instance of the target type (i.e., that the source array can be
cast to the target type array without conversion).
Closes gh-33212
Our recent switch from the `org.unbroken-dome.xjc` plugin to the
`com.github.bjornvester.xjc` plugin resulted in errors when trying to
import Spring Framework projects into the Eclipse IDE.
This commit fixes those issues as follows.
- @wilkinsona revised the XJC configuration in `spring-oxm.gradle` to
avoid the ConcurrentModificationException encountered when running
`./gradlew eclipse`.
- I added a workaround in `ide.gradle` to manually remove lingering
"main" classpath entries for sources generated by XJC.
Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
Closes gh-33264
This commit improves CodeWarnings so that it detects if an enclosing
class is deprecated. Previously, it would only consider the annotated
element itself and the enclosing element is important for a class as
it is required to refer to it.
Closes gh-33273
This commit upgrades our build to use a different plugin for XJC
processing, so that Gradle doesn't output a compatibility warning
anymore.
Unfortunately, com.github.bjornvester.xjc only works against main
sources and our schema is only used for test purposes. This commit
therefore reconfigure the task to remove the xjc main source set and
apply it to the test source set instead.
Closes gh-33264
This commit makes sure to consistently check that the content length
is not set above 2GB. Previously it was only checked in
setContentLength.
Closes gh-33256
* pr/33248:
Polish "Stop referring to STRUCT and ARRAY as they are deprecated"
Stop referring to STRUCT and ARRAY as they are deprecated
Closes gh-33248
Prior to this commit, the observation instrumentation for `@JmsListener`
annotated methods (implemented in `AbstractMessageListenerContainer`
would not instrument the JMS session using the Micrometer JMS support.
This means that response messages returned from the listener method
would be sent but no observation would be recorded. As a result, tracing
message properties would be also missing.
This commit ensures that the session provided to the listener method is
instrumented beforehand, if Micrometer is on the classpath and an
observation registry has been configured.
Fixes gh-33221
This change simplifies the CacheInterceptor way of dealing with cached
coroutines, thanks to the fact that lower level support for AOP has been
introduced in c8169e5c. This fix is similar to the one applied for
`@Transactional` in gh-33095.
Closes gh-33210
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with a primitive array
containing the variable arguments, although that is supported for a
varargs Method function. Attempting to do so resulted in the first
element of the primitive array being supplied as a single argument to
the MethodHandle, effectively ignoring any variable arguments after the
first one.
This commit addresses this by updating the
convertAllMethodHandleArguments(...) method in ReflectionHelper as
follows when the user supplies the varargs already packaged in a
primitive array.
- Regarding conversion, use the wrapper type for a primitive varargs
array, since we eventually need an Object array in order to invoke
the MethodHandle in FunctionReference#executeFunctionViaMethodHandle().
- When deciding whether to convert a single element passed as varargs,
we now check if the argument is an array that is assignable to the
varargs array type.
- When converting an array supplied as the varargs, we now convert that
array to the varargs array type instead of the varargs component type.
Note, however, that a SpEL expression cannot provide a primitive array
for an Object[] varargs target. This is due to the fact that the
ArrayToArrayConverter used by Spring's ConversionService does not
support conversion from a primitive array to Object[] -- for example,
from int[] to Object[].
See gh-33191
Closes gh-33198
This change tracks the multipart nature of the async request
within the `DispatcherServlet`, in the `WebAsyncManager`.
This allows for the second ASYNC dispatch to recognize the
multipart aspect and clean up the associated resources.
Closes gh-33161
This commit makes sure that JAXBContext.newInstance consistently use
the target class classloader to detect the necessary resources.
Previously, the current thread's context classloader was used, which
could lead to not finding the required JAXB components.
Closes gh-33158
This commit makes sure that docs artifacts have their attributes set
for staging as well. Previously they were not and deployment of Javadoc
did not occur.
Closes gh-33204
This commit ensures that the varargs component type for a MethodHandle
cannot be null in ReflectionHelper's
convertAllMethodHandleArguments(...) method in SpEL.
Closes gh-33193
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with an array containing the
variable arguments, although that is supported for a varargs Method
function. Attempting to do so resulted in the array being supplied as a
single argument to the MethodHandle.
This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference as
follows when the user supplies the varargs already packaged in an array.
- Creates a new array large enough to hold the non-varargs arguments
and the unpackaged varargs arguments.
- Adds the non-varargs arguments to the beginning of that array and
adds the unpackaged varargs arguments to the end of that array.
- Invokes the MethodHandle with the new arguments array.
Closes gh-33191
Previous to this change, the transactional aspect would supersed the
user-defined AspectJ aspect, shortcircuiting to calling the original
Kotlin suspending function.
This change simplifies the TransactionAspectSupport way of dealing with
transactional coroutines, thanks to the fact that lower level support
for AOP has been introduced in c8169e5c.
Closes gh-33095
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with zero variable arguments,
even though the variable arguments are not required. Attempting to do
so resulted in a SpelEvaluationException with an
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION message.
This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference so that
it properly checks the required number of arguments for both varargs
and non-varargs MethodHandle invocations.
This commit also improves the error message for varargs invocations
with too few arguments. For example, if the MethodHandle requires at
least 1 argument plus a variable number of additional arguments and 0
arguments were supplied, the error message now states:
"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 1 or more"
Instead of:
"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 2"
Closes gh-33190
This commit harmonizes the invocation of a bean supplier with what
SimpleInstantiationStrategy does. Previously, the current factory method
was set to `null` once the invocation completes. This did not take
into account recursive scenarios where an instance supplier triggers
another instance supplier.
For consistency, the thread local is removed now if we attempt to set
the current method to null. SimpleInstantiationStrategy itself uses
the shortcut to align the code as much as possible.
Closes gh-33180
Prior to this commit, the Spring Expression Language (SpEL) incorrectly
split single String arguments by comma for Object... varargs method and
constructor invocations.
This commit addresses this by checking if the single argument type is
already "assignable" to the varargs component type instead of "equal"
to the varargs component type.
Closes gh-33013
In preparation for releasing Spring Framework from GitHub actions, this
commit adds a `verify` workflow that validates that the released bits
are correct by running sample projects against them.
Closes gh-33178
This commit updates the CI workflow to build against Java 23-ea as
well, using the temurin distribution. For consistency, we're also
building against Java 22.
Closes gh-32090
This commit harmonizes our CI configuration with Spring Boot, in
particular the clever use of reusable custom actions that simplify
the workflow definition quite a bit.
One main difference compared to Spring Boot is that we can now
specify a different distribution for a Java version to test, in
preparation for the support of building against 23-ea
See gh-32090
Commit 84714fbae9 introduced usage of the
-Djava.locale.providers=COMPAT command-line argument for javac in order
to allow our JDK 20 builds to pass by using legacy locale data.
That was done to ensure that Date/Time formats using AM/PM produced a
standard space (" ") before the "AM" or "PM" instead of a narrow
non-breaking space (NNBSP "\u202F"), which was introduced in Java 20
due to adoption of Unicode Common Locale Data Repository (CLDR-14032).
This commit removes usage of the -Djava.locale.providers=COMPAT
command-line argument and updates all affected tests to:
- Use an NNBSP before "AM" or "PM" in input text when running on Java 20
or higher.
- Leniently match against any Unicode space character in formatted
values containing "AM" or "PM".
See https://jdk.java.net/20/release-notes#JDK-8284840
See https://unicode-org.atlassian.net/browse/CLDR-14032
See gh-30185
Closes gh-33144
When a response fails to be completely emitted by the remote (connection
termination during the transmission of the response for example), a
WebClientResponseException can be propagated with a confusing message
which mainly reflects the status code and reason phrase, leading to
messages like "200 OK" in such an exception.
This change improves the situation by appending a hint at the underlying
cause whenever getMessage() is called on a WebClientResponseException
which was created with a non-error status code.
Closes gh-33127
This change ensures that the cache error handler is used in case of
future-based or publisher-based asynchronous caching completing with an
exception.
Closes gh-33073
Prior to this commit, the fix for gh-32730 disabled the involvment of
the osbervation filter for async dispatches. Instead of relying on ASYNC
dispatches to close the observation for async requests, this is now
using an async listener instead: async dispatches are not guaranteed to
happen once the async request is handled.
This change caused another side-effect: because async dispatches are not
considered anymore by this filter, the observation scope is not
reinstated for async dispatches. For example, `ResponseBodyAdvice`
implementations do not have the observation scope opened during their
execution.
This commit re-enables async dispatches for this filter, but ensures
that observations are not closed during such dispatches as this will be
done by the async listener.
Fixes gh-33091
Fix argument in call to applyReturnValueValidation()
method in MethodValidationInterceptor.java. Method
argument was passed instead of the return value of the
method that was being validated.
See gh-33105
Prior to this commit, the "Method Arguments" documentation for WebFlux
in the reference manual stated that WebFlux controller methods can
accept arguments of type Map, Model, or ModelMap to access the model.
However, ModelMap is actually not supported and results in exception
due to a type mismatch.
This commit updates the documentation to reflect this.
In addition, this commit updates related Javadoc and tests to avoid
mentioning or using ModelMap in WebFlux.
Closes gh-33107
Prior to this commit, the comment in the XML configuration example in
the Method Injection section of the reference manual referred to the
wrong bean names.
Closes gh-33096
Prior to this commit, the `ProtobufMessageConverter` used in messaging
would try and serialize the message payload by calling "toString()" on
it in order to pass it to the Protobuf JSON encoder.
While this works for `String` payloads, this fails for `byte[]` types.
This commit ensures that such `byte[]` are first converted to `String`
instances using the given charset first.
Fixes gh-27408
Prior to this commit, RequestMappingViewResolutionIntegrationTests
invoked the following:
configurer.setTemplateLoaderPath(
"classpath*:org/springframework/web/reactive/view/freemarker/");
However, that configuration is invalid since `classpath*:` is not
supported for a `templateLoaderPath`.
Despite that, the tests still passed since FreeMarkerConfigurer already
registers a new ClassTemplateLoader(FreeMarkerConfigurer.class, ""),
which automatically finds template files in the same package as
FreeMarkerConfigurer (for the "spring.ftl" macro library support) and
coincidentally RequestMappingViewResolutionIntegrationTests as well
(which resides in the same package).
This commit therefore removes the invalid configuration and adds a
comment to explain what's going on.
Prior to this commit, the fix for gh-32575 introduced cases where the
client observation would be stopped twice.
This commit ensures that `RestClient` observations are stopped only once
when the response is closed, or before throwing an unhanlded exception.
Fixes gh-33068
Prior to this commit, the isClientDisconnectedException() method in
DisconnectedClientHelper checked whether the message of the ultimate
exception in an exception chain contained one of the phrases "broken
pipe" or "connection reset by peer". However, that failed to match if
the exception message contained "Connection reset", which is the case
for the SocketException thrown by throwConnectionReset() in
sun.nio.ch.SocketChannelImpl.
This commit therefore replaces the "connection reset by peer" phrase
with "connection reset" in order to support all exception messages
containing "connection reset".
Closes gh-33064
This commit changes the use of HttpSessionRequiredException in
ModelFactory::initModel to an IllegalStateException, because the former
extends ServletException and cannot be used in WebFlux.
Closes gh-33043
Prior to this commit, the `ContentCachingRequestWrapper` could allocate
a `FastByteArrayOutputStream` block that was larger than the content
cache limit given as a consturctor argument. This was due to an
optimization applied in gh-31834 for allocating the right content cache
size when the request size is known.
Fixes gh-32987
Prior to this commit, the `ServerHttpObservationFilter` would support
async dispatches and would do the following:
1. start the observation
2. call the filter chain
3. if async has started, do nothing
4. if not in async mode, stop the observation
This behavior would effectively rely on Async implementations to
complete and dispatch the request back to the container for an async
dispatch. This is what Spring web frameworks do and guarantee.
Some implementations complete the async request but do not dispatch
back; as a result, observations could leak as they are never stopped.
This commit changes the support of async requests. The filter now
opts-out of async dispatches - the filter will not be called for those
anymore. Instead, if the application started async mode during the
initial container dispatch, the filter will register an AsyncListener to
be notified of the outcome of the async handling.
Fixes gh-32730
Commit d7970e4ab8 introduced support for JAXBElement in
Jaxb2XmlEncoder's encodeValue() method; however, canEncode() still
returned false for a JAXBElement element type.
This commit revises canEncode() so that it returns true for an element
type that is assignable from JAXBElement.
See gh-30552
See gh-32972
Closes gh-32977
Prior to this commit, #31870 added support for constraint annotations on
container elements for handler method argument validation. Supporting
this use case:
```
public void addNames(List<@NotEmpty String> names)
```
This commit does the same for `@Valid` annotation:
```
public void addPeople(List<@Valid Person> people)
```
Fixes gh-32964
This commit updates
PersistenceManagedTypesBeanRegistrationAotProcessor
in order to infer hints for Hibernate annotations meta
annotated with `@ValueGenerationType` (like `@CreationTimestamp`)
and `@IdGeneratorType`.
`@GenericGenerator` is not supported as it is deprecated as of
Hibernate 6.5.
Closes gh-32842
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into a Map using a primitive literal
(boolean, int, long, float, or double).
This commit adds support for compilation of such expressions by
ensuring that primitive literals are boxed into their corresponding
wrapper types in the compiled bytecode.
Closes gh-32903
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into any array or list using an
Integer.
This commit adds support for compilation of such expressions by
ensuring that an Integer is unboxed into an int in the compiled
bytecode.
See gh-32694
Closes gh-32908
Prior to this commit, the Gradle build issued the following warning.
- The deprecated "gradleEnterprise.buildScan.value" API has been
replaced by "develocity.buildScan.value"
- Use same playbook as docs-build
- Use Env Variables to cause partial build (same as docs-build)
- Use package.json so that dependencies can be updated with dependabot
Includes JAXBContext locking revision (avoiding synchronization) and consistent treatment of DocumentBuilderFactory (in terms of caching as well as locking).
Closes gh-32851
This commit updates Spring AOT to suppress a deprecation warning for
a generic type that has a deprecated element. Previously we only were
checking for the raw class.
Closes gh-32850
This commit avoids several instances of MockHttpServletRequest to
have a common reader for empty content as closing it will have an
unwanted side effect on the others.
Closes gh-32820
Prior to this commit, the `ReactiveTypeHandler` would handle `Flux`-like
return types from controller methods and adapt them to SSE streams using
the `SseEmitter`/`ResponseBodyEmitter` APIs. In case an `IOException` is
thrown while writing to the HTTP response stream, the
`ReactiveTypeHandler` would rely on the Servlet container to call
`AsyncListener#onError` - this would be the signal for Spring MVC to
complete the async exchange. To prevent racing issues between this
signal and the actual handling of the exception, changes like gh-20173
were applied. Since then, robust checks were added with gh-32340 in
`StandardServletAsyncWebRequest.LifecycleHttpServletResponse`.
With Jetty 12, `AsyncListener#onError` would not be called as the error
would happen while writing in blocking mode to the response (so, not
using the Servlet WriteListener contract). But still, such `IOException`
would still result in the closing of the HTTP connection. As of Jetty
12.0.4, this is no longer the case and the party managing the async
lifecycle is in charge of completing the exchange, as it should. This
means that the current behavior leaks HTTP connections for these cases
and causes memory issues.
This commit ensures that such exceptions happening during response
writes are caught and result in the completion of the `SSEEmitter` and
the closing of the exchange. Even if other Servlet containers still
propagate the error `AsyncListener#onError`, competing signals are still
managed with gh-32340.
Closes gh-32629
This commit fixes links from Spring Framework's Dokka HTML to Javadoc
for Spring Framework and Servlet APIs by explicitly configuring the
`element-list` page as the `package-list` in the Dokka Gradle plugin.
Closes gh-32797
A bug has existed in Spring's MergedAnnotations support since it was
introduced in Spring Framework 5.2. Specifically, if the
MergedAnnotations API is used to search for annotations with "standard
repeatable annotation" support enabled (which is the default), it's
possible to search for a repeatable annotation but not for the
repeatable annotation's container annotation.
The reason is that MergedAnnotationFinder.process(Object, int, Object,
Annotation) does not process the container annotation and instead only
processes the "contained" annotations, which prevents a container
annotation from being included in search results.
In #29685, we fixed a bug that prevented the MergedAnnotations support
from recognizing an annotation as a container if the container
annotation declares attributes other than the required `value`
attribute. As a consequence of that bug fix, since Spring Framework
5.3.25, the MergedAnnotations infrastructure considers such an
annotation a container, and due to the aforementioned bug the container
is no longer processed, which results in a regression in behavior for
annotation searches for such a container annotation.
This commit addresses the original bug as well as the regression by
processing container annotations in addition to the contained
repeatable annotations.
See gh-29685
Closes gh-32731
Prior to this commit, HTTP requests sent with the
`HttpComponentsClientHttpRequestFactory` would not set a
"Content-Length" header for empty request bodies. Setting a request
entity is the expected behavior for unsafe HTTP methods, and this would
align the behavior with other HTTP clients.
Developers would often rely on `BufferingClientHttpRequestFactory` to
set this information on the request.
This commit ensures that a `NullEntity` is used for unsafe HTTP methods,
when no body has been set for the request. This result in a
"Content-Length:0" request header.
Fixes gh-32678
This commit changes the guard against multiple subscriptions, as the
previously used doOnSubscribe hook could not function as guard in
certain scenarios.
Closes gh-32727
This commit counterbalances the retain in the MessagingRSocket
handleConnectionSetupPayload method with a conditional release on SETUP
frame type in handleNoMatch, preventing Netty buffer leaks.
Closes gh-32424
This commit refines the preDetermineBeanTypes algorithm that AOT uses
to approximate the order of preInstantiateSingletons more closely.
Previously, the algorithm assumed that all beans where non-lazy
singletons in terms of initialization order, which led to inconsistent
order in CGLIB proxy generation.
We now explicitly park lazy beans so that their types are determined
during a second phase, matching the order of regular initialization
order.
Closes gh-32669
Co-authored-by: Juergen Hoeller <juergen.hoeller@broadcom.com>
Previously, a UriComponents build based on a method would require the
given method to be the annotated one as method parameter resolution only
applied locally. This was a problem when a controller was specified on
a method whose mapping is defined in a parent.
This commit harmonies the lookup using AnnotatedMethod who provides
support for a synthesized method parameter that takes annotations from
parent parameter into account.
Closes gh-32553
Previously, a BeanDefinition that has an instance supplier would be
used irrespective of custom arguments being provided. This commit only
applies the instance supplier if no arguments are provided. With
custom arguments, the regular lookup takes place based on the
information provided in the bean factory.
Closes gh-32657
Previously, if a factory method is defined on a parent, the generated
code would blindly use the method's declaring class for both the target
of the generated code, and the signature of the method.
This commit improves the resolution by considering the factory metadata
in the BeanDefinition.
Closes gh-32609
Prior to this commit, `RestClientException` thrown by status handlers
would not be registered as observation errors. This commit ensures that
such exceptions are first caught, registered in the observation and
rethrown as expected.
Closes gh-32575
Prior to this commit, the `RestClient` observations would be stopped as
soon as the exchange function was called. This means that all errors
related to response decoding or mapping would not be recorded by the
obsevations.
This commit extends the observation recording to the `ResponseSpec` DSL
calls as well as custom exchange functions.
Fixes gh-32575
Prior to this commit, the `BufferingClientHttpRequestFactory`, through
the `AbstractBufferingClientHttpRequest`, would set a "Content-Length"
header value, even if the buffered body was empty.
This behavior is invalid since no request body would be set by the
client code in the first place.
This commit ensures that this header is only set if a request body has
been buffered and is about to be written to the request.
Fixes gh-32650
This commit rephrases the `DefaultTransactionDefinition#setTimeout`
exception message to better reflect the fact that 0 is a valid input
value.
Even though this often leads to a transaction immediately timing out
after opening, there is one notable case where this has another
meaningful effect: in Jakarta transactions (`UserTransaction`), when
passing 0 "the transaction service restores the default value".
Closes gh-32635
This change improves the message of several parsing-related exceptions
that would previously entirely swallow the original exception's message
and sometimes have a slightly misleading message as a result.
This is done by appending the cause's `toString` representation to the
IllegalArgumentException messages instead of an hardcoded "cause".
Closes gh-32636
Before this change temporary files would not consistently be deleted
when the connection which uploads the multipart files closes naturally.
This change uses the usingWhen Reactor operator to ensure that the
termination of the connection doesn't prevent individual file parts
from being deleted due to a cancellation signal.
Closes gh-31217
This commit refines the expressions for the scheme, user info, host and
port parts of the URL in UriComponentsBuilder to better conform to
RFC 3986.
Fixes gh-32616
Prior to this commit, `BufferingClientHttpRequestWrapper` would always
write to the actual client request body, even if the buffered content
was empty (empty byte array).
This would cause issues with specific client request factories,
especially the OkHttp variant, that would consider empty byte arrays as
non-empty body and would reject such cases for GET requests with an
"IllegalArgumentException: method GET must not have a request body".
This commit only writes to the request if the buffered content is not
empty.
Fixes gh-32612
Prior to this commit, MethodIntrospector failed to properly detect
bridge methods for subsequent invocations of selectMethods() with the
same targetType and MetadataLookup, if such subsequent invocations
occurred after the ApplicationContext had been refreshed.
The reason this occurs is due to the following.
- Class#getDeclaredMethods() always returns "child copies" of the
underlying Method instances -- which means that `equals()` should be
used instead of `==` whenever the compared Method instances can come
from different sources (such as the static caches mentioned below).
- BridgeMethodResolver caches resolved bridge methods in a static cache
-- which is never cleared.
- ReflectionUtils caches declared methods in a static cache
-- which gets cleared when an ApplicationContext is refreshed.
Consequently, if you attempt to load an ApplicationContext twice in the
same ClassLoader, the second attempt uses the existing, populated cache
for bridged methods but a cleared, empty cache for declared methods.
This results in new invocations of Class#getDeclaredMethods(), and
identity checks with `==` then fail to detect equivalent bridge methods.
This commit addresses this by additionally comparing bridge methods
using `equals()` in MethodIntrospector.selectMethods().
Note that the `==` checks remain in place as an optimization for when
`equals()` is unnecessary.
Closes gh-32586
Prior to this commit, the `JmsTemplate#sendAndReceive` method would not
instrument the JMS session. This means that no metric would be recorded
when sending the message and no trace would be propagated downstream.
This commit ensures that the JMS session is instrumented in this case as
well. Note, the reception of the response message does not create a
`"jms.message.process"` observation as the session is only receiving the
message, no listener has been configured on the message consumer.
Fixes gh-32606
This commit ensures that the response body is drained and closed when
the response itself is closed, instead of disposing the connection, as
this will disable the connection pool.
Closes gh-32528
This commit reverts some null-safety changes which make sense
on main but are too impactful for 6.1.x for Kotlin developers
using -Xjsr305=strict.
See gh-32475
This commit ensures that `InvocableHandlerMethod` executes the method
on the desired thread if a non-blocking thread is specified, even in the
case where arguments resolution happens on a different thread. This is
notably the case if the method body is resolved as an input argument to
the controller method (`@RequestBody`).
Closes gh-32502
Prior to this commit, SpEL's CompoundExpression omitted the null-safe
syntax in AST string representations of the selection and projection
operators.
To address this, this commit implements isNullSafe() in Projection and
Selection.
Closes gh-32515
Prior to this commit, MethodReference and PropertyOrFieldReference
already defined local isNullSafe() methods, but we need identical
methods in Selection, Projection, and Indexer, and we may potentially
need null-safe support for additional operators in the future.
To address the common need for an is-null-safe check, this commit
introduces an isNullSafe() method in SpelNodeImpl with a default
implementation that returns false.
Closes gh-32516
The fix for #31254 resulted in an InvalidMimeTypeException being thrown
by MimeTypeUtils.sortBySpecificity() instead of an
IllegalArgumentException. However, InvalidMimeTypeException extends
IllegalArgumentException. Consequently, the change from
IllegalArgumentException to InvalidMimeTypeException did not result in
the desired effect in HeaderContentNegotiationStrategy.
HeaderContentNegotiationStrategy.resolveMediaTypes() still allows the
InvalidMimeTypeException to propagate as-is without wrapping it in an
HttpMediaTypeNotAcceptableException.
To address this issue, this commit catches InvalidMediaTypeException
and InvalidMimeTypeException in HeaderContentNegotiationStrategy and
wraps the exception in an HttpMediaTypeNotAcceptableException.
See gh-31254
See gh-31769
Closes gh-32483
There is no way to consistently test this use case because listener
container implementations have different behavior for unhandled errors
and might retry or close the container altogether.
See gh-32458
Prior to this commit, when using the `DefaultMessageListenerContainer`
as a backing listener container for JMS messages, the instrumentation
would not record JMS exceptions as observation errors when they were not
handled by configured `ErrorHandler`.
This commit ensures that this is the case.
Fixes gh-32458
Prior to this commit, gh-31609 added the current observation context as
a request attribute for `WebClient` calls. While it was not confirmed as
the main cause, this feature was linked to several reports of memory
leaks. This would indeed attach more memory to the request object graph
at runtime - although it shouldn't prevent its collection by the GC.
This commit removes this feature and instead developers should get the
current observation from the reactor context if they wish to interact
with it.
Closes gh-32198
Prior to this commit, error signals flowing from the client response
publisher in `WebClient` would be set on the `Observation.Context`. This
is enough for the observation convention to collect data about the error
but observation handlers are not notified of this error.
This commit sets the error instead on the observation directly to fix
this issue.
Fixes gh-32389
webmvc.fn now also uses the StandardServletAsyncWebRequest wrapped response
to enforce lifecycle rules from Servlet spec (section 2.3.3.4).
See gh-32340
KClass instantiation in CoroutinesUtils is suboptimal, and should be
replaced by KTypes#isSubtypeOf checks using pre-instantiated types for
Flow, Mono and Publisher.
This commit impact on performances is significant since a throughput
increase between 2x and 3x has been measured on basic endpoints.
Closes gh-32390
This commit fixes an issue where a Cacheable method which returns a
Flux (or multi-value publisher) will be invoked once, but the returned
publisher is actually subscribed twice.
The previous fix 988f3630c would cause the cached elements to depend on
the first usage pattern / request pattern, which is likely to be too
confusing to users. This fix reintroduces the notion of exhausting the
original Flux by having a second subscriber dedicated to that, but uses
`refCount(2)` to ensure that the original `Flux` returned by the cached
method is still only subscribed once.
Closes gh-32370
Also fix a couple of related issues:
- add AsyncRequestNotUsableException to the list of exceptions
that imply response issues.
- handle exceptions from @ExceptionHandler regardless of whether
thrown immediately or via Publisher.
Closes gh-32359
This commit fixes an issue where a Cacheable method which returns a
Flux (or multi-value publisher) will be invoked once, but the returned
publisher is actually subscribed twice.
By using the Reactor `tap` operator, we ensure that we can emit values
downstream AND accumulate emitted values into the List with a single
subscription.
The SignalListener additionally handles scenarios involving cancel,
for instance in case of a `take(1)` in the chain. In that case values
emitted up until that point will have been stored into the List buffer,
so we can still put it in the cache. In case of error, no caching occurs
and the internal buffer is cleared. This implementation also protects
against competing onComplete/onError signals and cancel signals.
Closes gh-32370
The following adjustments are also made as a result:
- Use int to check if lock is held and unlock is needed, given that
for non-async requests we don't need to obtain a lock.
- Protect access methods getOutputStream and getWriter with the
same locking and state checks.
Closes gh-32340
ServletResponseHttpHeaders#get should be annotated with `@Nullable` and
return null instead of a singleton list containing null when there is no
content type header.
Closes gh-32362
In addition to using the ServletOutputStream, it's also possible to call
ServletResponse#flushBuffer, so the ServletOutputStream wrapper logic needs
to apply there as well.
See gh-32340
The wrapped response prevents use after AsyncListener onError or completion
to ensure compliance with Servlet Spec 2.3.3.4.
The wrapped response is applied in RequestMappingHandlerAdapter.
The wrapped response raises AsyncRequestNotUsableException that is now
handled in DefaultHandlerExceptionResolver.
See gh-32340
Prior to this commit, if a Spring Expression Language (SpEL) expression
referenced the root context object via the #root or #this variable, we
inserted a checkcast in the generated byte code that cast the object to
its concrete type. However if the root context object's type was
non-public, that resulted in an IllegalAccessError when the compiled
byte code was executed.
VariableReference.getValueInternal() already contains a solution for
global variables which inserts a checkcast to Object in the generated
byte code instead of to the object's concrete non-public type.
This commit therefore applies the same logic to #root (or #this when
used to reference the root context object) that is already applied to
global variables.
Closes gh-32356
This commit refines WebMVC and WebFlux argument resolution in order to
convert properly Kotlin value class arguments by using the type of the
value instead of the type of the value class.
Closes gh-32353
The HttpHeaders.getAcceptLanguageAsLocales was incurring overhead from
using a Stream, as well as calling the fairly expensive
Locale.getDisplayName method.
Switch to using an ArrayList, and skipping over wildcard ranges to avoid
needing to check the display name.
Closes gh-32318
This commit fixes a performance regression caused by gh-31698,
and more specifically by KClass#isValue invocations which are slow since
they load the whole module to find the class to get the descriptor.
After discussing with the Kotlin team, it has been decided that only
checking for the presence of `@JvmInline` annotation is enough for
Spring use case.
As a consequence, this commit introduces a new
KotlinDetector#isInlineClass method that performs such check, and
BeanUtils, CoroutinesUtils and WebMVC/WebFlux InvocableHandlerMethod
have been refined to leverage it.
Closes gh-32334
For consistency with other examples, this commit omits `method` parameter
names in the "Migrating from RestTemplate to RestClient" section of the
reference docs.
Closes gh-32335
Based on feedback from several members of the community, we have
decided to revert the caching of the Content-Type header that was
introduced in ContentCachingResponseWrapper in 375e0e6827.
This commit therefore completely removes Content-Type caching in
ContentCachingResponseWrapper and updates the existing tests
accordingly.
To provide guards against future regressions in this area, this commit
also introduces explicit tests for the 6 ways to set the content length
in ContentCachingResponseWrapper and modifies a test in
ShallowEtagHeaderFilterTests to ensure that a Content-Type header set
directly on ContentCachingResponseWrapper is propagated to the
underlying response even if content caching is disabled for the
ShallowEtagHeaderFilter.
See gh-32039
Closes gh-32317
Prior to this commit, getHeaderNames() returned duplicates for the
Content-Type and Content-Length headers if they were set in the wrapped
response as well as in ContentCachingResponseWrapper.
This commit fixes that by returning a unique set from getHeaderNames().
In addition, this commit introduces a new test in
ContentCachingResponseWrapperTests to verify the expected behavior for
Content-Type and Content-Length headers that are set in the wrapped
response as well as in ContentCachingResponseWrapper.
See gh-32039
See gh-32317
Commit 375e0e6827 introduced a regression in
ContentCachingResponseWrapper (CCRW). Specifically, CCRW no longer
honors Content-Type and Content-Length headers that have been set on
the wrapped response and returns null for those header values if they
have not been set directly on the CCRW.
This commit fixes this regression as follows.
- The Content-Type and Content-Length headers set in the wrapped
response are honored in getContentType(), containsHeader(),
getHeader(), and getHeaders() unless those headers have been set
directly on the CCRW.
- In copyBodyToResponse(), the Content-Type in the wrapped response is
only overridden if the Content-Type has been set directly on the CCRW.
See gh-32039
Closes gh-32317
This commit adapts Hibernate native support to handle
the changes performed as part of HHH-17643 which impacts
Hibernate versions 6.4.3+ and 6.2.21+.
It ignores the BytecodeProvider services loaded by the
service loader feature in order to default to the
"no-op" provider with native, and makes the substitutions
more lenient when a substituted field or method does not
exist.
gh-32314 is expected to remove the need for such
substitutions which are not great for maintainability
by design.
Closes gh-32311
This commit revisits the improved detection algorithm for stored
procedure as, unfortunately, certain JDBC drivers do not support
the documented pattern for schema and procedure name.
To work around this limitation, this commit applies the escaping of
wildcard characters to the case where multiple procedures have been
found for a given search.
Closes gh-32295
Delegate to the spliterator method of the underlying collection in
MutablePropertyValues and MutablePropertySources. In both cases, those
collection types have specialized Spliterator implementations.
Delegating to these Spliterators also means the characteristics of the
Spliterator are properly set.
See gh-32281
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.1.x?groups=Build") [](https://ge.spring.io/scans?search.rootProjectNames=spring)
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3A6.1.x) [](https://ge.spring.io/scans?search.rootProjectNames=spring)
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
@@ -6,7 +6,7 @@ Spring provides everything required beyond the Java programming language for cre
## Code of Conduct
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@spring.io.
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.1.x[Spring Framework 6.1.x].
=== Setting up your development environment
If you're part of the Spring Framework project on GitHub, you can get access to CI management features.
First, you need to go to https://ci.spring.io and install the client CLI for your platform (see bottom right of the screen).
You can then login with the instance using:
[source]
----
$ fly -t spring login -n spring-framework -c https://ci.spring.io
----
Once logged in, you should get something like:
[source]
----
$ fly ts
name url team expiry
spring https://ci.spring.io spring-framework Wed, 25 Mar 2020 17:45:26 UTC
----
=== Pipeline configuration and structure
The build pipelines are described in `pipeline.yml` file.
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
You'll find in this folder the following resources:
* `pipeline.yml` the build pipeline
* `parameters.yml` the build parameters used for the pipeline
* `images/` holds the container images definitions used in this pipeline
* `scripts/` holds the build scripts that ship within the CI container images
* `tasks` contains the task definitions used in the main `pipeline.yml`
=== Updating the build pipeline
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
The pipeline can be deployed using the following command:
@@ -15,7 +15,7 @@ Applying such optimizations early implies the following restrictions:
* The classpath is fixed and fully defined at build time.
* The beans defined in your application cannot change at runtime, meaning:
** `@Profile`, in particular profile-specific configuration needs to be chosen at build time.
** `@Profile`, in particular profile-specific configuration, needs to be chosen at build time and is automatically enabled at runtime when AOT is enabled.
** `Environment` properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
* Bean definitions with instance suppliers (lambdas or method references) cannot be transformed ahead-of-time.
* Beans registered as singletons (using `registerSingleton`, typically from
@@ -36,7 +36,7 @@ NOTE: At the moment, AOT is focused on allowing Spring applications to be deploy
We intend to support more JVM-based use cases in future generations.
[[aot.basics]]
== AOT engine overview
== AOT Engine Overview
The entry point of the AOT engine for processing an `ApplicationContext` is `ApplicationContextAotGenerator`. It takes care of the following steps, based on a `GenericApplicationContext` that represents the application to optimize and a {spring-framework-api}/aot/generate/GenerationContext.html[`GenerationContext`]:
WARNING: Kotlin class names with backticks that use invalid Java identifiers (not starting with a letter, containing spaces, etc.) are not supported.
Since there isn't any particular condition on this class, `dataSourceConfiguration` and `dataSource` are identified as candidates.
The AOT engine will convert the configuration class above to code similar to the following:
@@ -209,6 +224,17 @@ There is a bean definition for `dataSourceConfiguration` and one for `dataSource
When a `datasource` instance is required, a `BeanInstanceSupplier` is called.
This supplier invokes the `dataSource()` method on the `dataSourceConfiguration` bean.
[[aot.running]]
== Running with AOT Optimizations
AOT is a mandatory step to transform a Spring application to a native executable, so it
is automatically enabled when running in this mode. It is possible to use those optimizations
on the JVM by setting the `spring.aot.enabled` System property to `true`.
NOTE: When AOT optimizations are included, some decisions that have been taken at build-time
are hard-coded in the application setup. For instance, profiles that have been enabled at
build-time are automatically enabled at runtime as well.
[[aot.bestpractices]]
== Best Practices
@@ -218,7 +244,7 @@ However, keep in mind that some optimizations are made at build time based on a
This section lists the best practices that make sure your application is ready for AOT.
[[aot.bestpractices.bean-registration]]
== Programmatic bean registration
=== Programmatic Bean Registration
The AOT engine takes care of the `@Configuration` model and any callback that might be
invoked as part of processing your configuration. If you need to register additional
@@ -240,7 +266,7 @@ notion of a classpath. For cases like this, it is crucial that the scanning happ
build time.
[[aot.bestpractices.bean-type]]
=== Expose The Most Precise Bean Type
=== Expose the Most Precise Bean Type
While your application may interact with an interface that a bean implements, it is still very important to declare the most precise type.
The AOT engine performs additional checks on the bean type, such as detecting the presence of `@Autowired` members or lifecycle callback methods.
@@ -300,6 +326,46 @@ However, this is not a best practice and flagging the preferred constructor with
In case you are working on a code base that you cannot modify, you can set the {spring-framework-api}/beans/factory/support/AbstractBeanDefinition.html#PREFERRED_CONSTRUCTORS_ATTRIBUTE[`preferredConstructors` attribute] on the related bean definition to indicate which constructor should be used.
[[aot.bestpractices.complex-data-structures]]
=== Avoid Complex Data Structures for Constructor Parameters and Properties
When crafting a `RootBeanDefinition` programmatically, you are not constrained in terms of types that you can use.
For instance, you may have a custom `record` with several properties that your bean takes as a constructor argument.
While this works fine with the regular runtime, AOT does not know how to generate the code of your custom data structure.
A good rule of thumb is to keep in mind that bean definitions are an abstraction on top of several models.
Rather than using such structures, decomposing to simple types or referring to a bean that is built as such is recommended.
As a last resort, you can implement your own `org.springframework.aot.generate.ValueCodeGenerator$Delegate`.
To use it, register its fully qualified name in `META-INF/spring/aot.factories` using the `Delegate` as the key.
[[aot.bestpractices.custom-arguments]]
=== Avoid Creating Beans with Custom Arguments
Spring AOT detects what needs to be done to create a bean and translates that in generated code using an instance supplier.
The container also supports creating a bean with {spring-framework-api}++/beans/factory/BeanFactory.html#getBean(java.lang.String,java.lang.Object...)++[custom arguments] that leads to several issues with AOT:
. The custom arguments require dynamic introspection of a matching constructor or factory method.
Those arguments cannot be detected by AOT, so the necessary reflection hints will have to be provided manually.
. By-passing the instance supplier means that all other optimizations after creation are skipped as well.
For instance, autowiring on fields and methods will be skipped as they are handled in the instance supplier.
Rather than having prototype-scoped beans created with custom arguments, we recommend a manual factory pattern where a bean is responsible for the creation of the instance.
[[aot.bestpractices.circular-dependencies]]
=== Avoid Circular Dependencies
Certain use cases can result in circular dependencies between one or more beans. With the
regular runtime, it may be possible to wire those circular dependencies via `@Autowired`
on setter methods or fields. However, an AOT-optimized context will fail to start with
explicit circular dependencies.
In an AOT-optimized application, you should therefore strive to avoid circular
dependencies. If that is not possible, you can use `@Lazy` injection points or
`ObjectProvider` to lazily access or retrieve the necessary collaborating beans. See
.Are annotations better than XML for configuring Spring?
****
The introduction of annotation-based configuration raised the question of whether this
approach is "`better`" than XML. The short answer is "`it depends.`" The long answer is
that each approach has its pros and cons, and, usually, it is up to the developer to
decide which strategy suits them better. Due to the way they are defined, annotations
provide a lot of context in their declaration, leading to shorter and more concise
configuration. However, XML excels at wiring up components without touching their source
code or recompiling them. Some developers prefer having the wiring close to the source
while others argue that annotated classes are no longer POJOs and, furthermore, that the
configuration becomes decentralized and harder to control.
Spring provides comprehensive support for annotation-based configuration, operating on
metadata in the component class itself by using annotations on the relevant class,
method, or field declaration. As mentioned in
xref:core/beans/factory-extension.adoc#beans-factory-extension-bpp-examples-aabpp[Example: The `AutowiredAnnotationBeanPostProcessor`],
Spring uses `BeanPostProcessors` in conjunction with annotations to make the core IOC
container aware of specific annotations.
No matter the choice, Spring can accommodate both styles and even mix them together.
It is worth pointing out that through its xref:core/beans/java.adoc[JavaConfig] option, Spring lets
annotations be used in a non-invasive way, without touching the target components'
source code and that, in terms of tooling, all configuration styles are supported by
{spring-site-tools}[Spring Tools] for Eclipse, Visual Studio Code, and Theia.
****
An alternative to XML setup is provided by annotation-based configuration, which relies
on bytecode metadata for wiring up components instead of XML declarations. Instead of
using XML to describe a bean wiring, the developer moves the configuration into the
component class itself by using annotations on the relevant class, method, or field
declaration. As mentioned in xref:core/beans/factory-extension.adoc#beans-factory-extension-bpp-examples-aabpp[Example: The `AutowiredAnnotationBeanPostProcessor`], using a
`BeanPostProcessor` in conjunction with annotations is a common means of extending the
Spring IoC container. For example, the xref:core/beans/annotation-config/autowired.adoc[`@Autowired`]
annotation provides the same capabilities as described in xref:core/beans/dependencies/factory-autowire.adoc[Autowiring Collaborators] but
For example, the xref:core/beans/annotation-config/autowired.adoc[`@Autowired`]
annotation provides the same capabilities as described in
xref:core/beans/dependencies/factory-autowire.adoc[Autowiring Collaborators] but
with more fine-grained control and wider applicability. In addition, Spring provides
support for JSR-250 annotations, such as `@PostConstruct` and `@PreDestroy`, as well as
support for JSR-330 (Dependency Injection for Java) annotations contained in the
@@ -36,13 +19,16 @@ can be found in the xref:core/beans/standard-annotations.adoc[relevant section].
[NOTE]
====
Annotation injection is performed before XML injection. Thus, the XML configuration
overrides the annotations for properties wired through both approaches.
Annotation injection is performed before external property injection. Thus, external
configuration (e.g. XML-specified bean properties) effectively overrides the annotations
for properties when wired through mixed approaches.
====
As always, you can register the post-processors as individual bean definitions, but they
can also be implicitly registered by including the following tag in an XML-based Spring
configuration (notice the inclusion of the `context` namespace):
Technically, you can register the post-processors as individual bean definitions, but they
are implicitly registered in an `AnnotationConfigApplicationContext` already.
In an XML-based Spring setup, you may include the following configuration tag to enable
mixing and matching with annotation-based configuration:
In addition to its role for component initialization, you can also place the `@Lazy`
annotation on injection points marked with `@Autowired` or `@Inject`. In this context,
it leads to the injection of a lazy-resolution proxy. However, such a proxy approach
is rather limited. For sophisticated lazy interactions, in particular in combination
with optional dependencies, we recommend `ObjectProvider<MyTargetBean>` instead.
====
Autowired fields and methods are supported, as previously discussed, with additional
support for autowiring of `@Bean` methods. The following example shows how to do so:
@@ -751,7 +755,7 @@ and bean definition show.
TIP: If you run into naming conflicts due to multiple autodetected components having the
same non-qualified class name (i.e., classes with identical names but residing in
different packages), you may need to configure a `BeanNameGenerator` that defaults to the
fully qualified class name for the generated bean name. As of Spring Framework 5.2.3, the
fully qualified class name for the generated bean name. The
`FullyQualifiedAnnotationBeanNameGenerator` located in package
`org.springframework.context.annotation` can be used for such purposes.
@@ -920,7 +924,8 @@ Kotlin::
[[beans-scanning-qualifiers]]
== Providing Qualifier Metadata with Annotations
The `@Qualifier` annotation is discussed in xref:core/beans/annotation-config/autowired-qualifiers.adoc[Fine-tuning Annotation-based Autowiring with Qualifiers].
The `@Qualifier` annotation is discussed in
xref:core/beans/annotation-config/autowired-qualifiers.adoc[Fine-tuning Annotation-based Autowiring with Qualifiers].
The examples in that section demonstrate the use of the `@Qualifier` annotation and
custom qualifier annotations to provide fine-grained control when you resolve autowire
candidates. Because those examples were based on XML bean definitions, the qualifier
@@ -644,7 +644,7 @@ Each `SpEL` expression evaluates against a dedicated context. The following tabl
items made available to the context so that you can use them for conditional event processing:
[[context-functionality-events-annotation-tbl]]
.Event SpEL available metadata
.Event metadata available in SpEL expressions
|===
| Name| Location| Description| Example
@@ -660,8 +660,8 @@ items made available to the context so that you can use them for conditional eve
| __Argument name__
| evaluation context
| The name of any of the method arguments. If, for some reason, the names are not available
(for example, because there is no debug information in the compiled byte code), individual
| The name of a particular method argument. If the names are not available
(for example, because the code was compiled without the `-parameters` flag), individual
arguments are also available using the `#a<#arg>` syntax where `<#arg>` stands for the
argument index (starting from 0).
| `#blEvent` or `#a0` (you can also use `#p0` or `#p<#arg>` parameter notation as an alias)
@@ -883,11 +883,12 @@ e.g. for processing all events asynchronously and/or for handling listener excep
== Convenient Access to Low-level Resources
For optimal usage and understanding of application contexts, you should familiarize
yourself with Spring's `Resource` abstraction, as described in xref:web/webflux-webclient/client-builder.adoc#webflux-client-builder-reactor-resources[Resources].
yourself with Spring's `Resource` abstraction, as described in
xref:core/resources.adoc[Resources].
An application context is a `ResourceLoader`, which can be used to load `Resource` objects.
A `Resource` is essentially a more feature rich version of the JDK `java.net.URL` class.
In fact, the implementations of the `Resource` wrap an instance of `java.net.URL`, where
In fact, implementations of `Resource` wrap an instance of `java.net.URL`, where
appropriate. A `Resource` can obtain low-level resources from almost any location in a
transparent fashion, including from the classpath, a filesystem location, anywhere
describable with a standard URL, and some other variations. If the resource location
Style-based formatting and parsing rely on locale-sensitive patterns which may change
depending on the Java runtime. Specifically, applications that rely on date, time, or
number parsing and formatting may encounter incompatible changes in behavior when running
on JDK 20 or higher.
Using an ISO standardized format or a concrete pattern that you control allows for
reliable system-independent and locale-independent parsing and formatting of date, time,
and number values.
For `@DateTimeFormat`, the use of fallback patterns can also help to address
compatibility issues.
For further details, see the
https://github.com/spring-projects/spring-framework/wiki/Date-and-Time-Formatting-with-JDK-20-and-higher[Date and Time Formatting with JDK 20 and higher]
Used at the class level as above, the annotation indicates a default for all methods of
the declaring class (as well as its subclasses). Alternatively, each method can be
annotated individually. See xref:data-access/transaction/declarative/annotations.adoc#transaction-declarative-annotations-method-visibility[method visibility] for
further details on which methods Spring considers transactional. Note that a class-level
Used at the class level as above, the annotation indicates a default for all methods
of the declaring class (as well as its subclasses). Alternatively, each method can be
@@ -19,6 +19,8 @@ A checkpoint can be created on demand, for example using a command like `jcmd ap
WARNING: Leveraging checkpoint/restore of a running application typically requires additional lifecycle management to gracefully stop and start using resources like files or sockets and stop active threads.
WARNING: Be aware that when defining scheduling tasks at a fixed rate, for example with an annotation like `@Scheduled(fixedRate = 5000)`, all missed executions between checkpoint and restore will be performed when the JVM is restored with on-demand checkpoint/restore. If this is not the behavior you want, it is recommended to schedule tasks at a fixed delay (for example with `@Scheduled(fixedDelay = 5000)`) or with a cron expression as those are calculated after every task execution.
NOTE: If the checkpoint is created on a warmed-up JVM, the restored JVM will be equally warmed-up, allowing potentially peak performance immediately. This method typically requires access to remote services, and thus requires some level of platform integration.
Micrometer defines an https://micrometer.io/docs/observation[Observation concept that enables both Metrics and Traces] in applications.
Micrometer defines an {micrometer-docs}/observation.html[Observation concept that enables both Metrics and Traces] in applications.
Metrics support offers a way to create timers, gauges, or counters for collecting statistics about the runtime behavior of your application.
Metrics can help you to track error rates, usage patterns, performance, and more.
Traces provide a holistic view of an entire system, crossing application boundaries; you can zoom in on particular user requests and follow their entire completion across applications.
@@ -38,7 +38,7 @@ As outlined xref:integration/observability.adoc[at the beginning of this section
|===
NOTE: Observations are using Micrometer's official naming convention, but Metrics names will be automatically converted
https://micrometer.io/docs/concepts#_naming_meters[to the format preferred by the monitoring system backend]
{micrometer-docs}/concepts/naming.html[to the format preferred by the monitoring system backend]
It uses the `io.micrometer.jakarta9.instrument.jms.DefaultJmsPublishObservationConvention` by default, backed by the `io.micrometer.jakarta9.instrument.jms.JmsPublishObservationContext`.
Similar observations are recorded with `@JmsListener` annotated methods when response messages are returned from the listener method.
[[observability.jms.process]]
=== JMS message Processing instrumentation
@@ -366,7 +368,7 @@ This means that during the execution of that task, the ThreadLocals and logging
If the application globally configures a custom `ApplicationEventMulticaster` with a strategy that schedules event processing on different threads, this is no longer true.
All `@EventListener` methods will be processed on a different thread, outside the main event publication thread.
In these cases, the https://micrometer.io/docs/contextPropagation[Micrometer Context Propagation library] can help propagate such values and better correlate the processing of the events.
In these cases, the {micrometer-context-propagation-docs}/[Micrometer Context Propagation library] can help propagate such values and better correlate the processing of the events.
The application can configure the chosen `TaskExecutor` to use a `ContextPropagatingTaskDecorator` that decorates tasks and propagates context.
For this to work, the `io.micrometer:context-propagation` library must be present on the classpath:
@@ -13,12 +13,12 @@ The Spring Framework provides the following choices for making calls to REST end
== `RestClient`
The `RestClient` is a synchronous HTTP client that offers a modern, fluent API.
It offers an abstraction over HTTP libraries that allows for convenient conversion from Java object to HTTP request, and creation of objects from the HTTP response.
It offers an abstraction over HTTP libraries that allows for convenient conversion from a Java object to an HTTP request, and the creation of objects from an HTTP response.
=== Creating a `RestClient`
The `RestClient` is created using one of the static `create` methods.
You can also use `builder` to get a builder with further options, such as specifying which HTTP library to use (see <<rest-request-factories>>) and which message converters to use (see <<rest-message-conversion>>), setting a default URI, default path variables, a default request headers, or `uriBuilderFactory`, or registering interceptors and initializers.
You can also use `builder()` to get a builder with further options, such as specifying which HTTP library to use (see <<rest-request-factories>>) and which message converters to use (see <<rest-message-conversion>>), setting a default URI, default path variables, default request headers, or `uriBuilderFactory`, or registering interceptors and initializers.
Once created (or built), the `RestClient` can be used safely by multiple threads.
@@ -64,35 +64,62 @@ val customClient = RestClient.builder()
=== Using the `RestClient`
When making an HTTP request with the `RestClient`, the first thing to specify is which HTTP method to use.
This can be done with `method(HttpMethod)`, or with the convenience methods `get()`, `head()`, `post()`, and so on.
This can be done with `method(HttpMethod)` or with the convenience methods `get()`, `head()`, `post()`, and so on.
==== Request URL
Next, the request URI can be specified with the `uri` methods.
This step is optional, and can be skipped if the `RestClient` is configured with a default URI.
The URL is typically specified as `String`, with optional URI template variables.
String URLs are encoded by default, but this can be changed by building a client with a custom `uriBuilderFactory`.
This step is optional and can be skipped if the `RestClient` is configured with a default URI.
The URL is typically specified as a `String`, with optional URI template variables.
The following example configures a GET request to `https://example.com/orders/42`:
The URL can also be provided with a function, or as `java.net.URI`, both of which are not encoded.
A function can also be used for more controls, such as specifying xref:web/webmvc/mvc-uri-building.adoc[request parameters].
String URLs are encoded by default, but this can be changed by building a client with a custom `uriBuilderFactory`.
The URL can also be provided with a function or as a `java.net.URI`, both of which are not encoded.
For more details on working with and encoding URIs, see xref:web/webmvc/mvc-uri-building.adoc[URI Links].
==== Request headers and body
If necessary, the HTTP request can be manipulated, by adding request headers with `header(String, String)`, `headers(Consumer<HttpHeaders>`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on.
For HTTP request that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`.
If necessary, the HTTP request can be manipulated by adding request headers with `header(String, String)`, `headers(Consumer<HttpHeaders>`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on.
For HTTP requests that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`.
The request body itself can be set by `body(Object)`, which internally uses <<rest-message-conversion>>.
Alternatively, the request body can be set using a `ParameterizedTypeReference`, allowing you to use generics.
Finally, the body can be set to a callback function that writes to an `OutputStream`.
==== Retrieving the response
Once the request has been set up, the HTTP response is accessed by invoking `retrieve()`.
The response body can be accessed by using `body(Class)`, or `body(ParameterizedTypeReference)` for parameterized types like lists.
The `body` method converts the response contents into various types, for instance bytes can be converted into a `String`, JSON into objects using Jackson, and so on (see <<rest-message-conversion>>).
The response body can be accessed by using `body(Class)` or `body(ParameterizedTypeReference)` for parameterized types like lists.
The `body` method converts the response contents into various types– for instance, bytes can be converted into a `String`, JSON can be converted into objects using Jackson, and so on (see <<rest-message-conversion>>).
The response can also be converted into a `ResponseEntity`, giving access to the response headers as well as the body.
This sample shows how `RestClient` can be used to perform a simple GET request.
This sample shows how `RestClient` can be used to perform a simple `GET` request.
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) <3>
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <3>
})
.body(String.class);
----
@@ -286,8 +314,9 @@ val result = restClient.get() <1>
======
==== Exchange
For more advanced scenarios, the `RestClient` gives access to the underlying HTTP request and response through the `exchange` method, which can be used instead of `retrieve()`.
Status handlers are not applied when you exchange, because the exchange function already provides access to the full response, allowing you to perform any error handling necessary.
For more advanced scenarios, the `RestClient` gives access to the underlying HTTP request and response through the `exchange()` method, which can be used instead of `retrieve()`.
Status handlers are not applied when use `exchange()`, because the exchange function already provides access to the full response, allowing you to perform any error handling necessary.
[tabs]
======
@@ -336,6 +365,7 @@ val result = restClient.get()
[[rest-message-conversion]]
=== HTTP Message Conversion
[.small]#xref:web/webflux/reactive-spring.adoc#webflux-codecs[See equivalent in the Reactive stack]#
The `spring-web` module contains the `HttpMessageConverter` interface for reading and writing the body of HTTP requests and responses through `InputStream` and `OutputStream`.
@@ -397,7 +427,7 @@ By default, this converter supports `text/xml` and `application/xml`.
|===
By default, `RestClient` and `RestTemplate` register all built-in message converters, depending on the availability of underlying libraries on the classpath.
You can also set the message converters to use explicitly, by using `messageConverters` on the `RestClient` builder, or via the `messageConverters` property of `RestTemplate`.
You can also set the message converters to use explicitly, by using the `messageConverters()` method on the `RestClient` builder, or via the `messageConverters` property of `RestTemplate`.
==== Jackson JSON Views
@@ -437,13 +467,13 @@ parts.add("xmlPart", new HttpEntity<>(myBean, headers));
----
In most cases, you do not have to specify the `Content-Type` for each part.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource` based on the file extension.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource`, based on the file extension.
If necessary, you can explicitly provide the `MediaType` with an `HttpEntity` wrapper.
Once the `MultiValueMap` is ready, you can use it as the body of a POST request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
Once the `MultiValueMap` is ready, you can use it as the body of a `POST` request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set to `multipart/form-data` by the `FormHttpMessageConverter`.
If the `MultiValueMap` has `String` values the `Content-Type` defaults to `application/x-www-form-urlencoded`.
If the `MultiValueMap` has `String` values, the `Content-Type` defaults to `application/x-www-form-urlencoded`.
If necessary the `Content-Type` may also be set explicitly.
[[rest-request-factories]]
@@ -453,17 +483,20 @@ To execute the HTTP request, `RestClient` uses a client HTTP library.
These libraries are adapted via the `ClientRequestFactory` interface.
Various implementations are available:
* `JdkClientHttpRequestFactory` for Java's `HttpClient`,
* `HttpComponentsClientHttpRequestFactory` for use with Apache HTTP Components `HttpClient`,
* `JettyClientHttpRequestFactory` for Jetty's `HttpClient`,
* `ReactorNettyClientRequestFactory` for Reactor Netty's `HttpClient`,
* `SimpleClientHttpRequestFactory` as a simple default.
* `JdkClientHttpRequestFactory` for Java's `HttpClient`
* `HttpComponentsClientHttpRequestFactory` for use with Apache HTTP Components `HttpClient`
* `JettyClientHttpRequestFactory` for Jetty's `HttpClient`
* `ReactorNettyClientRequestFactory` for Reactor Netty's `HttpClient`
* `SimpleClientHttpRequestFactory` as a simple default
If no request factory is specified when the `RestClient` was built, it will use the Apache or Jetty `HttpClient` if they are available on the classpath.
Otherwise, if the `java.net.http` module is loaded, it will use Java's `HttpClient`.
Finally, it will resort to the simple default.
TIP: Note that the `SimpleClientHttpRequestFactory` may raise an exception when accessing the status of a response that represents an error (e.g. 401).
If this is an issue, use any of the alternative request factories.
[[rest-webclient]]
== `WebClient`
@@ -473,12 +506,12 @@ synchronous, asynchronous, and streaming scenarios.
`WebClient` supports the following:
* Non-blocking I/O.
* Reactive Streams back pressure.
* High concurrency with fewer hardware resources.
* Functional-style, fluent API that takes advantage of Java 8 lambdas.
* Synchronous and asynchronous interactions.
* Streaming up to or streaming down from a server.
* Non-blocking I/O
* Reactive Streams back pressure
* High concurrency with fewer hardware resources
* Functional-style, fluent API that takes advantage of Java 8 lambdas
* Synchronous and asynchronous interactions
* Streaming up to or streaming down from a server
See xref:web/webflux-webclient.adoc[WebClient] for more details.
@@ -848,17 +881,17 @@ It can be used to migrate from the latter to the former.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.