Compare commits

..

1772 Commits

Author SHA1 Message Date
Stéphane Nicoll d5da602bc2 Release v6.2.2 2025-01-16 09:19:54 +01:00
rstoyanchev 384d2749c6 Polishing in HttpServiceMethod 2025-01-15 19:03:00 +00:00
rstoyanchev 5150a9a6ad Polishing contribution
Closes gh-34230
2025-01-15 18:31:50 +00:00
Yanming Zhou a8c5885aff Fix wrong document about RequestHeaderArgumentResolver
Also test is added to verify that.

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>

See gh-34230
2025-01-15 18:31:49 +00:00
Juergen Hoeller 7d844274dc Upgrade to Jetty 12.0.16, Netty 4.1.117, Protobuf 4.29.3, Checkstyle 10.21.1 2025-01-15 18:27:49 +01:00
Juergen Hoeller 70ceb3abdf Refer to local Consumer type instead of Kotlin test type 2025-01-15 17:41:22 +01:00
Sam Brannen 9181cce65f Support @⁠MockitoBean at the type level on test classes
Prior to this commit, @⁠MockitoBean could only be declared on fields
within test classes, which prevented developers from being able to
easily reuse mock configuration across a test suite.

With this commit, @⁠MockitoBean is now supported at the type level on
test classes, their superclasses, and interfaces implemented by those
classes. @⁠MockitoBean is also supported on enclosing classes for
@⁠Nested test classes, their superclasses, and interfaces implemented
by those classes, while honoring @⁠NestedTestConfiguration semantics.

In addition, @⁠MockitoBean:

- has a new `types` attribute that can be used to declare the type or
  types to mock when @⁠MockitoBean is declared at the type level

- can be declared as a repeatable annotation at the type level

- can be declared as a meta-annotation on a custom composed annotation
  which can be reused across a test suite (see the @⁠SharedMocks
  example in the reference manual)

To support these new features, this commit also includes the following
changes.

- The `field` property in BeanOverrideHandler is now @⁠Nullable.

- BeanOverrideProcessor has a new `default` createHandlers() method
  which is invoked when a @⁠BeanOverride annotation is found at the
  type level.

- MockitoBeanOverrideProcessor implements the new createHandlers()
  method.

- The internal findHandlers() method in BeanOverrideHandler has been
  completely overhauled.

- The @⁠MockitoBean and @⁠MockitoSpyBean section of the reference
  manual has been completely overhauled.

Closes gh-33925
2025-01-15 17:13:35 +01:00
Sam Brannen 8b6523a35b Cross reference @⁠NestedTestConfiguration for Bean Overrides 2025-01-15 17:13:35 +01:00
Stéphane Nicoll e7f349328d Merge pull request #34086 from rPraml
* pr/34086:
  Polish "Resolve base type in parameterized type if necessary"
  Resolve base type in parameterized type if necessary

Closes gh-34086
2025-01-15 17:07:58 +01:00
Stéphane Nicoll fe5f5d53b2 Polish "Resolve base type in parameterized type if necessary"
See gh-34086
2025-01-15 17:06:05 +01:00
Roland Praml 033d277bcf Resolve base type in parameterized type if necessary
See gh-34086
2025-01-15 17:03:20 +01:00
Juergen Hoeller 227385083d Restrict lenient nested matching to immediate type variable
Includes fix for matching multiple wildcard bounds properly.

Closes gh-34119
Closes gh-34234
2025-01-15 15:02:46 +01:00
Stéphane Nicoll d280358e98 Fix typo in HttpHeadersAssert#doesNotContainHeaders
This commit deprecates the existing doesNotContainsHeaders in favor of a
newly introduced method that does not have the typo.

Closes gh-34263
2025-01-15 11:19:00 +01:00
Stéphane Nicoll e08a7ece61 Merge pull request #34223 from remeio
* pr/34223:
  Polish contribution
  Polish HttpEntityMethodProcessor

Closes gh-34223
2025-01-14 17:36:45 +01:00
Stéphane Nicoll 24fa9ea394 Polish contribution
See gh-34223
2025-01-14 17:30:39 +01:00
Mengqi Xu 4acd9ee69b Polish HttpEntityMethodProcessor
Signed-off-by: Mengqi Xu <2663479778@qq.com>

See gh-34223
2025-01-14 17:28:00 +01:00
Stéphane Nicoll cd1aefa5e0 Upgrade to Reactor 2024.0.2
Closes gh-34252
2025-01-14 16:36:43 +01:00
Sam Brannen 3c3b8c7aac Track only qualifier annotations in BeanOverrideHandler
Closes gh-34260
2025-01-14 11:35:00 +01:00
Sam Brannen 5a68d1f029 Remove @⁠FunctionalInterface declaration from BeanOverrideProcessor
Closes gh-34259
2025-01-14 11:29:45 +01:00
Sam Brannen ff9b7678a7 Polish Bean Override internals and tests 2025-01-14 11:25:37 +01:00
Brian Clozel 799566573a Fix Wrong parentId tracking in JFR application startup
This commit fixes the tracking of the main event parentId for the Java
Flight Recorder implementation variant.

Fixes gh-34128
2025-01-13 19:03:43 +01:00
Juergen Hoeller 467d5f3ca3 Try late locking for waiting on specific bean to be finished
Closes gh-34186
2025-01-13 17:48:13 +01:00
Stéphane Nicoll 172c25fb0e Upgrade to Micrometer 1.14.3
Closes gh-34251
2025-01-13 13:54:47 +01:00
Juergen Hoeller 8771b9ea21 Defensively acquire singleton lock for FactoryBean type check
Closes gh-34247
2025-01-13 13:04:42 +01:00
Juergen Hoeller ff72652890 Defensively check expected type for qualified bean
Closes gh-34187
2025-01-13 13:03:25 +01:00
Stéphane Nicoll a1503a59ee Start building against Reactor 2024.0.2 snapshots
See gh-34252
2025-01-13 09:09:19 +01:00
Stéphane Nicoll 5f29df3ac3 Start building against Micrometer 1.14.3 snapshots
See gh-34251
2025-01-13 09:08:06 +01:00
Juergen Hoeller 25287205ba Use ReentrantLock for compilation without synchronization
Closes gh-34133
2025-01-12 18:11:47 +01:00
Juergen Hoeller 2bb4df79c3 Ignore SQLServerException with "not supported" message
Closes gh-34233
2025-01-12 18:08:54 +01:00
Juergen Hoeller 36fd82f32f Defensively resolve JarFile from JarURLConnection
Closes gh-34216
2025-01-12 18:07:09 +01:00
Juergen Hoeller 0f26f42da7 Defensively check for jar separator in jar entry names
Closes gh-34126
2025-01-12 18:05:49 +01:00
Juergen Hoeller c48fec885c Avoid caching invalid root directories
Closes gh-34111
2025-01-12 18:00:10 +01:00
Stéphane Nicoll 7c4351ab0a Polish
See gh-34231
2025-01-11 12:35:42 +01:00
rstoyanchev 07455b10f3 Use response decorator to check if error handled
Closes gh-34231
2025-01-10 10:51:39 +01:00
rstoyanchev a72855b2b3 DefaultResponseErrorHandler updates
Deprecate handleError(response), and ensure it continues to be invoked
if overridden.

See gh-34231
2025-01-10 10:51:11 +01:00
rstoyanchev cdddf09c20 Polishing in DefaultResponseErrorHandler
See gh-34231
2025-01-10 10:50:41 +01:00
xumengqi 53b3b934fc BindException declared but not handled by ExceptionHandler
Closes gh-34214

Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-01-08 16:29:12 +01:00
Brian Clozel 9173e13f74 Document that http.client.requests measure the entire HTTP exchange
Closes gh-34201
2025-01-08 14:39:50 +01:00
Brian Clozel 84be0d85b4 Refine location checks for PathResource
This commit ensures that checks for PathResource locations are skipped
because this resource implementation will always resolve under the
current location.

Closes gh-34167
2025-01-08 10:55:22 +01:00
Brian Clozel c971276f34 Refine default filtered headers for web data binding
Prior to this commit, HTTP request data binding had been improved to
filter out by default the "Priority" header in #34039.

This commit extends the set of filtered header names with:
"Accept", "Authorization", "Connection", "Cookie", "From", "Host",
"Origin", "Priority", "Range", "Referer", "Upgrade".

If an application wishes to let those header be bound, it will need to
configure the binder and replace the default header predicate by calling
`setHeaderPredicate`.

Closes gh-34182
2025-01-07 22:11:41 +01:00
Sam Brannen cd2fbb1ec5 Properly resolve @⁠TestBean factory method within class hierarchy
Prior to this commit, the search algorithm used to locate a @⁠TestBean
factory method within a test class hierarchy incorrectly found factory
methods declared in subclasses or nested test classes "below" the class
in which the @⁠TestBean field was declared. This resulted in "duplicate
bean override" failures for @⁠TestBean overrides which are clearly not
duplicates but rather "overrides of an override".

This commit ensures that @⁠TestBean factory method resolution is
consistent in type hierarchies as well as in enclosing class
hierarchies (for @⁠Nested test classes) by beginning the search for a
factory method in the class which declares the @⁠TestBean field.

Closes gh-34204
2025-01-07 17:20:52 +02:00
Sam Brannen e8745522fc Polishing 2025-01-07 11:52:33 +02:00
Brian Clozel 2bfb283c91 Update CONTRIBUTING guidelines for DCO
The CLA process has been replaced with a DCO, this commit updates the
CONTRIBUTING guidelines accordingly.
See https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring
2025-01-07 09:55:36 +01:00
Mattias-Sehlstedt 50b1fb0b15 Change the description for the uri client request observation
This commit describes what parts that are removed from the URI template
keyvalue.

Closes: gh-34116
Signed-off-by: Mattias-Sehlstedt <60173714+Mattias-Sehlstedt@users.noreply.github.com>
2025-01-07 09:02:25 +01:00
rstoyanchev a985b73939 Improve logging in ReactiveTypeHandler
See gh-34188
2025-01-06 12:13:29 +00:00
rstoyanchev 6ec7dcf2c1 Synchronize in WebAsyncManager onError/onTimeout
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
2025-01-06 12:06:43 +00:00
rstoyanchev d94e04d97a Minor refactoring in WebAsyncManager
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
2025-01-06 12:06:43 +00:00
rstoyanchev 5a44897c55 Polishing in WebAsyncManager
See gh-34192
2025-01-06 12:06:43 +00:00
Sam Brannen 181db1db75 Update copyright headers to 2025 2025-01-05 17:00:47 +02:00
Sam Brannen 138bdc597d Upgrade to AssertJ 3.27.2 2025-01-05 12:28:23 +02:00
Sam Brannen ef4f1f0a71 Ensure @⁠BeanOverride in subclass takes precedence over superclass
Prior to this commit, a @⁠BeanOverride (such as @⁠TestBean) for a
specific target bean which was declared in a superclass always took
precedence over a bean override for the same target bean in a subclass,
thereby rendering the bean override configuration in the subclass
useless. In other words, there was no way for a test class to override
a bean override declared in a superclass.

To address that, this commit switches from direct use of
ReflectionUtils.doWithFields() to a custom search algorithm that
traverses the class hierarchy using tail recursion for processing
@⁠BeanOverride fields (delegating now to
ReflectionUtils.doWithLocalFields() in order to continue to benefit
from the caching of declared fields in ReflectionUtils).

Closes gh-34194
2025-01-04 18:27:05 +02:00
Sam Brannen 51b89743e1 Polishing 2025-01-04 18:12:13 +02:00
Sam Brannen 019f76468b Revise TestBeanForInheritanceIntegrationTests
Amongst other refinements, this commit ensures that the "anotherBean"
use case is actually tested.
2025-01-04 14:16:59 +02:00
Stéphane Nicoll f802c0cf24 Restore use of MethodSource 2025-01-03 16:53:54 +01:00
Sam Brannen 0da4ae96b4 Rename internal MockitoBeans class to MockBeans
This is a prerequisite for gh-33925 which will introduce a public
@MockitoBeans container annotation in the same package.
2025-01-03 17:26:45 +02:00
Sam Brannen 2ba0022704 Polishing 2025-01-03 17:26:45 +02:00
Stéphane Nicoll c59ca087b4 Backport tests for exact match resolution
See gh-34124

(cherry picked from commit 898d3ec86a)
2025-01-03 17:10:17 +02:00
Sam Brannen 9de2b947cb Upgrade to AssertJ 3.27.1 2025-01-03 16:42:07 +02:00
Sam Brannen e73e7564d0 Upgrade to Mockito 5.15.2 2025-01-03 16:36:39 +02:00
Brian Clozel d927d64c40 Improve query params in uri KeyValue with HTTP interface client
Prior to this commit, the HTTP interface client would create URI
templates and name query params like so:
"?{queryParam0}={queryParam0[0]}".
While technically correct, the URI template is further used in
observations as a KeyValue. This means that several service methods
could result in having the exact same URI template even if they produce
a different set of query params.

This commit improves the naming of query params in the generated URI
templates for better observability integration.

Closes gh-34176
2025-01-02 20:00:38 +01:00
Stéphane Nicoll 8544435833 Merge pull request #34180 from v-perfilev
* pr/34180:
  Polish "Fix broken link to Code of Conduct in CONTRIBUTING.md"
  Fix broken link to Code of Conduct in CONTRIBUTING.md

Closes gh-34180
2025-01-01 10:08:39 +01:00
Stéphane Nicoll 80ea1f62b6 Polish "Fix broken link to Code of Conduct in CONTRIBUTING.md"
See gh-34180
2025-01-01 10:08:18 +01:00
Vladimir Perfilev bc287918f2 Fix broken link to Code of Conduct in CONTRIBUTING.md
See gh-34180
2025-01-01 10:07:29 +01:00
Stéphane Nicoll c9436992c9 Update actions in CI build 2024-12-31 09:49:43 +01:00
rstoyanchev 4350fc21b3 List constructor arg initialized correctly
DataBinder now uses the calculated List size rather than
the number of indexes to initialize the list.

Closes gh-34145
2024-12-30 14:47:26 +00:00
rstoyanchev 59ed4686c5 Create ParameterErrors for type level constraint
Closes gh-34105
2024-12-30 14:47:26 +00:00
Sébastien Deleuze d5bebd5ced Upgrade to Java 17.0.13 2024-12-30 12:15:24 +01:00
Johnny Lim 6d86b23fbe Apply Checkstyle MethodParamPadCheck module
This commit also fixes its violations.

Closes gh-34173
2024-12-30 09:02:06 +01:00
Simon Baslé 0f38c28e91 Fix ServletRequestDataBinder ctor binding with []-indexed query params
This change ensures that a request containing query parameters in the
array format `someArray[]=value` can be bound into a simple array in
constructors, even for cases where the array values don't have nested
properties.

The value resolver is directly called in the constructor case, before
any mutable properties are considered or even cleared (see
`WebDataBinder#adaptEmptyArrayIndices` method). As a result, we need to
accommodate the possibility that the request stores array elements under
the `name[]` key rather than `name`. This change attempts a secondary
lookup with the `[]` suffix if the type is a list or array, and the key
doesn't include an index.

Closes gh-34121
2024-12-27 10:59:15 +01:00
Simon Baslé 3505c4bcad Ensure DataBinder can bind constructor with a Map with simple values
This change ensures that DataBinder can bind constructor with a Map
parameter that has no nested properties, but just simple values like
a String: `someMap[0]=exampleString`.

Integration tests have been added to cover similar cases that use the
ServletRequestDataBinder.

Closes gh-34043
2024-12-27 10:57:30 +01:00
Stéphane Nicoll 58670db46e Merge pull request #34165 from brendenehlers
* pr/34165:
  Polish contribution
  Fix grammatical structure in "Basic Concepts"

Closes gh-34165
2024-12-27 09:31:47 +01:00
Stéphane Nicoll 0cdb8a1657 Polish contribution
Using commas render better than em dashes.

See gh-34165
2024-12-27 09:31:34 +01:00
Brenden Ehlers fe8c70dddb Fix grammatical structure in "Basic Concepts"
See gh-34165
2024-12-27 09:30:43 +01:00
Sébastien Deleuze 1ed74efa6b Polishing
Closes gh-34148
2024-12-26 13:16:09 +01:00
Brenden Ehlers eabd574038 Fix XML code snippet
See gh-34148
2024-12-26 13:15:51 +01:00
Stéphane Nicoll ea386c2398 Merge pull request #34149 from brendenehlers
* pr/34149:
  Fix typo in link

Closes gh-34149
2024-12-25 09:29:52 +01:00
Brenden Ehlers 6c6e8ad831 Fix typo in link
See gh-34149
2024-12-25 09:29:29 +01:00
Sébastien Deleuze 69b74d7645 Fix NullPointerException in HttpComponentsClientHttpResponse
Closes gh-34132
2024-12-23 15:34:04 +01:00
Stéphane Nicoll 5ce5647d09 Restore support of exact match property
This commit fixes a regression in property placeholder resolution where
the original key was no longer considered for an exact match before
processing the placeholder itself.

By default, property resolution uses ':' as the separator between the
key and the fallback value.

Consider a request to resolve ${prefix://service}. Previously,
placeholder resolution would first attempt to resolve the raw text, that
is 'prefix://service', before attempting to resolve the 'prefix' key and
then use '//service' if the key did not resolve.

This commit restores that behaviour purely for backward compatible
reason.

Closes gh-34124
2024-12-23 12:19:45 +01:00
Tran Ngoc Nhan ebae02a92b Fix broken links in the web reference documentation
Closes gh-34115
2024-12-23 11:14:40 +01:00
Sam Brannen 99cb6ba0a7 Upgrade to Gradle 8.12 2024-12-21 16:02:15 +01:00
Sam Brannen 2baf70768d Upgrade to AssertJ 3.27 2024-12-21 15:49:31 +01:00
Sam Brannen 724700d708 Polishing 2024-12-21 15:31:01 +01:00
Andreas Kruck 83ba7e69ec Fix minor typo in reference documentation for Kotlin annotations
Closes gh-34134
2024-12-21 15:28:33 +01:00
Sam Brannen c1236a3340 Support varargs-only MethodHandle as SpEL function
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
2024-12-18 17:59:14 +01:00
luozongle01 a942362221 Fix a typo
Closes gh-34101
2024-12-17 11:40:47 +01:00
Brian Clozel 1a34b0dd87 Improve PathMatcher/PatternParser XML configuration
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-34064
2024-12-17 10:14:18 +01:00
Sam Brannen b0fcde9aa3 Upgrade to JUnit 5.11.4
Closes gh-34095
2024-12-16 14:42:30 +01:00
Sam Brannen a89db89fc0 Polishing 2024-12-14 17:10:41 +01:00
Sam Brannen 3d0fffa8e4 Polish contribution
See gh-33945
2024-12-14 16:40:49 +01:00
Mico Piira 71f872e8bb Fix implicit variable resolution in JSP EvalTag
Prior to this commit, the order of parameters passed to
ELResolver#getValue was incorrect.

The `name` should correspond to the `property` parameter of the
`getValue` method instead the `base` parameter.

See gh-32383
See gh-33942
Closes gh-33945
2024-12-14 16:40:31 +01:00
Juergen Hoeller 54a90b20ed Avoid logger serialization behind shared EntityManager proxy
See gh-34084
2024-12-12 19:48:21 +01:00
Stéphane Nicoll d7a3971403 Merge pull request #34077 from scordio
* pr/34077:
  Polish "Prevent execution of Antora jobs on forks"
  Prevent execution of Antora jobs on forks

Closes gh-34077
2024-12-12 17:35:51 +01:00
Stéphane Nicoll cfa3463cec Polish "Prevent execution of Antora jobs on forks"
See gh-34077
2024-12-12 17:35:38 +01:00
Stefano Cordio d2264b221a Prevent execution of Antora jobs on forks
See gh-34077
2024-12-12 17:34:15 +01:00
Stéphane Nicoll 2c32601553 Add note about using @EventListener on lazy beans
Closes gh-34057
2024-12-12 17:32:18 +01:00
Sam Brannen ea8b18fbc7 Polish Javadoc for BeanOverrideHandler 2024-12-12 14:41:23 +01:00
Brian Clozel 3ab4ee2bba Next development version (v6.2.2-SNAPSHOT) 2024-12-12 10:53:14 +01:00
Juergen Hoeller 0aa721cad0 Polishing 2024-12-11 17:52:59 +01:00
Juergen Hoeller 63af572ce8 Upgrade to Jackson 2.18.2, RxJava 3.1.10, Checkstyle 10.20.2 2024-12-11 17:34:53 +01:00
Juergen Hoeller 72c2343f63 Avoid deprecated ListenableFuture name for internal class 2024-12-11 17:34:48 +01:00
rstoyanchev 8aeced9f80 Support header filtering in web data binding
Closes gh-34039
2024-12-11 16:11:22 +00:00
rstoyanchev 70c326ed30 Support headers in DataBinding via constructor args
Closes gh-34073
2024-12-11 16:10:08 +00:00
rstoyanchev 7b4e19c69b Make ExtendedServletRequestDataBinder public
Make it public and move it down to the annotations package alongside
InitBinderBindingContext. This is mirrors the hierarchy in Spring MVC
with the ExtendedServletRequestDataBinder. The change will allow
customization of the header names to include/exclude in data binding.

See gh-34039
2024-12-11 16:09:56 +00:00
rstoyanchev 3b95d2c449 Support Flux<ServerSentEvent<Fragment>> in WebFlux
Closes gh-33975
2024-12-11 16:09:38 +00:00
rstoyanchev 640e570583 Minor refactoring in ServerSentEvent
Extract re-usable method to serialize SSE fields.

See gh-33975
2024-12-11 16:09:22 +00:00
rstoyanchev 66f33a8265 MapMethodProcessor supportsParameter is more specific
Closes gh-33160
2024-12-11 16:09:01 +00:00
Juergen Hoeller 68997d8416 Avoid javadoc references to deprecated types/methods 2024-12-11 16:58:37 +01:00
Brian Clozel 52006b71bc Support Servlet error message in MockMvc assertions
Prior to this commit, `MockMvc` would support checking for the Servlet
error message as the "response status reason". While this error message
can be driven with the `@ResponseStatus` annotation, this message is not
technically the HTTP status reason listed on the response status line.

This message is provided by the Servlet container in the error page when
the `response.sendError(int, String)` method is used.

This commit adds the missing
`mvc.get().uri("/error/message")).hasErrorMessage("error message")`
assertion to check for this Servlet error message.

Closes gh-34016
2024-12-11 16:00:41 +01:00
Sam Brannen 41d9f21ab9 Log alias removal in DefaultListableBeanFactory
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
2024-12-11 15:03:52 +01:00
Sam Brannen 7206b28272 Implement toString() in TestBeanOverrideHandler
Closes gh-34072
2024-12-11 12:12:35 +01:00
Brian Clozel 0c688742e1 Fix custom scheduler support for @Scheduled methods
This commit fixes a regression introduced by gh-24560, when adding
execution metadata support for scheduled tasks. The
`OutcomeTrackingRunnable` would delegate to the actual runnable but
could also hide whether it implements the `SchedulingAwareRunnable`
contract.

This commit ensures that `OutcomeTrackingRunnable` always implements
that contract and delegates to the runnable if possible, or return
default values otherwise.

Fixes gh-34058
2024-12-10 22:33:20 +01:00
Juergen Hoeller 7de1dc826a Consistently handle generics in TypeDescriptor.equals
Properly processes recursive types through always comparing generics via the top-level ResolvableType (rather than through nested TypeDescriptors with custom ResolvableType instances).

Closes gh-33932
2024-12-10 22:16:10 +01:00
Juergen Hoeller 3e3ca74020 Log provider setup failure at info level without stacktrace
Closes gh-33979
2024-12-10 16:25:57 +01:00
Juergen Hoeller 66da5d7ab9 Restore original override behavior when override allowed
Closes gh-33920
2024-12-10 16:25:49 +01:00
Stéphane Nicoll 68d6cb9d35 Upgrade to Reactor 2024.0.1
Closes gh-34051
2024-12-10 14:06:07 +01:00
Stéphane Nicoll 6649a6e0f7 Upgrade to Micrometer 1.14.2
Closes gh-34050
2024-12-10 14:05:43 +01:00
Sam Brannen 54948a4e88 Log warning when one Bean Override overrides another Bean Override
It is currently possible for one Bean Override to override another
logically equivalent Bean Override.

For example, a @⁠TestBean can override a @⁠MockitoBean, and vice versa.

In fact, it's also possible for a @⁠MockitoBean to override another
@⁠MockitoBean, for a @⁠TestBean to override a @⁠TestBean, etc.

However, there may be viable use cases for one override overriding
another override. For example, one may have a need to spy on a bean
created by a @⁠TestBean factory method.

In light of that, we do not prohibit one Bean Override from overriding
another Bean Override; however, with this commit we now log a warning
to help developers diagnose issues in case such an override is
unintentional.

For example, given the following test class, where TestConfig registers
a single bean of type MyService named "myService"...

@⁠SpringJUnitConfig(TestConfig.class)
class MyTests {

  @⁠TestBean(methodName = "example.TestUtils#createMyService")
  MyService testService;

  @⁠MockitoBean
  MyService mockService;

  @⁠Test
  void test() {
    // ...
  }
}

... running that test class results in a log message similar to the
following, which has been formatted for readability.

WARN - Bean with name 'myService' was overridden by multiple handlers:
[
 [TestBeanOverrideHandler@44b21f9f
  field = example.MyService example.MyTests.testService,
  beanType = example.MyService,
  beanName = [null],
  strategy = REPLACE_OR_CREATE
 ],
 [MockitoBeanOverrideHandler@7ee8130e
  field = example.MyService example.MyTests.mockService,
  beanType = example.MyService,
  beanName = [null],
  strategy = REPLACE_OR_CREATE,
  reset = AFTER,
  extraInterfaces = set[[empty]],
  answers = RETURNS_DEFAULTS, serializable = false
 ]
]

NOTE: The last registered BeanOverrideHandler wins. In the above
example, that means that @⁠MockitoBean overrides @⁠TestBean, resulting
in a Mockito mock for the MyService bean in the test's
ApplicationContext.

Closes gh-34056
2024-12-10 12:49:48 +01:00
Sébastien Deleuze a00ba8dbcf Revert "Reuse NoTransactionInContextException instances"
This reverts commit 8e3846991d.

Closes gh-34048
2024-12-10 11:47:56 +01:00
Stéphane Nicoll 4f815b0055 Merge pull request #33891 from youabledev
* pr/33891:
  Polish

Closes gh-33891
2024-12-10 07:47:52 +01:00
youable 5494d78018 Polish
See gh-33891
2024-12-10 07:47:42 +01:00
Sam Brannen cd60a0013b Reject identical Bean Overrides
Prior to this commit, the Bean Override feature in the Spring
TestContext Framework (for annotations such as @⁠MockitoBean and
@⁠TestBean) silently allowed one bean override to override another
"identical" bean override; however, Spring Boot's @⁠MockBean and
@⁠SpyBean support preemptively rejects identical overrides and throws
an IllegalStateException to signal the configuration error to the user.

To align with the behavior of @⁠MockBean and @⁠SpyBean in Spring Boot,
and to help developers avoid scenarios that are potentially confusing
or difficult to debug, this commit rejects identical bean overrides in
the Spring TestContext Framework.

Note, however, that it is still possible for a bean override to
override a logically equivalent bean override. For example, a
@⁠TestBean can override a @⁠MockitoBean, and vice versa.

Closes gh-34054
2024-12-09 16:00:24 +01:00
Sam Brannen 2137750591 Improve Bean Override by-name integration tests 2024-12-09 13:01:42 +01:00
Brian Clozel 13df9058a4 Introduce "unsafeAllocated" flag in TypeHint
This metadata information is required for supporting libraries using
`sun.misc.Unsafe#allocateInstance(Class<?>)`, even though Spring
Framework is not using this feature.

Closes gh-34055
2024-12-09 11:08:48 +01:00
Sam Brannen aee52b53a1 Introduce MockitoAssertions 2024-12-08 18:41:10 +01:00
Sam Brannen 92bbaa21e0 Improve test coverage for @⁠MockitoSpyBean use cases 2024-12-08 18:41:10 +01:00
Stéphane Nicoll 837579c2e5 Start building against Reactor 2024.0.1 snapshots
See gh-34051
2024-12-08 10:49:57 +01:00
Stéphane Nicoll 03a75cf03a Start building against Micrometer 1.14.2 snapshots
See gh-34050
2024-12-08 10:48:45 +01:00
Sam Brannen aa7b459803 Fix Phantom Read problem for Bean Overrides in the TestContext framework
To make an analogy to read phenomena for transactional databases, this
commit effectively fixes the "Phantom Read" problem for Bean Overrides.

A phantom read occurs when the BeanOverrideBeanFactoryPostProcessor
retrieves a set of bean names by-type twice and a new bean definition
for a compatible type has been created in the BeanFactory by a
BeanOverrideHandler between the first and second retrieval.

Continue reading for the details...

Prior to this commit, the injection of test Bean Overrides (for
example, when using @⁠MockitoBean) could fail in certain scenarios if
overrides were created for nonexistent beans "by type" without an
explicit name or qualifier. Specifically, if an override for a SubType
was created first, and subsequently an attempt was made to create an
override for a SuperType (where SubType extends SuperType), the
override for the SuperType would "override the override" for the
SubType, effectively removing the override for the SubType.
Consequently, injection of the override instance into the SubType field
would fail with an error message similar to the following.

BeanNotOfRequiredTypeException: Bean named 'Subtype#0' is expected to
be of type 'Subtype' but was actually of type 'Supertype$Mock$XHb7Aspo'

This commit addresses this issue by tracking all generated bean names
(in a generatedBeanNames set) and ensuring that a new bean override
instance is created for the current BeanOverrideHandler if a previous
BeanOverrideHandler already created a bean override instance that now
matches the type required by the current BeanOverrideHandler.

In other words, if the generatedBeanNames set already contains the
beanName that we just found by-type, we cannot "override the override",
because we would lose one of the overrides. Instead, we must create a
new override for the current handler. In the example given above, we
must end up with overrides for both SuperType and SubType.

Closes gh-34025
2024-12-07 16:51:16 +01:00
Sam Brannen 03fe1f0df3 Improve documentation for BeanOverrideBeanFactoryPostProcessor 2024-12-07 16:05:54 +01:00
Stéphane Nicoll 0d72477742 Restore user type in generated root bean definitions
This commit restores the user class in generated RootBeanDefinition
instances. Previously the CGLIB subclass was exposed. While this is
important in regular runtime as the configuration class parser operates
on the bean definition, this is not relevant for AOT as this information
is internal and captured in the instance supplier.

Closes gh-33960
2024-12-06 15:34:00 +01:00
Stéphane Nicoll d26ee8f852 Merge pull request #34031 from ngocnhan-tran1996
* pr/34031:
  Fix link to MockMvcBuilders in reference documentation

Closes gh-34031
2024-12-06 09:44:01 +01:00
Tran Ngoc Nhan 47c66f4352 Fix link to MockMvcBuilders in reference documentation
See gh-34031
2024-12-06 09:43:41 +01:00
Juergen Hoeller b5dd0a60f8 Restore lenient match against unresolvable wildcard
Closes gh-33982
2024-12-05 17:41:49 +01:00
Stéphane Nicoll e618f922c2 Resolve nested placeholders with a fallback having one
This commit fixes a regression in PlaceHolderParser where it would no
longer resolve nested placeholders for a case where the fallback has a
placeholder itself.

This is due to the Part implementations and how they are structure, and
this commit makes sure that nested resolution happens consistently.

Closes gh-34020
2024-12-05 16:59:30 +01:00
Stéphane Nicoll 81a9f3d50b Restore public type for generated instance supplier of CGLIB proxy
This commit restores the signature of instance suppliers that are
exposing a CGLIB proxy. While calling the CGLIB proxy itself, and
making it available in BeanInstanceSupplier, is needed internally, such
type should not be exposed as it is an internal concern.

This was breaking InstanceSupplier.andThen as it expects the public
type of the bean to be exposed, not it's eventual CGLIB subclass.

Closes gh-33998
2024-12-05 15:48:49 +01:00
Sébastien Deleuze c807fa597f Remove unnecessary HandshakeHandlerRuntimeHints
Those hints are not needed anymore as of Spring Framework 6.1.

Closes gh-34032
2024-12-05 15:44:09 +01:00
Juergen Hoeller 576f109987 Use JDK proxy for introduction interface without target
Closes gh-33985
2024-12-04 21:03:09 +01:00
Juergen Hoeller 384dc2a9b8 Consistently use singleton lock for FactoryBean processing
Closes gh-33972
2024-12-04 21:02:30 +01:00
Juergen Hoeller edf7f3cd43 Polishing 2024-12-04 16:41:07 +01:00
Juergen Hoeller 58c64cba2c Consistent fallback to NoUpgradeStrategyWebSocketService
Closes gh-33970
2024-12-04 16:39:41 +01:00
Juergen Hoeller 307411631d Ignore SQLFeatureNotSupportedException on releaseSavepoint
Closes gh-33987
2024-12-04 16:38:57 +01:00
Sam Brannen 8d69370b95 Consider logical equality in AdvisedSupport.MethodCacheKey#equals
Prior to this commit, the equals() implementation in AdvisedSupport's
MethodCacheKey only considered methods to be equal based on an identity
comparison (`==`), which led to duplicate entries in the method cache
for the same logical method.

This is caused by the fact that AdvisedSupport's
getInterceptorsAndDynamicInterceptionAdvice() method is invoked at
various stages with different Method instances for the same method:

1) when creating the proxy
2) when invoking the method via the proxy

The reason the Method instances are different is due to the following.

- Methods such as Class#getDeclaredMethods() and
  Class#getDeclaredMethod() always returns "child copies" of the
  underlying Method instances -- which means that `equals()` should be
  used instead of (or in addition to) `==` whenever the compared Method
  instances can come from different sources.

With this commit, the equals() implementation in MethodCacheKey now
considers methods equal based on identity or logical equality, giving
preference to the quicker identity check.

See gh-32586
Closes gh-33915
2024-12-04 12:04:02 +01:00
Brian Clozel d990449b0d Improve toString for reactive ScheduledTask
Prior to this commit, the reactive Scheduled tasks would be wrapped as a
`SubscribingRunnable` which does not implement a custom `toString`. This
would result in task metadata using the default Java `toString`
representation for those.

This commit ensures that the bean class name and method name are used
for this `toString`.

Closes gh-34010
2024-12-03 15:06:27 +01:00
rstoyanchev 15dcc449a2 Refine Reactor Netty handling of request without body
Closes gh-34003
2024-12-02 17:52:39 +00:00
Sam Brannen 320831b18a Test status quo for StaticMethodMatcherPointcut#matches invocations
This commit introduces a test which verifies how many times the
matches() method of a StaticMethodMatcherPointcut is invoked during
ApplicationContext startup as well as during actual method invocations
via the advice chain, which also indirectly tests the behavior of the
equals() implementation in AdvisedSupport.MethodCacheKey.

In addition, this commit revises BeanFactoryTransactionTests to assert
that a transaction is started for the setAge() method.

See gh-33915
2024-12-01 16:28:32 +01:00
Sam Brannen 172c8b2c35 Polish AOP tests 2024-12-01 15:32:03 +01:00
Sam Brannen 51956fad89 Test MockReset strategy for @⁠MockitoSpyBean
As a follow up to commit 0088b9c7f8, this commit introduces an
integration test which verifies that a spy created via @⁠MockitoSpyBean
using the MockReset.AFTER strategy is not reset between the refresh of
the ApplicationContext and the first use of the spy within a @⁠Test
method.

See gh-33941
See gh-33986
2024-11-29 11:27:02 +01:00
Sébastien Deleuze ddec8d2653 Add missing @Contract annotation to ObjectUtils#isEmpty
Closes gh-33984
2024-11-28 15:17:02 +01:00
Sébastien Deleuze 1aede291bb Move Kotlin value class unboxing to InvocableHandlerMethod
Before this commit, in Spring Framework 6.2, Kotlin value class
unboxing was done at CoroutinesUtils level, which is a good fit
for InvocableHandlerMethod use case, but not for other ones like
AopUtils.

This commit moves such unboxing to InvocableHandlerMethod in
order to keep the HTTP response body support while fixing other
regressions.

Closes gh-33943
2024-11-27 16:39:26 +01:00
Sam Brannen ea3bd7ae0c Polish BeanValidationBeanRegistrationAotProcessor[Tests]
The log message for a NoClassDefFoundError is now a DEBUG level message
handled like a TypeNotPresentException and similar to the following.

DEBUG: Skipping validation constraint hint inference for class
org.example.CustomConstraint due to a NoClassDefFoundError for
com.example.MissingType

See gh-33949
2024-11-27 12:53:51 +01:00
Stefano Cordio 9b0253e117 Skip runtime hint registration for constraint with missing dependencies
Prior to this commit, AOT processing for bean validation failed with a
NoClassDefFoundError for constraints with missing dependencies.

With this commit, the processing no longer fails, and a warning is
logged instead.

See gh-33940
Closes gh-33949

Co-authored-by: Sam Brannen <sam.brannen@broadcom.com>
2024-11-27 12:42:12 +01:00
Stéphane Nicoll f3753e6d64 Merge pull request #33956 from CHOICORE
* pr/33956:
  Fix log level in PathMatchingResourcePatternResolver

Closes gh-33956
2024-11-26 20:04:25 +01:00
CHOICORE 41421d106b Fix log level in PathMatchingResourcePatternResolver
See gh-33956
2024-11-26 19:51:17 +01:00
Tran Ngoc Nhan 8c0ac8e062 Fix a typo in the filters documentation
Closes gh-33959
2024-11-26 16:09:45 +01:00
Sam Brannen 0088b9c7f8 Honor MockReset strategy for @⁠MockitoBean and @⁠MockitoSpyBean
Commit 6c2cba5d8a introduced a regression by inadvertently removing the
MockReset strategy comparison when resetting @⁠MockitoBean and
@⁠MockitoSpyBean mocks.

This commit reinstates the MockReset strategy check and introduces
tests for this feature.

Closes gh-33941
2024-11-26 11:54:46 +01:00
Sam Brannen 2b840ee7ef Upgrade to Gradle 8.11.1
Closes gh-33951
2024-11-24 14:27:39 +01:00
Sam Brannen 051f1dac24 Polish contribution
See gh-33950
2024-11-24 14:13:03 +01:00
Stefano Cordio 5e7b3a3bed Avoid infinite recursion in BeanValidationBeanRegistrationAotProcessor
Prior to this commit, AOT processing for bean validation failed with a
StackOverflowError for constraints with fields having recursive generic
types.

With this commit, the algorithm tracks visited classes and aborts
preemptively when a cycle is detected.

Closes gh-33950

Co-authored-by: Sam Brannen <sam.brannen@broadcom.com>
2024-11-24 14:09:48 +01:00
Johnny Lim 1910d32405 Replace TestObservationRegistryAssert.assertThat() with Assertions.assertThat()
See https://github.com/micrometer-metrics/micrometer/pull/5551

Closes gh-33929
2024-11-21 14:35:32 +01:00
sonallux 986ffc2072 Use full URI for URI template keyvalue with RestClient
Prior to this commit, `RestClient` would not use the full URI created by
the uri handler as a template request attribute.
This means that HTTP client observations would not contain the base URI
in recorded observations as the uri template keyvalue.

Closes gh-33928
2024-11-21 14:23:01 +01:00
Sam Brannen b9cf03f8f0 Construct consistent error messages in BeanOverrideBeanFactoryPostProcessor 2024-11-21 11:28:31 +01:00
Sam Brannen 08a789cee9 Honor @⁠Fallback semantics for Test Bean Overrides
Closes gh-33924
2024-11-21 09:50:17 +01:00
Sam Brannen 7a6e401d17 Document visibility requirements for Bean Overrides
This commit makes it clear that there are no visibility requirements
for @⁠TestBean fields or factory methods as well as @⁠MockitoBean or
@⁠MockitoSpyBean fields.

Closes gh-33923
2024-11-20 16:49:52 +01:00
Sam Brannen 3569cfe990 Reject static Bean Override fields for @⁠MockitoBean, @⁠TestBean, etc.
Closes gh-33922
2024-11-20 11:29:01 +01:00
Simon Baslé 8b66d3c79a Upgrade Undertow-servlet/websockets to 2.3.18.Final
Follow up to 35b452b4 which only upgraded undertow-core.
2024-11-19 16:59:04 +01:00
Sam Brannen a3c132c442 Polish XmlExpectationsHelper[Tests] 2024-11-19 13:33:20 +01:00
boiarshinov 91791c1756 Fail with full description for XML diff in XmlExpectationsHelper
Closes gh-33827
2024-11-19 13:23:58 +01:00
Sam Brannen dd92eac3ad Refer to message "receipt" instead of "reception" 2024-11-19 13:18:12 +01:00
Sam Brannen 874f056984 Polishing 2024-11-19 13:18:12 +01:00
Tran Ngoc Nhan b77db64459 Fix typos and link in Observability documentation
Closes gh-33910
2024-11-19 12:12:01 +01:00
Simon Baslé d597d2e159 Fix WebClientIntegrationTest#applyAttributesToNativeRequest flaky test
For Reactor Netty and Reactor Netty 2 (with Netty 5), the attributes are
stored as an `Attribute` on the netty channel. Reactor Netty replaces
the channel with a static placeholder one once the request has been
processed and as such, capturing the native request in the test will
lead to asserting an attribute-less channel.

This change switches to capturing the `Attribute` itself, which is a
value-holder that can be asserted later on.

Closes gh-33909
2024-11-18 16:30:16 +01:00
Sam Brannen f5c3f3522e Simplify @⁠EnumSource usage 2024-11-18 14:12:13 +01:00
Sam Brannen d421f61a4a Polish @⁠DurationFormat Javadoc and tests 2024-11-18 14:12:13 +01:00
Tran Ngoc Nhan 883254e1d0 Polish
- Update copyright header.
- Consistent use of "SIMPLE" link text for Style#SIMPLE in javadoc.

Closes gh-33883
2024-11-18 13:40:23 +01:00
Brian Clozel e919d0adcc Reflect well-known MediaTypes intent in Javadoc
Closes gh-33754
2024-11-18 11:57:22 +01:00
Brian Clozel 4aafae1c33 Reflect well-known HttpHeaders intent in Javadoc
Closes gh-33886
2024-11-18 11:57:15 +01:00
Brian Clozel afef439c1f Temporarily disable flaky integration test
See gh-33909
2024-11-18 11:57:09 +01:00
Sam Brannen 807e1e6126 Document support for varargs invocations in SpEL
Closes gh-33332
2024-11-18 11:54:22 +01:00
Stéphane Nicoll 5ac56bda87 Remove unnecessary workflow in maintenance branch 2024-11-18 11:52:08 +01:00
Sam Brannen 7196f3f554 Polish SpEL documentation 2024-11-18 11:38:20 +01:00
Sam Brannen a12d40e10b Fix SpEL examples in reference guide
Closes gh-33907
2024-11-18 11:37:30 +01:00
Sam Brannen 7f7819329c Update copyright headers
See gh-33903
2024-11-17 15:14:16 +01:00
KNU-K 2494ecb47b Simplify utility implementations in spring-core
Closes gh-33903
2024-11-17 15:08:30 +01:00
Sam Brannen 241b8b48f2 Clarify requirements for AOP around advice regarding MethodInterceptor
Closes gh-33901
2024-11-17 12:23:01 +01:00
Sam Brannen 173084f81a Polish Spring AOP documentation 2024-11-17 12:21:16 +01:00
Sam Brannen 6544698078 Polish contribution
See gh-33902
2024-11-17 11:45:37 +01:00
taehyun e0e96c487f Simplify implementation of FilteredIterator
Closes gh-33902
2024-11-17 11:41:22 +01:00
Sam Brannen bb32df0a06 Upgrade to Gradle 8.11
Closes gh-33895
2024-11-15 16:06:14 +01:00
Brian Clozel 66c3aeee84 Polishing 2024-11-15 15:37:00 +01:00
Brian Clozel 828980bd44 Fix workflow configuration for 6.2.x branch 2024-11-15 15:35:32 +01:00
Sam Brannen fe8573c0ab Upgrade to antora-ui-spring version 0.4.18
Closes gh-33892
2024-11-15 14:32:01 +01:00
Brian Clozel 130627f630 Next development version (v6.2.1-SNAPSHOT) 2024-11-14 17:48:54 +01:00
Simon Baslé 35b452b458 Upgrade to Undertow 2.3.18.Final, dispatch in UndertowHttpHandlerAdapter
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.

Closes gh-33885
2024-11-14 16:14:57 +01:00
Brian Clozel 56525da43a Merge branch '6.1.x' 2024-11-14 15:29:49 +01:00
Juergen Hoeller d4f8b5d820 Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-11-14 12:52:10 +01:00
Sam Brannen cca245020d Improve documentation for SpelCompilerMode
Closes gh-33223
2024-11-14 11:36:46 +01:00
rstoyanchev de8a94f30d Do not set up CookieStore in Apache connector
Closes gh-33822
2024-11-14 09:30:36 +00:00
Sam Brannen 973d815763 Merge branch '6.1.x' 2024-11-14 10:16:02 +01:00
Juergen Hoeller 1c2dbec971 Merge branch '6.1.x' 2024-11-13 22:26:54 +01:00
Juergen Hoeller 37b110a181 Polishing 2024-11-13 19:00:08 +01:00
Juergen Hoeller 18a3b52d5e Restore enum-style exception message expected by test 2024-11-13 18:56:19 +01:00
Sam Brannen b523f3caff Polish documentation and exception message for @⁠DurationFormat 2024-11-13 17:19:53 +01:00
Sam Brannen 7f9901d35d Merge branch '6.1.x' 2024-11-13 16:46:11 +01:00
Juergen Hoeller 25e2c1b7ce Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java
2024-11-13 15:12:55 +01:00
Sam Brannen d92c57f7a5 Merge branch '6.1.x' 2024-11-13 14:23:52 +01:00
Juergen Hoeller 4ca596b7bc Upgrade to Micrometer 1.14.0 and Reactor 2024.0.0
Includes Netty 4.1.114, Jetty 12.0.15, Jetty Reactive HttpClient 4.0.8, RxJava 3.1.9, RSocket 1.1.4, HSQLDB 2.7.4, H2 2.3.232, SnakeYAML 2.3, Groovy 4.0.24, JRuby 9.4.9, Jackson 2.18.1, Gson 2.11, Protobuf 4.28.3, XStream 1.4.21, Woodstox 6.7, TestNG 7.10.2, Selenium 4.26, HtmlUnit 4.6, XMLUnit 2.10, Checkstyle 10.20.1

Closes gh-33876
Closes gh-33878
2024-11-13 13:34:43 +01:00
Juergen Hoeller 90ef7ac514 Cache singleton results for @Lazy injection points
Includes consistent use of unmodifiable collections.

Closes gh-33841
2024-11-13 13:29:20 +01:00
Sam Brannen c3991392df Merge branch '6.1.x' 2024-11-13 12:32:48 +01:00
Sébastien Deleuze 357dbc0354 Add AOT support for container element constraints
This commit introduces support for bean validation container
element constraints, including transitive ones.

Transitive constraints in the parameterized types of a container
are not discoverable via the BeanDescriptor, so a complementary
type discovery is done on Spring side to cover the related use
case.

Closes gh-33842
2024-11-13 11:03:48 +01:00
Sam Brannen 525407e4b1 Merge branch '6.1.x' 2024-11-12 20:50:46 +01:00
rstoyanchev cbe2f36106 Decode static resource path with UriUtils
See gh-33859
2024-11-12 11:39:22 +00:00
Sam Brannen 9dabfdf0bf Remove obsolete AstUtilsTests
AstUtilsTests got accidentally reintroduced in 5b5a072351 after
AstUtils was renamed to AccessorUtils in e3ba957431.
2024-11-12 12:15:11 +01:00
rstoyanchev 942d2c5541 Merge branch '6.1.x' 2024-11-12 10:30:39 +00:00
Brian Clozel 5b5a072351 Merge branch '6.1.x' 2024-11-12 10:05:24 +01:00
Tran Ngoc Nhan 85cf563741 Fix typo in reference documentation
See gh-33865
2024-11-12 10:04:06 +01:00
Sam Brannen e3ba957431 Polish SpEL internals 2024-11-12 10:04:06 +01:00
Sam Brannen caec8f4f36 Revise Javadoc for PropertyAccessor & IndexAccessor regarding ordering
Closes gh-33862
2024-11-12 10:04:06 +01:00
Sam Brannen ae16a7fc08 Update tests for 6.2
See gh-33861
2024-11-12 10:04:06 +01:00
Sam Brannen 43e7921bcc Introduce tests for SpEL PropertyAccessor ordering
Closes gh-33861
2024-11-12 10:04:06 +01:00
Sam Brannen 8202282975 Polishing 2024-11-08 15:34:54 +01:00
rstoyanchev d4719493bd Empty string check after conversion in AbstractNamedValueArgumentResolver
Closes gh-33794
2024-11-08 09:21:08 +00:00
rstoyanchev 59ec871e76 Append trailing slash to static location
Closes gh-33815
2024-11-08 07:11:55 +00:00
rstoyanchev 37243f44e8 Refactor cookie support for Apache HttpClient
Closes gh-33822
2024-11-08 06:30:51 +00:00
longtanfei e67f892e44 Use optimistic locking where possible in ResponseBodyEmitter
Closes gh-33831
2024-11-07 16:33:05 +01:00
Sam Brannen 1ced8c3856 Merge branch '6.1.x' 2024-11-07 12:26:21 +01:00
Sam Brannen fd676ed932 Merge branch '6.1.x' 2024-11-07 10:44:47 +01:00
Simon Baslé 715e38c44f Merge branch '6.1.x' 2024-11-07 10:05:15 +01:00
Sam Brannen 2e6c8daec6 Fix anchor name, consistently use title case, and polish wording 2024-11-06 17:46:06 +01:00
Stéphane Nicoll c5f8dcc245 Merge branch '6.1.x' 2024-11-06 23:12:06 +09:00
Sébastien Deleuze 72e7f1552b Refine @Contract Javadoc
This commit refines `@Contract` Javadoc to mention
this and new return values.

Closes gh-33849
2024-11-06 12:03:19 +01:00
Simon Baslé bbe90a57ba Merge branch '6.1.x' 2024-11-06 11:40:46 +01:00
Hejow 4697ae10ee Relax the visibility of MockMVC DSL constructors
Closes gh-33778
2024-11-06 10:28:15 +01:00
Sébastien Deleuze fb98d74a47 Merge branch '6.1.x' 2024-11-06 10:09:13 +01:00
Sébastien Deleuze 7e1d6fe934 Merge branch '6.1.x' 2024-11-05 10:27:22 +01:00
Brian Clozel c6126b2033 Remove Java 22 from CI test matrix
Java 23 is now GA.
2024-11-04 09:48:48 +01:00
Brian Clozel f1e6482f92 Upgrade to Mockito 5.14.2
This version brings bytebuddy 1.15.4 which supports JDK 24.
2024-11-04 09:21:21 +01:00
Sam Brannen e3301dd1c4 Merge branch '6.1.x' 2024-11-03 16:17:43 +01:00
Stéphane Nicoll 2b601f9e51 Merge branch '6.1.x' 2024-11-03 18:16:31 +09:00
Sam Brannen a3b979c5ec Register runtime hints for @⁠TestBean fully-qualified method names
This commit introduces a TestBeanReflectiveProcessor that registers
GraalVM native image reflection hints for a fully-qualified method name
configured via @⁠TestBean.

Closes gh-33836
2024-11-01 16:48:06 +01:00
Sam Brannen a8f5848a5d Add missing runtime hint assertions for Bean Overrides 2024-11-01 16:47:36 +01:00
Sam Brannen 97f23dca22 Remove extra "Bean" from TestBeanBeanOverrideHandler class name
The extra "Bean" was accidentally added in commit ebdf6dc2fc.

See gh-33702
2024-11-01 14:57:30 +01:00
Sam Brannen 86784b61cc Introduce support for a custom reason in @⁠DisabledInAotMode
Closes gh-33833
2024-11-01 12:24:53 +01:00
Sam Brannen fdb763eeaf Merge branch '6.1.x' 2024-11-01 10:42:51 +01:00
Sam Brannen ba692aa3ef Honor MockReset without @⁠MockitoBean or @⁠MockitoSpyBean fields
Prior to this commit, the static factory methods in MockReset (such as
MockReset.before() and MockReset.after()) could only be applied to
beans within the ApplicationContext if the test class declared at least
one field annotated with either @⁠MockitoBean or @⁠MockitoSpyBean.

However, the Javadoc states that it should be possible to apply
MockReset directly to any mock in the ApplicationContext using the
static methods in MockReset.

To address that, this commit reworks the "enabled" logic in
MockitoResetTestExecutionListener as follows.

- We no longer check for the presence of annotations from the
  org.springframework.test.context.bean.override.mockito package to
  determine if MockReset is enabled.

- Instead, we now rely on a new isEnabled() method to determine if
  MockReset is enabled.

The logic in the isEnabled() method still relies on the mockitoPresent
flag as an initial check; however, mockitoPresent only determines if
Mockito is present in the classpath. It does not determine if Mockito
can actually be used. For example, it does not detect if the necessary
reachability metadata has been registered to use Mockito within a
GraalVM native image.

To address that last point, the isEnabled() method performs an
additional check to determine if Mockito can be used in the current
environment. Specifically, it invokes Mockito.mockingDetails().isMock()
which in turn initializes core Mockito classes without actually
attempting to create a mock. If that fails, that means that Mockito
cannot actually be used in the current environment, which typically
indicates that GraalVM reachability metadata has not been registered
for the org.mockito.plugins.MockMaker in use (such as the
ProxyMockMaker).

In addition, isEnabled() lazily determines if Mockito can be
initialized, since attempting to detect that during static
initialization results in a GraalVM native image error stating that
Mockito internals were "unintentionally initialized at build time".

If Mockito cannot be initialized, MockitoResetTestExecutionListener
logs a DEBUG level message providing access to the corresponding stack
trace, and MockReset support is disabled.

Closes gh-33829
2024-10-31 15:56:54 +01:00
Sam Brannen 0846706688 Adapt copyright headers copied from Spring Boot 2024-10-31 15:33:50 +01:00
rstoyanchev bc65f93467 Improve cancel in SubscriberInputStreamTests 2024-10-31 10:05:45 +00:00
rstoyanchev 38c88e769d Polishing in SubscriberInputStreamTests 2024-10-31 10:05:45 +00:00
Sam Brannen 4a0edc59cc Verify support for MockReset for beans within the ApplicationContext
This commit verifies that MockReset.before() and MockReset.after() are
supported for beans within the ApplicationContext.

However, the test class must declare a field annotated with either
@⁠MockitoBean or @⁠MockitoSpyBean in order for the MockReset feature to
be triggered.

See gh-33742
2024-10-30 17:31:15 +01:00
Juergen Hoeller c979eddab1 Consistent deprecation markers for 6.2 2024-10-30 16:45:00 +01:00
Juergen Hoeller 864cb25eec Upgrade to ASM 9.7.1
Closes gh-33821
2024-10-30 16:44:47 +01:00
Sam Brannen e23c8bfbb6 Polishing 2024-10-30 15:56:19 +01:00
Sam Brannen 08e0baac94 Honor @⁠Primary for test Bean Overrides such as @⁠MockitoBean
Spring Boot has honored @⁠Primary for selecting which candidate bean
@⁠MockBean and @⁠SpyBean should mock or spy since Spring Boot 1.4.3;
however, the support for @⁠Primary was not ported from Spring Boot to
Spring Framework's new Bean Overrides feature in the TestContext
framework.

To address that, this commit introduces support for @⁠Primary for
selecting bean overrides -- for example, for annotations such as
@⁠TestBean, @⁠MockitoBean, and @⁠MockitoSpyBean.

See https://github.com/spring-projects/spring-boot/issues/7621
Closes gh-33819
2024-10-30 15:49:16 +01:00
Sébastien Deleuze 9166688b6f Remove the pure attribute from @Contract
Closes gh-33820
2024-10-30 15:11:44 +01:00
Sébastien Deleuze da8925131e Polish @Contract Javadoc 2024-10-30 15:11:28 +01:00
Sébastien Deleuze 09d87fac57 Annotate RestClient retrieve() with @CheckReturnValue
This annotation triggers a warning in IDEs supporting
`@CheckReturnValue` when retrieve() return value is not
used.

Closes gh-33818
2024-10-30 14:45:35 +01:00
Sébastien Deleuze a005c325f7 Introduce @CheckReturnValue annotation
This commit introduces a `@CheckReturnValue` annotation,
inspired from org.jetbrains.annotations.CheckReturnValue,
that specifies that the method return value must be used.

See gh-33818
2024-10-30 14:45:35 +01:00
Sébastien Deleuze eaafdea1fb Fix ListenableFutureReturnValueHandler Javadoc
See gh-33808
2024-10-30 14:44:25 +01:00
Sébastien Deleuze f4b3520ab3 Suppress Kotlin code sample warnings 2024-10-30 11:54:14 +01:00
Sam Brannen f427ac383d (Re)suppress deprecation warnings
See gh-33780
2024-10-30 10:52:01 +01:00
Brian Clozel 79cf554850 Merge branch '6.1.x' 2024-10-30 10:37:17 +01:00
Sam Brannen c0c41ddda5 Disable unsupported tests in AOT mode as well 2024-10-30 10:29:02 +01:00
Sam Brannen 7148b28b2b Integration test Bean Override support for multiple candidate beans
This commit introduces integration tests which verify that Bean
Overrides (for example, @⁠MockitoBean and @⁠MockitoSpyBean) can select
a single candidate bean to override when there are multiple candidates
that match the required type.

To "select" the desired bean, these tests rely on one of the following.

- explicit bean name in the bean override annotation

- explicit @⁠Qualifier on the bean override field

- explicit @⁠Primary on one of the candidate beans

However, the @⁠Primary tests are currently @⁠Disabled until @⁠Primary
is honored in the Spring TestContext Framework.

See gh-33742
2024-10-30 10:22:19 +01:00
Juergen Hoeller 1255bd1fc9 Add remaining @SuppressWarnings("removal") for ListenableFuture
See gh-33780
2024-10-29 23:15:53 +01:00
Juergen Hoeller a1f6098158 Merge branch '6.1.x' 2024-10-29 23:04:05 +01:00
Juergen Hoeller 9e3371ef07 Mark ListenableFuture as deprecated for removal
Closes gh-33808
2024-10-29 18:36:40 +01:00
Sam Brannen c2c6bb25c6 Use BeanFactory to get type produced by a FactoryBean for Bean Overrides
Previously, we only looked at the OBJECT_TYPE_ATTRIBUTE on a
FactoryBean's bean definition; however this does not work for
situations where the information is provided by the definition's target
type rather than the attribute.

Rather than manually considering the target type in addition to the
existing consideration of the attribute, we now ask the BeanFactory for
the type that will be produced by the FactoryBean instead.

See https://github.com/spring-projects/spring-boot/issues/40234
Closes gh-33811

Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
2024-10-29 14:21:18 +01:00
Sam Brannen 40960fa85a Verify @⁠MockitoSpyBean can spy bean from FactoryBean with generics
This commit introduces a test which verifies that @⁠MockitoSpyBean on a
field with generics can be used to replace an existing bean with
matching generics that's produced by a FactoryBean that's
programmatically registered via an ImportBeanDefinitionRegistrar.

However, the test is currently @⁠Disabled until the fix for
https://github.com/spring-projects/spring-boot/issues/40234 has been
ported to Spring Framework.

See gh-33742
2024-10-29 13:55:22 +01:00
Sam Brannen 578928de39 Introduce test for Bean Override for "broken" FactoryBean
See gh-33800
2024-10-29 10:56:23 +01:00
Juergen Hoeller 015beb0058 Provide first-class virtual thread option for common executors
Closes gh-33807
2024-10-28 22:14:41 +01:00
Juergen Hoeller 3732c71168 Merge branch '6.1.x' 2024-10-28 22:12:12 +01:00
rstoyanchev 4749d810db Refactor ReactorClientHttpRequestFactory timeouts
Closes gh-33782
2024-10-28 12:45:53 +00:00
rstoyanchev 044da794f4 Polishing ReactorClientHttpRequestFactory 2024-10-28 12:45:53 +00:00
rstoyanchev 89d56b1fa6 Streaming ReactorClientHttpResponse
Closes gh-33781
2024-10-28 12:45:53 +00:00
rstoyanchev f1cfe7a3d4 InputStreamSubscriber instantiation and Javadoc
See gh-31677
2024-10-28 12:45:53 +00:00
rstoyanchev dfaf7a0c6a Rename InputStreamSubscriber to SubscriberInputStream
It is both, but InputStream is what's exposed for public use,
in effect an InputStream backed by a Subscriber source.

See gh-31677
2024-10-28 12:45:53 +00:00
rstoyanchev 86a42db002 InputStreamSubscriber/Tests conform to style
See gh-31677
2024-10-28 12:45:53 +00:00
rstoyanchev d4b31fd4b2 InputStreamSubscriber compiler issues
See gh-31677
2024-10-28 12:45:53 +00:00
rstoyanchev a366ea0e15 Align InputStreamSubscriber copies
There are legitimate differences, but also some are fixes that
should be on both sides.

See gh-31677
2024-10-28 12:45:53 +00:00
OlegDokuka 37622a7f90 Support Publisher to InputStream conversion
See gh-31677
2024-10-28 12:45:53 +00:00
Sam Brannen de2c10abcd Sync Javadoc for @⁠TestBean & @⁠MockitoBean with reference manual
See gh-33701
2024-10-28 12:58:33 +01:00
Sam Brannen 81d89f478a Relax singleton enforcement for Bean Overrides in the TestContext framework
In gh-33602, we introduced strict singleton enforcement for bean
overrides -- for example, for @⁠MockitoBean, @⁠TestBean, etc. However,
the use of BeanFactory#isSingleton(beanName) can result in a
BeanCreationException for certain beans, such as a Spring Data JPA
FactoryBean for a JpaRepository.

In light of that, this commit relaxes the singleton enforcement in
BeanOverrideBeanFactoryPostProcessor by only checking the result of
BeanDefinition#isSingleton() for existing bean definitions.

This commit also updates the Javadoc and reference documentation to
reflect the status quo.

See gh-33602
Closes gh-33800
2024-10-28 12:45:05 +01:00
Sam Brannen 52e813d0ad Improve structure and naming of ProxyExceptionHandlingTests
Closes gh-33797
2024-10-25 16:14:42 +02:00
Sam Brannen f19a1b50e5 Polishing 2024-10-25 15:22:56 +02:00
Sam Brannen 5532574f56 Remove unused casts and variables 2024-10-25 15:16:05 +02:00
Sam Brannen 1b3e96b9bf Merge branch '6.1.x' 2024-10-25 14:49:46 +02:00
Brian Clozel 9df4fcdc9e Merge branch '6.1.x' 2024-10-25 10:55:00 +02:00
Sam Brannen d1d6ff8737 Verify @⁠MockitoSpyBean can be used with circular dependencies
See gh-33742
2024-10-24 16:53:26 +02:00
Sam Brannen 9f0dbc4051 Fix heading level for "Programmatic bean registration" in AOT chapter 2024-10-24 16:43:17 +02:00
Brian Clozel acccbbec3f Document UrlHandler Servlet and reactive filters
Closes gh-33784
2024-10-24 16:14:18 +02:00
Sam Brannen 3cc76ef87c Polishing 2024-10-24 15:47:16 +02:00
Sam Brannen 0221471265 Verify @⁠Mockito[Spy]Bean can mock/spy parameterized types
See gh-33742
2024-10-24 15:45:28 +02:00
Sam Brannen 3b82733e1f Support @⁠Mockito[Spy]Bean & @⁠TestBean w/ @⁠DirtiesContext "before method" modes
Closes gh-33783
2024-10-24 15:06:03 +02:00
Sam Brannen ba8024d077 Verify @⁠MockitoBean can be used with generics and parameterized types
See gh-33742
2024-10-24 12:48:24 +02:00
Sam Brannen efda3f0f99 Reorganize Mockito integration tests 2024-10-24 12:21:58 +02:00
Sam Brannen 761850816c Verify @⁠MockitoBean can be used with JUnit 4 and SpringMethodRule
See gh-33742
2024-10-24 12:21:58 +02:00
Sam Brannen 2d028c39b4 Align with naming in ReflectionTestUtils 2024-10-24 10:25:18 +02:00
Juergen Hoeller fe6d9145e5 Avoid hard dependency on Spring AOP for mock resolution
Closes gh-33774
2024-10-23 21:26:06 +02:00
rstoyanchev c160e89d9d Merge branch '6.1.x' 2024-10-23 19:09:53 +01:00
rstoyanchev bff76d756b Refactor implementation of retrieve in RestClient
Closes gh-33777
2024-10-23 18:59:07 +01:00
Sam Brannen 8fa99dcbdd Polishing 2024-10-23 17:16:41 +02:00
Sam Brannen 5bf179b851 Remove proxyTargetAware attribute from @⁠MockitoSpyBean
This commit removes the proxyTargetAware attribute from @⁠MockitoSpyBean
while keeping the underlying feature in tact (i.e., transparent
verification for spies created via @⁠MockitoSpyBean).

Closes gh-33775
2024-10-23 16:39:01 +02:00
Brian Clozel 20d21a8251 Rework links to Spring Boot in reference docs
Closes gh-33776
2024-10-23 16:10:37 +02:00
Sam Brannen d8a6423c0c Support transparent verification for @⁠MockitoSpyBean
Prior to this commit, SpringAopBypassingVerificationStartedListener
provided partial support for transparent verification for Mockito spies
created via @⁠MockitoSpyBean when the spy is wrapped in a Spring AOP
proxy. However, attempting to actually verify invocations for a spy
resulted in an exception from Mockito since MockUtil.isMock() returned
false in such scenarios.

This commit addresses that by introducing a SpringMockResolver that
resolves mocks by walking the Spring AOP proxy chain until the target
or a non-static proxy is found.

SpringMockResolver is automatically registered whenever the spring-test
JAR is on the classpath, allowing Mockito to transparently resolve mocks
wrapped in Spring AOP proxies.

Closes gh-33774
2024-10-23 15:51:35 +02:00
Sam Brannen c85689b308 Polishing 2024-10-23 14:01:52 +02:00
Sam Brannen 982f7f8f58 Verify @⁠MockitoBean & @⁠MockitoSpyBean can be used Spring AOP proxies
Use cases not yet supported with @⁠MockitoSpyBean are currently @⁠Disabled.

See gh-33742
2024-10-23 13:54:11 +02:00
rstoyanchev d05f880d74 Fix test causing failure in RestClientObservationTests
See gh-33697
2024-10-23 12:24:28 +01:00
rstoyanchev 2b113e3fd0 Minor refactoring
Closes gh-33697
2024-10-23 11:38:19 +01:00
rstoyanchev 73e5aa38ec Polishing contribution
See gh-33697
2024-10-23 11:38:19 +01:00
Nicklas Wiegandt a0af708c03 Add cookie support to RestClient
See gh-33697
2024-10-23 11:38:18 +01:00
Brian Clozel d8c153a9d1 Remove support for Resin Servlet container
This commit removes all references to the Resin Servlet container, as it
is not supported as of Spring Framework 6.0 because we require a
JakartaEE baseline.

Closes gh-33772
2024-10-23 10:10:29 +02:00
Brian Clozel 1ba773170d Merge branch '6.1.x' 2024-10-23 09:26:40 +02:00
Juergen Hoeller 081d0b33d4 Consistently sort jar entries in doFindPathMatchingJarResources
Includes consistent clearCache() behavior for manifest entries.

Closes gh-33771
See gh-33705
2024-10-22 21:29:22 +02:00
Phillip Webb 1c69a3c521 Fix PathMatchingResourcePatternResolver manifest classpath discovery
Update `PathMatchingResourcePatternResolver` so that in addition to
searching the `java.class.path` system property for classpath enties,
it also searches the `MANIFEST.MF` files from within those jars.

Prior to this commit, the `addClassPathManifestEntries()` method
expected that the JVM had added `Class-Path` manifest entries to the
`java.class.path` system property, however, this did not always happen.

The updated code now performs a deep search by loading `MANIFEST.MF`
files from jars discovered from the system property. To deal with
potential performance issue, loaded results are also now cached.

The updated code has been tested with Spring Boot 3.3 jars extracted
using `java -Djarmode=tools`.

See gh-33705
2024-10-22 21:10:29 +02:00
rstoyanchev b7fc4bc5c8 Polishing contribution
Closes gh-33716
2024-10-22 17:37:45 +01:00
Ilya Serkov 657e002ed7 Fix HttpHeaders.setHost() to remove the header
See gh-33716
2024-10-22 17:37:44 +01:00
rstoyanchev 9252e741e1 Default webmvc handling of disconnected client errors
Closes gh-33753
2024-10-22 15:47:29 +01:00
rstoyanchev 5271f5b8a1 Polishing 2024-10-22 14:50:33 +01:00
Sam Brannen 626f4279f6 Merge branch '6.1.x' 2024-10-22 13:11:39 +02:00
Stéphane Nicoll 382b51a8d4 Polish 2024-10-22 11:33:52 +02:00
Sébastien Deleuze 2b0c1fa210 Improve the discoverability of Java and Kotlin APIs
This commit add external links in the refdoc to Java
and Kotlin APIs to make them more discoverable.

Closes gh-32835
2024-10-22 08:40:28 +02:00
Brian Clozel ec895534c5 Merge branch '6.1.x' 2024-10-21 18:34:49 +02:00
Juergen Hoeller 267d3a36ae Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java
2024-10-21 18:14:50 +02:00
Sam Brannen 1784ccb200 Upgrade to JUnit 5.11.3
Closes gh-33764
2024-10-21 16:58:14 +02:00
Sébastien Deleuze 57eb4823d2 Stop submitting Antora UI PR for 6.0.x and main branches
Closes gh-33765
2024-10-21 16:54:04 +02:00
Brian Clozel ab2f1f8885 Merge branch '6.1.x' 2024-10-21 16:20:57 +02:00
Juergen Hoeller a1dd2e7c96 Merge branch '6.1.x' 2024-10-21 15:39:10 +02:00
Juergen Hoeller ee1fe8a1e9 Consistently evaluate defaultCandidate flag on constructors and methods
Closes gh-33762
2024-10-21 13:53:28 +02:00
Sam Brannen 6f9413ba31 Merge branch '6.1.x' 2024-10-21 12:20:59 +02:00
RollW 6c93c67dd4 Add Kotlin code samples to the AOT documentation
Closes gh-33761
2024-10-21 11:21:05 +02:00
Sam Brannen 599d53465b Merge branch '6.1.x' 2024-10-20 17:43:45 +02:00
Sam Brannen 68d9e5d81a Merge branch '6.1.x' 2024-10-19 15:03:15 +02:00
Sam Brannen 23f19a0fad Add link to existing bug report 2024-10-19 13:06:21 +02:00
Sam Brannen 14c476bd42 Verify @⁠MockitoBean can replace Spring AOP advised beans
See gh-33742
2024-10-18 17:53:44 +02:00
Sam Brannen a8b36f7ad5 Verify @⁠MockitoBean can replace beans that have @⁠Async methods
See gh-33742
2024-10-18 17:38:02 +02:00
Sam Brannen d5e334339a Verify @⁠MockitoBean can replace a scoped-proxy
See gh-33742
2024-10-18 17:14:59 +02:00
Sam Brannen c0ad9c0081 Verify @⁠MockitoBean & @⁠MockitoSpyBean can be used with @⁠ContextHierarchy
See gh-33742
2024-10-18 17:10:53 +02:00
Sam Brannen 2aa3f40257 Polishing 2024-10-18 16:55:40 +02:00
Sam Brannen 3842f12d09 Verify that the MockitoExtension and SpringExtension can be combined
See gh-33742
2024-10-18 16:51:52 +02:00
Brian Clozel 5f14703105 Merge branch '6.1.x' 2024-10-18 14:43:54 +02:00
Sébastien Deleuze e02f8ca492 Merge branch '6.1.x' 2024-10-18 12:37:00 +02:00
Sébastien Deleuze 5abe5e1167 Merge branch '6.1.x' 2024-10-18 11:15:00 +02:00
Brian Clozel cee8b52de8 Merge branch '6.1.x' 2024-10-18 10:55:21 +02:00
Brian Clozel 9a761579c0 Remove ServerResponse.AsyncBuilder interface
This new interface is not strictly necessary and introduces a binary
incompatibility. This commit merges back all the method definitions into
`SseBuilder` and `StreamBuilder` interfaces.

Closes gh-33736
2024-10-18 09:09:41 +02:00
Stéphane Nicoll 67c7b80c2b Merge branch '6.1.x' 2024-10-17 10:28:33 +02:00
Stéphane Nicoll bdf76b2f8d Restore nested property resolution for non CharSequence types
Closes gh-33727

Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
2024-10-17 10:25:50 +02:00
Johnny Lim cbdfe815aa Add Javadoc since for headers() in Delete/Patch/Post/PutExchange
See gh-33309
Closes gh-33723
2024-10-16 18:11:29 +02:00
Sam Brannen ac458be845 Polish exception message 2024-10-16 17:49:57 +02:00
Sébastien Deleuze effe606b28 Refine record canonical constructor support in BeanUtils
This commit refines the contribution with the following changes:
 - Move the support to findPrimaryConstructor
 - Use a for loop instead of a Stream for more efficiency
 - Support other visibilities than public
 - Polishing

Closes gh-33707
2024-10-16 17:38:47 +02:00
evgenijnikiforov 514d6000d1 Support record canonical constructor in BeanUtils
See gh-33707
2024-10-16 17:38:47 +02:00
Sam Brannen 161d3995bf Introduce BeanOverrideHandler.createOverrideInstance() template method 2024-10-16 17:31:19 +02:00
Sam Brannen da856de100 Revise BeanOverrideRegistrar and rename it to BeanOverrideRegistry 2024-10-16 17:31:19 +02:00
Juergen Hoeller fa955934e7 Merge branch '6.1.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
2024-10-16 17:19:30 +02:00
rstoyanchev 92c9b0dc97 Reduce logging for unsent SUBSCRIBE messages
Closes gh-28252
2024-10-16 16:14:10 +01:00
Sam Brannen c0c78bd67e Rename OverrideMetadata for Bean Overrides
Prior to this commit, OverrideMetadata was the only public type in the
org.springframework.test.context.bean.override package whose name did
not start with BeanOverride. In addition, an OverrideMetadata component
plays multiple roles in addition to serving as a holder for metadata.

This commit therefore renames OverrideMetadata to BeanOverrideHandler.

In addition, this commit updates the affected documentation and renames
the following related methods in the Bean Override support.

- BeanOverrideHandler: createOverride() -> createOverrideInstance()
- BeanOverrideHandler: track() -> trackOverrideInstance()
- BeanOverrideProcessor: createMetadata() -> createHandler()
- BeanOverrideContextCustomizer: getMetadata() -> getBeanOverrideHandlers()
- BeanOverrideRegistrar: registerNameForMetadata() -> registerBeanOverrideHandler()
- BeanOverrideRegistrar: markWrapEarly() -> registerWrappingBeanOverrideHandler()

Closes gh-33702
2024-10-16 16:32:38 +02:00
Brian Clozel ab4fe5a29c Merge branch '6.1.x' 2024-10-16 16:26:12 +02:00
Sébastien Deleuze beac903423 Merge branch '6.1.x' 2024-10-16 14:21:11 +02:00
Sébastien Deleuze 0e70117d77 Merge branch '6.1.x' 2024-10-16 14:17:17 +02:00
rstoyanchev ca820c914f Polishing contribution
Closes gh-33715
2024-10-16 13:06:22 +01:00
Yanming Zhou f35ed8d044 Improve check whether to lowercase scheme
See gh-33715

```
Map has no value for 'thescheme'
java.lang.IllegalArgumentException: Map has no value for 'thescheme'
	at org.springframework.web.util.UriComponents$MapTemplateVariables.getValue(UriComponents.java:348)
	at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:263)
	at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:436)
	at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:53)
	at org.springframework.web.util.UriComponents.expand(UriComponents.java:161)
	at org.springframework.web.util.UriComponentsBuilder.buildAndExpand(UriComponentsBuilder.java:364)
```
2024-10-16 12:54:33 +01:00
Juergen Hoeller e89218b39a Merge branch '6.1.x' 2024-10-16 13:46:22 +02:00
rstoyanchev bdcfbee7df Merge branch '6.1.x' 2024-10-16 12:11:23 +01:00
Juergen Hoeller fb6a6892ef Merge branch '6.1.x' 2024-10-16 11:36:30 +02:00
Simon Baslé dbbc578676 Polishing
Inline `AbstractMockitoTestExecutionListener` since there's now only one
Mockito `TestExecutionListener`.
2024-10-16 10:22:38 +02:00
Simon Baslé 6f79c7e70f Remove support for Mockito annotations and MockitoSession
This change remove the support for Mockito annotations, `MockitoSession`
and opening/closing of mocks that was inherited from Boot's `@MockBean`
support, as well as the switch to `MockitoSession` made in 1c893e6.

Attempting to take responsability for things Mockito's own JUnit
Jupiter extension does better is not ideal, and we found it leads to
several corner cases which make `SpringExtension` and `MockitoExtension`
incompatible in the current approach.

Instead, this change refocuses our Mockito bean overriding support
exclusively on aspects specific to the Framework. `MockitoExtension`
will thus be usable in conjunction with `SpringExtension` if one needs
to use `@Captor`/`@InitMocks`/`@Mock`/`@Spy` or other Mockito utilities.

See gh-33318
Closes gh-33692
2024-10-16 09:40:57 +02:00
rstoyanchev c261ca3102 Ensure scheme not lowercased if URI variable
Closes gh-33699
2024-10-15 20:50:01 +01:00
rstoyanchev a63cf06496 Update Javadoc snippets for static resource locations
Switch to FileUrlResource, the same as what is used get with
the "file:" prefix in webmvc and webflux config.

See gh-33712
2024-10-15 19:23:07 +01:00
rstoyanchev 789d7effa9 Assert static resource location
Closes gh-33712
2024-10-15 19:23:07 +01:00
Brian Clozel f204f4962d Document XML parser usage against security false positives
Prior to this commit, our XML parser usage would be already haredened
against XXE (XML External Entities) attacks. Still, we recently received
several invalid security reports claiming that our setup should be
hardened.

This commit documents a few usages of XML parsers to add some more
context and hopefully prevent future invalid reports.

Closes gh-33713
2024-10-15 18:59:02 +02:00
Habin Song 166714c8f5 Update scheduling.adoc
Change quotation marks to backticks.

Closes gh-33709
2024-10-15 18:21:42 +02:00
Sam Brannen 67cb3c77ec Rename BeanOverrideStrategy enum constants
Closes gh-33701
2024-10-15 18:19:59 +02:00
Rossen Stoyanchev 7ea43bb252 Update SECURITY.md 2024-10-15 17:13:29 +01:00
Brian Clozel 88b684c981 Update security policy and issue template
Because Spring Framework already has a security policy, this shows up in
the issue template automatically. This commit removes the extra external
link and updates the original security policy.

See gh-33711
2024-10-15 17:57:04 +02:00
Brian Clozel 3bc2c91eff Revisit GitHub issue template
Prior to this commit, this repository had a single issue template
markdown file that listed all the information for creating a new issue
in this project. Because there was a lot, people missed warnings against
creating security reports publicly or asking questions in the issue
tracker.

This commit introduces an issue template configuration that provides
developers with a choice before creating the actual issue.

Closes gh-33711
2024-10-15 17:36:48 +02:00
Stéphane Nicoll 7f7de55b67 Merge branch '6.1.x' 2024-10-15 14:59:10 +02:00
Stéphane Nicoll 453849ab20 Upgrade to Reactor 2024.0.0-RC1
Closes gh-33636
2024-10-15 14:57:44 +02:00
Stéphane Nicoll f03f074581 Merge branch '6.1.x' 2024-10-15 09:13:35 +02:00
Stéphane Nicoll c79b575417 Upgrade to Micrometer 1.14.0-RC1
Closes gh-33648
2024-10-15 09:07:45 +02:00
rstoyanchev 5099657244 Merge branch '6.1.x' 2024-10-14 18:18:39 +01:00
rstoyanchev 7d3a3d35ce Update valid path checks for double encoding
See gh-33687
2024-10-14 18:14:01 +01:00
Sébastien Deleuze 20cdd192d9 Merge branch '6.1.x' 2024-10-14 19:01:43 +02:00
Sébastien Deleuze 60978ff4c7 Polish WebRequest Javadoc
See gh-33698
2024-10-14 17:07:07 +02:00
rstoyanchev cff6db02b4 Merge branch '6.1.x' 2024-10-14 16:00:48 +01:00
rstoyanchev 1a0b577bfc Do not support relative static resource paths
Closes gh-33687
2024-10-14 15:54:59 +01:00
Tran Ngoc Nhan e191c34078 Polishing
Closes gh-33681
2024-10-14 16:44:42 +02:00
KimJuHyun 5bcce17fd9 Add tests for CollectionUtils
- findValueOfType
- findCommonElementType
- firstElement
- lastElement
- toArray
- compositeMap

Closes gh-33694
2024-10-14 16:10:05 +02:00
Brian Clozel 9be3d85a06 Merge branch '6.1.x' 2024-10-14 15:04:58 +02:00
海子 Yang 3984266295 Remove unused method in UriComponentsBuilder
This commit removes HierarchicalUriComponents#checkSchemeAndHost
unused private method.

Closes gh-33684
2024-10-14 14:02:31 +02:00
Sébastien Deleuze a75f22e548 Merge branch '6.1.x' 2024-10-14 12:09:00 +02:00
Simon Baslé 12134e8619 Merge branch '6.1.x' 2024-10-14 11:57:39 +02:00
Sangmin Park ae32227b50 Polish ServletWebRequest
Closes gh-33698
2024-10-14 11:38:24 +02:00
Sam Brannen b3cc9a219e Ensure that @⁠MockitoBeanSettings is inherited in @⁠Nested test class
Closes gh-33685
2024-10-11 17:20:53 +02:00
Juergen Hoeller 7ea0ac55cd Restore special instance supplier generation for inner classes
Closes gh-33683
2024-10-11 16:59:15 +02:00
Juergen Hoeller b748cb38c5 Rename to Mockito(Spy)BeanForFactoryBeanIntegrationTests 2024-10-11 16:58:18 +02:00
Sam Brannen eb4bf1c0a6 Support @⁠MockitoBean reset and MockitoSession management with @⁠Nested tests
Prior to this commit, the MockitoResetTestExecutionListener failed to
reset mocks created via @⁠MockitoBean if the @⁠MockitoBean field was
declared in an enclosing class for a @⁠Nested test class. In addition,
the MockitoSession was not properly managed by the
MockitoTestExecutionListener.

This commit addresses those issue as follows.

1) The hasMockitoAnnotations() utility method has been overhauled so
that it finds Mockito annotations not only on the current test class
and on fields of the current test class but also on interfaces,
superclasses, and enclosing classes for @⁠Nested test classes as well
as on fields of superclasses and enclosing classes.

That allows the MockitoResetTestExecutionListener to properly detect
that it needs to reset mocks for fields declared in enclosing classes
for @⁠Nested classes.

2) MockitoTestExecutionListener has been revised so that it only
initializes a MockitoSession before each test method and closes the
MockitoSession after each test method. In addition, it now only manages
the MockitoSession when hasMockitoAnnotations() returns true for the
current test class (which may be a @⁠Nested test class). Furthermore,
it no longer attempts to initialize a MockitoSession during the
prepareTestInstance() callback since that results in an
UnfinishedMockingSessionException for a @⁠Nested test class due to the
fact that a MockitoSession was already created for the current thread
for the enclosing test class.

Closes gh-33676
2024-10-11 16:14:42 +02:00
Sam Brannen 7fb6a2e4f7 Polish Javadoc for Bean Override TestExecutionListeners 2024-10-11 15:50:56 +02:00
Sam Brannen e2d981e809 Extract common logic into AbstractMockitoTestExecutionListener 2024-10-11 10:15:49 +02:00
Simon Baslé 0f25c75b9e Document TestExecutionListener implementations introduced in 6.2
Closes gh-33661
2024-10-10 16:32:38 +02:00
Sam Brannen 0e8316e704 Add value attribute alias to @⁠MockitoBean and @⁠MockitoSpyBean
This commit improves the user experience for common use cases by
introducing new `value` attributes in @⁠MockitoBean and
@⁠MockitoSpyBean that are aliases for the existing `name` attributes.

For example, this allows developers to declare
@⁠MockitoBean("userService") instead of @⁠MockitoBean(name =
"userService"), analogous to the existing name/value alias support in
@⁠TestBean.

Closes gh-33680
2024-10-10 13:05:39 +02:00
Sam Brannen 1b8f2c46c1 Update Javadoc for @⁠Mockito[Spy]Bean to reflect current semantics 2024-10-10 12:19:36 +02:00
Sam Brannen f7e32a9c78 Revise singleton destruction for Bean Overrides
See gh-33678
2024-10-10 12:13:44 +02:00
Sam Brannen 8d652e9c12 Reinstate Bean Override support for replacing a manually registered singleton
Closes gh-33678
2024-10-09 18:10:07 +02:00
Sam Brannen c70a6d3be1 Fix test method names 2024-10-09 17:17:57 +02:00
Sam Brannen 1afcb22205 Change enforceOverride flag to false in @⁠TestBean and @⁠MockitoBean
Based on feedback from the Spring Boot team, we have decided to change
the default values for the enforceOverride flags in @⁠TestBean and
@⁠MockitoBean from true to false.

Closes gh-33613
2024-10-09 17:08:58 +02:00
Sam Brannen 381b16fba2 Simplify Bean Override field injection logic
This commit simplifies the field injection logic for Bean Overrides in
order to align with the semantics of the core container and the Spring
TestContext Framework.

Closes gh-33677
2024-10-09 15:43:32 +02:00
Sam Brannen 4758424f6c Clean up warnings in Gradle build 2024-10-09 15:43:32 +02:00
Sam Brannen 7c3624318b Polish Mockito TestExecutionListeners 2024-10-09 15:43:32 +02:00
Sam Brannen 461f1724b7 Colocate nonexistent bean definition processing for Bean Overrides 2024-10-09 15:43:32 +02:00
Sam Brannen b5c82b8dcb Reject bean names with factory prefix for Bean Overrides
Closes gh-33674
2024-10-09 15:43:32 +02:00
Sam Brannen c864afd6fe Polishing 2024-10-09 15:43:32 +02:00
Stéphane Nicoll f54fabad8f Merge pull request #33669 from Seungpang
* pr/33669:
  Polish "Reject empty strings in DurationFormatterUtils"
  Reject empty strings in DurationFormatterUtils

Closes gh-33669
2024-10-09 15:27:59 +02:00
Stéphane Nicoll e2238c0211 Polish "Reject empty strings in DurationFormatterUtils"
See gh-33669
2024-10-09 15:26:09 +02:00
Seungrae 02c990ca82 Reject empty strings in DurationFormatterUtils
See gh-33669
2024-10-09 15:20:11 +02:00
Stéphane Nicoll 7f7f65cfcb Merge branch '6.1.x' 2024-10-09 14:44:38 +02:00
rstoyanchev 8520fa5e2a Reduce warnings in WhatWgUrlParser 2024-10-09 13:29:49 +01:00
rstoyanchev f4967f202e Revise URI template handling in WhatWgUrlParser
Closes gh-33673
2024-10-09 13:29:49 +01:00
rstoyanchev 1f4743af54 Lenient handling of malformed query in ServletServerHttpRequest
Closes gh-30489
2024-10-09 13:29:49 +01:00
Stéphane Nicoll af85d1997b Merge branch '6.1.x' 2024-10-09 14:25:26 +02:00
Stéphane Nicoll 6677d452e7 Start building against Micrometer 1.14.0-RC1 snapshots
See gh-33648
2024-10-09 14:19:35 +02:00
Simon Baslé ef77b4064f Keep DefaultServerHttpRequestBuilder-mutated headers case-insensitive
This change avoids the trap of creating a copy of `HttpHeaders` using a
case-sensitive `MultiValueMap` by mistake. Since mutability is always
desirable, we make a mutable copy by using `addAll` on an empty
`HttpHeaders`.

We can't simply rely on HttpHeaders' map-based constructor to detect
read-only header in this particular case, because the container's
original headers representation might in some cases be read-only.

Closes gh-33666
2024-10-09 11:39:33 +02:00
Sam Brannen 59ef5e140f Update warning for use of convention-based annotation attribute overrides
See gh-28761
2024-10-09 10:03:22 +02:00
Sam Brannen e1c450d253 Support Bean Overrides with AOT and native image
This set of commits introduces AOT and native image support for the new
Bean Override feature in the Spring TestContext Framework -- for
example, for using @⁠TestBean and @⁠MockitoBean in AOT mode on the JVM
as well as in a GraalVM native image.

Note, however, that @⁠MockitoBean has currently only been tested in a
native image when mocking interfaces and using Mockito's
ProxyMockMaker, along with a custom runtime hints.

Closes gh-32933
2024-10-08 17:57:21 +02:00
Sam Brannen 65d219131c Stop disabling MockitoResetTestExecutionListener within a native image
Instead, MockitoResetTestExecutionListener is now only enabled if the
current test class uses Mockito annotations or Mockito-related
annotations in spring-test.

See gh-32933
2024-10-08 17:41:30 +02:00
Sam Brannen 9a4be95dee Verify registration of runtime hints for Bean Overrides
See gh-32933
2024-10-08 17:41:30 +02:00
Sam Brannen 6a2e234a87 Register runtime hints for BeanOverrideProcessors
This commit introduces a BeanOverrideReflectiveProcessor which
registers runtime hints for any BeanOverrideProcessor configured
via @⁠BeanOverride.

See gh-32933
2024-10-08 17:41:17 +02:00
Sam Brannen 5ddeb06640 Skip pseudo bean definition registration during AOT processing
Prior to this commit, AOT processing failed for tests that made use of
the Bean Override feature to "override" a nonexistent bean. The reason
is that we register a "pseudo" bean definition as a placeholder for a
nonexistent bean, and our AOT support cannot automatically convert that
"pseudo" bean definition to a functional bean definition for use at AOT
runtime.

To address that, this commit skips registration of "pseudo" bean
definitions during AOT processing, and by doing so we enable the JVM
runtime and AOT runtime to operate with the same semantics.

See gh-32933
2024-10-08 17:41:11 +02:00
Sam Brannen ce8e06cf10 Register Bean Override infrastructure beans as manual singletons
Prior to this commit, AOT processing failed for tests that made use of
the Bean Override feature, since the Set<OverrideMetadata> constructor
argument configured in the bean definition for the
BeanOverrideBeanFactoryPostProcessor cannot be properly processed by
our AOT support. The reason is that each OverrideMetadata instance is
effectively an arbitrary object graph that cannot be automatically
converted to a functional bean definition for use at AOT runtime.

To address that, this commit registers Bean Override infrastructure
beans as manual singletons instead of via bean definitions with the
infrastructure role.

See gh-32933
2024-10-08 16:58:59 +02:00
Juergen Hoeller f590511112 Introspect pre-registered singletons in preDetermineBeanTypes as well
Closes gh-33668
2024-10-08 16:50:12 +02:00
rstoyanchev c4b6a02091 Polishing contribution
Closes gh-33594
2024-10-08 13:32:33 +01:00
Johnny Lim 1ec9a115a8 Replace RFC 7807 with RFC 9457 in documentation
See gh-33594
2024-10-08 13:32:33 +01:00
Brian Clozel 3303c98650 Fix link to code of conduct
Closes gh-33663
2024-10-08 14:03:54 +02:00
rstoyanchev 000b8a699c Auto-detect Reactor Netty client in RestClient
Closes gh-33635
2024-10-08 10:56:43 +01:00
rstoyanchev a84a41fa43 Polishing contribution
Closes gh-33638
2024-10-08 10:56:42 +01:00
Dariusz Jędrzejczyk a78385f8e5 Handle X-Forwarded-Prefix parsed by Reactor Netty
See gh-33638
2024-10-08 10:56:42 +01:00
Juergen Hoeller f9f025df43 Add note on autowireCandidate versus defaultCandidate
Closes gh-33392
2024-10-08 11:36:39 +02:00
Juergen Hoeller 1eee795143 Merge branch '6.1.x' 2024-10-08 11:34:27 +02:00
rstoyanchev b13f86cf46 Fix failing tests in spring-test after recent changes
See gh-33639
2024-10-07 21:09:10 +01:00
rstoyanchev 2389748e25 Parameterize URI parsing tests
Closes gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev d6fcad9ad7 Add logging to RfcUriParser
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev ef0a21ec7a Update documentation for URI parsing types
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev 6c62965cbb Remove regular expressions from UriComponentsBuilder
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev bbb53d03c4 Pluggable URI parsing, use RFC parser by default
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev 52805da733 Add URI parser based on syntax in RFC 3986
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev 10f45223aa Rename UrlParser to WhatWgUrlParser
See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev 6ba3bb54a0 Add efficient isUnreservedOrSubDelimiter method
isUnreserved and isSubDelimiter are usually checked together. It helps
to have a shortcut with an efficient lookup.

See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev e04b115a7e Remove test for IPv4 compatible IPv6 address
An example of this can be found in RFC 2732, but it is obsoleted by
RFC 3986 whose syntax for IPv6address does not allow dots.

Also, Appendix D of RFC 3986:

As [RFC2732] defers to [RFC3513] for definition of an IPv6 literal
address, which, unfortunately, lacks an ABNF description of
IPv6address, we created a new ABNF rule for IPv6address that matches
the text representations defined by Section 2.2 of [RFC3513].

See gh-33639
2024-10-07 18:35:03 +01:00
rstoyanchev 92308ac83f Polishing in UrlParser 2024-10-07 18:35:02 +01:00
Sam Brannen 98bee41630 Polish BeanOverrideBeanFactoryPostProcessor 2024-10-07 14:22:53 +02:00
Juergen Hoeller c10a7f300c Merge branch '6.1.x' 2024-10-07 10:20:38 +02:00
Khyojun f86bc1cbe8 Polish CorsConfiguration
Closes gh-33650
2024-10-07 09:11:36 +02:00
KimJuHyun f1cbbd2aa8 Remove redundant array length check
Closes gh-33655
2024-10-07 08:24:37 +02:00
Stéphane Nicoll c73e76cf2e Merge branch '6.1.x' 2024-10-07 08:06:50 +02:00
Sam Brannen ad4f0c99bf Polish StringUtilsTests 2024-10-06 15:36:16 +02:00
zinzo 2cd1ee8a24 Add unit tests for StringUtils.hasLength()
Closes gh-33658
2024-10-06 15:28:41 +02:00
Johnny Lim 1016743fc3 Remove Javadoc @⁠since tag from MapAccessor default constructor
See gh-33222
Closes gh-33659
2024-10-06 15:18:48 +02:00
Sam Brannen 28b9cf3b83 Simplify and document BeanOverrideTestExecutionListener
This commit simplifies the implementation of
BeanOverrideTestExecutionListener by introducing a static
injectFields() utility method and removing the use of BiConsumers,
records, and duplicated code.

This commit also introduces Javadoc for all methods in
BeanOverrideTestExecutionListener.

Closes gh-33660
2024-10-06 15:05:10 +02:00
Sam Brannen b0c7d15d9f Polishing 2024-10-05 13:57:24 +02:00
Park Sung Jun 32df079b05 Polish use of constants in StringUtils
The hardcoded '.' and '\\' literals have been replaced by the use of
EXTENSION_SEPARATOR and WINDOWS_FOLDER_SEPARATOR_CHAR.

Closes gh-33654
2024-10-05 13:57:24 +02:00
Sam Brannen d89983d633 Upgrade to Mockito 5.14.1 2024-10-04 17:24:55 +02:00
Sam Brannen d957d01d14 Polishing 2024-10-04 15:48:26 +02:00
Sam Brannen c4c005b82e Emulate AbstractAotProcessor.process() in AOT endToEndTests() 2024-10-04 15:46:23 +02:00
Sam Brannen 21d80dd849 Upgrade to JUnit 5.11.2 2024-10-04 15:39:00 +02:00
Sam Brannen b7f394c2a1 Merge branch '6.1.x' 2024-10-04 15:36:51 +02:00
Sam Brannen 2569aa157e Make use of Executable abstraction in ProxyRuntimeHintsRegistrar 2024-10-04 15:05:37 +02:00
Sam Brannen 911d1b03cd Polishing 2024-10-04 15:05:37 +02:00
Sam Brannen fb5e4c0ef2 Remove obsolete method parameter 2024-10-04 11:16:49 +02:00
Stéphane Nicoll beca562ac2 Merge branch '6.1.x' 2024-10-04 10:20:28 +02:00
SungbinYang 65ac17ee78 Refactor: Replace hardcoded path separator with PATH_SEPARATOR constant
Replaced the hardcoded '/' path separator with the `PATH_SEPARATOR` constant
to improve code readability and maintainability. This change ensures
consistency across the codebase when handling path separators.

Closes gh-33646
2024-10-04 09:19:16 +02:00
Sébastien Deleuze d65bdce0e8 Remove CglibMethodInvocation
This class does not add anything anymore and can be
replaced by a plain ReflectiveMethodInvocation.

Closes gh-33585
2024-10-03 19:53:49 +02:00
Sébastien Deleuze eebaa3538a Fix a regression in Cglib Kotlin proxies
The commit skips using UndeclaredThrowableStrategy for
Kotlin classes in CglibAopProxy in order to fix a
related regression caused by gh-32469.

See gh-33585
2024-10-03 19:49:59 +02:00
Sam Brannen 02094b258c Destroy singleton instead of removing and re-registering bean definition 2024-10-03 16:43:59 +02:00
Sam Brannen 39a27256a7 Reduce scope of BeanDefinitionRegistry usage in Bean Override BFPP 2024-10-03 16:39:43 +02:00
Sam Brannen f26a266c41 Optimize BeanOverrideRegistrar lookup in BeanOverrideTestExecutionListener 2024-10-03 16:39:43 +02:00
Sam Brannen d44701f828 Extract WrapEarlyBeanPostProcessor to top-level class 2024-10-03 16:39:43 +02:00
Sam Brannen 4c3bc3ba69 Emulate AbstractAotProcessor.process() in AotIntegrationTests 2024-10-03 16:39:43 +02:00
Simon Baslé 6c5e63e446 Merge branch '6.1.x' 2024-10-03 16:33:40 +02:00
Sam Brannen 32309e86ce Fix context caching for Bean Overrides w/ different annotation order
Prior to this commit, ApplicationContext caching support was broken if
two Bean Override fields declared the same annotations but in a
different order.

This commit fixes that by switching to Set semantics for the
annotations declared on a Bean Override field.

Closes gh-33633
2024-10-02 11:23:48 +02:00
Brian Clozel 8cd2c40860 Improve random source in SockJS server support
Prior to this commit, the SockJs server support would use
`java.util.Random` to send a random value to clients when they request
the `/info` endpoint. Per protocol, clients can use this value as a
source of entropy for generating a random session id.

In practice, this is not used by clients. For example, the SockJS
javascript client is using a cryptographically safe API to generate
session ids.

While this has no concrete effect on known clients, this commit improves
the random source in the server support by switching to
`java.security.SecureRandom`.

Closes gh-33632
2024-10-01 21:29:19 +02:00
Sam Brannen 309897497a Update copyright header 2024-10-01 12:35:01 +02:00
Hyunwoo Kim 893f5dcb9b Replace "null" with NULL_STRING constant in ObjectUtils.nullSafeConciseToString()
Closes gh-33625
2024-10-01 12:33:40 +02:00
Sam Brannen a21c557101 Do not replace existing Bean Override definition with pseudo-definition
Prior to this commit, BeanOverrideBeanFactoryPostProcessor replaced
existing bean definitions with "pseudo" bean definitions; however, that
is unnecessary. An existing BeanDefinition is suitable as-is and does
not need to be replaced with a pseudo/fake definition.

To address that, this commit reregisters an existing bean definition
and only registers a new bean definition when creating a bean
definition for a nonexistent bean.

As a side effect, we no longer need to copy primary and fallback flags.

Closes gh-33627
2024-10-01 12:20:27 +02:00
Sébastien Deleuze 56a0a33e5d Add a missing test case for ObjectUtils#unwrapOptional
Closes gh-33618
2024-10-01 09:42:58 +02:00
Tran Ngoc Nhan 4d87c77649 Add test cases for ObjectUtils#unwrapOptional
See gh-33618
2024-10-01 09:41:39 +02:00
SungbinYang fc8bd64f34 Simplify ObjectUtils#unwrapOptional
This commit replaces optional.isEmpty() and optional.get() with
optional.orElse(null) for better efficiency and readability.

Closes gh-33612
2024-09-30 18:32:43 +02:00
Sam Brannen 1c87e4795d Introduce enforceOverride flag in @⁠TestBean and @⁠MockitoBean
Prior to this commit, @⁠MockitoBean could be used to either create or
replace a bean definition, but @⁠TestBean could only be used to replace
a bean definition.

However, Bean Override implementations should require the presence of
an existing bean definition by default (i.e. literally "override" by
default), while giving the user the option to have a new bean
definition created if desired.

To address that, this commit introduces a new `enforceOverride`
attribute in @⁠TestBean and @⁠MockitoBean that defaults to true but
allows the user to decide if it's OK to create a bean for a nonexistent
bean definition.

Closes gh-33613
2024-09-30 14:32:53 +02:00
Juergen Hoeller 30dc86810e Upgrade to Jackson 2.18
Closes gh-33615
2024-09-30 13:53:22 +02:00
Sam Brannen 38c9af2385 Merge branch '6.1.x' 2024-09-30 12:42:17 +02:00
Juergen Hoeller b59d0a396e Add equals/hashCode methods to ServerSentEvent
Closes gh-33606
2024-09-30 11:22:43 +02:00
Juergen Hoeller 8ab965c981 Merge branch '6.1.x'
# Conflicts:
#	spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java
#	spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java
2024-09-30 11:17:55 +02:00
Simon Baslé 854f6ffd39 Merge branch '6.1.x' 2024-09-30 10:19:36 +02:00
Sam Brannen d79258ac73 Reject non-singletons in Test Bean Override support
Prior to this commit, a non-singleton FactoryBean was silently replaced
by a singleton bean. In addition, bean definitions for prototype-scoped
and custom-scoped beans were replaced by singleton bean definitions
that were incapable of creating the desired bean instance. For example,
if the bean type of the original bean definition was a concrete class,
an attempt was made to invoke the default constructor which either
succeeded with undesirable results or failed with an exception if the
bean type did not have a default constructor. If the bean type of the
original bean definition was an interface or a FactoryBean that claimed
to create a bean of a certain interface type, an attempt was made to
instantiate the interface which always failed with a
BeanCreationException.

To address the aforementioned issues, this commit reworks the logic in
BeanOverrideBeanFactoryPostProcessor so that an exception is thrown
whenever an attempt is made to override a non-singleton bean.

Closes gh-33602
2024-09-29 18:12:00 +02:00
Sam Brannen 4e9b503055 Polish OverrideMetadata 2024-09-29 18:02:09 +02:00
Sam Brannen ba1d01d9b7 Add missing final declaration to OverrideMetadata.getBeanName() 2024-09-29 16:31:20 +02:00
Sam Brannen 5c08f81d80 Polishing 2024-09-29 16:28:06 +02:00
Sam Brannen 625614a4d2 Stop "collecting" annotations in MockitoAnnotationDetector
There is no need to collect/track the actual annotations. Rather, we
only need to know if there is at least once such annotation present.
2024-09-29 15:34:40 +02:00
Sam Brannen 40ca83dfd4 Revise Bean Override internals and Javadoc 2024-09-28 17:13:24 +02:00
Juergen Hoeller 56f3a48879 Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/aot/AbstractAotProcessor.java
2024-09-27 19:17:32 +02:00
Sébastien Deleuze 8e3846991d Reuse NoTransactionInContextException instances
New NoTransactionInContextException instances are created frequently in
TransactionContextManager#currentContext() when there is no transaction,
we could reuse the same instance instead to reduce the GC pressure.

Closes gh-33601
2024-09-27 17:45:02 +02:00
Sam Brannen bed3025274 Restructure BeanOverrideBeanFactoryPostProcessor and improve documentation 2024-09-27 17:08:08 +02:00
Sam Brannen ea8b8ae910 Polishing 2024-09-27 17:03:49 +02:00
Sam Brannen 9c746905bc Test status quo for Bean Override singleton semantics
The tests introduced in this commit reveal the following issues in our
Bean Override support.

- If a FactoryBean signals it does not manage a singleton, the Bean
  Override support silently replaces it with a singleton.

- An attempt to override a prototype-scoped bean or a bean configured
  with a custom scope results in one of the following.

  - If the bean type of the original bean definition is a concrete
    class, an attempt will be made to invoke the default constructor
    which will either succeed with undesirable results or fail with an
    exception if the bean type does not have a default constructor.

  - If the bean type of the original bean definition is an interface or
    a FactoryBean that claims to create a bean of a certain interface
    type, an attempt will be made to instantiate the interface which
    will always fail with a BeanCreationException.
2024-09-27 15:42:12 +02:00
Sam Brannen c3ff6cf319 Reverse engineer documentation for Bean Override internals 2024-09-27 15:39:35 +02:00
Sam Brannen ded5c13e19 Reinstate BeanOverrideTestSuite 2024-09-27 13:48:56 +02:00
Juergen Hoeller 594ed95f3c Replace transaction isolation synchronization with ReentrantLock
Closes gh-33546
2024-09-27 11:36:21 +02:00
Juergen Hoeller 8680c43368 Check for advisor-introduced interfaces specifically
See gh-31304
2024-09-27 11:07:11 +02:00
Juergen Hoeller d3dd01e227 Adapt transactional test component declaration
See gh-33470
2024-09-27 11:06:30 +02:00
오영택 cc3948e14c feat: Implemented to throw a runtime error if a class has @Transactional 2024-09-27 10:59:52 +02:00
Tran Ngoc Nhan e3cf23d15a remove unused keyword 2024-09-26 21:49:22 +02:00
Juergen Hoeller 07d281c6d8 Expose public constant for spring.aot.processing system property
Closes gh-33388
2024-09-26 18:31:36 +02:00
Juergen Hoeller 5326640f79 Initialize application context with initializer-given ServletContext
Closes gh-22319
2024-09-26 18:31:02 +02:00
Juergen Hoeller 13b49d41c3 Merge branch '6.1.x' 2024-09-26 15:30:39 +02:00
Juergen Hoeller 552a5cde36 Create CGLIB proxy in case of no target interfaces (just introductions)
Closes gh-31304
2024-09-26 14:48:42 +02:00
Yanming Zhou 8941e2876e Replace 'e.g.' with 'for example' in documentation and comments
Closes gh-33515
2024-09-26 14:11:17 +02:00
Sam Brannen e55fe9077f Make DynamicPropertyRegistrarBeanInitializer public
In order to allow third parties (for example, Spring Boot) to ensure
that a DynamicPropertyRegistrarBeanInitializer has been registered in
an ApplicationContext which has not been customized by the
DynamicPropertiesContextCustomizer, this commit converts
DynamicPropertyRegistrarBeanInitializer to a public API for use in such
special use cases.

Closes gh-33593
2024-09-26 13:01:57 +02:00
Sam Brannen b4bfb8952c Polishing 2024-09-26 12:18:57 +02:00
Sam Brannen 8e85dd0673 Fix error message for XML qualifier 'attribute' tag 2024-09-26 12:11:27 +02:00
Sam Brannen b943bdeec2 Polishing 2024-09-25 17:28:47 +02:00
rstoyanchev dea4f71846 Update contribution
Closes gh-33090
2024-09-25 16:09:01 +01:00
cfredri4 883f123583 Use only one timeout in JdkClientHttpRequest
Previously, a timeout was set both on HttpRequest, and used on
httpClient.sendAsync().get(). This leads to inconsistent behaviour
depending on which timeout gets triggered first.

See gh-33090
2024-09-25 16:09:01 +01:00
Juergen Hoeller 073cfd405b Merge branch '6.1.x' 2024-09-25 14:24:35 +02:00
Juergen Hoeller 885f650911 Merge branch '6.1.x' 2024-09-25 12:46:37 +02:00
rstoyanchev 7051cddcf7 Align OutputStreamPublisher's
Align internal handling and contracts. The core copy could do without
those contracts, but it helps with alignment, and it's internal to
the implementation.

Closes gh-33592
2024-09-25 11:42:26 +01:00
rstoyanchev f6c31bb6c3 Align OutputStreamPublisher's
Update constructors to match and drop unnecessary factory methods.

See gh-33592
2024-09-25 11:42:26 +01:00
rstoyanchev 113b430fab Align OutputStreamPublisher's
Apply recent nullability changes, and formatting differences.

See gh-33592
2024-09-25 11:42:26 +01:00
Sébastien Deleuze a1613d1352 Merge branch '6.1.x' 2024-09-25 12:15:06 +02:00
Sam Brannen 17f319b957 Upgrade to JUnit 5.11.1 2024-09-25 11:33:29 +02:00
Juergen Hoeller 8cfd6aed04 Separate internal ScheduledExecutorService for fixed-delay tasks
Closes gh-33408
2024-09-25 10:04:17 +02:00
Sébastien Deleuze 81a66a0334 Add an AbstractGenericHttpMessageConverter constructor
This commit adds a new
AbstractGenericHttpMessageConverter(Charset, MediaType...)
constructor, similar to the one present in
AbstractHttpMessageConverter.

Closes gh-33563
2024-09-24 19:40:15 +02:00
Juergen Hoeller 5f6b8d5582 Polishing 2024-09-24 18:59:17 +02:00
Juergen Hoeller d6e4bd7c90 Resolve AOT factory method target by bean name and reduce reflective method exposure
Includes consistent withShortcut naming and consistent bean definition flag exposure.
Removes support for inner classes in alignment with standard core container behavior.

Closes gh-32834
2024-09-24 18:59:08 +02:00
Sam Brannen aef5143642 Merge branch '6.1.x' 2024-09-24 16:50:12 +02:00
Sam Brannen 6da114054e Update comment 2024-09-24 15:49:35 +02:00
Sam Brannen 23528a5075 Merge branch '6.1.x' 2024-09-24 15:48:08 +02:00
Sam Brannen dae871b5d3 Clean up warnings in Gradle build 2024-09-24 12:34:20 +02:00
Sam Brannen f6fcf15745 Merge branch '6.1.x' 2024-09-24 12:33:58 +02:00
Sam Brannen 66a518abd5 Merge branch '6.1.x' 2024-09-24 12:23:47 +02:00
Sam Brannen 6a9b5d21f4 Document that TestContextAnnotationUtils is required for @⁠Nested support
Closes gh-33586
2024-09-24 11:55:44 +02:00
Simon Baslé f7aa4409bb Merge branch '6.1.x' 2024-09-24 11:01:57 +02:00
Sam Brannen 5bc2ff70b5 Merge branch '6.1.x' 2024-09-24 10:47:14 +02:00
Sam Brannen 28dbcb2421 Improve FactoryBean Javadoc 2024-09-23 17:20:19 +02:00
Tran Ngoc Nhan c85050eb43 Consistently use CharSequence.isEmpty() for emptiness checks
Closes gh-33577
2024-09-23 17:10:21 +02:00
Sam Brannen f321ef9ec2 Improve toString() for AbstractBeanDefinition and BeanMetadataAttribute
Closes gh-33579
2024-09-23 16:45:56 +02:00
Sam Brannen 59eaed0b28 Ensure integration tests are suitable for AOT processing 2024-09-23 16:45:56 +02:00
Sam Brannen 7d99790c34 Polishing 2024-09-23 16:45:56 +02:00
rstoyanchev c6fa180602 Extract shared resource handling utility methods
Closes: gh-33574
2024-09-20 19:25:12 +01:00
Juergen Hoeller df5489b81a Introduce optionalValue() method on ResultQuerySpec
Closes gh-33560
2024-09-20 19:16:02 +02:00
Yanming Zhou 24a8f1b26d AnnotatedBeanDefinitionReader should respect @Fallback qualifier analogous to @Primary
Also add tests to cover qualifier classes.
2024-09-20 19:10:16 +02:00
Johnny Lim 159e23730c Fix Javadoc @⁠since tags in JettyCoreRequestUpgradeStrategy
See gh-32097
Closes gh-33569
2024-09-20 11:34:39 +02:00
Sam Brannen 8931b75b95 Polishing 2024-09-20 10:58:37 +02:00
Johnny Lim 3ba9d35e22 Polish
Closes gh-33566
2024-09-20 10:58:37 +02:00
rstoyanchev 6120076437 Merge branch '6.1.x' 2024-09-20 09:33:09 +01:00
rstoyanchev 4706ebc81e Minor refactoring in UrlHandlerFilter
See gh-33565
2024-09-19 11:55:53 +01:00
rstoyanchev 2090ece62a UrlHandlerFilter ignores trailing slash in contextPath
Closes gh-33565
2024-09-19 11:55:25 +01:00
Sam Brannen e587753b1d Introduce @⁠EasyMockBean bean override example
This commit introduces example support for a custom @⁠EasyMockBean
annotation that allows tests to use EasyMock as the mocking framework
for bean overrides in a test's ApplicationContext.

The point of this exercise is to ensure that it is possible for third
parties to introduce bean override support for mocking frameworks other
than Mockito, and that they can do so with the APIs currently in place.

Closes gh-33562
2024-09-18 17:10:06 +02:00
Sam Brannen 6c2cba5d8a Polish bean override internals 2024-09-18 14:22:15 +02:00
Simon Baslé c832d5f496 Polishing contribution
Fixes gh-33556
2024-09-18 11:44:29 +02:00
Carl Magnuson 453e7961a8 Add read timeout setter on HttpComponentsClientHttpRequestFactory
This commit adds support for HttpComponentsClientHttpRequestFactory to
set a read timeout, used on the underlying client as a RequestTimeout.

This brings the HttpComponentsClientHttpRequestFactory into alignment
with JDK, Jetty, OkHttp3, Reactor and SimpleClient
ClientHttpRequestFactory implementations.

See gh-33556
2024-09-18 11:44:29 +02:00
Brian Clozel 6f09c21f05 Merge branch '6.1.x' 2024-09-18 11:21:03 +02:00
Simon Baslé 06d240b558 Merge branch '6.1.x' 2024-09-17 16:42:09 +02:00
Juergen Hoeller 20bc5ef68b Accept nested array type for upUntilUnresolvable check as well
Closes gh-33535
2024-09-17 16:20:54 +02:00
Sébastien Deleuze 383fa43ded Merge branch '6.1.x' 2024-09-16 16:59:31 +02:00
Sam Brannen 13e175ab46 Avoid use of static import in production code 2024-09-16 15:50:05 +02:00
Sam Brannen b60bb44256 Polish test @⁠Configuration classes 2024-09-16 15:45:32 +02:00
Sam Brannen 31a6e98eaf Introduce @⁠Disabled AOT tests for @⁠TestBean support
See gh-32933
2024-09-16 15:43:54 +02:00
Sébastien Deleuze d3755aba06 Add RestClient.Builder#messageConverters(List)
This commit also introduces the validation of the RestClient
message converters for both variants.

Closes gh-33536
2024-09-13 16:00:38 +02:00
Brian Clozel 0a001482c3 Merge branch '6.1.x' 2024-09-13 15:53:18 +02:00
Sam Brannen 16d8df8c2f Merge branch '6.1.x' 2024-09-13 15:29:33 +02:00
Sébastien Deleuze 52f0e8fb6d Refine null-safety for additional Assert methods
Closes gh-33530
2024-09-13 14:47:00 +02:00
Brian Clozel 598580020e Merge branch '6.1.x' 2024-09-13 10:21:43 +02:00
Brian Clozel 5838bf5888 Merge branch '6.1.x' 2024-09-13 09:33:10 +02:00
Stéphane Nicoll f6c6f7c02c Merge branch '6.1.x' 2024-09-12 14:11:13 +02:00
Sam Brannen 29ffa4963c Restructure content in testing resources section 2024-09-12 13:37:58 +02:00
Sam Brannen 39e9e88932 Link to MockMvc AssertJ support from resources section 2024-09-12 13:31:13 +02:00
Sam Brannen a73b048b68 Update link to Mockito 2024-09-12 13:24:49 +02:00
Sam Brannen 129a486f52 Remove obsolete link to MockObjects.com 2024-09-12 13:23:44 +02:00
Sam Brannen d097eea3a8 Polish DynamicPropertyRegistrar documentation 2024-09-12 13:20:59 +02:00
rstoyanchev 398e5528a1 Merge branch '6.1.x' 2024-09-12 08:40:58 +01:00
Sam Brannen 884105d469 Merge branch '6.1.x' 2024-09-11 18:08:30 +02:00
Sam Brannen e7b52cf8b2 Introduce DynamicPropertyRegistrar to replace DynamicPropertyRegistry bean
Spring Boot's testing support registers a DynamicPropertyRegistry as a
bean in the ApplicationContext, which conflicts with the
DynamicPropertyRegistry registered as a bean by the Spring TestContext
Framework (TCF) since Spring Framework 6.2 M2.

To avoid that conflict and to improve the user experience for Spring's
testing support, this commit introduces a DynamicPropertyRegistrar API
to replace the DynamicPropertyRegistry bean support.

Specifically, the TCF no longer registers a DynamicPropertyRegistry as
a bean in the ApplicationContext.

Instead, users can now register custom implementations of
DynamicPropertyRegistrar as beans in the ApplicationContext, and the
DynamicPropertiesContextCustomizer now registers a
DynamicPropertyRegistrarBeanInitializer which eagerly initializes
DynamicPropertyRegistrar beans and invokes their accept() methods with
an appropriate DynamicPropertyRegistry.

In addition, a singleton DynamicValuesPropertySource is created and
registered with the Environment for use in
DynamicPropertiesContextCustomizer and
DynamicPropertyRegistrarBeanInitializer, which allows
@⁠DynamicPropertySource methods and DynamicPropertyRegistrar beans to
transparently populate the same DynamicValuesPropertySource.

Closes gh-33501
2024-09-11 17:42:04 +02:00
Juergen Hoeller 78028cde05 Upgrade to Mockito 5.13 (depends on JUnit 5.11)
See gh-33395
2024-09-11 17:20:01 +02:00
Juergen Hoeller e9f9a7ae8e Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-09-11 17:17:38 +02:00
Juergen Hoeller 042346aa6a Harmonize Reactor client class names within the http.client package
Closes gh-33382
2024-09-11 16:27:56 +02:00
Juergen Hoeller e9e5fee149 Consistently resolve exceptions for resources and handler functions
Closes gh-33381
2024-09-11 15:51:01 +02:00
Juergen Hoeller a044357c31 Apply lenient locking fallback to singleton pre-instantiation phase only
Closes gh-33463
2024-09-11 14:09:57 +02:00
rstoyanchev 1ff2678147 Add UrlHandlerFilter for WebFlux
Closes gh-32830
2024-09-11 11:51:21 +01:00
rstoyanchev 5671744a94 Refactoring in UrlHandlerFilterTests 2024-09-11 11:51:21 +01:00
Patrick Strawderman 7827188e8e Avoid empty array allocations in AnnotationTypeMapping
Closes gh-33507
2024-09-11 09:49:39 +02:00
Brian Clozel 2b9b581024 Add streaming support to MVC functional endpoints
Prior to this commit, MVC function endpoints would allow Server Sent
Event responses through `ServerResponse.sse()`. While this covers a
common use case for streaming responses, other technologies would
benefit from a "low-level", unopinionated streaming support.

This commit introduces a new `BodyBuilder.stream()` methods that enables
such use cases. Developers are in charge of setting the relevant HTTP
response headers beforehand, and then can write to the response as raw
`String`, `byte[]` or using complex objects and the configured message
converters for serialization.

Because each streaming protocol has different message separator
semantics, it is also the developers' responsibility to flush buffered
content to the network once a message has been fully written.

Closes gh-32710
2024-09-10 15:41:21 +02:00
Stéphane Nicoll 6c8a859937 Merge branch '6.1.x' 2024-09-10 15:21:17 +02:00
Stéphane Nicoll 0fec2cf17a Upgrade to Reactor 2024.0.0-M6
Closes gh-33521
2024-09-10 15:10:59 +02:00
Stéphane Nicoll f1f69544b7 Upgrade to Micrometer 1.14.0-M3
Closes gh-33520
2024-09-10 15:10:12 +02:00
rstoyanchev 88ff5e1dcc Remove unused imports 2024-09-10 13:36:16 +01:00
rstoyanchev ebef599146 Fix checkstyle violations 2024-09-10 13:05:57 +01:00
rstoyanchev 9d57c0ba89 Add compare method to ETag
Closes gh-33385
2024-09-10 12:29:33 +01:00
rstoyanchev 19700d07b1 Quote ETag if not quoted in HttpHeaders#setETag
This aligns HttpHeaders with other places like ServletWebRequest and
DefaultWebExchange where an ETag is accepted as input.

It also allows us to remove quoting from places that delegate to
HttpHeaders#setETag since it now does that internally.

Closes gh-33412
2024-09-10 09:17:56 +01:00
rstoyanchev 3dd4a8350a Update more places to use quoteETagIfNecessary
Closes gh-33412
2024-09-10 08:56:03 +01:00
rstoyanchev 1b26122e64 Polishing and minor refactoring
Update checks whether quoting is needed to be more complete
than what we've used so far, making sure the there is both
opening and closing quotes independent of each other.

See gh-33412
2024-09-10 08:56:01 +01:00
hyunmin0317 80b264ba82 Refactor eTag formatting into utility method
See gh-33412
2024-09-10 08:55:39 +01:00
Sébastien Deleuze cc3f4b87ff Update mime.types
This commit updates mime.types based on revision 1918129 of
https://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types.

Closes gh-33512
2024-09-09 19:23:57 +02:00
Sébastien Deleuze 413cbca2c0 Remove commented entries from mime.types
See gh-33512
2024-09-09 18:59:29 +02:00
Sébastien Deleuze b0b5fcea0e Merge branch '6.1.x' 2024-09-09 18:44:22 +02:00
Sam Brannen eff19ec972 Sync MockHttpServletRequest implementations 2024-09-09 15:42:21 +02:00
Sam Brannen d5f1e055d5 Merge branch '6.1.x' 2024-09-09 15:35:36 +02:00
Stéphane Nicoll e311d9848a Expose the uriTemplate used to build a MockHttpServletRequest
This commit exposes the unexpanded URI template used to build a
MockHttpServletRequest. This allows MockMvc users to retrieve that
information, in consistency with ExchangeResult in WebTestClient.

Closes gh-33509
2024-09-09 14:46:05 +02:00
rstoyanchev d2b25c0378 Merge branch '6.1.x' 2024-09-09 11:56:21 +01:00
Sam Brannen 6518a56cee Revise introductory content for MockMvc 2024-09-08 17:59:15 +02:00
Sam Brannen 4fb70b671a Remove obsolete role attributes for tab groups in the reference manual
Since we now use asciidoctor-tabs instead of spring-asciidoctor-backends,
we no longer need the `role="primary"` and `role="secondary"` attributes
for tab groups.

Closes gh-33506
2024-09-08 17:20:10 +02:00
Brian Clozel 761fb8f6c9 Allow multiple listeners on ResponseBodyEmitter
Prior to this commit, `ResponseBodyEmitter` woud accept a single
`Runnable` callback on each of its `onTimeout`, `onError` or
`onCompletion` methods. This would limit the developers' ability to
register multiple sets of callbacks: one for managing the publication of
streaming values, another one for managing other concerns like
keep-alive signals to maintain the connection.

This commit now allows multiple calls to `onTimeout`, `onError` and
`onCompletion` and will register all callbacks accordingly.

Closes gh-33356
2024-09-06 15:30:18 +02:00
Patrick Strawderman 2b6639e587 Avoid storing duplicate empty array in MethodParameter field
Avoid storing duplicate empty arrays in the parameterAnnotations field of MethodParameter.

Closes gh-33496
2024-09-06 10:02:02 +02:00
Brian Clozel e9b0a19d3f Document TaskDecorator usage with TaskExecutors
Closes gh-33438
2024-09-05 21:04:22 +02:00
Sam Brannen d1920c0982 Merge branch '6.1.x' 2024-09-05 17:46:20 +02:00
Brian Clozel 046724b940 Document that WebFlux does not support forward redirects
Closes gh-33441
2024-09-05 16:02:42 +02:00
Sébastien Deleuze 5e3c5d466f Avoid collecting Flux elements in KotlinSerializationJsonEncoder
Closes gh-33428
2024-09-05 14:47:49 +02:00
Sam Brannen 907859f2f3 Merge branch '6.1.x' 2024-09-04 17:30:49 +02:00
Sébastien Deleuze 2f56a59ba0 Merge branch '6.1.x' 2024-09-04 16:13:04 +02:00
Patrick Strawderman f88c314e83 Avoid empty array allocations in ResolvableType
Avoid allocating empty arrays in a few places in ResolvableType.

Closes gh-33473
2024-09-04 10:40:20 +02:00
Sébastien Deleuze daba9e55b6 Merge branch '6.1.x' 2024-09-03 20:22:12 +02:00
Sam Brannen 717b972f88 Polish contribution
See gh-33452
2024-09-03 18:08:23 +02:00
Yanming Zhou 019c0b1d4e Expand acronyms FQN and FQCN
Closes gh-33452
2024-09-03 17:30:27 +02:00
Sam Brannen 529f311bd4 Polish and harmonize implementations of SpEL components in spring-context 2024-09-03 17:16:20 +02:00
Sébastien Deleuze ea8f8f77c5 Merge branch '6.1.x' 2024-09-03 15:35:03 +02:00
Sam Brannen 1af6480217 Revise reference documentation for Spring JMX annotations
This commit revises the reference documentation for Spring JMX
annotations for various reasons including, but not limited to, the
following.

- Type names such as ManagedResource are often ambiguous, especially
  when discussing an annotation like @⁠ManagedResource instead of
  org.springframework.jmx.export.metadata.ManagedResource which is a
  class.
- AnnotationTestBean implements IJmxTestBean, even though an annotated
  MBean is not required to implement any interfaces, and in fact the
  example is meant to demonstrate that an annotated POJO suffices.
- @⁠ManagedOperationParameter annotations are unnecessarily declared in
  the @⁠ManagedOperationParameters container.
- The documentation sometimes refers to JmxTestBean when it should
  instead refer to AnnotationTestBean.
- Inconsistent and confusing wording for annotation attributes,
  properties, managed attributes, etc.
- The tables refer to "source-level metadata types/parameters" when
  they should refer to Spring JMX annotations and their attributes.
- The annotation and attribute tables have inconsistent ordering and
  naming for column headers.
- @⁠ManagedNotification and @⁠ManagedMetric are not mentioned.
- The AutodetectCapableMBeanInfoAssembler example is broken since it
  uses the non-annotated JmxTestBean instead of the AnnotationTestBean.

As a side note, the JmxTestBean in our test suite still contains
XDoclet "annotations" which can be safely removed. 😉

Closes gh-33466
2024-09-02 18:18:10 +02:00
Johnny Lim 6e640f0800 Add Javadoc since for ReflectionHints.registerForInterfaces()
See gh-32824
Closed gh-33458
2024-09-02 16:21:35 +02:00
zhoukq aca264942d Update Content-Length if body changed by client interceptor
Prior to this commit, the HTTP interceptor model used for `RestTemplate`
and `RestClient` would not update the "Content-Length" request header,
even when the request body had been updated by a
`ClientHttpRequestInterceptor`.

Even though this is the `ClientHttpRequestInterceptor`'s responsibility
(along with the content type and encoding changes if needed), this
would result in invalid requests. This invalid situation can be detected
by `InterceptingClientHttpRequest`.

This commit ensures that such situations are detected and fixed
automatically by setting the Content-Length header to the actual body
size, right before executing the actual request, after all interceptors
are done.

Closes gh-33459
2024-09-02 16:19:26 +02:00
Brian Clozel be5d5fa52d UrlHandlerFilter should not strip slash for "/" request paths
This commit ensures that the `UrlHandlerFilter` does not handle "/"
paths in general, as they should not be altered and are meaningful for
web applications.

Closes gh-33444
2024-09-02 15:29:42 +02:00
Juergen Hoeller 69d5587f53 Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java
2024-08-31 12:04:29 +02:00
Brian Clozel 52c4ffa4d2 Merge branch '6.1.x' 2024-08-30 21:23:29 +02:00
Sam Brannen 940eef0646 Merge branch '6.1.x' 2024-08-30 19:09:38 +02:00
Sam Brannen ba64d0fae6 Fix titles for Java tabs in Testing chapter of reference manual 2024-08-30 17:13:14 +02:00
Sam Brannen 72f912549d Revise AOP proxying section of the reference manual
This commit revises the AOP proxying section as follows.

- Documents all limitations of CGLIB-based proxies
- Documents self injection as alternative to AopContext.currentProxy()
- Avoids use of flippant language

See gh-33454
Closes gh-33455
2024-08-30 16:05:15 +02:00
Sam Brannen 5e1de19ba3 Consolidate self injection documentation in the reference manual
Closes gh-33454
2024-08-30 15:47:54 +02:00
Sam Brannen a19acc65b4 Merge branch '6.1.x' 2024-08-30 11:24:59 +02:00
Sam Brannen 167cb5d494 Polishing 2024-08-29 17:02:08 +02:00
Sam Brannen 2ddf495802 Delete unused method and polish formatting 2024-08-29 16:53:49 +02:00
Sam Brannen a2b7b1c8af Merge branch '6.1.x' 2024-08-29 16:30:26 +02:00
Sam Brannen 9b28e584af Merge branch '6.1.x' 2024-08-29 15:40:12 +02:00
rstoyanchev 7aa25e083a Merge branch '6.1.x' 2024-08-28 18:59:47 +03:00
Sam Brannen 5bcfcdd0be Polishing 2024-08-28 14:46:12 +02:00
Sam Brannen 38a56b3fda Unwrap CGLIB proxy when invoking non-proxied methods in ReflectionTestUtils
Prior to this commit, when ReflectionTestUtils was used to invoke a
method on a CGLIB proxy, the invocation was always performed directly
on the proxy. Consequently, if the method was not proxied/intercepted
by the CGLIB proxy -- for example, if the method was final or
effectively private -- the invoked method could not operate on the
state of the target object or interact with other private methods in
the target object.

With this commit, if the supplied target object is a CGLIB proxy which
does not intercept the method, the proxy will be unwrapped allowing the
method to be invoked directly on the ultimate target of the proxy.

Closes gh-33429
2024-08-28 14:31:24 +02:00
Sébastien Deleuze 6d1294ddad Merge branch '6.1.x' 2024-08-27 15:39:04 -07:00
Sam Brannen ba774c6290 Restore behavior for ClassUtils.getInterfaceMethodIfPossible()
Commit 47f88e123f introduced support for invoking init/destroy/SpEL
methods via public types whenever possible. To achieve that,
getInterfaceMethodIfPossible() was modified so that it only returned
interface methods from public interfaces; however, we have learned that
third parties relied on the previous behavior which found any interface
method (even in non-public interfaces).

In light of the above, this commit partially reverts commit 47f88e123f
in order to reinstate getInterfaceMethodIfPossible() in non-deprecated
form with its previous behavior.

See gh-33216
2024-08-27 11:42:07 +02:00
Sam Brannen d2ea5b4448 Polish internal Javadoc 2024-08-23 11:24:22 +02:00
Sam Brannen 47f88e123f Invoke init/destroy/SpEL methods via public types whenever possible
Prior to this commit, when invoking init methods and destroy methods
for beans as well as methods within Spring Expression Language (SpEL)
expressions via reflection, we invoked them based on the "interface
method" returned from ClassUtils.getInterfaceMethodIfPossible(). That
works well for finding methods defined in an interface, but it does not
find public methods defined in a public superclass.

For example, in a SpEL expression it was previously impossible to
invoke toString() on a non-public type from a different module. This
could be seen when attempting to invoke toString() on an unmodifiable
list created by Collections.unmodifiableList(...). Doing so resulted in
an InaccessibleObjectException.

Although users can address that by adding an appropriate --add-opens
declaration, such as --add-opens java.base/java.util=ALL-UNNAMED, it is
better if applications do not have to add an --add-opens declaration
for such use cases in SpEL. The same applies to init methods and
destroy methods for beans.

This commit therefore introduces a new
getPubliclyAccessibleMethodIfPossible() method in ClassUtils which
serves as a replacement for getInterfaceMethodIfPossible().

This new method finds the first publicly accessible method in the
supplied method's type hierarchy that has a method signature equivalent
to the supplied method. If the supplied method is public and declared
in a public type, the supplied method will be returned. Otherwise, this
method recursively searches the class hierarchy and implemented
interfaces for an equivalent method that is public and declared in a
public type. If a publicly accessible equivalent method cannot be
found, the supplied method will be returned, indicating that no such
equivalent method exists.

All usage of getInterfaceMethodIfPossible() has been replaced with
getPubliclyAccessibleMethodIfPossible() in spring-beans and
spring-expression. In addition, getInterfaceMethodIfPossible() has been
marked as deprecated in favor of the new method.

As a bonus, the introduction of getPubliclyAccessibleMethodIfPossible()
allows us to delete a fair amount of obsolete code within the SpEL
infrastructure.

See gh-29857
Closes gh-33216
2024-08-22 14:35:21 +02:00
Sam Brannen cac623b3f4 Refer to the "Java Module System" instead of "Jigsaw" 2024-08-22 13:00:39 +02:00
Brian Clozel c5f51aab67 Merge branch '6.1.x' 2024-08-22 09:32:11 +02:00
Sébastien Deleuze c71409821d Polishing
Closes gh-33402
2024-08-20 18:32:37 +02:00
dev-chpark a9cbb01a45 Rename test method to clarify its purpose
See gh-33402
2024-08-20 18:32:30 +02:00
Sam Brannen 4a099d213e Add missing @⁠TestMethodOrder declarations 2024-08-19 14:46:21 +02:00
Sam Brannen 9f0417fb33 Merge branch '6.1.x' 2024-08-19 13:58:31 +02:00
Brian Clozel 96573ee5e1 Merge branch '6.1.x' 2024-08-19 11:48:36 +02:00
Simon Baslé 107ae6159b Add tests for MockitoBean reset of mocks/spies from a FactoryBean
Closes gh-33405
2024-08-19 11:10:19 +02:00
Sébastien Deleuze 94d8fc7af8 Merge branch '6.1.x' 2024-08-19 10:46:54 +02:00
Sébastien Deleuze eb7a95cfdb Merge branch '6.1.x' 2024-08-19 09:47:08 +02:00
Sam Brannen 346b6f740a Polish contribution
See gh-33401
2024-08-18 14:58:05 +02:00
tafjwr 4ffeddb099 Add tests for ControllerAdviceBean#resolveBean() and revise existing tests
Closes gh-33401
2024-08-18 14:52:05 +02:00
Sam Brannen 59c779d8fe Enforce order of Javadoc tags for records introduced in 6.2
See gh-33403
2024-08-18 13:12:47 +02:00
Sam Brannen 04271c3ead Merge branch '6.1.x' 2024-08-18 13:04:21 +02:00
Sam Brannen e50383e921 Improve Javadoc for SpEL's Expression API 2024-08-17 15:59:00 +02:00
Sébastien Deleuze f854800043 Merge branch '6.1.x' 2024-08-16 17:05:23 +02:00
Sam Brannen de33056c83 Use new features from JUnit Jupiter 5.11
This commit migrates additional parameterized tests (that were missed in
the previous commit) to the new argumentSet() feature.

See gh-33395
2024-08-16 15:48:47 +02:00
Sébastien Deleuze a9a1798012 Merge branch '6.1.x' 2024-08-16 14:37:56 +02:00
Sam Brannen d749d2949d Use new features from JUnit Jupiter 5.11
This commit primarily migrates to the new argumentSet() feature but also
applies additional polishing to our use of parameterized tests.

See gh-33395
2024-08-16 13:48:19 +02:00
Sam Brannen 2eff5cb463 Upgrade to JUnit 5.11
Closes gh-33395
2024-08-15 18:15:15 +02:00
Stéphane Nicoll 6cc0561625 Merge branch '6.1.x' 2024-08-14 13:27:57 +02:00
rstoyanchev 974dec262c Merge branch '6.1.x' 2024-08-14 07:33:15 +03:00
Juergen Hoeller e1cf203295 Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-08-13 19:05:20 +02:00
Juergen Hoeller 552936627a Reject method name mismatch in case of bean name overloading
Closes gh-33330
2024-08-13 18:22:34 +02:00
Stéphane Nicoll 599fc8796b Upgrade to Reactor 2024.0.0-M5
Closes gh-33328
2024-08-13 18:07:31 +02:00
Stéphane Nicoll 57171143b9 Upgrade to Micrometer 1.14.0-M2
Closes gh-33327
2024-08-13 18:07:08 +02:00
Stéphane Nicoll 50c927b649 Merge branch '6.1.x' 2024-08-13 17:30:16 +02:00
Sam Brannen 1aea01687a Merge branch '6.1.x' 2024-08-13 17:40:13 +03:00
rstoyanchev 5fee796659 Merge branch '6.1.x' 2024-08-13 16:59:32 +03:00
rstoyanchev cef1b7ea6d Polishing in HTTP interface argument resolvers 2024-08-12 21:01:03 +03:00
Olga Maciaszek-Sharma 51de84e148 Reject null for non-optional arguments
Closes gh-33339
2024-08-12 21:01:03 +03:00
Stéphane Nicoll 4ac4c1b868 Revert "Merge pull request #33366 from kashike"
This reverts commit a1ec7669f6, reversing
changes made to e27192e8ad.

See gh-33366
2024-08-12 17:47:35 +02:00
Sébastien Deleuze bb4a96f227 Merge branch '6.1.x' 2024-08-12 17:32:53 +02:00
Simon Baslé 4dcdd9a224 Polishing
See gh-21590
2024-08-12 15:20:37 +02:00
Simon Baslé 2eda5d7a2a Handle low-level errors for sync/flux/mono/future gets
This change adds 3 protected methods to `AbstractCacheInvoker` that wrap
additional `Cache#retrieve` and `Cache#get` calls with
`handleCacheGetError` in case the Cache call itself fails.

For example, if the cache is remote and a connection to it cannot be
established.

Closes gh-21590
2024-08-12 15:02:05 +02:00
Simon Baslé 5e72ee36e2 Merge branch '6.1.x' 2024-08-12 14:54:54 +02:00
Stéphane Nicoll b7ddf1b4f4 Fix typo 2024-08-12 12:18:44 +02:00
Stéphane Nicoll a1ec7669f6 Merge pull request #33366 from kashike
* pr/33366:
  Polish "Make CacheControl immutable"
  Make CacheControl immutable

Closes gh-33366
2024-08-12 11:51:10 +02:00
Stéphane Nicoll 9f22e0c2de Polish "Make CacheControl immutable"
See gh-33366
2024-08-12 11:44:17 +02:00
Riley Park c3ab9bba11 Make CacheControl immutable
See gh-33366
2024-08-12 11:28:47 +02:00
Stéphane Nicoll e27192e8ad Merge branch '6.1.x' 2024-08-12 11:02:07 +02:00
Sam Brannen 4f607b59a3 Improve document for SpEL Bean References 2024-08-10 16:44:17 +03:00
Sam Brannen eab96073da Document that SpEL expressions using bean references are not compilable
Closes gh-33363
2024-08-10 16:33:55 +03:00
Simon Baslé bf5e218b35 Add support for headers in @HttpExchange
On the client side, supports `name=value` pairs. Placeholders in values
are resolved by the `embeddedValueResolver`.
On the server side, additionally supports `name` and `!name` syntax.

Closes gh-33309
2024-08-09 18:02:16 +02:00
rstoyanchev b61eee7fb0 Support cross-parameter validation
Closes gh-33271
2024-08-09 18:53:30 +03:00
rstoyanchev 0d64c90a79 Move status/header handling into FragmentsRendering
Based on feedback from htmx-spring-boot. It's more generally useful
to process those from within DefaultFragmentsRendering rather than
in ModelAndViewMethodReturnValueHandler. That way a custom
return value handler can create a FragmentsRendering as well and
get the same result.

See gh-33194
2024-08-09 18:01:15 +03:00
Stéphane Nicoll ce5e247c3b Merge branch '6.1.x' 2024-08-09 15:52:35 +02:00
Stéphane Nicoll ae38c88f82 Merge branch '6.1.x' 2024-08-09 15:46:01 +02:00
Stéphane Nicoll ea2c441008 Merge branch '6.1.x' 2024-08-09 09:52:19 +02:00
Stéphane Nicoll bd61da12b2 Merge branch '6.1.x' 2024-08-09 09:05:12 +02:00
Sam Brannen f6110dda06 Polishing 2024-08-08 17:48:57 +03:00
Sam Brannen cd7c650941 Merge branch '6.1.x' 2024-08-08 17:16:19 +03:00
Simon Baslé d3e1e35d76 Merge branch '6.1.x' 2024-08-08 15:59:28 +02:00
rstoyanchev e670c6b50a Documentation updates for fragment rendering
Closes gh-33195
2024-08-08 16:25:03 +03:00
rstoyanchev 0bac8d48a5 Polishing in view rendering documentation
See gh-33195
2024-08-08 16:25:03 +03:00
rstoyanchev 062c18a81d Add DataBuffer management in fragment rendering
See gh-33194
2024-08-08 16:25:03 +03:00
rstoyanchev 8e2b27e5d8 WebFlux support for SSE with multiline fragments
See gh-33194
2024-08-08 16:25:03 +03:00
rstoyanchev b734156f32 Update WebFlux fragment stream rendering
Thymeleaf has its own special handling for SSE that gets in the way
of fragment rendering. This is why we need to set the response
content-type before streaming, and then pass text/html to the
View for rendering each fragment.

See gh-33194
2024-08-08 16:25:02 +03:00
rstoyanchev f5ed1b8f6d Refactoring in ViewResolutionResultHandler
See gh-33194
2024-08-08 16:25:02 +03:00
Sam Brannen 3863b77536 Merge branch '6.1.x' 2024-08-08 14:20:56 +03:00
Stéphane Nicoll 4ceefa7501 Merge branch '6.1.x' 2024-08-08 11:41:53 +02:00
Stéphane Nicoll 7d72a03427 Start building against Micrometer 1.14.0-M2 snapshots
See gh-33327
2024-08-08 10:55:14 +02:00
Stéphane Nicoll 27aa341ab0 Merge branch '6.1.x' 2024-08-08 10:47:43 +02:00
Stéphane Nicoll dbb3a9ab08 Merge branch '6.1.x' 2024-08-08 09:33:40 +02:00
Stéphane Nicoll 873c9fe0d8 Merge branch '6.1.x' 2024-08-08 09:14:30 +02:00
Stéphane Nicoll 67838f3ff9 Provide all counters in BatchUpdateException
This commit updates JbcTemplate#batchUpdate to provide additional
information when one batch fails. Previously, the raw
BatchUpdateException was thrown with no way to know what had completed
thus far.

This commit creates an AggregatedBatchUpdateException that wraps the
original BatchUpdateException, yet providing the counters of the batches
that ran prior to the exception. In essence, this represents the same
state as the return value of the method if no batch fails.

AggregateBatchUpdateException exposes the original BatchUpdateException
in advanced case, such as checking for a sub-class that may contain
additional information.

Closes gh-23867
2024-08-08 08:35:06 +02:00
Sam Brannen a55207e88f Add tests for read-only IndexAccessors in 6.2 2024-08-07 19:23:06 +03:00
Sam Brannen b0999641dd Merge branch '6.1.x' 2024-08-07 18:26:13 +03:00
Simon Baslé 70e5af7d16 Polishing: remove unnecessary code 2024-08-07 16:57:52 +02:00
Simon Baslé 52bc3cf5aa Polishing 2024-08-07 16:43:09 +02:00
Stéphane Nicoll 25b57d4808 Merge branch '6.1.x' 2024-08-07 16:32:20 +02:00
Simon Baslé 71927b3487 Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/scheduling/concurrent/SimpleAsyncTaskScheduler.java
2024-08-07 16:07:00 +02:00
Stéphane Nicoll 313b063aef Polish 2024-08-07 15:28:52 +02:00
Simon Baslé 7052af97a6 Polish test to focus on the FactoryBean results being mocked 2024-08-07 14:57:15 +02:00
Simon Baslé 1c893e6354 Add @MockitoBeanSettings, use MockitoSession with strict stubs default
This commit changes the way the `MockitoTestExecutionListener` sets up
mockito, now using the `MockitoSession` feature. Additionally, stubbing
now defaults to a STRICT mode which can be overruled with a newly
introduced annotation: `@MockitoBeanSettings`.

Closes gh-33318
2024-08-07 14:57:15 +02:00
Stéphane Nicoll bc05474271 Merge branch '6.1.x' 2024-08-07 10:26:07 +02:00
Stéphane Nicoll 88a408474d Start building against Reactor 2024.0.0-M5 snapshots
See gh-33328
2024-08-07 10:22:53 +02:00
Sam Brannen a698f66c3a Merge branch '6.1.x'
# Conflicts:
#	spring-expression/src/main/java/org/springframework/expression/spel/support/SimpleEvaluationContext.java
2024-08-06 13:56:57 +03:00
Juergen Hoeller 28668d774b Enforce non-null value in requiredSingleResult/requiredUniqueResult
Closes gh-33300
2024-08-05 15:53:17 +02:00
Sam Brannen 1e804d8d4f Merge branch '6.1.x' 2024-08-05 16:37:57 +03:00
rstoyanchev 622c1b9e8c WebMvc support for SSE Fragment stream
Closes gh-33194
2024-08-05 14:38:23 +03:00
rstoyanchev 184bb7c23c Polishing in ResponseBodyEmitterReturnValueHandler
See gh-33194
2024-08-05 14:38:23 +03:00
Sam Brannen f3ab3905b8 Merge branch '6.1.x' 2024-08-05 14:21:27 +03:00
Sam Brannen 74b0bb105e Merge branch '6.1.x' 2024-08-05 11:58:49 +03:00
Sam Brannen 46a4ad4a75 Merge branch '6.1.x' 2024-08-05 11:07:47 +03:00
Stéphane Nicoll 5c3f1b1741 Merge pull request #33316 from zinzoddari
* pr/33316:
  Polishing Javadoc and comment

Closes gh-33316
2024-08-05 10:06:33 +02:00
zinzo edbaf68707 Polishing Javadoc and comment
See gh-33316
2024-08-05 10:05:00 +02:00
Stéphane Nicoll 6bcffe3b4a Shorten PR jobs to 60 minutes
See gh-33302
2024-08-05 10:03:25 +02:00
Sam Brannen f4604cfab3 Merge branch '6.1.x' 2024-08-04 17:14:10 +03:00
Stéphane Nicoll 776a1d45f8 Merge branch '6.1.x' 2024-08-04 09:34:38 +02:00
Stéphane Nicoll 499cf5e84c Merge pull request #33308 from benelog
* pr/33308:
  Remove duplicated "the" in Javadoc

Closes gh-33308
2024-08-03 09:54:39 +02:00
Sanghyuk Jung ca377e4854 Remove duplicated "the" in Javadoc
See gh-33308
2024-08-03 09:52:23 +02:00
Stéphane Nicoll 0a2611b22f Harmonize NoUniqueBeanDefinitionException message
This commit makes sure that the programmatic exception that is thrown
by the cache abstraction uses the same message structure as a default
message produced by NoUniqueBeanDefinitionException.

Closes gh-33305
2024-08-02 16:24:43 +02:00
Stéphane Nicoll 29dce74fcd Merge branch '6.1.x' 2024-08-02 10:57:57 +02:00
Stéphane Nicoll 3aec39973c Polish 2024-08-02 09:16:15 +02:00
Simon Baslé 25f62c8765 Merge branch '6.1.x' 2024-08-01 16:29:52 +02:00
Stéphane Nicoll 47780747ba Merge pull request #33298 from zinzoddari
* pr/33298:
  Polish "Improve test coverage of StringUtils"
  Improve test coverage of StringUtils

Closes gh-33298
2024-08-01 07:35:01 +02:00
Stéphane Nicoll ec9d29ea8f Polish "Improve test coverage of StringUtils"
See gh-33298
2024-08-01 07:32:41 +02:00
zinzo a2cae4c8f4 Improve test coverage of StringUtils
This commit adds tests for `trimArrayElements()` and
`delimitedListToStringArray()` in StringUtils.

See gh-33298
2024-08-01 07:23:28 +02:00
Stéphane Nicoll f63fc01d22 Merge branch '6.1.x' 2024-07-31 16:56:22 +02:00
rstoyanchev 31a3119784 Add FilterRegistration's defensively
Follow-up to d2225c, which broke Boot tests because the ServletContext can
be the one of the embedded Servlet container if initializing a live server
and as well as MockMvc (e.g. via `@AutoConfigureMockMvc`).

See gh-33252
2024-07-31 14:50:08 +03:00
Simon Baslé f1a99cd968 Allow setting filename for inline elements in MimeMessageHelper
This change adds several overloads of `MimeMessageHelper#addInline`
which allow users to specify a file name for inline elements added from
an `InputStreamResource` or a `jakarta.activation.DataSource`.

Closes gh-33230
2024-07-31 11:39:16 +02:00
Stéphane Nicoll c71f98acba Merge branch '6.1.x' 2024-07-30 17:21:28 +02:00
Simon Baslé 6174d95ba2 Add multi-unit DurationFormat.Style for duration parsing/printing
This adds the COMPOSITE style, which allows multiple segments each
similar to the SIMPLE style.

See gh-30396
Closes gh-33262
2024-07-30 16:58:42 +02:00
rstoyanchev f967f6f9f0 Update contribution
Closes gh-33220
2024-07-30 13:15:21 +03:00
Seokjae Lee 5e9308e0cb Flexible collection handling in RequestParamArgumentResolver
See gh-33220
2024-07-30 11:42:44 +03:00
rstoyanchev dbc69284c8 ResponseEntityExceptionHandler handles AsyncRequestNotUsableException
Closes gh-33225
2024-07-30 11:33:47 +03:00
rstoyanchev 5ac7e74bf2 Replace test FilterRegistration with the one in testFixtures
See gh-33252
2024-07-30 11:33:47 +03:00
rstoyanchev 24ab6f61de Add FilterRegistration to spring-web textFixtures
See gh-33252
2024-07-30 11:33:47 +03:00
rstoyanchev d2225c2140 MockMvc supports FilterRegistration filter init
Closes gh-33252
2024-07-30 11:33:47 +03:00
Brian Clozel 38453910cd Add DatabaseClient bind variant for list of parameters
Prior to this commit, the `DatabaseClient` interface would allow batch
operations for binding parameters by their names and values. Positional
parameters did not have such equivalent.

This commit adds a new `bindValues(List<?>)` method variant for adding
multiple positional arguments in a single call and avoiding allocation
overhead when the parameters count is large.

Closes gh-33274
2024-07-29 14:07:15 +02:00
Stéphane Nicoll 1f2c6c33ac Merge branch '6.1.x' 2024-07-29 11:34:12 +02:00
Juergen Hoeller 7c13d55906 Merge branch '6.1.x' 2024-07-29 10:48:11 +02:00
Stéphane Nicoll 70f3b0eb91 Only register DynamicPropertySourceBeanInitializer if necessary
This commit makes sure to check first if
DynamicPropertySourceBeanInitializer has been registered before trying
to register it.

When running with AOT optimizations, the bean definition has been
contributed so there is no need to register it again when the context
customizer runs.

Closes gh-33272
2024-07-29 09:30:27 +02:00
Stéphane Nicoll 2596e29013 Refine "Add AOT/Native support"
This commit review the support for AOT by only ignoring beans that are
using an instance supplier. The Kotlin DSL has a way to register a
bean by type where all inferences should happen as usual and that was
previously ignored.

This commit no longer ignores those beans so AOT can optimize them, and
makes sure that they are not registered again when running with AOT
optimizations. This change makes it so that the order in which beans are
registered is now different when running with AOT optimizations, and
we'll have to find a solution for that.

See gh-29555
2024-07-29 09:01:57 +02:00
Brian Clozel b888f362e5 Document ControllerAdviceBean as internal usage
This commit documents `ControllerAdviceBean` as internal usage, as it is
not meant for application to manually create controller advice bean
instances.

This also refactors the existing partial implementation of the support
for creating controller advice beans "programmatically".

Closes gh-32776
2024-07-26 17:52:20 +02:00
Sam Brannen 94e2bef9a3 Merge branch '6.1.x' 2024-07-26 16:41:13 +03:00
Stéphane Nicoll de2335bee3 Merge branch '6.1.x' 2024-07-26 10:05:06 +02:00
Stéphane Nicoll fc28926c15 Merge branch '6.1.x' 2024-07-25 16:29:07 +02:00
Stéphane Nicoll 65faca8236 Consistently using credentials for creating the JMSContext
This commit updates UserCredentialsConnectionFactoryAdapter to apply
the same handling of credentials for creating the JMSContext.

Closes gh-33270
2024-07-25 09:41:43 +02:00
rstoyanchev 6e55e78b22 WebFlux support for SSE Fragment stream
See gh-33194
2024-07-24 15:34:13 +01:00
rstoyanchev aa6b47bfce Polishing in FragmentsRendering
See gh-33194
2024-07-24 15:34:13 +01:00
Stéphane Nicoll 7c9bb24296 Polish 2024-07-24 13:59:06 +02:00
Stéphane Nicoll b8f9913aa1 Add AOT/Native support
This commit adds AOT/Native support for beans that are contributed by
the Kotlin DSL.

Since they use an instance supplier, such beans are now configured to
be ignored by AOT generation. They are part of the bean factory still
so any hint generation works.

This commit removes a previous attempt at fixing this issue when we
were not checking for instance suppliers. Rather than skipping the
initializr at runtime, it runs again as intended since their state
can't be stored in AOT-generated code.

Closes gh-29555
2024-07-24 13:58:36 +02:00
Stéphane Nicoll e741d6edbb Exclude bean definition from AOT processing using an attribute
This commits allows a particular bean definition to be excluded from
AOT processing using an attribute.

If BeanRegistrationAotProcessor#IGNORE_REGISTRATION_ATTRIBUTE is set
to `true`, then the bean definition is excluded. This complement the
existing BeanRegistrationExcludeFilter capability.

Closes gh-33243
2024-07-24 12:42:45 +02:00
Stéphane Nicoll bbfc3364e1 Merge branch '6.1.x' 2024-07-24 11:45:49 +02:00
Sam Brannen e547313fa6 Sync MapAccessor implementations 2024-07-23 18:27:52 +03:00
Sam Brannen 4fa9781549 Ensure MapAccessor#canWrite only returns true for a Map target
Closes gh-33265
2024-07-23 18:26:53 +03:00
Sam Brannen 4684a17f00 Polishing 2024-07-23 18:21:12 +03:00
Brian Clozel f3123d88f3 Merge branch '6.1.x' 2024-07-23 17:10:08 +02:00
Stéphane Nicoll de002ec12a Merge branch '6.1.x' 2024-07-23 16:21:04 +02:00
Stéphane Nicoll 7c558a3d6d Merge branch '6.1.x' 2024-07-23 15:07:21 +02:00
Simon Baslé c92e043bbc Support multiple style of parsing/printing Durations
This commit introduces a notion of different styles for the formatting
of Duration.
The `@DurationFormat` annotation is added to ease selection of a style,
which are represented as DurationFormat.Style enum, as well as a
supported time unit represented as DurationFormat.Unit enum.

DurationFormatter has been retroffited to take such a Style,
optionally, at construction. The default is still the JDK style a.k.a.
ISO-8601.

This introduces the new SIMPLE style which uses a single number + a
short human-readable suffix. For instance "-3ms" or "2h".

This has the same semantics as the DurationStyle in Spring Boot and
is intended as a replacement for that feature, providing access to the
feature to projects that only depend on Spring Framework.

Finally, the `@Scheduled` annotation is improved by adding detection
of the style and parsing for the String versions of initial delay, fixed
delay and fixed rate.

See gh-22013
See gh-22474

Closes gh-30396
2024-07-23 11:56:48 +02:00
Stéphane Nicoll d219362eb1 Keep fallback flag in AOT-generated code
Closes gh-33261
2024-07-23 11:30:37 +02:00
Stéphane Nicoll eda21c4d22 Merge branch '6.1.x' 2024-07-23 10:51:56 +02:00
Stéphane Nicoll 92385418ae Polish assertion 2024-07-23 10:16:04 +02:00
Brian Clozel ccc0a54c1c Merge branch '6.1.x' 2024-07-23 09:22:15 +02:00
Stéphane Nicoll 00301440cd Merge pull request #32876 from quaff
* pr/32876:
  Polish "Resolved nested placeholder for CharSequence"

Closes gh-32876
2024-07-22 15:04:06 +02:00
Stéphane Nicoll b6fbbeccdc Polish "Resolved nested placeholder for CharSequence"
See gh-32876
2024-07-22 14:59:58 +02:00
Stéphane Nicoll 5331499393 Do not further process imports of Object.class
This commit filters out source classes that didn't pass a predicate
filter so that they are no longer considered.

Closes gh-27080
2024-07-22 12:31:02 +02:00
Stéphane Nicoll e011d4f798 Merge branch '6.1.x' 2024-07-21 13:06:10 +02:00
Stéphane Nicoll 2190c6ec79 Merge branch '6.1.x' 2024-07-21 11:42:39 +02:00
Stéphane Nicoll 28b044cdb4 Merge pull request #33247 from izeye
* pr/33247:
  Polish "Add missing Javadoc since in AbstractUrlHandlerMapping"
  Add missing Javadoc since in AbstractUrlHandlerMapping

Closes gh-33247
2024-07-21 09:34:06 +02:00
Stéphane Nicoll d5abc071f1 Polish "Add missing Javadoc since in AbstractUrlHandlerMapping"
See gh-33247
2024-07-21 09:30:06 +02:00
Johnny Lim edc356d5a0 Add missing Javadoc since in AbstractUrlHandlerMapping
See gh-33247
2024-07-21 09:29:53 +02:00
Stéphane Nicoll 97411ddd55 Merge branch '6.1.x' 2024-07-20 11:53:31 +02:00
Brian Clozel b701b26b07 Merge branch '6.1.x' 2024-07-19 17:23:14 +02:00
rstoyanchev dcabddddc2 Expose HttpExchange metadata to argument resolvers
See gh-33220
2024-07-19 11:00:43 +01:00
Stéphane Nicoll 0bfc8e27cc Merge branch '6.1.x' 2024-07-19 11:33:54 +02:00
Stéphane Nicoll 7b5e4b014b Merge pull request #33233 from deblockt
* pr/33233:
  Polish "Support JAXBElement in Jaxb2RootElementHttpMessageConverter"
  Support JAXBElement in Jaxb2RootElementHttpMessageConverter

Closes gh-33233
2024-07-19 10:22:45 +02:00
Stéphane Nicoll f4b2886775 Polish "Support JAXBElement in Jaxb2RootElementHttpMessageConverter"
See gh-33233
2024-07-19 10:20:06 +02:00
Thomas Deblock a5e2557738 Support JAXBElement in Jaxb2RootElementHttpMessageConverter
See gh-33233
2024-07-19 10:12:53 +02:00
Stéphane Nicoll e4edd3246a Restore Freemarker support now it supports Jakarta
Closes gh-30186
2024-07-18 17:55:52 +02:00
rstoyanchev ade8128060 Remove deprecated methods
Closes gh-33123
2024-07-18 11:37:20 +01:00
rstoyanchev 9409543dac Update deprecation notices
See gh-33123
2024-07-18 11:37:20 +01:00
Stéphane Nicoll 89453905cb Copy tests for multipart request builder
See gh-33229
2024-07-18 12:11:59 +02:00
Stéphane Nicoll 6590ab6bf9 Consistently set content type of the request with multipart
Closes gh-33232
2024-07-18 12:01:47 +02:00
Stéphane Nicoll 265299c790 Restore source and binary compatibility in MockMvc
Previous to this commit, MockHttpServletRequestBuilder was not binary
compatible as its methods had moved to a parent class with a generic
argument on the return type. MockMultipartHttpServletRequestBuilder
was also not source compatible as it no longed extended from
MockHttpServletRequestBuilder.

Both these changes were introduced to allow the AssertJ support to
expose builders that implement an extra AssertJ interface, without
copying the features the builders provide.

This commit restore compatibility. For MockHttpServletRequestBuilder
we simply override all methods that returns the generic type into
the resolved type.

MockMultipartHttpServletRequestBuilder is more involved. Because we
need to extend from MockHttpServletRequestBuilder, we have no other
choice than duplicating the code. For now, the abstract builder for
multipart is only used by the AssertJ support, but we can revisit this
again in a major release.

Closes gh-33229
2024-07-18 11:21:35 +02:00
Stéphane Nicoll 5715b2a783 Fix javadoc references 2024-07-17 16:54:59 +02:00
rstoyanchev b9509d3c85 Initialize RequestPath on demand
Closes gh-33227
2024-07-17 15:15:31 +01:00
Stéphane Nicoll 30a64d6a0b Avoid code too large with AOT processing
This commit adapts code generation to "slice" the registration of bean
definitions in separate bean methods rather than a unique method for
all of them.

If the bean factory has more than a thousand bean, a method is created
for each slice of 1000 bean definitions.

Closes gh-33126
2024-07-17 16:04:32 +02:00
Stéphane Nicoll 48dead4017 Harmonize milestone release workflow 2024-07-17 11:50:56 +02:00
Stéphane Nicoll 9b34400504 Merge pull request #33222 from quaff
* pr/33222:
  Polish "Add support for making MapAccessor read-only"
  Add support for making MapAccessor read-only

Closes gh-33222
2024-07-17 11:39:29 +02:00
Stéphane Nicoll 821109bd06 Polish "Add support for making MapAccessor read-only"
See gh-33222
2024-07-17 11:34:47 +02:00
Yanming Zhou a0e43b1f46 Add support for making MapAccessor read-only
See gh-33222
2024-07-17 11:32:21 +02:00
Stéphane Nicoll ec383f69f2 Merge branch '6.1.x' 2024-07-16 09:59:56 +02:00
rstoyanchev b2decb4e5d Merge branch '6.1.x' 2024-07-15 15:21:39 +01:00
rstoyanchev 39c040005e Lazy use of Reactor Scheduler in DefaultPartHttpMessageReader
Closes gh-33218
2024-07-15 15:10:30 +01:00
Simon Baslé 50906e7fcb Merge branch '6.1.x' 2024-07-15 11:49:47 +02:00
Stéphane Nicoll 681cfce730 Merge branch '6.1.x' 2024-07-14 11:22:14 +02:00
Sam Brannen aa2829455b Expand test coverage for gh-14200 2024-07-13 17:26:26 +02:00
Sam Brannen 6ca8fbc2da Merge ArgumentsMatchInfo into ArgumentsMatchKind in SpEL
The internal ArgumentsMatchInfo type seems to have once had additional
methods beyond the functionality provided by the ArgumentsMatchKind
enum; however, that is no longer the case. Consequently, there is no
need to maintain both types.

This commit therefore merges the convenience methods from
ArgumentsMatchInfo into the ArgumentsMatchKind enum and removes the
unnecessary ArgumentsMatchInfo type.
2024-07-13 14:34:24 +02:00
rstoyanchev 007a347ade Refine executor description in WebSocketMessageBrokerStats
Closes gh-33104
2024-07-12 17:35:35 +01:00
rstoyanchev bd31e8dacc Provide access to underlying ConstraintViolation
Closes gh-33025
2024-07-12 17:35:35 +01:00
Sam Brannen 3e48498663 Change MIME mapping for .js from application/javascript to text/javascript
This application/javascript MIME type is deprecated.

This commit therefore changes the MIME type mapping for *.js files from
application/javascript to text/javascript in order to align with
industry standards.

Closes gh-33197
2024-07-12 18:22:18 +02:00
Sam Brannen 59b9404956 Specify nullability @⁠Contract for TypeDescriptor.array() 2024-07-12 18:02:26 +02:00
Sam Brannen 09d8e4458c Merge branch '6.1.x' 2024-07-12 17:37:51 +02:00
Simon Baslé fbe781b172 Merge branch '6.1.x' 2024-07-12 12:52:40 +02:00
Stéphane Nicoll 348764620d Merge branch '6.1.x' 2024-07-12 12:02:45 +02:00
Stéphane Nicoll bac8a86419 Merge branch '6.1.x' 2024-07-12 08:37:47 +02:00
Sam Brannen c93598835c Merge branch '6.1.x' 2024-07-11 18:31:37 +02:00
Stéphane Nicoll a421fc4fb3 Merge branch '6.1.x' 2024-07-11 17:01:01 +02:00
Juergen Hoeller d1f9e35b35 Merge branch '6.1.x' 2024-07-11 16:16:31 +02:00
Stéphane Nicoll 022b91980e Publish release notes as a pre-release for milestones
This commit updates the "create-github-release" action to allow an
additional input that specifies whether this is a pre-release. If that
is the case, then the `--prerelease` flag is set.

Closes gh-33200
2024-07-11 16:11:47 +02:00
Stéphane Nicoll 1a21977965 Only promote a milestone when verify has completed
See gh-gh-33179
2024-07-11 10:47:10 +02:00
Stéphane Nicoll c038f551fc Merge branch '6.1.x' 2024-07-11 10:14:21 +02:00
rstoyanchev 93d5be621b Merge branch '6.1.x' 2024-07-10 17:55:48 +01:00
Sébastien Deleuze 7617a01f60 Unwrap Kotlin inline value classes return values
The result returned by Kotlin reflective invocation of a function
returning an inline value class is wrapped, which makes sense
from Kotlin POV but from a JVM perspective the associated value
and type should be unwrapped to be consistent with what
would happen with a reflective invocation done by Java.

This commit unwraps such result.

Closes gh-33026
2024-07-10 18:38:37 +02:00
Sébastien Deleuze 82c5aa4a48 Refactor InvocableHandlerMethodKotlinTests
See gh-33026
2024-07-10 18:32:10 +02:00
rstoyanchev b93b7e013a Add FragmentsRendering to documentation for return values
Closes gh-33162
2024-07-10 16:50:12 +01:00
rstoyanchev 65296c6aad Add status/headers to WebMVC FragmentsRendering
See gh-33162
2024-07-10 16:40:40 +01:00
rstoyanchev 14c1faa5ee Updates to WebMVC fragment rendering API
See gh-33162
2024-07-10 16:40:40 +01:00
rstoyanchev 6ee8786385 Updates to WebFlux fragment rendering API
See gh-33162
2024-07-10 16:40:40 +01:00
rstoyanchev 54e76c8105 Support List and Publisher<Fragment> return values
See gh-33162
2024-07-10 16:40:40 +01:00
Stéphane Nicoll f2028d2339 Add workflow for releases to the milestone repository
See gh-33179
2024-07-10 16:58:34 +02:00
Sam Brannen f7d4742ab8 Merge branch '6.1.x' 2024-07-10 16:52:08 +02:00
Sam Brannen 4de2aadf72 Merge branch '6.1.x' 2024-07-10 16:22:17 +02:00
Juergen Hoeller 8cfdaaaabc Merge branch '6.1.x' 2024-07-10 15:57:24 +02:00
Stéphane Nicoll 6de624d537 Provide a template method to expose the currently invoked factory method
This commit improves SimpleInstantiationStrategy by providing a common
template method before the regular runtime and AOT. As a result, the
method to set the currently invoked factory method is deprecated as it
should no longer be used.

Closes gh-33192
2024-07-10 15:38:17 +02:00
Simon Baslé 0c319a89d7 Merge branch '6.1.x' 2024-07-10 15:36:03 +02:00
Juergen Hoeller a9efe10428 Merge branch '6.1.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java
2024-07-10 15:16:40 +02:00
Sam Brannen bb64e22266 Merge branch '6.1.x' 2024-07-10 13:51:44 +02:00
Stéphane Nicoll c6b20c04c2 Merge branch '6.1.x' 2024-07-10 12:39:05 +02:00
Sam Brannen ee6402eeca Merge branch '6.1.x' 2024-07-10 12:04:26 +02:00
Stéphane Nicoll 555e11b6b9 Merge branch '6.1.x' 2024-07-10 10:23:51 +02:00
Stéphane Nicoll 074348e047 Merge branch '6.1.x' 2024-07-10 10:13:42 +02:00
Stéphane Nicoll 9e34edad3d Merge branch '6.1.x' 2024-07-09 16:10:53 +02:00
Stéphane Nicoll 16b6d42adf Upgrade to Reactor 2024.0.0-M4
Closes gh-33171
2024-07-09 15:52:43 +02:00
Stéphane Nicoll 8ac55e1463 Merge branch '6.1.x' 2024-07-09 14:39:37 +02:00
Stéphane Nicoll b2ba61155a Upgrade to Micrometer 1.14.0-M1
Closes gh-33170
2024-07-09 14:39:28 +02:00
Sébastien Deleuze 4ad5c59dea Upgrade to Kotlin Coroutines 1.8.1
Closes gh-33176
2024-07-09 14:35:15 +02:00
Sébastien Deleuze ea2895f7c7 Merge branch '6.1.x' 2024-07-09 14:34:47 +02:00
Stéphane Nicoll 0f66192e80 Merge branch '6.1.x' 2024-07-09 14:24:04 +02:00
Sam Brannen 028ff9b548 Unwrap InvocationTargetException in SpEL's FunctionReference
FunctionReference in the Spring Expression Language (SpEL) currently
does not unwrap an InvocationTargetException; however,
ConstructorReference and MethodReference do.

For example, currently one may encounter an exception like the
following, where the 'null' comes from the fact that an
InvocationTargetException doesn't always have a message.

SpelEvaluationException: EL1023E: A problem occurred whilst attempting
  to invoke the function 'formatObjectVarargs': 'null'

To address that, and to align with the behavior of ConstructorReference
and MethodReference, this commit modifies FunctionReference so that it
unwraps the InvocationTargetException to use its cause for the
exception message, resulting in an exception message like the following.

SpelEvaluationException: EL1023E: A problem occurred whilst attempting
  to invoke the function 'formatObjectVarargs': 'Format specifier '%s''

Closes gh-33174
2024-07-09 13:32:06 +02:00
Sébastien Deleuze e2ce811407 Merge branch '6.1.x' 2024-07-09 12:06:29 +02:00
rstoyanchev 9d45a8d512 Merge branch '6.1.x' 2024-07-09 06:54:56 +01:00
Juergen Hoeller f91f7916ac Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-07-08 22:57:14 +02:00
Juergen Hoeller c6347025d6 Merge branch '6.1.x'
# Conflicts:
#	spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ViewResolutionIntegrationTests.java
2024-07-08 19:54:07 +02:00
Simon Baslé 8918a772bf Polishing
See gh-32097
2024-07-08 18:36:46 +02:00
gregw 0a60c622cc Implement Eclipse Jetty core HTTP handler adapter
This provides an implementation of an HTTP Handler Adapter that is coded
directly to the Eclipse Jetty core API, bypassing any servlet
implementation.

This includes a Jetty implementation of the spring `WebSocketClient`
interface, `JettyWebSocketClient`, using an explicit dependency to the
jetty-websocket-api.

Closes gh-32097

Co-authored-by: Lachlan Roberts <lachlan@webtide.com>
Co-authored-by: Arjen Poutsma <arjen.poutsma@broadcom.com>
2024-07-08 18:36:46 +02:00
Stéphane Nicoll b7ec028149 Merge branch '6.1.x' 2024-07-08 16:52:01 +02:00
rstoyanchev ef6a3768ee Support multi-view rendering
See gh-33162
2024-07-08 12:47:10 +01:00
rstoyanchev 545228d693 Remove unused tiles config files 2024-07-08 12:47:10 +01:00
Stéphane Nicoll 078dfd47dc Add MessageHeaderAccessor to be created with existing headers
This commit mirrors toMap/toMessageHeaders with from factory methods
that allow to create an instance without having to create an
intermediate message if all they have is the headers.

Closes gh-33153
2024-07-08 13:40:38 +02:00
Stéphane Nicoll d89cb34c29 Merge branch '6.1.x' 2024-07-08 13:16:29 +02:00
Stéphane Nicoll 93587da394 Introduce ReflectiveScan
This commit allows `@Reflective` to be used on arbitrary types, not
only Spring beans. This makes the feature much more powerful as
components can be tagged directly.

Scanning happens during AOT processing (typically at build-time) when
`@ReflectiveScan` is used. Types do not need to have a particular
annotation, and types that can't be loaded are ignored.

This commit also exposes the infrastructure that does the scanning so
that custom code can do the scanning in an AOT contribution if they
don't want to rely on the annotation.

Closes gh-33132
2024-07-08 11:11:48 +02:00
Stéphane Nicoll f1658079a5 Polish documentation for RegisterReflection
See gh-29194
2024-07-06 09:31:12 +02:00
Sam Brannen c1f7d15c09 Merge branch '6.1.x' 2024-07-05 19:01:21 +02:00
rstoyanchev 194b4cedfb Use parsed path for checks in UrlHandlerFilter
See gh-32830
2024-07-05 09:35:57 +01:00
rstoyanchev 4054dc7088 Revise handler hierarchy in UrlHandlerFilter
See gh-32830
2024-07-05 09:35:57 +01:00
rstoyanchev 6ad8d6e5e3 Optimize path matching in UrlHandlerFilter
See gh-32830
2024-07-05 09:35:57 +01:00
rstoyanchev 80d1d50478 Polishing and minor refactoring in UrlHandlerFilter
See gh-32830
2024-07-05 09:35:57 +01:00
Stéphane Nicoll fd3bf5b352 Harmonize CI configuration
This commit is a continuation of eacfd77d but for workflows specific
to the main branch.
2024-07-05 10:26:43 +02:00
Stéphane Nicoll 3dba68fc5f Merge branch '6.1.x' 2024-07-05 10:00:37 +02:00
Stéphane Nicoll 00738c17fa Merge branch '6.1.x' 2024-07-05 09:51:02 +02:00
Stéphane Nicoll db1e6e1e26 Polish 2024-07-05 08:26:27 +02:00
Stéphane Nicoll f4607da45f Introduce RegisterReflection
This commit introduces a declarative way of registering reflection
information for arbitrary types. Types can be specified as a class,
a class name, or by annotating the type itself.

This existing RegisterReflectionForBinding becomes a specialized
version of the new annotation, registering the necessary hints for
data binding.

Closes gh-29194
2024-07-04 17:49:41 +02:00
Stéphane Nicoll b0807d847e Fix broken Javadoc reference
See gh-33102
2024-07-04 17:13:04 +02:00
Sam Brannen 8eb204b8dd Merge branch '6.1.x'
# Conflicts:
#	buildSrc/src/main/java/org/springframework/build/TestConventions.java
2024-07-04 17:05:38 +02:00
Stéphane Nicoll 6fa340760d Merge branch '6.1.x' 2024-07-04 16:52:48 +02:00
Stéphane Nicoll ca8bd7b06b Simplify tests 2024-07-04 16:34:33 +02:00
Simon Baslé 5cb9469a29 Merge branch '6.1.x' 2024-07-04 16:19:10 +02:00
Stéphane Nicoll 4bdb772d39 Introduce HttpMessageContentConverter
This commit introduces an abstraction that allows to convert HTTP
inputs to a data type based on a set of HttpMessageConverter.

Previously, the AssertJ integration was finding the first converter
that is able to convert JSON to a Map (and vice-versa) and used that
in its API. With the introduction of SmartHttpMessageConverter, exposing
a specific converter is fragile.

The added abstraction allows for converting other kind of input than
JSON if we need to do that in the future.

Closes gh-33148
2024-07-04 14:06:00 +02:00
Stéphane Nicoll 206d81ee08 Merge branch '6.1.x' 2024-07-04 10:26:46 +02:00
Stéphane Nicoll 6cccbeda5b Merge branch '6.1.x' 2024-07-04 04:26:46 +02:00
Sam Brannen abcad5dbcf Support property placeholders in @⁠Sql script paths
Prior to this commit, paths configured via the scripts attribute in
@⁠Sql were required to be final paths without dynamic placeholders;
however, being able to make script paths dependent on the current
environment can be useful in certain testing scenarios.

This commit introduces support for property placeholders (${...}) in
@⁠Sql script paths which will be replaced by properties available in
the Environment of the test's ApplicationContext.

Closes gh-33114
2024-07-03 17:16:53 +02:00
Juergen Hoeller 384d0e4fd5 Merge branch '6.1.x' 2024-07-03 16:37:36 +02:00
Stéphane Nicoll 1ea4eb147a Polish 2024-07-03 10:04:51 +02:00
Stéphane Nicoll 99e8978a91 Restore binary backward compatibility for GeneratedFiles
See gh-31331
2024-07-03 09:57:22 +02:00
Simon Baslé 78d594c012 Merge branch '6.1.x' 2024-07-02 11:40:39 +02:00
Sam Brannen a8e8897a00 Stop referring to old Spring versions in the reference manual 2024-07-01 18:37:46 +02:00
Sam Brannen e02cddd155 Delete obsolete documentation for JNDI mock support 2024-07-01 18:32:28 +02:00
Sam Brannen 932ce04541 Stop referring to old Spring versions in Javadoc 2024-07-01 17:50:52 +02:00
Sam Brannen e427ac2683 Document parallel execution regarding @⁠MockitoBean & @⁠MockitoSpyBean 2024-07-01 17:08:09 +02:00
Sam Brannen 56fe857f1e Don't reference "Spring Framework 5.0" in parallel test execution section 2024-07-01 17:03:43 +02:00
Arjen Poutsma bd4823e3de Remove deprecated methods scheduled for removal in 6.2
See gh-33123
2024-07-01 16:26:49 +02:00
Arjen Poutsma 5864f57198 Resolve URI to baseUrl in RestClient
Closes gh-32679
2024-07-01 15:10:30 +02:00
Sébastien Deleuze 98e89d8fba Leverage KType in Kotlin Serialization WebFlux support
In order to take in account properly Kotlin null-safety with the
annotation programming model.

Closes gh-33016
2024-07-01 15:06:08 +02:00
Sébastien Deleuze 23dccc5977 Leverage KType in Kotlin Serialization WebMVC support
In order to take in account properly Kotlin null-safety with the
annotation programming model.

See gh-33016
2024-07-01 15:06:08 +02:00
Sébastien Deleuze 4555384528 Introduce SmartHttpMessageConverter
SmartHttpMessageConverter is similar to GenericHttpMessageConverter,
but more consistent with WebFlux Encoder and Decoder contracts, with
the following differences:
 - A ResolvableType parameter is used instead of the Type one
 - The MethodParameter can be retrieved via the ResolvableType source
 - No contextClass parameter
 - `@Nullable Map<String, Object> hints` additional parameter for write
   and read methods

This commit also refines RestTemplate#canReadResponse in order to use
the most specific converter contract when possible.

Closes gh-33118
2024-07-01 15:05:57 +02:00
Brian Clozel 0717748f58 Merge branch '6.1.x' 2024-07-01 11:49:13 +02:00
Sam Brannen cc002875c4 Support fully-qualified factory method names in @⁠TestBean
Prior to this commit, @⁠TestBean factory methods had to be defined in
the test class, one of its superclasses, or in an implemented
interface. However, users may wish to define common factory methods in
external classes that can be shared easily across multiple test classes
simply by referencing an external method via a fully-qualified method
name.

To address that, this commit introduces support for referencing a
@⁠TestBean factory method via its fully-qualified method name following
the syntax <fully-qualified class name>#<method name>.

Closes gh-33125
2024-06-30 21:16:04 +02:00
Sam Brannen c2f8d4803f Update Javadoc for @⁠TestBean 2024-06-30 21:15:56 +02:00
Sam Brannen b105fdc87a Polishing 2024-06-30 14:41:43 +02:00
Sam Brannen b64edb2d2a Update Content-Type based on encoding in MVC FreeMarkerView
Closes gh-33119
2024-06-29 17:12:48 +02:00
Sam Brannen ce53443cf0 Polishing 2024-06-29 17:12:47 +02:00
Juergen Hoeller 775a23b39d Merge branch '6.1.x' 2024-06-28 18:10:53 +02:00
rstoyanchev acb427d460 Merge branch '6.1.x' 2024-06-28 15:35:13 +01:00
Juergen Hoeller c681614bc2 Merge branch '6.1.x' 2024-06-28 11:36:53 +02:00
Sam Brannen 3715df11de Merge branch '6.1.x' 2024-06-27 17:02:16 +02:00
Sam Brannen d902bd7696 Reject ModelMap argument types in WebFlux
Prior to this commit, if ModelMap was used as an argument type in a
WebFlux controller method, the user encountered an exception similar to
the following.

java.lang.IllegalStateException: argument type mismatch
  Controller [example.SampleController]
  Method [java.lang.String example.SampleController.index(org.springframework.ui.ModelMap)] with argument values:
  [0] [type=org.springframework.validation.support.BindingAwareConcurrentModel] [value={}]

However, the above error message is a bit cryptic since the error
occurs while attempting to invoke the controller method with an
instance of BindingAwareConcurrentModel which is not compatible with
ModelMap. More importantly, this error message does not explicitly
convey to the user that a ModelMap is not supported.

This commit improve the diagnostics for the user in such scenarios by
rejecting the use of ModelMap upfront in WebFlux.

Consequently, for the same use case as above, the user now encounters
an exception similar to the following.

java.lang.IllegalStateException:
  Could not resolve parameter [0] in
  java.lang.String example.SampleController.index(org.springframework.ui.ModelMap):
  No suitable resolver

Closes gh-33109
2024-06-27 16:16:48 +02:00
Juergen Hoeller 053af5f75b Merge branch '6.1.x' 2024-06-27 12:04:59 +02:00
Sam Brannen e1567b93c2 Merge branch '6.1.x' 2024-06-27 11:40:16 +02:00
Sam Brannen 8b95697c8d Set output_encoding in FreeMarkerView implementations
According to the official FreeMarker documentation, Spring's
FreeMarkerView implementations should be configuring the
output_encoding for template rendering.

To address that, this commit modifies the FreeMarkerView
implementations in Web MVC and WebFlux to explicitly set the
output_encoding for template rendering.

See https://freemarker.apache.org/docs/pgui_misc_charset.html#autoid_53
See gh-33071
Closes gh-33106
2024-06-27 10:07:47 +02:00
Sam Brannen 95887c81b9 Polish naming for Charset setters in FreeMarker support
See gh-33102
2024-06-26 17:51:11 +02:00
Sam Brannen 08112963a2 Merge branch '6.1.x' 2024-06-26 16:45:34 +02:00
Sam Brannen 73c0783df1 Allow encoding to be set with a Charset in FreeMarker support
Closes gh-33102
2024-06-26 16:18:09 +02:00
rstoyanchev 4e13a69948 Fix spring-websocket test failure after 6c2f60
See gh-32813
2024-06-26 09:31:08 +01:00
Brian Clozel 7f9e541f58 Merge branch '6.1.x' 2024-06-25 21:19:27 +02:00
Sam Brannen 7183a19dbe Merge branch '6.1.x' 2024-06-25 16:58:45 +02:00
rstoyanchev 6c2f602369 Propagate context to send for SSE Flux
Closes gh-32813
2024-06-25 15:39:43 +01:00
rstoyanchev c1250b1898 Replace use of deprecated ContextSnapshot methods
See gh-32813
2024-06-25 15:39:43 +01:00
Stephane Nicoll 0ea7af7465 Polish
See gh-31331
2024-06-24 18:07:59 +02:00
Sébastien Deleuze 8ef74dfdad Prevent compilation warnings with @Nullable
This commit replaces `@Nonnull(when = When.MAYBE)` meta-annotation in
org.springframework.lang.Nullable by `@CheckForNull` in order to
prevent "unknown enum constant When.MAYBE" compilation warnings.

IntelliJ IDEA 2024.1.2+ is required to interpret correctly the related
annotations.

Closes gh-27183
2024-06-24 14:56:07 +02:00
Juergen Hoeller 0a0f4c7460 Accept file separator difference in exception message (for Windows compatibility) 2024-06-24 12:28:43 +02:00
Juergen Hoeller d9a2e0b731 Merge branch '6.1.x' 2024-06-24 12:27:23 +02:00
rstoyanchev 6e82bf05b6 Document list/map/array constructor data binding
Closes gh-32426
2024-06-24 11:25:22 +01:00
rstoyanchev e48cbc5ba8 Support list/map/array constructor data binding
See gh-32426
2024-06-24 10:44:32 +01:00
Brian Clozel f9af5d400d Use custom path separator for pattern comparisons
As pointed out in gh-33085, the `AntPatternComparator` hardcodes the "/"
separator when checking for "catch all" patterns like "/**".
This commit ensures that the custom path separator is used for those
checks, in order to guarantee consistent comparator results.

See gh-33085
2024-06-24 11:37:24 +02:00
Brian Clozel 6d1f117103 Polishing contribution
Closes gh-33085
2024-06-24 11:37:16 +02:00
tafjwr 83fcdfba64 Fix AntPathMatcher URI template variable extractor
See gh-33085
2024-06-24 11:37:09 +02:00
Sam Brannen 9b58e1ff71 Merge branch '6.1.x' 2024-06-23 17:44:47 +02:00
Stephane Nicoll 2650da2b53 Provide more control over registration of GeneratedFiles
This commit provides an advanced handling of generated files that
provides more control over files registration. The callback provides
a FileHandler that can determine if the file already exists and its
content. The caller can then chose to override the content or leave it
as it is.

Closes gh-31331
2024-06-22 18:52:33 +02:00
Sam Brannen e6b77d301d Merge branch '6.1.x' 2024-06-22 16:52:42 +02:00
Stéphane Nicoll b134f253b5 Move the testing section after data and web
Closes gh-33083
2024-06-21 14:35:33 +02:00
Stéphane Nicoll 043b93d255 Upgrade to HtmlUnit 4.2.0
Closes gh-33081
2024-06-21 14:30:02 +02:00
Stéphane Nicoll 6e87aba100 Merge branch '6.1.x' 2024-06-21 14:14:26 +02:00
Stéphane Nicoll d43dba63a1 Document AssertJ support for MockMvc
This commit restructures the section on MockMvc so that the anchors
are easier to read. The standard integration has moved to a
Hamcrest Integration section  at the same level as HtmlUnit Integration,
and a new AssertJ Integration section has been created.

Closes gh-32454
2024-06-21 12:51:35 +02:00
Juergen Hoeller 7d236e29bb Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
2024-06-21 11:23:37 +02:00
Juergen Hoeller 7fc2814a34 Merge branch '6.1.x' 2024-06-20 18:57:49 +02:00
Sam Brannen eeb9959cb9 Polishing 2024-06-20 17:13:48 +02:00
Stéphane Nicoll e5993d92c4 Merge branch '6.1.x' 2024-06-20 14:16:13 +02:00
Juergen Hoeller 52e1f30bfe Merge branch '6.1.x' 2024-06-20 13:48:55 +02:00
Brian Clozel e3048bce11 Merge branch '6.1.x' 2024-06-19 18:15:55 +02:00
Stéphane Nicoll 5cf8978d22 Restore proper code generation for types with nested generics
This commit aligns code generation to recent improvement in the core
container regarding type detection. Now that nested types are properly
resolved, our code generation that uses hasResolvableGenerics() is
taking the wrong decision if only a nested type has an unresolved
generics. Previously, this was hidden by the fact that the core
container would not resolve them recursively.

A new hasResolvableGenerics() method allows to verify that at least
one direct generic type is resolved. This restore our intent of checking
at the first level only and let recursive invocations figure out if they
have to write the raw type or the type with generics.

Closes gh-33069
2024-06-19 17:48:39 +02:00
Juergen Hoeller 1047e1f722 Declare complete set of default methods on ObjectProvider
Closes gh-33070
2024-06-19 16:53:10 +02:00
Brian Clozel 4cbaaa3b1d Move Servlet HTTP Message Conversion to its own section
Closes gh-33063
2024-06-19 15:45:16 +02:00
Arjen Poutsma e62255512a Encode based on response character encoding
Before this commit, characters were always encoded with the default
encoding (i.e. ISO-8859-1). Now, the character encoding of the response
is used.

Closes gh-files
2024-06-19 14:26:38 +02:00
Brian Clozel c72e31bcf5 Merge branch '6.1.x' 2024-06-19 12:51:23 +02:00
Sam Brannen ce49354400 Sync MockHttpServletResponse implementations
See gh-33019
2024-06-19 12:31:17 +02:00
Sébastien Deleuze 1d363e5a41 Use UTF-8 with JSON in MockHttpServletResponse
This commit makes MockHttpServletResponse consistent with the other
parts of the framework where the body of a response is read as an UTF-8
String when the content type is application/json or similar, overriding
the ISO-8859-1 default Servlet encoding.

Closes gh-33019
2024-06-19 09:33:43 +02:00
Brian Clozel 2116d71d81 Merge branch '6.1.x' 2024-06-18 19:28:05 +02:00
Juergen Hoeller 82af8e62c1 Merge branch '6.1.x' 2024-06-18 18:32:29 +02:00
Sam Brannen d7668eec00 Merge branch '6.1.x' 2024-06-18 16:45:28 +02:00
Stéphane Nicoll 1eaa9cd2f4 Polish 2024-06-18 16:04:19 +02:00
Brian Clozel 17abb4d25d Add codecs for JSON support with Protobuf
Prior to this commit, WebFlux had Protobuf codecs for managing the
`Message`/`"application/x-protobuf"` encoding and decoding.
The `com.google.protobuf:protobuf-java-util` library has additional
support for JSON (de)serialization, but this is not supported by
existing codecs.

This commit adds the new `ProtobufJsonEncode` and `ProtobufJsonDecoder`
classes that support this use case. Note, the `ProtobufJsonDecoder` has
a significant limitation: it cannot decode JSON arrays as
`Flux<Message>` because there is no available non-blocking parser able
to tokenize JSON arrays into streams of `Databuffer`. Instead,
applications should decode to `Mono<List<Message>>` which causes
additional buffering but is properly supported.

Closes gh-25457
2024-06-18 15:48:46 +02:00
Stéphane Nicoll 24bbc6d80d Improve support of async request in MockMvcTester
This commit improves the handling of asynchronous requests by offering
a way to opt-in for the raw async result. This provides first class
support for asserting a request that might still be in process as well
as the asyncResult, if necessary.

See gh-33040
2024-06-18 15:19:47 +02:00
Stéphane Nicoll a7503e7200 Add explicit support for asynchronous requests in MockMvcTester
This commit makes asynchronous requests first class by providing a
MvcTestResult that represents the final, completed, state of a request
by default. Previously, the result was an intermediate step that may
require an ASYNC dispatch to be fully usable. Now it is de facto
immutable.

To make things a bit more explicit, an `.exchange(Duration)` method has
been added to provide a dedicated time to wait. The default applies a
default timeout that is consistent with what MVcResult#getAsyncResult
does.

Given that we apply the ASYNC dispatch automatically, the intermediate
response is no longer available by default. As a result, the asyncResult
is not available for assertions.

As always, it is possible to use plain MockMvc by using the `perform`
method that takes the regular RequestBuilder as an input. When this
method is invoked, no asynchronous handling is done.

Closes gh-33040
2024-06-18 13:03:09 +02:00
Stéphane Nicoll a1b0099795 Add missing debug(Writer) alternative
See gh-33059
2024-06-18 12:40:29 +02:00
Arjen Poutsma 54c37ffd6f Check response code in SimpleClientHttpResponse::getBody
The error stream can be null with an empty body, so check the response
code instead.

Closes gh-33020
2024-06-18 12:33:56 +02:00
Stéphane Nicoll acf73404c1 Simplify Mock[Multipart]HttpServletRequestBuilder
This commit simplifies the package private constructors on those two
builders now that the URI can be specified by dedicated builder methods.

Closes gh-33062
2024-06-18 10:10:07 +02:00
Stéphane Nicoll d76f37c90b Add multipart support for MockMvcTester
File uploads with MockMvc require a separate
MockHttpServletRequestBuilder implementation. This commit applies the
same change to support AssertJ on this builder, but for the multipart
version.

Any request builder can now use `multipart()` to "down cast" to a
dedicated multipart request builder that contains the settings
configured thus far.

Closes gh-33027
2024-06-18 09:43:08 +02:00
Stéphane Nicoll f2137c99e5 Add debug support for MvcResult
This commit adds a debug() shortcut to print the detail of a MvcResult
to ease debugging when a request did not work as expected.

Closes gh-33059
2024-06-18 06:43:26 +02:00
Stéphane Nicoll 84bcb65dd1 Streamline assertions on exceptions
This commit simplifies assertions on MockMvc requests that have failed
to process. A now general hasFailed/doesNotHaveFailed/failure provides
the necessary to assert the exception.

Any attempt to access anything from the result with an unresolved
exception still fails as before.

Closes gh-33060
2024-06-18 06:23:13 +02:00
Juergen Hoeller 6561490fd9 Expose isClosed() method on AbstractApplicationContext
Closes gh-33058
2024-06-17 21:08:28 +02:00
Juergen Hoeller 5c68f3f4ef Reject @Bean method with method-level @Autowired declaration
Closes gh-33051
2024-06-17 21:08:21 +02:00
Juergen Hoeller a58e27eded Use CollectionFactory#newLinkedHashSet for method arguments
See gh-32291
2024-06-17 18:50:31 +02:00
Juergen Hoeller 6d5c312027 Merge branch '6.1.x' 2024-06-17 18:44:50 +02:00
Stéphane Nicoll 1582f5f7d1 Handle URI as candidate for a merge from a parent builder
Closes gh-33057
2024-06-17 17:06:10 +02:00
Stéphane Nicoll b8790077b9 Polish 2024-06-17 16:47:37 +02:00
Arjen Poutsma b65b3350be Merge branch '6.1.x' 2024-06-17 14:20:05 +02:00
Stéphane Nicoll e4c881be73 Merge branch '6.1.x' 2024-06-17 13:43:23 +02:00
Brian Clozel 7658a8064d Merge branch '6.1.x'
Closes gh-33049
2024-06-17 12:55:31 +02:00
Stéphane Nicoll 5edb4cb2c9 Merge branch '6.1.x' 2024-06-16 16:51:15 +02:00
Stéphane Nicoll e9d5d68628 Merge branch '6.1.x' 2024-06-16 09:59:21 +02:00
Juergen Hoeller 4b58626fa4 Merge branch '6.1.x' 2024-06-14 22:09:31 +02:00
Stéphane Nicoll 9db24d23ae Merge branch '6.1.x' 2024-06-14 19:56:08 +02:00
Stéphane Nicoll 4fac6a91c7 Merge branch '6.1.x' 2024-06-13 14:10:53 +02:00
Arjen Poutsma df01b013fa Merge branch '6.1.x' 2024-06-13 11:11:13 +02:00
Stéphane Nicoll 69c44dee99 Add support for conversion of the whole JSON document
Closes gh-33018
2024-06-13 00:12:33 +02:00
Johnny Lim f3d390a95f Fix package description for org.springframework.validation.annotation
See gh-32532
2024-06-12 17:45:32 +02:00
Juergen Hoeller b196167f19 Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-06-12 14:28:53 +02:00
Juergen Hoeller 8b8604db73 Align after merge from 6.1.x 2024-06-12 13:34:53 +02:00
Juergen Hoeller 4bb755e2d2 Merge branch '6.1.x' 2024-06-12 13:31:38 +02:00
Juergen Hoeller 7a7f34f4ad Defensive access to volatile ScheduledFuture field
Includes defensive test arrangement for isInThePast() with at least 1 ms having passed.

See gh-24560
2024-06-12 13:01:58 +02:00
Arjen Poutsma 099d016857 Handle trailing semicolon in Accept-Language
Closes gh-32259
2024-06-12 12:28:26 +02:00
Stéphane Nicoll 1d0af7e5d3 Move TestBeanFactory to example package 2024-06-12 11:05:22 +02:00
Stéphane Nicoll 3f2d9c372d Migrate "Failing" test cases to regular tests
This commit replaces the use of EngineTestKit to test scenarios where
bean override could not process the test class. There is no need to
run an actual test for this as:

1. Regular integration tests are already validating that adding the
annotation triggers the processing as part of executing the test.
2. The entry point is a ContextCustomizer that can easily be invoked
in a regular test.

As part of harmonizing this, AbstractTestBeanIntegrationTestCase can
be nested, and BeanOverrideTestSuite serve no purpose. The tests can
be executed in an IDE without any special setup.
2024-06-12 11:03:14 +02:00
Stéphane Nicoll 1318f65223 Harmonize test class names
This commit harmonizes the class names of the bean override support by
using a consistent prefix for integration test, inspire from the one
that was used in Spring Boot
2024-06-12 08:54:24 +02:00
Stéphane Nicoll 2d48371c6d Revert polish on Bean Override support
This commit revers the removal of the `private` keyword in the examples
of the reference documentation and the tests for consistency. While the
default visibility makes the example more concise, it could imply to the
reader that the field (or the factory method) cannot be private.

Also, there is no need to multiply anything returned from `Objects.hash`
as its very distinct on its own already.
2024-06-12 08:11:18 +02:00
Brian Clozel dc2c8d6094 Add execution metadata to tasks and scheduled tasks
This commit adds new information about the execution and scheduling of
tasks.

The `Task` type now exposes the `TaskExecutionOutcome` of the latest
execution; this includes the instant the execution started, the
execution outcome and any thrown exception.

The `ScheduledTask` contract can now provide the time when the next
execution is scheduled.

Closes gh-24560
2024-06-11 19:34:41 +02:00
Sam Brannen 46dccd8f97 Polishing 2024-06-11 16:39:24 +02:00
Sam Brannen a4912dd5b1 Remove obsolete field
See gh-32992
2024-06-11 16:35:13 +02:00
Sam Brannen f35c39fe1e Clean up warnings in Gradle build 2024-06-11 16:32:14 +02:00
Sam Brannen f481a4b60b Polish reference documentation 2024-06-11 16:31:56 +02:00
Arjen Poutsma 60b5bbe334 Introduce request attributes in RestClient
This commit introduces request attributes in the RestClient and
underlying infrastructure (i.e. HttpRequest).

Closes gh-32027
2024-06-11 15:51:29 +02:00
Stéphane Nicoll c36e270481 Upgrade to Reactor 2024.0.0-M3
Closes gh-33006
2024-06-11 14:47:40 +02:00
Stéphane Nicoll a5432a82e9 Merge branch '6.1.x' 2024-06-11 14:46:32 +02:00
Stéphane Nicoll 89e894205a Improve exception message to include affected configuration class
Closes gh-32998
2024-06-11 14:24:28 +02:00
Brian Clozel a6fb7e99a0 Support for Protobuf 4.x
This commit compiles our Protobuf against 4.27, effectively raising our
baseline to 3.9+.

This commit also re-generates all the Java messages from the .proto spec
using the latest protoc binary.

Closes gh-33011
2024-06-11 14:12:55 +02:00
Stéphane Nicoll 2a680934ee Harmonize equals/hashCode of OverrideMetadata to use class identity
This commit harmonizes the equals/hashCode behavior of OverrideMetadata
to always take the implementation class as a factor for its identity.

This is important as two OverrideMetadata implementations could use
the same strategy and other settings while creating the override value
in a totally different way. This commit makes sure they are identified
as different.

Closes gh-33005
2024-06-11 12:03:31 +02:00
Stéphane Nicoll 1be92f82af Polish 2024-06-11 11:58:19 +02:00
Stéphane Nicoll 28f62abda4 Use the field name as a fallback qualifier for Bean Overriding
This commit harmonizes how a candidate bean definition is determined
for overriding using `@TestBean`, `@MockitoBean`, and `@MockitoSpyBean`.

Previously, a qualifier was necessary even if the name of the annotated
field matches the name of a candidate. After this commit, such candidate
will be picked up transparently, the same it is done for regular
autowiring.

This commit also reviews the documentation of the feature as considering
the field means that its name is taken into account to compute a cache
key if by-type lookup is requested.

Closes gh-32939
2024-06-11 11:30:01 +02:00
Sébastien Deleuze 4c7374797e Polishing
Closes gh-32931
2024-06-11 10:20:14 +02:00
Sébastien Deleuze 611367e4bb Add coroutine variant of WebExceptionHandler
See gh-32931
2024-06-11 10:09:17 +02:00
Juergen Hoeller 3d8488a7d8 Upgrade to Micrometer 1.13.1
Closes gh-33000
2024-06-11 09:13:42 +02:00
Juergen Hoeller e43e659983 Merge branch '6.1.x'
# Conflicts:
#	framework-docs/modules/ROOT/pages/core/beans/definition.adoc
#	framework-platform/framework-platform.gradle
#	spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java
2024-06-11 09:11:42 +02:00
Stéphane Nicoll 720b7c1dac Merge branch '6.1.x' 2024-06-11 06:53:22 +02:00
Sébastien Deleuze 68e6b152ef Merge branch '6.1.x' 2024-06-10 22:46:03 +02:00
Juergen Hoeller 42c17eb787 Documentation notes for @Bean overriding and bean name matching
See gh-31052
See gh-28122
2024-06-10 16:43:05 +02:00
Stéphane Nicoll b9a6ba1242 Fix package tangle in bean override tests
This commit fixes a package tangle between the root bean override
package and its sub-packages. This was vastly improved with the
introduction of `@DummyBean` but we still had a few tests that were
at the wrong place.
2024-06-10 15:23:36 +02:00
Stéphane Nicoll 96302a7102 Stop using a conventional suffix for TestBean factory methods
This commit changes how factory method for `@TestBean` usage is
discovered. Previously the field name or bean name suffixed with
'TestOverride' was used. It sounds more natural to just use the
field name or bean name, leaving cases where a suffix is required
to explicitly providing the method name.

As part of this change, the exception messages have been revisited as
it's less since the method name candidates have the exact same name
as the field or bean name. A `()` is added to make it more clear the
name is for a method.

Closes gh-32940
2024-06-10 12:52:21 +02:00
rstoyanchev 5787bc569d Merge branch '6.1.x' 2024-06-10 10:48:49 +01:00
Stéphane Nicoll 45e9f04b57 Remove TestOverrideMetadata and use dummy implementation
TestOverrideMetadata was doing byName lookup by default, even without
a bean name. This makes writing tests that need to do by type lookup
way more complicated that it should.

This commit introduces DummyBean, that merely replaces two types with
hardcoded values. It also exposes the raw attribute of OverrideMetadata
and doesn't override anything from it to make sure the behavior is not
altered.

Closes gh-32982
2024-06-10 11:27:27 +02:00
Juergen Hoeller 457bf9416c Configure individual timeouts for specific shutdown phases
Closes gh-32985
2024-06-10 11:00:47 +02:00
Stéphane Nicoll b7e4fa06c3 Merge branch '6.1.x' 2024-06-10 10:02:41 +02:00
Stéphane Nicoll 536de9ac80 Allow MockitoBean to create a mock for a bean that does not exist
This commit aligns the by-type lookup for bean overrides with what was
done when a bean name is present. It now correctly generate a bean
name rather than failing because no bean of that type exists.

Closes gh-32990
2024-06-10 09:57:27 +02:00
Brian Clozel bc98410acf Merge branch '6.1.x' 2024-06-10 09:47:57 +02:00
Carlos Corbacho e95e4423bb Do not swallow exceptions on failing to release a savepoint
By swallowing the exception on failing to release a savepoint, we are hiding
client code from database errors that they may need to be aware of or handle.

e.g. if the connection is now dead when trying to release the savepoint, by
swallowing the exception here, client code has no way of knowing this now until
the next operation on the database, which will yield a confusing message about
the problem and obscures where the failure occurred as it will be in a different
part of their code that throws any exception.

Swallowing the exception here is also inconsistent with all the other database
calls in the Transaction Object, where we always raise an exception up and let
client code decide how to handle the error.
2024-06-09 13:08:57 +02:00
Brian Clozel 24997b3356 Merge branch '6.1.x' 2024-06-07 19:02:53 +02:00
Sébastien Deleuze c39ce10619 Merge branch '6.1.x' 2024-06-07 18:42:10 +02:00
Stéphane Nicoll 373cf30b75 Polish 2024-06-07 17:11:38 +02:00
Stéphane Nicoll 55a7a49863 Merge pull request #32941 from m4tt30c91
* pr/32941:
  Polish contribution
  Add support for specifying a read timeout for the reactive jdk client

Closes gh-32941
2024-06-07 17:08:49 +02:00
Stéphane Nicoll 329b53309a Polish contribution
See gh-32941
2024-06-07 17:06:28 +02:00
Matteo Cristoforo 916ed5c0a9 Add support for specifying a read timeout for the reactive jdk client
See gh-32941
2024-06-07 17:01:23 +02:00
Stéphane Nicoll 7916f74942 Review TCF cache support for bean override
This commit reviews how bean override support can influence the key of
an application context cached by the TCF. OverrideMetadata and its
subclasses now implement a proper equals/hashCode pair that is tested
in various scenarios.

Due to how the TCF operates, OverrideMetadata has to be computed in
two locations:

1. In a ContextCustomizerFactory, using the metadata in the enclosing
class if any. This determines whether a customizer is needed in the
first place. The computed set of unique metadata identifies the
customizer and participates in the application context cache's key.
2. In the TestExecutionListener so that it knows the override points
it has to process.

Parsing of the metadata based on a test class has been greatly
simplified and moved to OverrideMetadata proper as we don't need several
flavors. 1 and 2 are using the same algorithm with the former wrapping
that in a Set to compute a proper key.

BeanOverrideContextCustomizerEqualityTests provides a framework for
testing edge cases as we only care about whether the created
ContextCustomizer behaves correctly against the identity of another.

Closes gh-32884
2024-06-07 16:44:57 +02:00
Stéphane Nicoll 02517e5011 Polish
This commit reviews the structure of several classes to comply with
our guidelines. Also, rather than exposing a static method to configure
the context in a test, we call the high-level API directly.
2024-06-07 16:44:57 +02:00
Stéphane Nicoll 0165529d97 Align OverrideMetadata arguments and harmonize bean name
Rather than having to override the getBeanName method when there is one,
this commit moves it as a @Nullable argument. This makes sure that
equals and hashCode consistently use the bean name. getBeanName cannot
be final just yet as the test infrastructure overrides it.

Also, arguments are now ordered consistently, which improves code
readability and type signature.
2024-06-07 16:44:57 +02:00
Stéphane Nicoll 8b66eca932 Harmonize OverrideMetadata implementations
This commit makes sure that each OverrideMetadata implementation is
a top level class with a consistent name.
2024-06-07 16:44:57 +02:00
Brian Clozel e8c122c00a Fix MockCookie Partitioned support
See gh-31454
2024-06-07 14:49:15 +02:00
Sam Brannen 9cfd455dde Merge branch '6.1.x' 2024-06-07 14:19:38 +02:00
Sébastien Deleuze 20d23584f6 Merge branch '6.1.x' 2024-06-07 13:45:19 +02:00
Sébastien Deleuze 8073f32ca6 Merge branch '6.1.x' 2024-06-07 13:36:39 +02:00
Sébastien Deleuze b442e0d3d5 Merge branch '6.1.x' 2024-06-07 11:44:36 +02:00
Arjen Poutsma 35e8f1c423 Support queries in opaque URLs
Closes gh-32920
2024-06-07 11:11:43 +02:00
Brian Clozel 7fc4937199 Add Partitioned cookie attribute support for servers
This commit adds support for the "Partitioned" cookie attribute in
WebFlux servers and the related testing infrastructure.
Note, Undertow does not support this feature at the moment.

Closes gh-31454
2024-06-07 10:03:52 +02:00
Juergen Hoeller 2aabe238c6 Merge branch '6.1.x'
# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java
2024-06-06 20:47:02 +02:00
Sébastien Deleuze 7b9cbd7876 Add support for Kotlin BeanPostProcessor beans
This commit adds support for Kotlin BeanPostProcessor beans which should
be defined in a companion object and annotated with `@JvmStatic`.

Closes gh-32946
2024-06-06 19:23:25 +02:00
Simon Baslé 0758ae5ead Polishing: remove unused import 2024-06-06 16:55:12 +02:00
Simon Baslé d38e4d869f Better support for FactoryBeans in BeanOverrideBeanFactoryPostProcessor
This commit makes sure to account for FactoryBean names when registering
a bean override. In the case of ReplaceDefinition mode, if there is a
factory bean name, it is used to check singleton status and as the name
in the registrar.

Closes gh-32971
2024-06-06 15:49:40 +02:00
Alexej Timonin 416eff1b04 Fix typo in WebTestClient expectedXml
Closes gh-32969
2024-06-06 14:24:40 +02:00
Brian Clozel 52af43d6d2 Handle ResponseStatusException thrown by MVC functional endpoints
Prior to this commit, exceptions thrown by MVC functional handlers would
not be considered by `ExceptionHandlerExceptionResolver`. This means
that common exceptions would not be handled consistently between
annotated and functional handlers. This is true, for example, for all
`ProblemDetails`-related exception handling.

While MVC functional and annotation models are separate concepts,
WebFlux has a different error handling model that processes all
exceptions in a central place.

This commit ensures that `ExceptionHandlerExceptionResolver` considers
exceptions thrown by handlers of type `HandlerFunction<?>` and processes
them accordingly.

Closes gh-32689
2024-06-06 14:21:17 +02:00
Arjen Poutsma 859b97ce05 Revert "Do not read Map in FormHttpMessageConverter"
This reverts commit 726ac9110c and
80faa94afc.

See gh-32826
2024-06-06 12:39:18 +02:00
Stéphane Nicoll c127421e38 Revert "Disable warnings for deprecated for removal in Eclipse"
We should not disable such warnings
2024-06-06 11:44:09 +02:00
Sébastien Deleuze d39fe9a444 Merge branch '6.1.x' 2024-06-06 10:06:24 +02:00
Juergen Hoeller 09c1081645 Merge branch '6.1.x' 2024-06-06 08:55:16 +02:00
Stéphane Nicoll 5706ee1762 Merge branch '6.1.x' 2024-06-06 08:08:47 +02:00
Brian Clozel 316e531c69 Merge branch '6.1.x' 2024-06-05 20:05:50 +02:00
Juergen Hoeller 3305485d1e Merge branch '6.1.x' 2024-06-05 16:33:44 +02:00
Sam Brannen 667b74b53f Return all events from EngineTestKitUtils.executeTestsForClass() 2024-06-05 16:29:11 +02:00
Sam Brannen 17e4c241c3 Avoid use of deprecated AssertJ APIs 2024-06-05 14:50:30 +02:00
Sam Brannen 43a60a7e3f Polishing 2024-06-05 14:50:01 +02:00
Sam Brannen 9e1ef83669 Avoid issues with system line separator in tests
See f10caf6aa6
2024-06-05 12:36:58 +02:00
rstoyanchev f4f89aa2a4 Add headers to data binding values
Closes gh-32676
2024-06-05 11:30:32 +01:00
rstoyanchev 23160a43dd Conditional use of URI vars for data binding in WebFlux
This commit aligns Spring WebFlux with WebMvc in adding URI variables
conditionally if not already in the map. The idea is that data
binding is primarily through form data and query params, with URI
variables, and request headers (to be implemented next) also made
available but without shadowing existing values.

See gh-32676
2024-06-05 11:30:32 +01:00
rstoyanchev 398aae2b9a Polishing in data binding tests
See gh-32676
2024-06-05 11:30:32 +01:00
Stéphane Nicoll 36b0702c0b Merge branch '6.1.x' 2024-06-05 10:45:06 +02:00
Juergen Hoeller a26d31ee3a Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-06-05 00:02:33 +02:00
Juergen Hoeller 017bf4534d Merge branch '6.1.x' 2024-06-04 23:00:46 +02:00
Juergen Hoeller 28eb9aebcf Add BeanFactoryInitializer callback before preInstantiateSingletons
Closes gh-32836
2024-06-04 22:50:42 +02:00
Juergen Hoeller f10caf6aa6 Compare text with system line separator (for Windows compatibility)
See gh-32756
2024-06-04 22:50:14 +02:00
Sam Brannen cf3171dae0 Find unique @⁠TestBean factory methods in class hierarchy
I accidentally introduced a regression in commit d185bb1d97 by no
longer checking the number of unique method names found when searching
for @⁠TestBean factory methods.

This commit reintroduces that check and introduces a proper unit test
in TestBeanOverrideProcessorTests.

It turns out that we already had an integration test that was intended
to check for this scenario; however, that test actually did not test
this scenario due to a copy-and-paste error. Thus, this commit also
updates TestBeanInheritanceIntegrationTests so that
fieldInSupertypeWithPrioritizedFactoryMethodInSubtype() tests what it's
supposed to.
2024-06-04 18:47:32 +02:00
Sam Brannen 069c6788f5 Polishing 2024-06-04 18:47:32 +02:00
Stéphane Nicoll aa4b226a22 Add support for converting json values using AssertFactory
This commit benefits from a feature introduced in AssertJ 3.26.0, see
https://github.com/assertj/assertj/pull/3377.

This allows to use any AssertFactory and convert the actual value to
the type the factory manages. Previously, we were using
ParameterizedTypeReference to express the type with its generic
signature but the returned assert object would not be narrowed to the
converted type.

Thanks to this change, we can request to convert the actual value to
`InstanceOfAssertFactories.list(Member.class)` and get a `ListAssert`
of `Member` as a result, rather than an `ObjectAssert` of `List<User>`.

Thanks very much to @scordio for his efforts.

Closes gh-32953
2024-06-04 17:11:08 +02:00
Sébastien Deleuze 6212831f5f Merge branch '6.1.x' 2024-06-04 16:47:36 +02:00
Stéphane Nicoll 5cd4b87bfa Merge branch '6.1.x' 2024-06-04 15:52:26 +02:00
Sam Brannen 4d961fa472 Find @⁠TestBean factory methods in multi-level @⁠Nested hierarchy
Prior to this commit, a @⁠TestBean factory method was found in the
directly enclosing class for a @⁠Nested test class; however, such a
factory method was not found in the enclosing class of the enclosing
class, etc.

This commit updates the search algorithm for @⁠TestBean factory methods
so that it recursively searches the enclosing class hierarchy for
@⁠Nested test classes.

Closes gh-32951
2024-06-04 15:36:40 +02:00
Sam Brannen f68130d2e5 Update Javadoc for @⁠TestBean support
See gh-32943
2024-06-04 15:12:06 +02:00
Stéphane Nicoll 42ace2c2c9 Provide dedicated AOT exception hierarchy
This commit adds a number of catch point that provides additional
context when an AOT processor fails to execute. Amongst other things,
this makes sure that the bean name and its descriptor is consistently
provided in the error message when available.

Closes gh-32777
2024-06-04 09:36:21 +02:00
Sébastien Deleuze f31113e325 Merge branch '6.1.x' 2024-06-03 18:58:33 +02:00
Sébastien Deleuze eefdf42e7e Merge branch '6.1.x' 2024-06-03 18:28:17 +02:00
Sam Brannen acdd8a0015 Improve exception handling in bean override support
- Do not silently abort bean override processing if the ApplicationContext
  is not a BeanDefinitionRegistry.

- Include conflicting bean names in error messages instead of just the
  number of conflicting beans.

- Consistently throw IllegalStateException.

- etc.
2024-06-03 16:57:19 +02:00
Sam Brannen 7a11899c0c Stop using deprecated ThemeChangeInterceptor in WebConfiguration example 2024-06-03 16:14:07 +02:00
Sam Brannen d185bb1d97 Support @⁠TestBean factory methods defined in interfaces
Prior to this commit, @⁠TestBean factory methods were required to be
defined in the test class or one of its superclasses. However, users
may wish to define common factory methods in interfaces that can be
shared easily across multiple test classes simply by implementing the
necessary interface(s).

This commit therefore switches from ReflectionUtils to
MethodIntrospector to find @⁠TestBean factory methods in implemented
interfaces within the type hierarchy of the test class.

Closes gh-32943
2024-06-03 16:04:46 +02:00
Stéphane Nicoll 6a761412a8 Simplify BeanRegistrationsAotProcessor
Closes gh-32944
2024-06-03 16:01:12 +02:00
Juergen Hoeller 34eccbe8e6 Remove final declaration from getMessageSource() and getLocale() methods
Includes checking the Servlet 3.0+ ServletRequest.getServletContext() method in the request-only constructors, being able to fall back to the root WebApplicationContext.

See gh-32926
2024-06-03 15:27:33 +02:00
Andre Blanke a582e48dd0 Use getMessageSource internally in RequestContext 2024-06-03 15:22:44 +02:00
Sam Brannen 9ceaf21d24 Extract findMethods() logic in TestBeanOverrideProcessor 2024-06-03 14:56:43 +02:00
Sam Brannen 1536f34fff Fix broken tests 2024-06-03 14:40:13 +02:00
Sam Brannen 8047a22237 Polish TestBeanOverrideProcessor 2024-06-03 13:29:50 +02:00
Juergen Hoeller f7e7d1b7b0 Merge branch '6.1.x' 2024-06-03 12:47:17 +02:00
Sam Brannen df238d08eb Polishing 2024-05-31 18:01:49 +02:00
Sam Brannen 742c41a568 Polishing 2024-05-31 16:18:31 +02:00
Sam Brannen 3a448701f7 Improve class names 2024-05-31 15:49:26 +02:00
Sam Brannen 967800a2f9 Merge branch '6.1.x' 2024-05-31 12:23:22 +02:00
Sam Brannen 87c93d35d6 Revise bean override tests with a focus on AOT support
As a follow up to the previous commit (31f8e12adb), this commit
polishes bean override tests and revises them with a focus on AOT
testing support and simplified maintenance.

- Introduce EngineTestKitUtils to simplify working with JUnit's
  EngineTestKit.

- Use idiomatic EngineTestKit APIs to simplify assertions on
  EngineTestKit results.

- Introduce BeanOverrideTestSuite to simplify running all bean override
  tests within the IDE.

- Separate failure and success scenario tests, so that failure tests do
  not launch the JUnit Platform to run tests using the Spring
  TestContext Framework (TCF) within a test class that itself uses the
  TCF.

- Make AbstractTestBeanIntegrationTestCase actually abstract.

- Rename test case classes to give them meaningful names and simplify
  understanding of what's being tested.

- Ensure tests for @⁠MockitoSpyBean functionality use @⁠MockitoSpyBean
  instead of @⁠MockitoBean.

- Declare @⁠Configuration classes local to @⁠SpringJUnitConfig test
  classes whenever possible.

See gh-29122
See gh-32925
2024-05-31 12:19:31 +02:00
Sam Brannen 31f8e12adb Separate failure and success scenario tests for @⁠TestBean
This commit also ensures that @⁠Bean methods are declared within
@⁠Configuration classes instead of within test classes.

See gh-29122
2024-05-29 14:21:58 +02:00
Sam Brannen 1f537b97d5 Demonstrate how to disable Bean Override tests in AOT mode
See gh-29122
2024-05-29 14:20:35 +02:00
Sam Brannen cade3c7b0e Ensure MockMvcTesterIntegrationTests runs in AOT mode
See gh-29122
2024-05-29 13:32:22 +02:00
Sam Brannen a0c9a204b8 Polishing 2024-05-29 13:32:02 +02:00
Juergen Hoeller 8f21137883 Merge branch '6.1.x' 2024-05-28 18:47:38 +02:00
Juergen Hoeller 5a275443b5 Apply ThreadLocal#remove() to pre-instantiation threads
See gh-13410
See gh-32874
2024-05-28 16:35:58 +02:00
Sam Brannen 27985b1439 Disable class data sharing (CDS) for tests
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.
2024-05-28 15:58:02 +02:00
Stéphane Nicoll bad4e18b4d Add support for building a request directly from MockMvcTester
Closes gh-32913'
2024-05-28 15:33:21 +02:00
Sam Brannen defb6b7a62 Polish documentation and implementation of SpEL's Indexer 2024-05-28 15:29:54 +02:00
Stéphane Nicoll 8d2bc3bdba Add support for fluent preparation of the request in MockMvcTester
See gh-32913
2024-05-28 15:29:14 +02:00
Stéphane Nicoll a3e7fd47c6 Allow MockHttpServletRequestBuilder to support AssertJ
This commit moves the features of MockHttpServletRequestBuilder in
an abstract class so that another class can offer the same feature
whilst providing AssertJ support. This wasn't possible previously as
the builder's return type would lose the concrete builder types.

This change benefits MockMultipartHttpServletRequestBuilder that can
use the same mechanism to offer additional settings.

This change also makes it so that a builder instance can be created
using only the HttpMethod. Previously, the URI had to be provided as
well and that makes it impossible to specify it using the builder.

See gh-32913
2024-05-28 15:29:14 +02:00
Arjen Poutsma 726ac9110c Do not read Map in FormHttpMessageConverter
This commit ensures that the FormHttpMessageConverter no longer supports
 reading Maps (just MultiValueMaps). Plain maps are often used to
 represent JSON.

See gh-32826
2024-05-28 15:25:08 +02:00
Stéphane Nicoll fc54cf4430 Harmonize use of uri in MockMvc
Closes gh-32915
2024-05-28 11:17:40 +02:00
Sam Brannen 54c07eddcc Merge branch '6.1.x' 2024-05-28 10:26:56 +02:00
Stéphane Nicoll 2d1e58b928 Polish 2024-05-28 09:31:44 +02:00
Stéphane Nicoll f6504c5f91 Deprecate use of raw String for HttpMethod in MockMvc
Closes gh-32914
2024-05-28 09:24:08 +02:00
Sam Brannen 8871d67298 Merge branch '6.1.x' 2024-05-27 17:13:01 +02:00
Marcus Hert Da Coregio 57fae7a59e Add update-antora-ui-spring.yml workflow 2024-05-27 16:56:13 +02:00
Sam Brannen b3cc603401 Avoid usage of deprecated AssertJ feature 2024-05-27 16:51:39 +02:00
Sam Brannen 870d15c0b6 Merge branch '6.1.x' 2024-05-27 16:44:19 +02:00
Brian Clozel 3b53165574 Expose WebSocketMessageBrokerStats contracts
Prior to this commit, the `WebSocketMessageBrokerStats` would be in
charge of periodically logging WebSocket stats. This class would also
publicly expose each stats type with dedicated methods, as `String`.
This would not allow observation libraries to easily extract information
and turn them into metrics.

This commit introduces new methods exposing the `Stats` types directly
and deprecates the former `String` variants. This will allow
observability libraries like Micrometer to expose this as metrics:

```
MeterRegistry meterRegistry = ...;

Gauge.builder("spring.stomp.frames", stats.getStompSubProtocolStats(),
      StompSubProtocolHandler.Stats::getTotalConnect)
  .tag("type", "CONNECT")
  .description("number of CONNECT frames processed")
  .register(meterRegistry);
```

Closes gh-31604
2024-05-27 16:06:32 +02:00
Brian Clozel e856e7e590 Add checkstyle rule for "@since" javadoc convention 2024-05-27 09:28:23 +02:00
Stéphane Nicoll e2c5887cea Allow JSON content assertions to be nested
Previously, AbstractJsonContentAssert worked on a raw String, which
made standard AssertJ nested calls, such as satisfies, to return an
assert on the raw string, rather than one with JSON support.

This commit rework AbstractJsonContentAssert so that it no longer
extend from AbstractStringAssert. This makes the list of methods more
focused on JSON assertions, and allow standard operations to provide
the right assert object.

Closes gh-32894
2024-05-27 09:25:12 +02:00
Sam Brannen 489d18a169 Merge branch '6.1.x' 2024-05-24 15:42:39 +02:00
Sam Brannen 7e3a4a12f8 Use consistent version strings for 6.2 2024-05-24 15:19:30 +02:00
Sam Brannen b82b83c8f0 Disable warnings for deprecated for removal in Eclipse 2024-05-24 14:30:56 +02:00
Sam Brannen 5d39598025 Disable warnings for unclosed @⁠AutoCloseable in Eclipse 2024-05-24 14:15:25 +02:00
Sam Brannen 159c2cd7c6 Remove obsolete code 2024-05-24 14:14:43 +02:00
Sam Brannen dac18a3ff1 Clean up warnings in Gradle build 2024-05-24 13:39:56 +02:00
Sam Brannen 77f7da01e4 Polishing 2024-05-24 13:39:56 +02:00
Sam Brannen e999f4e47d Sync changes to MockHttpServletRequest 2024-05-24 13:39:55 +02:00
Sam Brannen e3c268ef18 Fix formatting 2024-05-24 13:39:55 +02:00
Juergen Hoeller 49caa02584 Merge branch '6.1.x' 2024-05-24 13:06:21 +02:00
Juergen Hoeller dae4366325 Merge branch '6.1.x' 2024-05-24 11:55:53 +02:00
Arjen Poutsma 903493e9a9 Various MultiValueMap improvements
This commit makes several improvements to MultiValueMap:
- asSingleValueMap offers a single-value view (as opposed to the
  existing toSingleValueMap, which offers a copy)
- fromSingleValue is a static method that adapts a Map<?,?> to the
  MultiValueMap interface
- fromMultiValue is a static method that adapts a Map<?,List<?>> to the
  MultiValueMap interface

Closes gh-32832
2024-05-24 11:44:55 +02:00
Stéphane Nicoll 97647ef5f6 Flag tests using deprecated json method deprecated
See gh-32791
2024-05-24 11:03:33 +02:00
Juergen Hoeller 0110c5ac82 Merge branch '6.1.x' 2024-05-23 17:08:22 +02:00
Juergen Hoeller 35278d09ac Polishing 2024-05-23 16:34:24 +02:00
Stéphane Nicoll 975e2f4218 Revert "Avoid deprecation warnings for WebJarsResourceResolver"
This reverts commit 61db499ae2.
2024-05-23 16:21:42 +02:00
Stéphane Nicoll 0ac7e41beb Provide an implementation of JsonComparator
See gh-32791
2024-05-23 16:17:02 +02:00
Sébastien Deleuze f62275d674 Merge branch '6.1.x' 2024-05-23 16:05:54 +02:00
Brian Clozel 51f6e78e25 Fall back on */* during content negotiation for errors
Prior to this commit, gh-31936 enabled content negotiation for
`@ExceptionHandler` annotated methods in Spring MVC and WebFlux.
In the case of WebFlux, HTTP clients sending invalid media types in the
"Accept" request header would fail with a `NotAcceptableStatusException`
This exception would be handled with an HTTP 406 response status,
instead of processing the original exception.

This commit ensures that invalid media types are ignored during the
exception handling phase and that we fall back to "*/*".

Fixes gh-32878
2024-05-23 13:57:02 +02:00
Stéphane Nicoll 94348d9d41 Revert "Merge pull request #32876 from quaff"
This reverts commit 3b2a4da023, reversing
changes made to 181b68088a.

See gh-32876
2024-05-23 13:13:02 +02:00
Phillip Webb d8dcd3af0b Introduce JSON comparison abstraction for tests
This commit introduces a JsonComparator abstraction, with an
implementation using JSONAssert. Previously, JSONAssert was the only
choice.

Test APIs have been adapted to allow the new abstraction while relying
on JSONAssert still for high-level methods.

Closes gh-32791

Co-authored-by: Stéphane Nicoll <stephane.nicoll@broadcom.com>
2024-05-23 12:32:39 +02:00
Arjen Poutsma 80faa94afc Support Map in FormHttpMessageConverter
This commit changes the FormHttpMessageConverter from a
HttpMessageConverter<MultiValueMap<String, ?>> to a
HttpMessageConverter<Map<String, ?>>, so that normal, single-value maps
can also be used as form representation, both for reading and writing.

Closes gh-32826
2024-05-23 10:33:49 +02:00
Arjen Poutsma 67d2b2566e Revert "WIP"
This reverts commit c09b0f57631905a7b9cca32be5516853e4263ac0.
2024-05-23 10:33:49 +02:00
Arjen Poutsma 14861024d5 WIP 2024-05-23 10:33:49 +02:00
Stéphane Nicoll fa275f908e Polish 2024-05-23 08:49:03 +02:00
Stéphane Nicoll 3b2a4da023 Merge pull request #32876 from quaff
* pr/32876:
  Polish "Extend nested placeholders resolution to any CharSequence"
  Extend nested placeholders resolution to any CharSequence

Closes gh-32876
2024-05-23 08:41:59 +02:00
Stéphane Nicoll 79b5ee75d3 Polish "Extend nested placeholders resolution to any CharSequence"
See gh-32876
2024-05-23 08:36:34 +02:00
Yanming Zhou 5a7bfa9dec Extend nested placeholders resolution to any CharSequence
See gh-32876
2024-05-23 08:36:15 +02:00
Stéphane Nicoll 181b68088a Merge branch '6.1.x' 2024-05-23 08:14:59 +02:00
rstoyanchev 39320b904e Merge branch '6.1.x' 2024-05-22 17:16:18 +01:00
rstoyanchev 1ddc84862e Improve docs on controller method validation
Closes gh-32807
2024-05-22 17:12:09 +01:00
Sam Brannen 48e7908eff Polishing 2024-05-22 15:57:41 +02:00
Sam Brannen 61db499ae2 Avoid deprecation warnings for WebJarsResourceResolver 2024-05-22 15:57:41 +02:00
Juergen Hoeller 2170db6996 Skip expression resolution in getShadowMatch (aligned with 6.1.x)
See gh-32793
See gh-32838
2024-05-22 15:39:36 +02:00
Sam Brannen bc291949c2 Polishing 2024-05-22 15:09:54 +02:00
Stéphane Nicoll 1bc71824ea Merge branch '6.1.x' 2024-05-22 14:46:33 +02:00
Sam Brannen b47cdaa259 Lazily register DynamicValuesPropertySource in the TestContext framework
Prior to this commit, as a result of commit 6cdb34410b, the
DynamicValuesPropertySource was eagerly registered in the Environment
even if the DynamicPropertyRegistry was never used to register dynamic
properties.

This commit ensures that the DynamicValuesPropertySource is only
registered if we know that the DynamicPropertyRegistry is actually used
-- either by a @⁠DynamicPropertySource method in a test class or via a
bean in the ApplicationContext that invokes add() on the
DynamicPropertyRegistry bean.

See gh-32271
Closes gh-32871
2024-05-22 14:25:19 +02:00
Sébastien Deleuze c9a6b7f01e Merge branch '6.1.x' 2024-05-22 10:32:05 +02:00
Juergen Hoeller e4f35ebcc5 Merge branch '6.1.x' 2024-05-22 10:01:30 +02:00
Brian Clozel 1bd6b30ddd Allow ServerHttpObservationFilter to be extended
This commit allows to extend  the `ServerHttpObservationFilter` when the
observation scope is opened. This typically allows to add the current
traceId as a response header.

Closes gh-30632
2024-05-21 20:01:17 +02:00
Juergen Hoeller 559fec052f Merge branch '6.1.x' 2024-05-21 19:22:55 +02:00
Juergen Hoeller 0e5e81e7ef Merge branch '6.1.x' 2024-05-21 17:39:59 +02:00
rstoyanchev 8c9b6e2205 Use default phase 0 for WebSocket messaging
Closes gh-27519
2024-05-21 15:49:38 +01:00
Simon Baslé d5c7a5e2db Bean overriding by type uses isAutowireCandidate for matching
This commit uses the bean factory `isAutowiredCandidate` method directly
in `BeanOverrideBeanFactoryPostProcessor` to select a single match among
multiple candidates when matching by type.

The expected consequence, in most cases, is that this will delegate to
a `@Qualifier`-aware `QualifierAnnotationAutowireCandidateResolver`.
In that sense, bean overriding by-type matching is now potentially
taking Qualifier annotations or meta-annotations into account.

It also changes the way existing bean definitions are checked in case
a bean name has been specified: factory beans are now taken into account
when checking the type of an existing definition matches the expected
bean override type.

Closes gh-32822
2024-05-21 14:06:52 +02:00
Simon Baslé b17d1c5124 Polishing BeanOverrideBeanFactoryPostProcessor to also copy isFallback 2024-05-21 14:06:52 +02:00
Juergen Hoeller 6f6e25bd5b Merge branch '6.1.x' 2024-05-21 11:17:16 +02:00
Stéphane Nicoll ddf5521bc9 Merge branch '6.1.x' 2024-05-21 08:56:41 +02:00
Brian Clozel 4d4b343815 Support Content Negotiation with @ExceptionHandler
Prior to this commit, `@ExceptionHandler` annotated controller methods
could be mapped using the exception type declaration as an annotation
attribute, or as a method parameter.
While such methods support a wide variety of method arguments and return
types, it was not possible to declare the same exception type on
different methods (in the same controller/controller advice).

This commit adds a new `produces` attribute on `@ExceptionHandler`; with
that, applications can vary the HTTP response depending on the exception
type and the requested content-type by the client:

```
@ExceptionHandler(produces = "application/json")
public ResponseEntity<ErrorMessage> handleJson(IllegalArgumentException exc) {
	return ResponseEntity.badRequest().body(new ErrorMessage(exc.getMessage(), 42));
}

@ExceptionHandler(produces = "text/html")
public String handle(IllegalArgumentException exc, Model model) {
	model.addAttribute("error", new ErrorMessage(exc.getMessage(), 42));
	return "errorView";
}
```

This commit implements support in both Spring MVC and Spring WebFlux.

Closes gh-31936
2024-05-20 17:22:30 +02:00
Stéphane Nicoll 991be14847 Merge branch '6.1.x' 2024-05-20 13:58:44 +02:00
Stéphane Nicoll 99adc58ee3 Merge branch '6.1.x' 2024-05-20 13:58:09 +02:00
Stéphane Nicoll f2605fd9e5 Avoid reader on empty content to be shared by multiple requests
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
2024-05-20 13:32:04 +02:00
Stéphane Nicoll 4bbfd4c5e7 Add convenient request/response accessors on MvcTestResult
Closes gh-32846
2024-05-20 11:19:12 +02:00
Sébastien Deleuze 268043a28c Merge branch '6.1.x' 2024-05-20 10:24:42 +02:00
Juergen Hoeller f0c6fab39e Merge branch '6.1.x'
# Conflicts:
#	gradle.properties
#	spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java
2024-05-17 12:30:39 +02:00
Sam Brannen 93387e69b5 Polishing 2024-05-16 16:47:02 +02:00
Juergen Hoeller 28398624bf Avoid cyclic package import for javadoc reference 2024-05-15 22:19:20 +02:00
rstoyanchev da3b59e7a9 Merge branch '6.1.x' 2024-05-15 20:07:13 +01:00
rstoyanchev edb6bb717d Add UrlHandlerFilter
Closes gh-31366
2024-05-15 18:45:07 +01:00
rstoyanchev 48ad7b1bcd Remove unused code in WebHttpHandlerBuilder
The code was necessary while ForwardedHeaderFilter was deprecated
but still possible to use. When the filter was removed, this code
could have been removed as well.
2024-05-15 18:45:07 +01:00
SharadK10 a3b62a80bc Improve wording in Spring Framework Overview documentation
Closes gh-32829
2024-05-15 19:00:27 +02:00
Sam Brannen 6cdb34410b Register DynamicPropertyRegistry as singleton bean in test ApplicationContext
Prior to this commit, DynamicPropertyRegistry could only be used with a
static @⁠DynamicPropertySource method in an integration test class;
however, it can also be useful to be able to register a "dynamic
property" from within a test's ApplicationContext -- for example, in a
@⁠Bean method in a @⁠Configuration class that is specific to testing
scenarios.

To support such use cases, this commit updates the dynamic property
source infrastructure so that a DynamicPropertyRegistry is always
registered as a singleton bean in a test's ApplicationContext. This
allows DynamicPropertyRegistry to be autowired into a @⁠Configuration
class or supplied to a @⁠Bean method as an argument as shown in the
following example.

@⁠Bean
@⁠DynamicPropertySource
ApiServer apiServer(DynamicPropertyRegistry registry) {
	ApiServer apiServer = new ApiServer();
	registry.add("api.url", apiServer::getUrl);
	return apiServer;
}

Note that the use of @⁠DynamicPropertySource on the @⁠Bean method is
optional and results in the corresponding bean being eagerly
initialized so that other singleton beans in the context can be given
access to the dynamic properties sourced from that bean when those
other beans are initialized.

Side note: DynamicPropertySourceBeanInitializer temporarily implements
LoadTimeWeaverAware since doing so is currently the only way to have a
component eagerly initialized before the
ConfigurableListableBeanFactory.preInstantiateSingletons() phase.
However, we plan to introduce a first-class callback to support such
use cases in the future.

Closes gh-32271
2024-05-15 17:09:03 +02:00
Juergen Hoeller 7d8279afec Merge branch '6.1.x' 2024-05-15 14:16:51 +02:00
Sam Brannen d625b3de27 Document SpEL IndexAccessor support in the reference manual
Closes gh-32735
2024-05-15 11:47:42 +02:00
Simon Baslé 531da015e1 Improve MediaTypeAssert to-string-equality assertions
This commit introduces a `isNotEqualTo(String)` assertion in order to
avoid false negatives when using the default Object-based assertion.

This is a risk since MediaTypeAssert has a `isEqualTo(String)` method
that overrides the base object method and parses the provided String
into a MediaType. Users may thus be tempted to use the reverse assertion
and expect the same parsing behaviour.

This commit also adds tests around the String parsing and the isNotEqual
cases.

Closes gh-32756
2024-05-15 11:14:13 +02:00
Juergen Hoeller 60c5f44e1d Upgrade reactor.util.annotation content
See gh-32785
2024-05-14 22:59:43 +02:00
Juergen Hoeller c69ab069b7 Upgrade to Reactor 2024.0.0-M2
Closes gh-32785
2024-05-14 22:03:38 +02:00
Juergen Hoeller 7c534eeeeb Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-05-14 22:02:32 +02:00
Sam Brannen 716e7de841 Simplify implementation of SpelNodeImpl.loadClassForExitDescriptor(...) 2024-05-14 17:58:05 +02:00
Brian Clozel f7a6a7b814 Allow ReflectionHints to register hints on interface hierarchies
This commit promotes a previously private method in
`BeanRegistrationsAotContribution` to a top-level method in
`ReflectionHints`.

This helps to register hints on all interfaces implemented in the class
hierarchy of the given type.

Closes gh-32824
2024-05-14 17:54:12 +02:00
Simon Baslé a86612a254 Use by-type semantics in bean overriding if no explicit name is provided
This change switches default behavior of `@TestBean`, `@MockitoBean` and
`@MockitoSpyBean` to match the bean definition / bean to override by
type in the case there is no explicit bean name provided via the
annotation. The previous behavior of using the annotated field's name
is still an option for implementors, but no longer the default.

Closes gh-32761
2024-05-14 16:42:11 +02:00
Sam Brannen fc07946e60 Polishing 2024-05-14 15:03:25 +02:00
Sam Brannen 061c13d367 Support compilation of varargs invocations in SpEL for array subtypes
This commit merges support for compiling SpEL expressions that contain
varargs invocations where the supplied array is a subtype of the
declared varargs array type.

Closes gh-32804
2024-05-14 14:13:46 +02:00
Sam Brannen 8fe4493a7d Revise compilation support in SpEL for varargs array subtypes
This commit first reverts changes to SpelNodeImpl from the previous
commit in order to reduce the scope of the overall change set.

This commit then implements a different approach to support type-safe
checks for array subtype compatibility.

In order to support backward compatibility, this commit also
reintroduces generateCodeForArguments(MethodVisitor, CodeFlow, Member,
SpelNodeImpl[]) in deprecated form.

See gh-32804
2024-05-14 14:09:35 +02:00
Mikaël Francoeur 12727a2c4f Support compilation of varargs invocations in SpEL for array subtypes
This commit introduces support for compiling SpEL expressions that
contain varargs invocations where the supplied array is a subtype of
the declared varargs array type.

See gh-32804
2024-05-14 14:09:35 +02:00
Sam Brannen 29bb7b907c Polish SpelCompilationCoverageTests
See gh-32804

Co-authored-by: Mikaël Francoeur <mikael.francoeur@ticketmaster.com>
2024-05-14 14:09:34 +02:00
Juergen Hoeller 9516f87e5e Merge branch '6.1.x' 2024-05-14 13:48:01 +02:00
evan-mc 376d7839e0 Align StandaloneMockMvcBuilder with trailing slash defaults
Prior to this commit, trailing slash matching was disabled by default in
Spring MVC with gh-28552. `StandaloneMockMvcBuilder` was not changed as
a result and still had the trailing slash match option enabled.

This commit aligns the defaults in `StandaloneMockMvcBuilder` to better
reflect the expected behavior in tests.

Closes gh-32796
2024-05-14 09:15:56 +02:00
Brian Clozel ec4f3ea6d0 Merge branch '6.1.x'
Closes gh-32811
2024-05-13 21:26:56 +02:00
Brian Clozel cd56b47302 Merge branch '6.1.x' 2024-05-13 21:19:21 +02:00
mysend12 3547491590 Handle DataBufferLimitException as HTTP 413 responses
Prior to this commit, `DataBufferLimitException` would be thrown by
codecs when the request body was too large for the configured buffer
limit. This exception would not be handled by the web infrastructure and
would result in an HTTP 500 server error.

This commit introduces a new `PayloadTooLargeException` type that will
result in an HTTP 413 "Payload too large" response status.

Closes gh-32558
2024-05-13 14:07:21 +02:00
Brian Clozel 80ec951fcf Merge branch '6.1.x' 2024-05-13 13:15:01 +02:00
rstoyanchev 10e3d3b434 Merge branch '6.1.x' 2024-05-13 11:41:22 +01:00
rstoyanchev 2c9ed4608f Improve RequestAttributesThreadLocalAccessor
Ensure access to request attributes after initial REQUEST dispatch
is done, and the RequestAttributes markedCompleted.

Closes gh-32296
2024-05-13 11:41:07 +01:00
rstoyanchev 3ada9a0c79 Polishing in tests of ThreadLocalAccessor implementations
See gh-32296
2024-05-13 11:41:07 +01:00
Brian Clozel 5cb4985234 Merge branch '6.1.x' 2024-05-13 10:44:09 +02:00
Sam Brannen 19792f9670 Merge branch '6.1.x' 2024-05-12 12:32:20 +02:00
Sam Brannen f629fc9dc5 Polish Javadoc for SmartInstantiationAwareBeanPostProcessor 2024-05-11 16:13:26 +02:00
Sam Brannen 589b6dbba0 Merge branch '6.1.x' 2024-05-11 16:01:31 +02:00
Juergen Hoeller b3005fcdde Merge branch '6.1.x' 2024-05-10 13:53:04 +02:00
Juergen Hoeller b2d43f54e0 Merge branch '6.1.x' 2024-05-10 12:29:49 +02:00
earlgrey02 797f586f9a Polish RouterFunctionDsl
Place the lambda outside the method call.

Closes gh-32765
2024-05-10 12:15:22 +02:00
Sébastien Deleuze 8ac39d0062 Polishing 2024-05-10 11:57:42 +02:00
Sébastien Deleuze 7985ab33f4 Throw an exception for suspending factory methods
Suspending factory methods are not supported, and can
have side effects, so it is better to fail explicitly
for such use case.

Closes gh-32719
2024-05-10 11:56:50 +02:00
Yanming Zhou a02861f7db Insist on using CollectionUtils.isEmpty() and StringUtils.hasLength()
search `(\w+) != null && !(\1).isEmpty\(\)`
2024-05-09 09:25:09 +02:00
Yanming Zhou 8137cc9566 Polishing 2024-05-08 18:20:13 +02:00
Juergen Hoeller 7b16988ec9 Merge branch '6.1.x' 2024-05-08 17:52:42 +02:00
Stéphane Nicoll 8d90817ba3 Polish and fix build failure 2024-05-08 15:59:28 +02:00
Stéphane Nicoll 36295e664a Merge branch '6.1.x' 2024-05-08 15:47:10 +02:00
Sam Brannen 3ce79c3fbf Polishing 2024-05-08 11:54:55 +03:00
Chad Attermann cb48077698 Adds support for qualifying columns with table.
Adds support common in other ResultSet implemenatations for qualifying column names with table name to distinguish potentially duplicate column names in a join of two or more tables from one another. The expected format is {table_name}.{column_namne}, where column_name is the actuall designated column name and not the column label.
2024-05-08 10:35:55 +02:00
Stéphane Nicoll 2d942a6e91 Merge branch '6.1.x' 2024-05-08 10:30:19 +02:00
Stéphane Nicoll 168276aaab Review AssertJ support for MockMvc
Closes gh-32712
2024-05-07 16:30:44 +02:00
Stéphane Nicoll bcecce7aac Add shortcuts for frequently used assertions
See gh-32712
2024-05-07 16:28:44 +02:00
Stéphane Nicoll c8967de065 Provide better name for entry points
This commit renames AssertableMockMvc to MockMvcTester as the former
was too mouthful, and we are looking for a naming pattern that can be
applied consistently to test utilities that rely on AssertJ.

Rather than AssertableMvcResult, we now use MvcTestResult and it no
longer extends from MvcResult itself. That avoids having existing code
that is migrated to the new API whilst assigning the result to MvcResult
and get a bad DevXP as that doesn't bring any of the AssertJ support.

See gh-32712
2024-05-07 16:28:44 +02:00
Stéphane Nicoll 5567d14700 Move response body directly in AbstractMockHttpServletResponseAssert
This commit removes ResponseBodyAssert and rather offers first-class
access support for the response body at the root level using bodyText(),
bodyJson(), and body().

This avoids a double navigation to assert the response body.

See gh-32712
2024-05-07 16:28:44 +02:00
Stéphane Nicoll 24cc77655f Merge JSON assertions in a single Assert type
This commit merges the JSONCompare and JsonPath support in a single
assert object. The rationale for the previous situation was that
JsonPath is optional but merging the assertions methods do not make
it mandatory as the usage if JsonPath is triggered only if it is
actually used.

See gh-32712
2024-05-07 16:28:44 +02:00
Juergen Hoeller 645556a28c Merge branch '6.1.x' 2024-05-07 15:53:00 +02:00
Sam Brannen ac0136b75c Clarify supported targets for annotations in the TestContext framework
Closes gh-32772
2024-05-07 16:45:12 +03:00
Juergen Hoeller 3048cfe9d9 Polishing 2024-05-06 20:16:07 +02:00
Juergen Hoeller d9ca263065 Merge branch '6.1.x' 2024-05-06 20:11:56 +02:00
Sébastien Deleuze 39889744b0 Polish JdbcTemplate Best Practices section 2024-05-06 18:28:54 +02:00
Sébastien Deleuze 12272d6e41 Remove unneeded @SuppressWarnings("NullAway")
Closes gh-32542
2024-05-06 18:28:54 +02:00
Stéphane Nicoll 93dcbc41b0 Polish 2024-05-06 17:40:23 +02:00
Stéphane Nicoll 371d1a02f2 Fix typo 2024-05-06 17:38:52 +02:00
Sébastien Deleuze 04944a1f56 Modernize the lazy-initialized beans refdoc section
Closes gh-32767
2024-05-06 17:08:49 +02:00
Sébastien Deleuze c6459b40e4 Modernize the integration section of the refdoc
This commit adds Java and Kotlin tabs to XML code snippets where
relevant, and leverages code includes.

Closes gh-32600
2024-05-06 16:05:35 +02:00
Sam Brannen bdc4ecd599 Merge branch '6.1.x'
# Conflicts:
#	spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java
2024-05-03 17:12:40 +03:00
Arjen Poutsma 92f54da628 Bug fixes in WebMvc.fn testing support
See gh-30477
2024-05-03 14:28:21 +02:00
Arjen Poutsma 8bca7cd8e7 Various UrlParser improvements
- Consistent use of codePointAt instead of charAt.
- Fix bug in domainToAscii

See gh-32513
2024-05-03 13:41:56 +02:00
Arjen Poutsma 4df80a8d09 Various CPU and memory improvements in UrlParser
Improvements include:
- Replace throwing exceptions with failure results in hot areas,
- Verify digits of a string before passing it to Integer::parseInt
- Lazily initialization of fields
- Using LinkedList instead of ArrayList where size is not known
  beforehand

See gh-32513
2024-05-03 13:41:55 +02:00
Sam Brannen 12b285add3 Polishing 2024-05-03 14:03:50 +03:00
Sam Brannen b0a2f269cb Merge branch '6.1.x' 2024-05-03 12:18:34 +03:00
Sébastien Deleuze 8de7c64637 Upgrade to webjars-locator-lite 1.0.0
Closes gh-32564
2024-05-03 09:38:31 +02:00
Stéphane Nicoll 305ebca56d Merge branch '6.1.x' 2024-05-02 17:02:08 +02:00
Brian Clozel 09ca4cdc70 Merge branch '6.1.x' 2024-05-02 16:01:56 +02:00
Arjen Poutsma 7ccd4ce886 Reduce logging level in UrlParser
See gh-32513
2024-05-02 15:33:06 +02:00
Arjen Poutsma 8f3b7484e2 Add testing support for WebMvc.fn
This commit introduces testing support for WebMvc.fn in the form of a
RouterFunctionMockMvcBuilder and RouterFunctionMockMvcSpec.

Closes gh-30477
2024-05-02 15:20:56 +02:00
Stéphane Nicoll d708343a05 Upgrade to HtmlUnit 4.1.0
As well as Selenium 4.20.0

Closes gh-32740
2024-05-02 13:45:31 +02:00
Sam Brannen 1ffd0dcf06 Merge branch '6.1.x' 2024-05-02 13:29:08 +03:00
Stéphane Nicoll 759ec52fd2 Merge branch '6.1.x' 2024-05-02 11:49:24 +02:00
Sébastien Deleuze a8430878ca Merge branch '6.1.x' 2024-05-02 11:08:30 +02:00
Arjen Poutsma 3897ea78bb Resolve collisions in composite collections
Before this commit, creating a CompositeMap from two maps with the same
key has strange results, such as entrySet returning duplicate entries
with the same key.

After this commit, we give precedence to the first map by filtering out
all entries in the second map that are also mapped by the first map.

See gh-32245
2024-05-02 10:51:57 +02:00
Arjen Poutsma d5664ba01a Ensure old attributes are not removed by accident
This commit ensures that a copy is made of old attributes before
replacing it with new attributes. Because new attributes can be
composed of old, clearing the old would also remove entries from the
 new.

See gh-32245
2024-05-02 10:51:38 +02:00
George Papadopoulos 3f3995f846 Add ServerRequest.pathVariableOrNull Kotlin extension
Closes gh-32738
2024-05-02 10:11:37 +02:00
Brian Clozel 02b3801f1a Merge branch '6.1.x' 2024-05-02 09:17:01 +02:00
Juergen Hoeller 69eaf8f828 Merge branch '6.1.x' 2024-05-01 18:07:13 +02:00
Juergen Hoeller 649a537891 Merge branch '6.1.x' 2024-05-01 15:42:14 +02:00
Sam Brannen 153d1bc923 Support Collection target types in custom IndexAccessors
Prior to this commit, an IndexAccessor could not provide support for a
Collection target type, since the built-in support for indexing into a
Collection in SpEL's Indexer took precedence.

This commit allows an IndexAccessor to support custom Collection target
types by separating the built-in List and Collection support and
applying the built-in Collection support after custom index accessors
have been applied.

Closes gh-32736
2024-05-01 16:12:04 +03:00
Sam Brannen 4e6591e1a9 Polishing 2024-05-01 16:12:04 +03:00
Arjen Poutsma 37dd47c6fc Set request timeout in JettyClientHttpRequestFactory
Closes gh-32330
2024-05-01 09:58:35 +02:00
Brian Clozel 57dd2f46db Merge branch '6.1.x' 2024-04-30 19:11:01 +02:00
Sam Brannen 512ff7ce3c Merge branch '6.1.x' 2024-04-30 18:09:41 +03:00
Arjen Poutsma a3afe51c9f Fix guard against multiple subscriptions
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
2024-04-30 16:06:53 +02:00
Juergen Hoeller f1a1190700 Merge branch '6.1.x'
# Conflicts:
#	framework-docs/modules/ROOT/pages/data-access/transaction/declarative/annotations.adoc
2024-04-30 15:47:48 +02:00
Sam Brannen 35c183d634 Introduce ReflectiveIndexAccessor in SpEL
This commit introduces ReflectiveIndexAccessor for the Spring
Expression Language (SpEL) which is somewhat analogous to the
ReflectivePropertyAccessor implementation of PropertyAccessor.

ReflectiveIndexAccessor is a flexible IndexAccessor implementation that
uses reflection to read from and optionally write to an indexed
structure of a target object. ReflectiveIndexAccessor also implements
CompilableIndexAccessor in order to support compilation to bytecode for
read access.

For example, the following creates a read-write IndexAccessor for a
FruitMap type that is indexed by Color, including built-in support for
compilation to bytecode for read access.

IndexAccessor indexAccessor = new ReflectiveIndexAccessor(
    FruitMap.class, Color.class, "getFruit", "setFruit");

Closes gh-32714
2024-04-30 16:26:11 +03:00
Sébastien Deleuze b232aefdeb Use lowercase package in code snippets
Closes gh-32734
2024-04-30 15:05:15 +02:00
Stéphane Nicoll 2b62897dc5 Merge pull request #32064 from awmeinema
* pr/32064:
  Polish "Allow AbstractUrlHandlerMapping to add/remote handlers"
  Allow AbstractUrlHandlerMapping to add/remote handlers

Closes gh-32064
2024-04-30 13:48:54 +02:00
Stéphane Nicoll ad0c488767 Polish "Allow AbstractUrlHandlerMapping to add/remote handlers"
See gh-32064
2024-04-30 13:48:34 +02:00
ameinema 109d985f89 Allow AbstractUrlHandlerMapping to add/remote handlers
See gh-32064
2024-04-30 12:58:29 +02:00
Stéphane Nicoll a7ceedf2bb Merge pull request #28958 from jerzykrlk
* pr/28958:
  Polish "Include URL and HTTP method in DefaultResponseErrorHandler"
  Include URL and HTTP method in DefaultResponseErrorHandler

Closes gh-28958
2024-04-30 11:37:24 +02:00
Stéphane Nicoll f85c4e1ea7 Polish "Include URL and HTTP method in DefaultResponseErrorHandler"
See gh-28958
2024-04-30 11:34:17 +02:00
jerzykrlk 4972d18dd6 Include URL and HTTP method in DefaultResponseErrorHandler
See gh-28958
2024-04-30 11:34:17 +02:00
Sébastien Deleuze 2350c8a8f5 Remove Hibernate substitutions and deprecated properties usage
This commit raises the baseline to Hibernate 6.5 for native support,
which allows to remove remaining Hibernate substitutions as well as
deprecated properties usage.

Closes gh-32314
2024-04-30 11:24:19 +02:00
Juergen Hoeller dfc053ad65 Merge branch '6.1.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2024-04-29 18:05:40 +02:00
Stéphane Nicoll 87855e2d34 Clear ShadowMatch instances when they are no longer needed
This commit gathers the ShadowMatch instances that AspectJ requires in
a dedicated class that can be used to clear the instances when they are
no longer required.

As those are mainly triggered via AspectJAwareAdvisorAutoProxyCreator,
it now implements the necessary callbacks to clear the cache.

Closes gh-12334
2024-04-29 16:25:11 +02:00
Sébastien Deleuze 331bdb066e Add BodyInserters.fromValue(T, ParameterizedTypeReference<T>)
This commit introduces
BodyInserters.fromValue(T, ParameterizedTypeReference<T>) variant as
well as related WebClient.RequestBodySpec API,
ServerResponse.BodyBuilder API and Kotlin extensions.

Closes gh-32713
2024-04-29 15:28:42 +02:00
Stéphane Nicoll 9492d88270 Stop wrapping low-level exceptions in CacheAspectSupport initialization
This commit replaces the IllegalStateException thrown in
CacheAspectSupport when a CacheManager cannot be determined. These were
added to provide a dedicated error message, but it is possible to do
so without hiding the more adequate exception type.

Closes gh-22442
2024-04-29 15:24:36 +02:00
Sam Brannen 9b85c93b6b Polishing 2024-04-29 16:17:38 +03:00
Brian Clozel 65f118bdec Merge branch '6.1.x' 2024-04-29 13:40:51 +02:00
Sam Brannen fc3dddac9c Polishing 2024-04-28 11:43:14 +03:00
donghui a662f5e719 Add a requiredBody() extension to RestClient.ResponseSpec
Closes gh-32703
2024-04-26 16:21:32 +02:00
Sam Brannen 3002813598 Clean up warnings in spring-test 2024-04-26 15:49:09 +03:00
Arjen Poutsma 3cfa4ed4f7 Various UrlParser improvements
See gh-32513
2024-04-26 11:44:32 +02:00
Sam Brannen 27d2200058 Introduce CompilableIndexAccessor SPI in SpEL
This commit introduces a new CompilableIndexAccessor SPI for the Spring
Expression Language (SpEL) which allows an IndexAccessor to support
compilation to bytecode for operations that read an index.

This analogous to the CompilablePropertyAccessor SPI.

This commit also includes a prototype for a general purpose
ReflectiveIndexAccessor in the tests.

Closes gh-32613
2024-04-26 12:19:10 +03:00
Sam Brannen 0b5800ae39 Introduce generateCodeForArgument() in CodeFlow
Closes gh-32708
2024-04-25 15:12:21 +03:00
Sam Brannen 25fd5659cb Polishing 2024-04-25 15:10:00 +03:00
Sam Brannen de9ce800bf Polishing 2024-04-25 14:00:35 +03:00
Sam Brannen 8f579b3144 Make SpelNode compilation aware
In order to make SpelNode compilation aware, this method moves the
declaration of isCompilable() and generateCode(...) from SpelNodeImpl
to SpelNode.

Closes gh-32707
2024-04-25 13:47:57 +03:00
Sam Brannen 14689256c4 Support String index type in custom IndexAccessor
Closes gh-32706
2024-04-25 12:17:13 +03:00
Sam Brannen a3d3bc0a1f Polishing 2024-04-25 12:14:23 +03:00
Sam Brannen a986374da7 Use records to track cached state in Indexer 2024-04-25 11:51:11 +03:00
Simon Baslé 4e6325a277 Merge branch '6.1.x' 2024-04-25 10:09:23 +02:00
Sam Brannen aaf33100d9 Add IndexAccessor support to SpEL's SimpleEvaluationContext
Closes gh-32702
2024-04-24 16:19:39 +03:00
Sam Brannen 1e4275a0f9 Implement optional get<list>() methods in EvaluationContext as default methods 2024-04-24 15:54:05 +03:00
Sam Brannen 33fbd7141d Make AstUtils package-private
AstUtils was never intended to be a public utility class.
2024-04-24 15:44:02 +03:00
Sam Brannen 461d7a82f6 Avoid redefining getSpecificTargetClasses() in [Property|Index]Accessor 2024-04-24 15:39:01 +03:00
Sam Brannen 00da781c44 Merge branch '6.1.x' 2024-04-24 15:33:19 +03:00
Juergen Hoeller 0402ea13c0 Merge branch '6.1.x' 2024-04-24 13:42:43 +02:00
Stéphane Nicoll 6682d75481 Merge branch '6.1.x' 2024-04-24 11:13:27 +02:00
rstoyanchev 75a5409c97 Add PreFlightRequestHandler for Spring MVC
This is equivalent of the same contract for WebFlux. It is implemented
by HandlerMappingIntrospector, and may be called directly by Spring
Security to handle a pre-flight request without delegate to the rest
of the filter chain.

HandlerMappingIntrospector also has the boolean method
allHandlerMappingsUsePathPatternParser that checks whether all handler
mappings are configured to use parsed PathPattern's.

See gh-31823
2024-04-23 19:00:10 +01:00
Juergen Hoeller 3991cae875 Merge branch '6.1.x' 2024-04-23 16:07:46 +02:00
Stéphane Nicoll a77895bd90 Merge branch '6.1.x' 2024-04-23 15:34:49 +02:00
Stéphane Nicoll ed188f82d8 Merge branch '6.1.x' 2024-04-23 15:25:20 +02:00
Arjen Poutsma df41bb1ae9 Merge pull request #32622 from NadChel:bugfix/GH-32620_remove_content_type_if_no_body
* gh-32622:
  Polishing external contribution
  Remove Content-Type when body is empty
2024-04-23 15:04:53 +02:00
Arjen Poutsma 6c5ef9715b Polishing external contribution
See gh-32622
2024-04-23 14:59:28 +02:00
Sergey Zolotaryov 3f8a10c19f Remove Content-Type when body is empty
Closes gh-32622
See gh-32620
2024-04-23 14:58:20 +02:00
Juergen Hoeller adc7f73170 Merge branch '6.1.x' 2024-04-23 13:17:08 +02:00
Stéphane Nicoll af4a986256 Merge branch '6.1.x' 2024-04-23 12:43:40 +02:00
Stéphane Nicoll 4e1b8f9be3 Merge branch '6.1.x' 2024-04-23 11:04:02 +02:00
Sam Brannen ca6d987c56 Support compilation of array and list indexing with Integer in SpEL
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.

Closes gh-32694
2024-04-23 11:36:48 +03:00
Stéphane Nicoll 8124491249 Merge branch '6.1.x' 2024-04-22 17:01:04 +02:00
Stéphane Nicoll c21090ad31 Merge branch '6.1.x' 2024-04-22 15:16:50 +02:00
Stéphane Nicoll 9f46dd7d86 Merge branch '6.1.x' 2024-04-22 14:52:31 +02:00
Juergen Hoeller 6a1ec0ed73 Merge branch '6.1.x' 2024-04-22 13:43:57 +02:00
Stéphane Nicoll b965336467 Merge branch '6.1.x' 2024-04-22 12:13:14 +02:00
Brian Clozel c80bf57834 Merge branch '6.1.x' 2024-04-20 19:46:23 +02:00
Sam Brannen 80fb8ea813 Avoid unnecessary compilation attempts in SpEL's Indexer
Closes gh-32677
2024-04-19 17:20:24 +02:00
Sam Brannen 1eed71bb1d Polishing 2024-04-19 14:34:09 +02:00
Sam Brannen c8090fe0b4 Extract generateIndexCode() in SpEL's Indexer 2024-04-19 14:33:22 +02:00
Sam Brannen 9eab7bb11d Introduce null-safe indexing test for custom IndexAccessor 2024-04-19 14:29:43 +02:00
Sam Brannen a01f7cefae Polish Javadoc for SpelNode 2024-04-19 14:27:11 +02:00
Brian Clozel ccf9ba86a0 Merge branch '6.1.x' 2024-04-18 21:45:23 +02:00
Brian Clozel 0893cf948d Merge branch '6.1.x' 2024-04-18 21:27:50 +02:00
Arjen Poutsma 62a1b5558f Resolve UrlParser review comments
See gh-32513
2024-04-18 15:20:02 +02:00
rstoyanchev aa05a6a3b3 Merge branch '6.1.x' 2024-04-18 14:18:43 +01:00
Simon Baslé a985c0bb35 Polishing: fix link fragments in test bean override annotation pages 2024-04-18 14:54:57 +02:00
Juergen Hoeller e42c5ca52b Merge branch '6.1.x' 2024-04-18 12:20:14 +02:00
Sam Brannen f96d0a6c4a Merge branch '6.1.x' 2024-04-18 11:54:02 +02:00
rstoyanchev 0bc447c304 Jackson decoder supports array/Collection elements
Closes gh-32579
2024-04-18 10:40:25 +01:00
Michael Kunze 00c7002354 Fix typo in class name
Closes gh-32664
2024-04-18 09:32:10 +02:00
Onji Kim ec055da7c3 Reject negative Content-Length values in HttpHeaders
Prior to this commit, `HttpHeaders#setContentLength` would accept
negative values. Those are not allowed by the RFC and the headers
implementation only uses "-1" as a way to convey that no value was set.

This commit ensures that negative values are rejected.

Fixes gh-32660
2024-04-17 23:05:13 +02:00
Brian Clozel c03f798dad Merge branch '6.1.x' 2024-04-17 22:47:44 +02:00
Arjen Poutsma af23cc233e Add support for state override in new URL parser
See gh-32513
2024-04-17 16:33:53 +02:00
Arjen Poutsma f21e05a9e4 Introduce new URL parser
This commit introduces a new URL parser based on algorithm provided in
the Living URL standard. This new UrlParser is used by
UriComponentsBuilder::fromUriString, replacing the regular expressions.

Closes gh-32513
2024-04-17 11:17:01 +02:00
Sam Brannen 8727d723f3 Polish "Bean Overriding in Tests" support 2024-04-16 17:08:15 +02:00
Simon Baslé ce8758b83c Merge branch '6.1.x' 2024-04-16 16:47:01 +02:00
Simon Baslé 43b5c81dad Merge branch '6.1.x' 2024-04-16 16:29:53 +02:00
Sam Brannen 69cb2a347a Update copyright date
See gh-32647
2024-04-16 15:11:12 +02:00
janghs 0d4ef4eafe Omit empty resource description in DeprecatedBeanWarner's log message
Closes gh-32647
2024-04-16 15:07:18 +02:00
Arjen Poutsma 051fd2ae4f Merge branch '6.1.x' 2024-04-16 11:44:02 +02:00
Simon Baslé 02ee5de470 Document bean override in TestContext framework section of the manual
This change splits the documentation in the reference manual: the
`@TestBean`, `@MockitoBean` and `@MockitoSpyBean` annotations are kept
in the appendix and the general documentation about the feature is moved
into a dedicated sub-section of the TCF section.

Close gh-32490
2024-04-15 17:07:14 +02:00
Sam Brannen afbce96fb7 Introduce getName() in SpEL's BeanReference
Closes gh-32640
2024-04-15 16:44:37 +02:00
Sam Brannen 3f34a13436 Polishing 2024-04-15 16:30:51 +02:00
Simon Baslé fe83003324 Merge branch '6.1.x' 2024-04-15 14:21:51 +02:00
laterlaugh 5012843b12 Fix typos in comment and test
Closes gh-32628
2024-04-12 17:40:54 +02:00
Sam Brannen b13963ee81 Reject private JUnit Jupiter lifecycle methods annotated with @⁠Autowired
Closes gh-32627
2024-04-12 14:27:38 +02:00
Sam Brannen 43cc18a5a1 Use literal monospace in SpEL templating section
Prior to this commit, the text `#{ }` was displayed as { } with a bright
green background.

This commit addresses this by making use of Asciidoc's literal monospace
feature: `+#{ }+`.
2024-04-11 14:00:46 +02:00
Brian Clozel 4d5536db21 Merge branch '6.1.x' 2024-04-11 11:33:16 +02:00
Brian Clozel d99113661e Merge branch '6.1.x' 2024-04-11 11:24:58 +02:00
Brian Clozel 54dab45151 Merge branch '6.1.x' 2024-04-11 08:51:13 +02:00
Stéphane Nicoll 2e3a923225 Polish 2024-04-11 08:45:26 +02:00
Juergen Hoeller 77c6f160fe Merge branch '6.1.x'
# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java
#	spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java
#	spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java
2024-04-10 18:29:48 +02:00
Simon Baslé 2d33aac350 Improve Bean Overriding support, testing and documentation
This commit improves on the bean overriding feature in several ways:
the API is simplified and polished (metadata and processor contracts,
 etc...).

The commit also reworks infrastructure classes (context customizer,
test execution listener, BeanOverrideBeanFactoryPostProcessor, etc...).
Parsing of annotations is now fully stateless.

In order to avoid OverrideMetadata in bean definition and to make a
first step towards AOT support, the BeanOverrideBeanFactoryPostProcessor
now delegates to a BeanOverrideRegistrar to track classes to parse,
the metadata-related state as well as for the field injection methods
for tests.

Lastly, this commit increases the test coverage for the provided
annotations and adds integration tests and fixes a few `@TestBean`
issues.
2024-04-10 18:16:43 +02:00
Sébastien Deleuze 711ddd1ac6 Merge branch '6.1.x' 2024-04-10 17:55:09 +02:00
Brian Clozel 35a0d24dc3 Merge branch '6.1.x' 2024-04-10 16:44:20 +02:00
Sam Brannen ae3dc0d4b1 Merge SpEL IndexAccessor feature into main
This set of commits introduces a new IndexAccessor SPI for the Spring
Expression Language (SpEL) which allows third parties to customize the
SpEL Indexer.

A custom IndexAccessor implementation can be registered in a
StandardEvaluationContext.

For an example, see the JacksonArrayNodeIndexAccessor in IndexingTests
in the spring-expression module.

See gh-26409
Closes gh-26478
2024-04-10 16:07:33 +02:00
Sam Brannen 1c9cff668c Honor IndexAccessor#canWrite() and cache accessors
See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
Sam Brannen 15511890bd Revise Javadoc for IndexAccessor
See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
Sam Brannen 22bfe7da5a Introduce proper error handling for IndexAccessor support in SpEL
See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
Sam Brannen 5c6b82a947 Change IndexAccessor#read()'s return type to TypedValue
Prior to this commit, the read() method in the IndexAccessor SPI
declared a return type of ValueRef which introduced a package cycle.

This commit addresses this by aligning with the PropertyAccess SPI and
returning TypedValue from IndexAccessor's read() method. This commit
also reworks the internals of Indexer based on a new, local
IndexAccessorValueRef implementation.

See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
Sam Brannen b7c3833732 Revise null-safety contracts in IndexAccessor SPI
When indexing into an object, the target object can never be null.

See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
Sam Brannen d91277095a Initial review and polish of IndexAccessor support in SpEL
See gh-26409
See gh-26478
2024-04-10 15:54:34 +02:00
ljmn3211 50a0000ed7 Introduce IndexAccessor SPI to customize the SpEL Indexer
See gh-26409
See gh-26478
2024-04-10 15:14:50 +02:00
Sébastien Deleuze d6e9562aeb Revert "Prevent compilation warnings with @Nullable"
This reverts commit dc242df533.
2024-04-10 14:39:47 +02:00
Juergen Hoeller f6089afd0e Use ClassLoaderAwareGeneratorStrategy with UndeclaredThrowableStrategy delegate
See gh-32469
2024-04-10 13:23:24 +02:00
Mikaël Francoeur 561583842f Consistent handling of undeclared checked exceptions in CGLIB proxies (#32469)
Co-authored-by: hengyunabc <hengyunabc@gmail.com>
Co-authored-by: Mikaël Francoeur <mikael.francoeur@ticketmaster.com>
2024-04-10 12:11:33 +02:00
Sam Brannen bed3689001 Polishing 2024-04-10 10:56:41 +02:00
Stéphane Nicoll 3d85ec2354 Merge pull request #32610 from alidandach
* pr/32610:
  Polish "Use try-with-resources when applicable"
  Use try-with-resources when applicable

Closes gh-32610
2024-04-10 09:52:25 +02:00
Stéphane Nicoll 330dcf15bc Polish "Use try-with-resources when applicable"
See gh-32610
2024-04-10 09:49:35 +02:00
ali dandach 82b51479d5 Use try-with-resources when applicable
See gh-32610
2024-04-10 09:49:17 +02:00
Stéphane Nicoll 2d408685ce Merge branch '6.1.x' 2024-04-09 19:53:43 +02:00
Stéphane Nicoll cc7815145f Upgrade to Reactor 2024.0.0-M1
Closes gh-32591
2024-04-09 19:51:42 +02:00
rstoyanchev a1586ff0a0 Merge branch '6.1.x' 2024-04-09 18:25:11 +01:00
Sam Brannen 0637b699cd Merge branch '6.1.x' 2024-04-09 19:01:38 +02:00
Brian Clozel c3aa0cd815 Merge branch '6.1.x' 2024-04-09 18:36:53 +02:00
Juergen Hoeller a9fffa844f Merge branch '6.1.x' 2024-04-09 16:15:19 +02:00
Sébastien Deleuze bb04c6b1f3 Merge branch '6.1.x' 2024-04-09 15:22:58 +02:00
Stéphane Nicoll cb8b7a455a Start building against Reactor 2024.0.0-M1 snapshots
See gh-32591
2024-04-09 13:54:10 +02:00
Stéphane Nicoll 9dbb269bb9 Merge branch '6.1.x' 2024-04-09 13:40:03 +02:00
Stéphane Nicoll f3aa61c5bb Upgrade to Micrometer 1.13.0-RC1
Closes gh-32595
2024-04-09 13:39:49 +02:00
Sébastien Deleuze dc242df533 Prevent compilation warnings with @Nullable
This commit replaces `@Nonnull(when = When.MAYBE)` meta-annotation in
`org.springframework.lang.Nullable` by `@CheckForNull` in order to
prevent `unknown enum constant When.MAYBE` compilation warnings.

Closes gh-27183
2024-04-09 13:35:49 +02:00
Sébastien Deleuze c05b4bcd71 Add missing dependency and remove warnings
See gh-22171
2024-04-09 12:50:36 +02:00
Sébastien Deleuze 246f291f67 Use code includes and tabs in WebSocket documentation
See gh-22171
2024-04-09 12:21:36 +02:00
Juergen Hoeller 4eb93da31d Merge branch '6.1.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
2024-04-08 22:41:02 +02:00
Sébastien Deleuze cabd1f53df Polishing 2024-04-08 18:03:19 +02:00
Sébastien Deleuze a471aa6a9a Use code includes and tabs in Regexp Pointcuts documentation
See gh-22171
2024-04-08 18:03:10 +02:00
Sébastien Deleuze 515295e205 Use code includes and tabs in AOP documentation
See gh-22171
2024-04-08 16:54:45 +02:00
Sam Brannen 1455a9fe22 Polishing 2024-04-08 16:37:47 +02:00
Stéphane Nicoll 36636b000b Consistent newline at the end of files
See gh-22171
2024-04-08 13:34:44 +02:00
Sébastien Deleuze 94050b3638 Use code includes and tabs in SpEL documentation
See gh-22171
2024-04-08 11:53:56 +02:00
Stéphane Nicoll 62db2680f5 Merge branch '6.1.x' 2024-04-08 11:11:15 +02:00
Sébastien Deleuze 5c8043dcea Use code includes and tabs in date/time format documentation
See gh-22171
2024-04-08 10:32:16 +02:00
Juergen Hoeller 13df59cef4 Merge branch '6.1.x' 2024-04-08 09:52:42 +02:00
Sébastien Deleuze 78f08ed1dd Upgrade to webjars-locator-lite 0.0.4
See gh-27619
2024-04-08 09:33:35 +02:00
Juergen Hoeller 03dd8e20e2 Merge branch '6.1.x' 2024-04-05 18:05:37 +02:00
Arjen Poutsma dcab1f2237 Merge branch '6.1.x' 2024-04-05 16:13:58 +02:00
Stéphane Nicoll 3e93ca02cc Merge branch '6.1.x' 2024-04-05 15:58:08 +02:00
Stéphane Nicoll 583dc04986 Merge branch '6.1.x' 2024-04-05 15:57:39 +02:00
Stéphane Nicoll 749d7671a0 Stop linking to Websphere's Javadoc
Closes gh-32581
2024-04-05 15:54:41 +02:00
Arjen Poutsma 08bc959c9b Merge branch '6.1.x' 2024-04-05 15:43:49 +02:00
Sébastien Deleuze 4e6532f639 Merge branch '6.1.x' 2024-04-05 15:00:48 +02:00
Sébastien Deleuze 0c42874629 Merge branch '6.1.x' 2024-04-05 14:33:20 +02:00
Stéphane Nicoll 5253af1a04 Merge branch '6.1.x' 2024-04-04 14:43:38 +02:00
Stéphane Nicoll e3281a527c Merge branch '6.1.x' 2024-04-02 18:01:59 +02:00
Stéphane Nicoll a96f22d5e2 Merge branch '6.1.x' 2024-04-02 15:48:04 +02:00
Stéphane Nicoll 7a74e45946 Make use of bean definition overriding more visible
This commit makes the use of bean definition overriding more visible and
prepare for a deprecation of the feature in the next major release.

As of this commit, use of bean definition overriding logs at INFO level.
The previous log level can be restored by setting the
allowBeanDefinitionOverriding flag explicitly on the BeanFactory (or
via the related ApplicationContext).

A number of tests that are using bean overriding on purpose have been
updated to set this flag, which will make them easier to find once we
actually deprecate the feature.

Closes gh-31288
2024-04-02 14:05:12 +02:00
Sébastien Deleuze 8af3eb1aea Polishing
See gh-22171
2024-04-02 13:33:29 +02:00
Sébastien Deleuze d26265420a Avoid removal warnings in tests
See gh-27619
2024-04-02 13:19:34 +02:00
Sébastien Deleuze bede619e7d Refine @EnableWebFlux documentation
This commit refines the documentation related to `@EnableWebFlux` in
order to make it more relevant for modern Boot applications.

See gh-22171
2024-04-02 11:48:12 +02:00
Sébastien Deleuze bf2a72b043 Upgrade webjars-locator-lite to 0.0.3
See gh-27619
2024-04-02 10:22:31 +02:00
Sébastien Deleuze 67edcde0a2 Introduce support for webjars-locator-lite
This commit introduces support for org.webjars:webjars-locator-lite
via a new LiteWebJarsResourceResolver in Spring MVC and WebFlux, and
deprecates WebJarsResourceResolver which is performing a classpath
scanning that slows down application startup.

Closes gh-27619
2024-04-02 10:16:51 +02:00
Stéphane Nicoll 81bc586e15 Merge branch '6.1.x' 2024-04-02 09:34:39 +02:00
Stéphane Nicoll 6f95af978e Merge branch '6.1.x' 2024-04-01 12:14:56 +02:00
Sam Brannen d360def92e Polishing 2024-03-30 16:06:06 +01:00
Łukasz Jernaś 86b87d7d85 Prevent package summaries from being truncated due to incorrect sentence detection
Javadoc doesn't seem to like having `e.g.` as it thinks the sentence
ends there, which is usually incorrect and results in broken descriptions.

This commit rewords the doc strings slightly to avoid problematic parts.

Closes gh-32532
2024-03-30 15:44:41 +01:00
Sébastien Deleuze 186e70cd04 Use code includes and tabs in MVC Config documentation
Additional fixes.

See gh-22171
2024-03-29 18:24:50 +01:00
Sébastien Deleuze 91bb7d8daf Use code includes and tabs in MVC Config documentation
This commit also refines the documentation related to
`@EnableWebMvc` in order to make it more relevant for modern Boot
applications.

See gh-22171
2024-03-29 17:58:01 +01:00
Sébastien Deleuze db1010f9c9 Add CBOR support to AllEncompassingFormHttpMessageConverter
Closes gh-32428
2024-03-28 14:59:22 +01:00
Sébastien Deleuze cf87441a26 Remove unnecessary method.isAccessible() invocation
Closes gh-32548
2024-03-28 11:50:29 +01:00
Sébastien Deleuze dc982d0d51 Merge branch '6.1.x' 2024-03-28 11:14:42 +01:00
Sébastien Deleuze 996e66abdb Perform NullAway build-time checks in spring-test
Closes gh-32475
2024-03-26 18:14:56 +01:00
Sébastien Deleuze 96d9081190 Merge branch '6.1.x' 2024-03-26 18:10:25 +01:00
Stéphane Nicoll bf5b22d64f Merge branch '6.1.x' 2024-03-26 17:45:25 +01:00
Sébastien Deleuze 8b51b36729 Perform NullAway build-time checks in more modules
This commit enables null-safety build-time checks in
all remaining modules except spring-test.

See gh-32475
2024-03-26 15:53:01 +01:00
Sébastien Deleuze 2fea3d7921 Merge branch '6.1.x' 2024-03-26 15:41:46 +01:00
Sam Brannen f47352ff04 Polish PropertyOrFieldReference 2024-03-26 13:21:46 +01:00
Stéphane Nicoll c1ed504ac1 Avoid classpath scanning in test
This commit updates SpringConfiguratorTests to not rely on classpath
scanning as it could have side effect. In this particular case, the
configuration class that sources the scan is detected again, leading
to bean overriding.

Irrespective of that, adding more code in that package may have side
effect as they could be scanned as well.

Closes gh-32535
2024-03-26 10:41:00 +01:00
Sébastien Deleuze 5b660da52d Perform NullAway build-time checks in more modules
This commit enables null-safety build-time checks in:
 - spring-jdbc
 - spring-r2dbc
 - spring-orm
 - spring-beans
 - spring-aop

See gh-32475
2024-03-26 09:59:30 +01:00
Sébastien Deleuze 3b4f8dbb8e Merge branch '6.1.x' 2024-03-26 09:47:09 +01:00
Sam Brannen 4b0a048570 Polish SpEL internals and remove duplicate code 2024-03-25 17:47:14 +01:00
Sam Brannen 57632f9f08 Fix wording in SpEL's PropertyAccessor Javadoc
The documentation now properly refers to "property accessors" instead
of "resolvers".
2024-03-25 14:26:40 +01:00
Sébastien Deleuze 7c009ccc1f Perform NullAway build-time checks in spring-messaging
See gh-32475
2024-03-25 12:30:03 +01:00
Sébastien Deleuze f421f38e24 Merge branch '6.1.x' 2024-03-25 12:28:53 +01:00
Sébastien Deleuze 88e26a9570 Merge branch '6.1.x' 2024-03-25 11:28:43 +01:00
Sébastien Deleuze 2fc78dfb69 Perform NullAway build-time checks in spring-jms
See gh-32475
2024-03-25 11:27:04 +01:00
Sébastien Deleuze e52ee01ec8 Perform NullAway build-time checks in spring-web
Also in spring-websocket.

See gh-32475
2024-03-25 11:11:09 +01:00
Sébastien Deleuze 2b1eb488fc Merge branch '6.1.x' 2024-03-25 11:04:49 +01:00
Sam Brannen 5bec072dcb Polish SpEL internals 2024-03-24 17:07:42 +01:00
Stéphane Nicoll 8736ca038a Merge branch '6.1.x' 2024-03-24 09:23:10 +01:00
Stéphane Nicoll aa9f0b3cb2 Merge pull request #32524 from izeye
* pr/32524:
  Fix Javadoc since to ChannelRegistration.executor()

Closes gh-32524
2024-03-24 08:29:45 +01:00
Johnny Lim 56b14dc54a Fix Javadoc since to ChannelRegistration.executor()
See gh-32524
2024-03-24 08:29:22 +01:00
Sam Brannen 2a74fe5ddb Introduce null-safe index operator in SpEL
This set of commits introduces support for a null-safe operator in the
Spring Expression Language (SpEL), including support for compiling
expressions that use the null-safe index operator.

Note, however, that compilation is not supported for null-safe indexing
into a String or any kind of Collection (other than a List).

See gh-21468
Closes gh-29847
2024-03-23 15:03:51 +01:00
Sam Brannen 218a148898 Document null-safe index operator in SpEL
See gh-29847
2024-03-23 14:56:01 +01:00
Sam Brannen 38c473fd05 Support compilation of null-safe index operations in SpEL
See gh-29847
2024-03-23 13:48:20 +01:00
Sam Brannen d2bd0d5716 Retain null-safe syntax in AST representation of SpEL indexers
Prior to this commit, SpEL's CompoundExpression omitted the null-safe
syntax in AST string representations of indexing operations.

To address this, this commit implements isNullSafe() in Indexer.

See gh-29847
2024-03-23 12:46:03 +01:00
Sam Brannen 4d433174eb Revise null-safe index operator support in SpEL
See gh-29847
2024-03-23 12:46:03 +01:00
Grigory Stepanov 9f4d46fe33 Introduce null-safe index operator in SpEL
See gh-29847
2024-03-23 12:38:10 +01:00
Sam Brannen 2a1abb5553 Simplify compilation of array indexing in SpEL's Indexer 2024-03-23 12:35:25 +01:00
Sam Brannen 7edd4e8e22 Clean up warnings in Gradle build 2024-03-23 09:28:49 +01:00
Felix 05b15812bb Apply instanceof pattern matching in RootBeanDefinition
Closes gh-32520
2024-03-23 09:09:25 +01:00
Sébastien Deleuze 0e7aba4179 Perform NullAway build-time checks in spring-webmvc
See gh-32475
2024-03-22 17:49:03 +01:00
Sébastien Deleuze cf8810042a Merge branch '6.1.x' 2024-03-22 17:46:35 +01:00
Sam Brannen 88bc3f270e Merge branch '6.1.x' 2024-03-22 17:18:38 +01:00
Sam Brannen b695dbc2bf Merge branch '6.1.x' 2024-03-22 16:37:55 +01:00
Stéphane Nicoll cf4ac96688 Merge branch '6.1.x' 2024-03-22 16:33:17 +01:00
Sébastien Deleuze 0a50854e1a Perform NullAway build-time checks in spring-webflux
See gh-32475
2024-03-22 16:09:18 +01:00
Sébastien Deleuze 637aa9f71f Merge branch '6.1.x' 2024-03-22 16:06:25 +01:00
Sébastien Deleuze b1b9ee0ccf Merge branch '6.1.x' 2024-03-21 17:56:14 +01:00
Sam Brannen a30c06b883 Polishing and consistent use of exception assertions 2024-03-21 16:36:14 +01:00
Andrea Mauro 458c30cb63 Resolve property-dependent parameter names for exception messages
Prior to this commit when a required parameter defined as a property or
expression placeholder was missing, the exception thrown would refer to
the placeholder instead of the resolved name.

This change covers messaging handlers and web controllers, both blocking
and reactive. It also fixes the error message when handling null values
for non-required parameters, as well as in cases that need conversion.

See gh-32323
Closes gh-32462
2024-03-20 17:40:38 +01:00
Sam Brannen 5698191ba0 Rename listener to CommonCachesTestExecutionListener
See gh-30954
2024-03-20 16:37:22 +01:00
Sam Brannen 7d197972e0 Polishing 2024-03-20 13:05:30 +01:00
Sam Brannen 1732844137 Polishing 2024-03-20 12:55:35 +01:00
Sam Brannen 7f40b49f4d Improve names of classes generated by the SpEL compiler
Prior to this commit, the SpEL compiler generated classes in a package
named "spel" with names following the pattern "Ex#", where # was an
index starting with 2.

This resulted in class names such as:

- spel.Ex2
- spel.Ex3

This commit improves the names of classes created by the SpEL compiler
by generating classes in a package named
"org.springframework.expression.spel.generated" with names following
the pattern "CompiledExpression#####", where ##### is a 0-padded
counter starting with 00001.

This results in class names such as:

- org.springframework.expression.spel.generated.CompiledExpression00001
- org.springframework.expression.spel.generated.CompiledExpression00002

This commit also moves the saveGeneratedClassFile() method from
SpelCompilationCoverageTests to SpelCompiler and enhances it to:

- Save classes in a "build/generated-classes" directory.
- Convert package names to directories.
- Create missing parent directories.
- Use logging instead of System.out.println().

Running a test with saveGeneratedClassFile() enabled now logs something
similar to the following.

DEBUG o.s.e.s.s.SpelCompiler - Saving compiled SpEL expression [(#root.empty ? 0 : #root.size)] to [/Users/<username>/spring-framework/spring-expression/build/generated-classes/org/springframework/expression/spel/generated/CompiledExpression00001.class]

Closes gh-32497
2024-03-20 12:34:01 +01:00
Stéphane Nicoll 2f070e59e6 Merge branch '6.1.x' 2024-03-20 10:16:26 +01:00
Sébastien Deleuze f648fd7c3b Perform NullAway build-time checks in spring-expression
See gh-32475
2024-03-20 10:10:00 +01:00
Sébastien Deleuze 1ccd5512c5 Merge branch '6.1.x' 2024-03-20 10:08:30 +01:00
Stéphane Nicoll 5a86ab99df Merge branch '6.1.x' 2024-03-20 10:01:56 +01:00
Stéphane Nicoll 29d307e211 Clear ApplicationContext cache after a test class completes if necessary
The ApplicationContext has a resource cache that it uses while the
context is being refreshed. Once the refresh phase completes, the
cache is cleared as its content is no longer in use. If beans are
lazily initialized, there is a case where the cache might be filled
again as processing is deferred past the refresh phase.

For those cases, the cache is not cleared. This can be a problem when
running in this mode with a large set of test configurations as the TCF
caches the related contexts.

This commit includes an additional TestExecutionListener to the TCF that
clears the resource cache if necessary once a test class completes. It
is ordered so that it runs after `@DirtiesContext` support as marking
the context as dirty will remove it from the cache and make that extra
step unnecessary.

Closes gh-30954
2024-03-20 09:42:41 +01:00
Sébastien Deleuze 4c7735016b Refine null-safety with NullAway build-time checks
This commit introduces null-safety checks for spring-core at build-time
in order to validate the consistency of Spring null-safety annotations
and generate errors when inconsistencies are detected during a build
(similar to what is done with Checkstyle).

In order to make that possible, this commit also introduces a new
org.springframework.lang.Contract annotation inspired from
org.jetbrains.annotations.Contract, which allows to specify semantics
of methods like Assert#notNull in order to prevent artificial
additional null checks in Spring Framework code base.

This commit only checks org.springframework.core package, follow-up
commits will also extend the analysis to other modules, after related
null-safety refinements.

See gh-32475
2024-03-19 16:30:32 +01:00
Sam Brannen 0a715bcab3 Merge branch '6.1.x' 2024-03-19 15:52:12 +01:00
Sébastien Deleuze 8d23ec4747 Merge branch '6.1.x' 2024-03-19 13:36:39 +01:00
Juergen Hoeller 14bc0d6469 Fix typo in condition check
See gh-21190
2024-03-19 13:17:33 +01:00
Sam Brannen 3bd342ee7d Polish bean override support in the TestContext framework 2024-03-19 12:41:06 +01:00
Sébastien Deleuze 871860798e Merge branch '6.1.x' 2024-03-19 11:05:22 +01:00
Juergen Hoeller e58ea0d945 Merge branch '6.1.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java
2024-03-19 10:06:48 +01:00
Sam Brannen 8f56b4a8ae Fix logic error hidden by auto-boxing 2024-03-18 18:19:34 +01:00
Sam Brannen 2ca10e20ca Simplify implementation of BeanOverrideParser
See gh-29917
2024-03-18 18:13:36 +01:00
Sam Brannen 0ef5a4090b Support non-public BeanOverrideProcessors in the TestContext framework
Closes gh-32485
2024-03-18 18:02:51 +01:00
Juergen Hoeller 6df27644eb Merge branch '6.1.x' 2024-03-18 16:04:26 +01:00
Juergen Hoeller 2f2c4188e5 Nullability refinements
See gh-32475
2024-03-18 15:49:20 +01:00
Sam Brannen ccebaa6b0c Merge branch '6.1.x' 2024-03-18 15:18:06 +01:00
Brian Clozel ae5cff1705 Merge branch '6.1.x' 2024-03-18 14:37:21 +01:00
Stéphane Nicoll 3e102e5d8e Merge branch '6.1.x' 2024-03-18 14:11:02 +01:00
Brian Clozel 9cd4d32195 Merge branch '6.1.x' 2024-03-18 12:18:29 +01:00
Stéphane Nicoll 73a1c2d509 Polish 2024-03-18 08:59:22 +01:00
Juergen Hoeller 2b56ca08d4 Restore canonical name representation for 6.2
See gh-32405
2024-03-17 21:03:02 +01:00
Juergen Hoeller b89cf2b16a Merge branch '6.1.x' 2024-03-17 21:00:00 +01:00
Johnny Lim 99e1b0d117 Make SimpleAliasRegistry.aliasNames final 2024-03-17 13:33:31 +01:00
Juergen Hoeller 89d563097f Merge branch '6.1.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
2024-03-16 23:24:51 +01:00
Brian Clozel 10e8039de8 Merge branch '6.1.x' 2024-03-15 22:48:12 +01:00
Juergen Hoeller 2086cda296 Merge branch '6.1.x' 2024-03-15 21:30:55 +01:00
Juergen Hoeller 66235fa8c8 Consistent TaskDecorator and ErrorHandler support in schedulers
Closes gh-23755
Closes gh-32460
2024-03-15 21:07:59 +01:00
Sam Brannen cf31d088e2 Polish AssertJ support for MockMvc
See gh-21178
2024-03-15 17:15:32 +01:00
Stéphane Nicoll 4a74e1fc2d Add AssertJ support for MockMvc
Closes gh-21178
2024-03-15 13:32:49 +01:00
Stéphane Nicoll e7d7cb8641 Add AssertJ support for MockMvc
This commit adds a new way to use MockMvc by returning a MvcResult that
is AssertJ compatible. Compared to the existing MockMvc infrastructure,
this new model has the following advantages:

* Can be created from a MockMvc instance
* Dedicated builder methods for easier setup
* Assertions use familiar AssertJ syntax with discoverable assertions
through a DSL
* Improved exception message

See gh-21178

Co-authored-by: Brian Clozel <brian.clozel@broadcom.com>
2024-03-15 13:30:32 +01:00
Stéphane Nicoll 555d4a6004 Add AssertJ support for cookies
This commit adds AssertJ compatible assertions for cookies

See gh-21178

Co-authored-by: Brian Clozel <brian.clozel@broadcom.com>
2024-03-15 13:28:12 +01:00
Stéphane Nicoll 1cdbcc58f3 Add AssertJ support for the Model
This commit adds AssertJ compatible assertions for the Model that is
generated from an HTTP request.

See gh-21178
2024-03-15 13:28:12 +01:00
Stéphane Nicoll b46e528922 Add AssertJ support for the HTTP handler
This commit adds AssertJ compatible assertions for the component that
produces the result from the request.

See gh-21178
2024-03-15 13:28:12 +01:00
Stéphane Nicoll e97ae434fb Add AssertJ support for HTTP requests and responses
This commit adds AssertJ compatible assertions for HTTP request and
responses, including headers, media type, and response body. The latter
delegate to the recently included JSON assert support.

See gh-21178
2024-03-15 13:28:11 +01:00
Stéphane Nicoll 76f45c4289 Add support for JSON assertions using JSON path
This commit moves JSON path AssertJ support from Spring Boot.

See gh-21178

Co-authored-by: Brian Clozel <brian.clozel@broadcom.com>
2024-03-15 13:28:11 +01:00
Stéphane Nicoll 97ebc43ea9 Add support for JSON assertions using JSON compare
This commit moves JSON content AssertJ support from Spring Boot.

See gh-21178

Co-authored-by: Brian Clozel <brian.clozel@broadcom.com>
2024-03-15 13:28:11 +01:00
Stéphane Nicoll 214a54dd6f Run CI on main only once a day 2024-03-15 08:40:09 +01:00
Stéphane Nicoll 875037c431 Merge branch '6.1.x' 2024-03-15 08:28:24 +01:00
Stéphane Nicoll 35e8ae2a84 Merge branch '6.1.x' 2024-03-14 17:47:51 +01:00
Stéphane Nicoll 26cab0616e Merge branch '6.1.x' 2024-03-14 17:43:32 +01:00
Sam Brannen e1b1435a00 Stop referring to JDK 1.5 plus polishing 2024-03-14 16:00:51 +01:00
Stéphane Nicoll 8e2134c6a7 Merge branch '6.1.x' 2024-03-14 15:29:18 +01:00
Stéphane Nicoll 7c7a59bdd2 Merge branch '6.1.x' 2024-03-14 15:17:47 +01:00
Stéphane Nicoll acd69d38e9 Merge branch '6.1.x' 2024-03-14 15:05:46 +01:00
Sam Brannen 4a3daa7812 Polishing 2024-03-14 14:20:59 +01:00
Sam Brannen 27d5213176 Polish Javadoc for @⁠TestBean support 2024-03-14 13:44:27 +01:00
Stéphane Nicoll 19dfc781f5 Build Pull Requests on CI using GitHub Actions
Closes gh-32443
2024-03-14 11:10:41 +01:00
rstoyanchev 1d2b55e670 Merge branch '6.1.x' 2024-03-14 08:46:46 +00:00
Juergen Hoeller 7f7c0d59f6 Merge branch '6.1.x' 2024-03-13 18:07:21 +01:00
Stéphane Nicoll 7d4db434a5 Merge branch '6.1.x' 2024-03-13 17:28:23 +01:00
Sam Brannen 986c4fd926 Revise use of Objects.requireNonNull()
Historically, we have rarely intentionally thrown a
NullPointerException in the Spring Framework. Instead, we prefer to
throw either an IllegalArgumentException or IllegalStateException
instead of a NullPointerException.

However, changes to the code in recent times have introduced the use of
Objects.requireNonNull(Object) which throws a NullPointerException
without an explicit error message.

The latter ends up providing less context than a NullPointerException
thrown by the JVM (since Java 14) due to actually de-referencing a
null-pointer. See https://openjdk.org/jeps/358.

In light of that, this commit revises our current use of
Objects.requireNonNull(Object) by removing it or replacing it with
Assert.notNull().

However, we still use Objects.requireNonNull(T, String) in a few places
where we are required to throw a NullPointerException in order to
comply with a third-party contract such as Reactive Streams.

Closes gh-32430
2024-03-13 16:00:22 +01:00
Sam Brannen d6422d368a Revise @⁠TestBean support
See gh-29917
2024-03-13 16:00:22 +01:00
Sam Brannen 21ed8aad74 Add missing test 2024-03-13 15:59:28 +01:00
Sam Brannen 7211db9262 Polishing 2024-03-13 15:59:28 +01:00
Juergen Hoeller 3b87c87a33 Merge branch '6.1.x' 2024-03-12 20:11:21 +01:00
Sébastien Deleuze 460ffbc0f6 Use code includes and tabs in mvc-controller/ann.adoc
See gh-22171
2024-03-12 19:18:42 +01:00
Sébastien Deleuze 8a67018e61 Use code includes and tabs in embedded-database-support.adoc
See gh-22171
2024-03-12 17:46:38 +01:00
Sébastien Deleuze 68ae1e5700 Fix a link in MockitoResetTestExecutionListener javadoc 2024-03-12 17:43:10 +01:00
Brian Clozel 4b732d62c2 Deprecate HttpHeaders.writableHttpHeaders
Prior to this commit, gh-21783 introduced `ReadOnlyHttpHeaders` to avoid
parsing media types multiple times during the lifetime of an HTTP
exchange: such values are cached and the headers map is made read-only.
This also added a new `HttpHeaders.writableHttpHeaders` method to unwrap
the read-only variant when needed.

It turns out this method sends the wrong signal to the community
because:
* the underlying map might be unmodifiable even if this is not an
  instance of ReadOnlyHttpHeaders
* developers were assuming that modifying the collection that backs the
  read-only instance would work around the cached values for
  Content-Type and Accept headers

This commit adds more documentation to highlight the desired behavior
for cached values by the read-only variant, and deprecates the
`writableHttpHeaders` method as `ReadOnlyHttpHeaders` is package private
and we should not surface that concept anyway.
Instead, this commit unwraps the read-only variant if needed when a new
HttpHeaders instance is created.

Closes gh-32116
2024-03-12 14:04:09 +01:00
rstoyanchev 670fc9bb4e Merge branch '6.1.x' 2024-03-12 11:43:43 +00:00
Sébastien Deleuze 7a65aad09c Merge branch '6.1.x' 2024-03-12 12:24:30 +01:00
Sébastien Deleuze b1bf8c5242 Prevent NPE when using pathExtension predicate
This commit ensures pathExtension predicate is skipped when the value
is null, in order to provide a more predictable behavior, and allow
a better compatibility with collections not supporting null elements
like the ones created by List#of.

Closes gh-32404
2024-03-12 12:11:50 +01:00
rstoyanchev 6767f7010c Polishing contribution
Closes gh-29958
2024-03-12 10:43:32 +00:00
rstoyanchev 8af1d8e842 Remove applyAttributes flag from contribution
See gh-29958
2024-03-12 10:43:31 +00:00
PhilKes 052b6357c8 Apply attributes to the underlying HTTP request
See gh-29958
2024-03-12 10:43:31 +00:00
rstoyanchev 282ee02419 Polishing contribution
Closes gh-31924
2024-03-12 10:43:31 +00:00
Anton Ždanov 667e30f580 Set UTF-8 as default multipart charset to ContentRequestMatchers
See gh-31924
2024-03-12 10:43:31 +00:00
rstoyanchev f9883d8bd6 Polishing contribution
Closes gh-31970
2024-03-12 10:43:31 +00:00
rstoyanchev 73ee86c666 Split messages only if configured to do so
See gh-31970
2024-03-12 10:43:31 +00:00
injae-kim 76d00d78db Support splitting STOMP messages in WebSocketStompClient
See gh-31970
2024-03-12 10:43:31 +00:00
Brian Clozel bf014ef18b Merge branch '6.1.x' 2024-03-12 09:52:22 +01:00
Stéphane Nicoll 13679bb906 Reject use of component scan with REGISTER_BEAN condition
This commit introduce a change of behaviour when component scan is used
with conditions. Previously, any condition in the REGISTER_BEAN phase
were ignored and the scan was applied regardless of the outcome of
those conditions. This is because REGISTER_BEAN condition evaluation
happens later in the bean factory preparation.

Rather than ignoring those conditions, this commit fails fast when it
detects such use case. Code will have to be adapted accordingly.

Closes gh-23206
2024-03-12 08:39:53 +01:00
Stéphane Nicoll 6fc1f72704 Merge branch '6.1.x' 2024-03-12 08:21:08 +01:00
Sam Brannen 04e69bdb26 Polish contribution
Closes gh-32412
2024-03-11 17:04:53 +01:00
Mikaël Francoeur 3e48031601 Reject null return value from MethodReplacer for primitive return type
This commit throws an exception instead of silently converting a null
return value from a MethodReplacer to a primitive 0/false value.

See gh-32412
2024-03-11 17:04:53 +01:00
Sam Brannen f285971cb3 Polishing 2024-03-11 17:04:53 +01:00
Stéphane Nicoll 89f6e8ec49 Enable test now that the related issue is resolved
See gh-20765
2024-03-11 16:45:30 +01:00
Stéphane Nicoll 53ed15e4a7 Remove disabled test of declined issue
See gh-19689
2024-03-11 16:44:50 +01:00
Brian Clozel 9af4f5cf17 Remove deprecated API in WebContentGenerator
Closes gh-31492
2024-03-11 15:35:12 +01:00
Stéphane Nicoll 92d1ebefbb Upgrade to HtmUnit 3.11.0
This commit upgrades to a major new release of HtmlUnit. This is a
breaking change as HtmlUnit 3 moves to a `org.htmlunit` package and
calling code needs to be restructured.

Our use of Selenium has been adapted accordingly, moving to Selenium
3, using the new org.seleniumhq.selenium:htmlunit3-driver integration.

Closes gh-30392
2024-03-11 14:36:46 +01:00
Sam Brannen 71245f9655 Relocate bean override infrastructure to the proper package in the TCF 2024-03-11 14:21:04 +01:00
Sam Brannen f30a67c9d0 Remove duplicate dependency 2024-03-11 13:59:23 +01:00
Sébastien Deleuze 0435e9c49e Merge branch '6.1.x' 2024-03-11 13:40:23 +01:00
Sam Brannen 38c831f15f Relocate findPublicDeclaringClass() to CodeFlow
This commit moves findPublicDeclaringClass() from ReflectionHelper to
CodeFlow, since findPublicDeclaringClass() is only used for bytecode
generation and therefore not for reflection-based invocations.
2024-03-11 11:33:52 +01:00
Sam Brannen c4e0f96ef7 Polishing 2024-03-11 11:28:59 +01:00
Sébastien Deleuze 5ee11fb1b3 Polish Yaml support
Closes gh-32345
2024-03-11 09:27:25 +01:00
Hyoungjune 6a8f0d6d7d Add web support for Yaml via Jackson
This commit adds support for application/yaml in MediaType and leverages
jackson-dataformat-yaml in order to support Yaml in RestTemplate,
RestClient and Spring MVC.

See gh-32345
2024-03-11 09:22:51 +01:00
Yanming Zhou 246e4977a2 Polishing Optional usage 2024-03-11 09:13:49 +01:00
Stéphane Nicoll 4e5723ca9e Merge pull request #32411 from quaff
* pr/32411:
  Polish contribution
  Polish Bean Overriding in Tests section of the reference guide

Closes gh-32411
2024-03-11 08:57:57 +01:00
Stéphane Nicoll ffb1caaff4 Polish contribution
See gh-32411
2024-03-11 08:56:59 +01:00
Yanming Zhou 918c5f1f33 Polish Bean Overriding in Tests section of the reference guide
See gh-32411
2024-03-11 08:43:40 +01:00
Sam Brannen b431594021 Make SpEL's OptimalPropertyAccessor private
It was never necessary for SpEL's OptimalPropertyAccessor to be public.

Instead, clients should interact with OptimalPropertyAccessor
exclusively via the CompilablePropertyAccessor API.

In light of that, this commit makes SpEL's OptimalPropertyAccessor
private.

Closes gh-32410
2024-03-10 20:38:19 +01:00
Sam Brannen fc885224f0 Merge branch '6.1.x' 2024-03-10 17:41:49 +01:00
ZeroCyan 5dc1190930 Fix typo in web documentation
Fixed a small typo.

Closes gh-32407
2024-03-10 16:50:00 +01:00
Sam Brannen 6f5d3a4b12 Polish Bean Override support in the TestContext framework 2024-03-10 16:05:55 +01:00
Sam Brannen 4c246b7c96 Consistently use canonical annotation names in string representations 2024-03-10 15:54:53 +01:00
Sam Brannen 5345a13918 Polish contribution
See gh-32405
2024-03-10 12:36:08 +01:00
Patrick Strawderman 7fa2a28970 Avoid cloning empty Annotation array in TypeDescriptor
Rework AnnotatedElementAdapter to avoid cloning the underlying
Annotation array if it is empty when getAnnotations() is called.

Additionally, make the class static and add a factory method that
returns a singleton instance for null or empty Annotation arrays.

Closes gh-32405
2024-03-10 12:26:49 +01:00
Stéphane Nicoll 8172d7adfe Polish 2024-03-09 17:27:44 +01:00
Sam Brannen 6b64e9992a Merge branch '6.1.x' 2024-03-09 16:31:28 +01:00
Sam Brannen c188f22378 Polishing 2024-03-09 16:08:17 +01:00
Stéphane Nicoll e53ed3e3c6 Merge branch '6.1.x' 2024-03-09 16:03:04 +01:00
Sam Brannen f4c1ad7ae6 Polishing
See gh-29857
2024-03-09 15:38:52 +01:00
Sam Brannen 20be9e150c Polishing 2024-03-09 14:28:01 +01:00
Sam Brannen 65d77624d1 Support SpEL compilation for public methods in private subtypes
Commit c79436f832 ensured that methods are invoked via a public
interface or public superclass when compiling Spring Expression
Language (SpEL) expressions involving method references or property
access (see MethodReference, PropertyOrFieldReference, and
collaborating support classes). However, compilation of expressions
that access properties by indexing into an object by property name is
still not properly supported in all scenarios.

To address those remaining use cases, this commit ensures that methods
are invoked via a public interface or public superclass when accessing
a property by indexing into an object by the property name – for
example, `person['name']` instead of `person.name`.

In addition, SpEL's Indexer now properly relies on the
CompilablePropertyAccessor abstraction instead of hard-coding support
for only OptimalPropertyAccessor. This greatly reduces the complexity
of the Indexer and simultaneously allows the Indexer to potentially
support other CompilablePropertyAccessor implementations.

Closes gh-29857
2024-03-09 14:01:00 +01:00
Sam Brannen 107f47cfcf Add tests for status quo for SpEL compiler 2024-03-09 13:46:39 +01:00
Juergen Hoeller fad544e077 Merge branch '6.1.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
2024-03-08 19:51:05 +01:00
Juergen Hoeller 19fec0633f Local root directory and jar caching in PathMatchingResourcePatternResolver
Closes gh-21190
2024-03-08 19:12:14 +01:00
Simon Baslé 729dc0b671 Polishing javadoc 2024-03-08 18:07:51 +01:00
rstoyanchev 38d5c0fed6 Add RFC-7807 response interception
Closes gh-31822
2024-03-08 16:56:38 +00:00
Sam Brannen 3577e3b758 Polish SpEL internals and tests 2024-03-08 17:49:58 +01:00
Simon Baslé e1bbdf0913 Add support for bean overriding in tests
This commit introduces two sets of annotations (`@TestBean` on one side
and `MockitoBean`/`MockitoSpyBean` on the other side), as well as an
extension mecanism based on the `@BeanOverride` meta-annotation.

Extension implementors are expected to only provide an annotation,
a BeanOverrideProcessor implementation and an OverrideMetadata subclass.

Closes gh-29917.
2024-03-08 16:52:39 +01:00
Sam Brannen 90867e7e62 Merge branch '6.1.x' 2024-03-08 15:50:29 +01:00
Sébastien Deleuze 5cac2ca11a Fix code snippet compilation error
See gh-22171
2024-03-08 12:28:37 +01:00
Sébastien Deleuze db3c7a157e Use consistently snippet tags
See gh-22171
2024-03-08 12:15:51 +01:00
Sébastien Deleuze d2e55a2038 Use code includes and tabs in jdbc/core.adoc
See gh-22171
2024-03-08 12:15:51 +01:00
Sam Brannen ae6c64abc5 Fix Javadoc errors 2024-03-08 11:59:53 +01:00
Brian Clozel c1bd9243ee Merge branch '6.1.x' 2024-03-08 11:36:54 +01:00
Sébastien Deleuze e66d965fed Merge branch '6.1.x' 2024-03-08 09:25:17 +01:00
Sébastien Deleuze aa4282d7f8 Polishing
See gh-22171
2024-03-07 18:16:57 +01:00
Sébastien Deleuze 34f0c27b5e Fix build link 2024-03-07 17:42:49 +01:00
Sébastien Deleuze 722199fe6d Use code includes and tabs in connections.adoc
See gh-22171
2024-03-07 17:40:11 +01:00
Sébastien Deleuze 9cb8766977 Add support for Kotlin and XML code includes
See gh-22171
2024-03-07 17:37:48 +01:00
rstoyanchev 8d24e22e33 Merge branch '6.1.x' 2024-03-07 16:06:18 +00:00
Sam Brannen c79436f832 Support SpEL compilation for public methods in private subtypes
Although the Spring Expression Language (SpEL) generally does a good
job of locating the public declaring class or interface on which to
invoke a method in a compiled expression, prior to this commit there
were still a few unsupported use cases.

To address those remaining use cases, this commit ensures that methods
are invoked via a public interface or public superclass whenever
possible when compiling SpEL expressions.

See gh-29857
2024-03-07 16:20:50 +01:00
rstoyanchev 1ffffef85e Merge branch '6.1.x' 2024-03-07 14:48:41 +00:00
Sébastien Deleuze f0039833c8 Merge branch '6.1.x' 2024-03-07 14:31:26 +01:00
Sam Brannen ac1176af53 Use Map#computeIfAbsent in SpEL support classes
Closes gh-32385
2024-03-07 13:55:35 +01:00
Sam Brannen dcbc2ef134 Polishing 2024-03-07 13:55:35 +01:00
Juergen Hoeller 4ec4e93ece Document when the JPA infrastructure is ready for use
Closes gh-26153
See gh-21868
2024-03-07 13:35:58 +01:00
Simon Baslé 7f0ab22c47 Merge branch '6.1.x' 2024-03-07 12:10:07 +01:00
Sébastien Deleuze 92f4e883b3 Merge branch '6.1.x' 2024-03-07 11:11:46 +01:00
Juergen Hoeller dedc6a7e9b Enforce JPA/Hibernate initialization before context refresh completion
Closes gh-21868
2024-03-07 11:03:08 +01:00
Juergen Hoeller c9e85ec297 Introduce callback for singleton availability
Closes gh-21362
2024-03-07 09:57:29 +01:00
rstoyanchev 1a8d64f9d8 Merge branch '6.1.x' 2024-03-06 18:17:40 +00:00
Juergen Hoeller 13221ac0ef Merge branch '6.1.x'
# Conflicts:
#	spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java
#	spring-tx/src/test/java/org/springframework/transaction/interceptor/TransactionInterceptorTests.java
2024-03-06 18:09:32 +01:00
Sam Brannen 40da093f58 Polishing 2024-03-06 15:42:14 +01:00
Sam Brannen b32a2cadfb Update class-level Javadoc for ParameterNameDiscoverer 2024-03-06 14:49:46 +01:00
Sam Brannen d87465f9e9 Use ELContext instead of VariableResolver in JspPropertyAccessor
The JSP VariableResolver API has been deprecated since JSP 2.1 in favor
of the newer ELContext API.

This commit therefore refactors JspPropertyAccessor to use the
ELContext API.

Closes gh-32383
2024-03-06 14:31:21 +01:00
Juergen Hoeller 14a461e795 Consider type-level qualifier annotations for transaction manager selection
Closes gh-24291
2024-03-06 13:36:33 +01:00
Sam Brannen 6461eec582 Revise contribution
Closes gh-32380
2024-03-06 11:49:21 +01:00
Yanming Zhou be136d79ee Improve Javadoc for NamedParameterUtils.substituteNamedParameters()
This commit documents that an empty list is not guaranteed to be
supported by the database. For example, MySQL and PostgreSQL do not
support `foo in ()`.

See gh-32380
2024-03-06 11:49:15 +01:00
Sam Brannen 9eea768205 Polish SpEL internals 2024-03-06 11:31:10 +01:00
Simon Baslé 19b5f11734 Merge branch '6.1.x' 2024-03-05 18:33:48 +01:00
Juergen Hoeller 6f7f032ced Merge branch '6.1.x' 2024-03-05 18:24:01 +01:00
Juergen Hoeller 7d4c8a403e Introduce configurable default rollback rules
Includes rollbackOn annotation attribute on @EnableTransactionManagement and addDefaultRollbackRule method on AnnotationTransactionAttributeSource, as well as publicMethodsOnly as instance-level flag (also on AnnotationCacheOperationSource).

Closes gh-23473
2024-03-05 18:08:08 +01:00
ali dandach eb01cc0d9d Use String#isEmpty where feasible
This commit replaces checks for empty strings ("".equals(...)) with the
String#isEmpty method.

Closes gh-32377
2024-03-05 17:38:29 +01:00
Juergen Hoeller 30e75e4a09 Enable efficient pointcut checks for composite sources as well
Closes gh-20072
2024-03-05 13:34:48 +01:00
Sam Brannen 1fa6ac30b5 Remove unused lastReadInvokerPair field in ReflectivePropertyAccessor 2024-03-05 12:55:30 +01:00
rstoyanchev ddab971fca Merge branch '6.1.x' 2024-03-05 11:42:17 +00:00
Sam Brannen b44c31e997 Polishing 2024-03-05 12:01:55 +01:00
Sam Brannen 1ea593e777 Convert PropertyCacheKey to a record 2024-03-05 12:01:55 +01:00
Sam Brannen 70a545e13a Use appropriate variable names in ReflectivePropertyAccessor 2024-03-05 11:52:30 +01:00
Sam Brannen c29c67839b Cache parameterTypes in ClassUtils.getInterfaceMethodIfPossible 2024-03-05 11:48:01 +01:00
Sébastien Deleuze f6dfbac582 Merge branch '6.1.x' 2024-03-05 11:01:29 +01:00
Arjen Poutsma 6d9aba88d0 Fix typo
See gh-32360
2024-03-05 10:48:06 +01:00
Sébastien Deleuze db826551a6 Upgrade to Dokka 1.9.20
Closes gh-32374
2024-03-05 10:31:29 +01:00
Arjen Poutsma 646bd7f893 Document StringUtils::uriDecode limitations
Closes gh-32360
2024-03-05 10:03:15 +01:00
ali dandach 1cb2dfa459 enh: use isEmpty() instead of length() 2024-03-04 23:55:33 +01:00
Juergen Hoeller 79c54098ab Merge branch '6.1.x' 2024-03-04 23:49:55 +01:00
Juergen Hoeller dc6c96de0a Merge branch '6.1.x'
# Conflicts:
#	spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractFallbackJCacheOperationSource.java
#	spring-context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java
#	spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java
2024-03-04 22:50:22 +01:00
Juergen Hoeller b5ca646431 Leniently tolerate late bean retrieval during destroySingletons()
Closes gh-22526
Closes gh-29730
2024-03-04 17:21:02 +01:00
Sébastien Deleuze 138e7a0e07 Use ServletResponse#getContentType in ServletServerHttpResponse
This commit updates ServletServerHttpResponse.ServletResponseHttpHeaders
in order to use ServletResponse#getContentType instead of
ServletResponse#getHeader.

It allows to have a consistent behavior between Tomcat (which sets only
the former) and Undertow/Jetty (which set both).

Closes gh-32339
2024-03-04 15:32:32 +01:00
Sébastien Deleuze 4ce2559980 Merge branch '6.1.x' 2024-03-04 14:43:18 +01:00
rstoyanchev 1c5bb732b9 Merge branch '6.1.x' 2024-03-04 13:36:30 +00:00
Juergen Hoeller 3d7ef3ebfc Avoid storage of null marker per method for proxy decision purposes
Includes missing isCandidateClass support on JCacheOperationSource.

Closes gh-20072
2024-03-04 12:55:33 +01:00
Sébastien Deleuze 219004ef13 Merge branch '6.1.x' 2024-03-03 22:26:37 +01:00
rstoyanchev 0758c8b14c Merge branch '6.1.x' 2024-03-03 20:53:36 +00:00
Sam Brannen 4a6dbb17f4 Merge branch '6.1.x' 2024-03-03 14:51:01 +01:00
Sam Brannen a29c84f663 Merge branch '6.1.x' 2024-03-02 18:08:27 +01:00
Juergen Hoeller 390fe0fe78 Add support for resolving multiple bounds in type variables
Closes gh-22902
See gh-32327
2024-03-02 11:30:17 +01:00
Stéphane Nicoll ac1a030c35 Make PlaceholderResolutionException extend from IllegalArgumentException
To smooth upgrade from 6.1.x, this commit makes sure that code that used
to catch an IAE to ignore a faulty placeholder resolution still works.

See gh-9628
2024-03-02 08:28:38 +01:00
Sam Brannen fdbefad59c Improve documentation for SpEL indexing support
Prior to this commit, the reference manual only documented indexing
support for arrays, lists, and maps.

This commit improves the overall documentation for SpEL's property
navigation and indexing support and introduces additional documentation
for indexing into Strings and Objects.

Closes gh-32355
2024-03-01 18:08:29 +01:00
Sébastien Deleuze bdcd10e228 Merge branch '6.1.x' 2024-03-01 16:53:27 +01:00
Juergen Hoeller 861ef88d9f Expose savepoint callbacks on TransactionSynchronization
Closes gh-30509
2024-03-01 16:48:51 +01:00
Sam Brannen 193424c465 Polish "Background Initialization" documentation 2024-03-01 16:14:12 +01:00
Sam Brannen c76d681dc4 Merge branch '6.1.x' 2024-03-01 14:41:49 +01:00
Sébastien Deleuze 4149d5cb2b Merge branch '6.1.x' 2024-03-01 11:55:08 +01:00
Juergen Hoeller 89a10d5c9b Reference documentation for @Bean(bootstrap=BACKGROUND)
See gh-13410
2024-02-29 17:51:31 +01:00
Juergen Hoeller 4ac521607e Reference documentation for @Fallback
See gh-26241
2024-02-29 17:51:12 +01:00
Stéphane Nicoll 57c10a1fac Merge branch '6.1.x' 2024-02-29 17:23:08 +01:00
Arjen Poutsma d81619addd Merge branch '6.1.x' 2024-02-29 15:55:29 +01:00
Yanming Zhou 246ebd24bf Add missing method BeanDefinitionBuilder.setFallback() 2024-02-29 13:34:55 +01:00
Yanming Zhou 9a1e5eb8d7 Add test for @Fallback with BeanFactory.getBean(Class) 2024-02-29 13:33:43 +01:00
Juergen Hoeller 4ff0f86ae2 Merge branch '6.1.x' 2024-02-28 21:46:15 +01:00
Juergen Hoeller e68487a481 Merge branch '6.1.x' 2024-02-28 19:27:07 +01:00
Juergen Hoeller cfb29db278 Initial support for Servlet 6.1
Closes gh-31159
2024-02-28 18:54:36 +01:00
Sébastien Deleuze 570c5b34e6 Merge branch '6.1.x' 2024-02-28 18:35:29 +01:00
Juergen Hoeller fbc265b72b Add DataSource configuration/exposure to LocalEntityManagerFactoryBean
Closes gh-32344
2024-02-28 17:35:46 +01:00
Juergen Hoeller 5acee7b22e Initial support for JPA 3.2
Includes proxy support for Query#getSingleResultOrNull() and EntityManagerFactory#getName() invocations.

Closes gh-31157
2024-02-28 17:35:37 +01:00
Sébastien Deleuze 7c5bcbcba4 Merge branch '6.1.x' 2024-02-28 17:24:08 +01:00
Juergen Hoeller 3477738bed Consistently pick lowest superclass level to replace
See gh-28676
2024-02-28 15:49:05 +01:00
Juergen Hoeller fa5d246a1b Replace all exposed superclasses in final step after traversal
See gh-28676
2024-02-28 15:39:53 +01:00
Juergen Hoeller aeb77cf4e1 Restore correct threadWithLock check without isInfoEnabled()
See gh-23501
2024-02-28 11:47:39 +01:00
Sam Brannen 18dc7d73d6 Merge branch '6.1.x' 2024-02-28 10:42:31 +01:00
Juergen Hoeller 17b2087198 Introduce background bootstrapping for individual singleton beans
Closes gh-13410
Closes gh-19487
See gh-23501
2024-02-27 22:33:18 +01:00
Sébastien Deleuze 9e7c64270b Merge branch '6.1.x' 2024-02-27 15:52:13 +01:00
Sam Brannen 69dabe9df5 Merge branch '6.1.x' 2024-02-26 18:12:55 +01:00
Juergen Hoeller 4d206f79d0 Merge branch '6.1.x'
# Conflicts:
#	spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java
2024-02-26 13:42:00 +01:00
Juergen Hoeller 5c589833d7 Revise idleReceivesPerTaskLimit for surplus tasks on default/simple executor
Closes gh-32260
2024-02-25 19:00:56 +01:00
Juergen Hoeller 9198774f13 Detect wildcard without bounds returned from VariableResolver as well
See gh-32327
See gh-20727
2024-02-25 16:32:11 +01:00
Sam Brannen 430824038e Merge branch '6.1.x' 2024-02-25 16:28:13 +01:00
Juergen Hoeller 260404b7f2 Consistently detect wildcard without bounds as unresolvable
Closes gh-32327
See gh-20727
2024-02-24 20:25:56 +01:00
Juergen Hoeller 567547b63c Skip shortcut resolution for non-standard dependency descriptors
Closes gh-32326
See gh-28122
2024-02-24 18:05:23 +01:00
Sam Brannen 98efa1df5a Merge branch '6.1.x' 2024-02-24 16:42:47 +01:00
Juergen Hoeller 87ea3bd31a Merge branch '6.1.x' 2024-02-24 08:35:10 +01:00
Sam Brannen f59c4023e9 Polishing 2024-02-23 14:46:12 +01:00
Juergen Hoeller 58b8330e8d Consistent documentation of defaults and related methods
See gh-32308
2024-02-23 14:41:37 +01:00
Sam Brannen c2d2e99c2f Polishing 2024-02-23 13:18:09 +01:00
Sam Brannen eab1a3dc6b Fix BridgeMethodResolverTests.isBridgeMethodFor() in Eclipse IDE 2024-02-23 12:57:14 +01:00
Sam Brannen 4b5e96578d Extract runningInEclipse() into IdeUtils test fixture 2024-02-23 12:57:06 +01:00
Sam Brannen b0d08fe2d4 Spring cleaning: avoid deprecation warnings 2024-02-23 12:38:40 +01:00
Sam Brannen 122372c580 Spring cleaning: update copyright headers 2024-02-23 12:21:22 +01:00
Sam Brannen 9c610d9a70 Spring cleaning: remove unnecessary semicolon 2024-02-23 12:21:22 +01:00
Sam Brannen 5ae6c0e8ca Spring cleaning: avoid unnecessary super() invocations 2024-02-23 12:21:22 +01:00
Sam Brannen eb8492d597 Spring cleaning: avoid use of Iterator for Iterable 2024-02-23 12:21:12 +01:00
Sam Brannen c98bebd6d3 Spring cleaning: add missing @⁠Override annotations 2024-02-23 12:20:11 +01:00
Sam Brannen d0ffc16efc Spring cleaning: avoid unnecessary static imports 2024-02-23 12:20:11 +01:00
Sam Brannen 4bd1485ce4 Spring cleaning: use method references 2024-02-23 12:20:11 +01:00
Sam Brannen 4339c8eac2 Spring cleaning: use diamond operator 2024-02-23 12:20:11 +01:00
Sam Brannen 233b59f144 Polish Javadoc 2024-02-23 12:20:11 +01:00
Sam Brannen 3c00637c88 Fix @⁠inheritDoc usage 2024-02-23 12:08:29 +01:00
Juergen Hoeller 524588ef93 Avoid transaction listener execution without transaction management setup
Closes gh-32319
2024-02-23 11:53:05 +01:00
yuhangbin bed4d684e6 Polishing 2024-02-23 08:37:46 +01:00
Juergen Hoeller 229214a9b0 Merge branch '6.1.x'
# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/JdbcUpdateAffectedIncorrectNumberOfRowsException.java
2024-02-22 17:01:04 +01:00
Sébastien Deleuze 906109e129 Merge branch '6.1.x' 2024-02-22 16:37:58 +01:00
cboy 00edba07ff Polishing Javadoc (#32313) 2024-02-22 15:21:33 +01:00
Arjen Poutsma aee03c5201 Use composite collections in attribute merging
This commit introduces composite collections (i.e. Collection, Set, Map)
and uses these composites in request predicates, where before new
collections were instantiated.

Closes gh-32245
2024-02-22 13:11:20 +01:00
Arjen Poutsma 89d746ddf8 Avoid async dispatch if completed in AsyncServerResponse
This commit checks whether the CompletableFuture<ServerResponse> passed
to AsyncServerResponse.async has been completed, and if so returns a
CompletedAsyncServerResponse that simply delegates to the completed
response, instead of the DefaultAsyncServerResponse that uses async
dispatch.

Closes gh-32223
2024-02-22 11:29:51 +01:00
Juergen Hoeller 3ddc512108 Add missing @Override annotations 2024-02-22 11:21:51 +01:00
Yanming Zhou 76eb5b8c19 Replace redundant javadoc with {@inheritDoc} for AbstractBeanDefinition 2024-02-22 10:59:35 +01:00
Juergen Hoeller 491ebb4ec4 Merge branch '6.1.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java
2024-02-21 23:01:09 +01:00
Juergen Hoeller f811f0dc18 Clarify primary/fallback autowiring for arrays/collections/maps
Closes gh-32301
2024-02-21 20:24:57 +01:00
Juergen Hoeller f5397d6426 Consistent processing of overridden bean methods
Closes gh-28286
2024-02-21 18:36:03 +01:00
Brian Clozel 2a1b30dbed Merge branch '6.1.x' 2024-02-21 18:24:45 +01:00
Sam Brannen 734fc476ee Polish SpEL's Indexer and test 2024-02-21 17:44:09 +01:00
Sam Brannen 5a2b127a21 SpEL's StringIndexingValueRef.isWritable() should return false 2024-02-21 17:36:46 +01:00
Sam Brannen bfed6a3bc5 Clean up warnings in Gradle build 2024-02-21 16:22:38 +01:00
Sam Brannen 644887e094 Polish (Linked)HashSet usage
See gh-32291
2024-02-21 16:22:31 +01:00
Sam Brannen b9c304b890 Polish contribution
See gh-32291
2024-02-21 16:19:53 +01:00
Patrick Strawderman e1a32d4ba9 Avoid resizing of fixed-size HashSet/LinkedHashSet variants
Add helpers to CollectionUtils for building HashSets and LinkedHashSets
that can hold an expected number of elements without needing to
resize/rehash.

Closes gh-32291
2024-02-21 16:19:53 +01:00
Stéphane Nicoll 6383a0d7ca Merge branch '6.1.x' 2024-02-21 15:55:55 +01:00
Sam Brannen 3fb170058f Polish contribution
See gh-32294
2024-02-21 14:09:09 +01:00
Patrick Strawderman f9fe8efb2e Use ConcurrentHashMap.newKeySet
In places where a ConcurrentHashMap was used as a set by wrapping it
with Collections.newSetFromMap, switch to just using the set returned
by ConcurrentHashMap.newKeySet directly.

Closes gh-32294
2024-02-21 14:08:38 +01:00
Juergen Hoeller ff9c7141c5 Replace superclass exposure in case of late configuration class skipping
Closes gh-28676
2024-02-21 11:10:27 +01:00
Stéphane Nicoll 871f705bca Remove ComponentScan duplicate condition
Closes gh-27077
2024-02-21 10:09:31 +01:00
Juergen Hoeller 22b41c33ba Preserve existing imported class over scanned configuration class
Closes gh-24643
2024-02-20 20:43:41 +01:00
Juergen Hoeller 266953195c Avoid enhancement of configuration class in case of existing instance
Closes gh-25738
2024-02-20 20:43:09 +01:00
Juergen Hoeller 889c4e0ff5 Reject multiple primary candidates in ancestor factory as well
Closes gh-26612
2024-02-20 16:24:03 +01:00
Juergen Hoeller ad2e95be4b Merge branch '6.1.x' 2024-02-20 15:43:24 +01:00
Juergen Hoeller 63ca8d5d17 Consider defaultCandidate flag in case of no annotations as well
See gh-26528
2024-02-20 15:30:38 +01:00
Juergen Hoeller bc01e3116f Ignore fallback bean for shortcut resolution
See gh-26241
See gh-28122
2024-02-20 13:51:37 +01:00
Juergen Hoeller 480051a21c Introduce fallback flag and annotation (as companion to primary)
Closes gh-26241
2024-02-20 13:37:41 +01:00
Arjen Poutsma c077805761 Set correct capacity in DefaultDataBuffer::setNativeBuffer
Closes gh-30984
2024-02-20 12:36:55 +01:00
Arjen Poutsma ceb7afdca2 Merge pull request #32009 from injae-kim:fix-defaultDataBuffer-getNativeBuffer
* gh-32009:
  Polishing external contribution
  Set correct limit in DefaultDataBuffer::getNativeBuffer
2024-02-20 12:20:22 +01:00
Arjen Poutsma 70004e9ad0 Polishing external contribution
Change position and limit on duplicate, rather than source.

See gh-30967
Closes gh-32009
2024-02-20 12:12:35 +01:00
injae-kim 969d0bd08b Set correct limit in DefaultDataBuffer::getNativeBuffer
Closes gh-30967
2024-02-20 12:12:35 +01:00
Juergen Hoeller a8fb16b47c Introduce defaultCandidate flag (for plain type vs. qualified match)
Closes gh-26528
2024-02-20 12:00:47 +01:00
Arjen Poutsma bc2257aaff Invoke defaultRequest earlier in RestClient and WebClient
Closes gh-32053
2024-02-20 11:21:24 +01:00
Stéphane Nicoll 218957f0e8 Merge branch '6.1.x' 2024-02-20 10:19:41 +01:00
Juergen Hoeller a001319f1f Add additional shortcut for qualifier value matching target bean name
Closes gh-17677
See gh-28122
2024-02-19 22:39:37 +01:00
Juergen Hoeller 874e61a0c6 Test for async event publication before listener initialized
Closes gh-20904
See gh-23501
See gh-25799
2024-02-19 18:18:09 +01:00
Juergen Hoeller 4a02893c31 Avoid early singleton inference outside of original creation thread
See gh-23501
2024-02-19 17:44:30 +01:00
Juergen Hoeller 902e5707a8 Revise singleton registry for lenient locking (fallback instead of deadlock)
Closes gh-23501
2024-02-19 15:49:33 +01:00
Stéphane Nicoll f529386ce2 Merge pull request #31781 from rstoyanchev
* pr/31781:
  Write form data without charset parameter

Closes gh-31781
2024-02-19 15:23:59 +01:00
rstoyanchev b8715811f8 Write form data without charset parameter
This commit updates the content-type for form data to not include the
charset, unless it is different from the default charset.

Some servers don't handle charset parameter and the spec is unclear.

See gh-31781
2024-02-19 15:21:54 +01:00
Stéphane Nicoll 08998376cc Merge branch '6.1.x' 2024-02-19 10:52:17 +01:00
Stéphane Nicoll 6adda31328 Upgrade CI image to Java 22+36 RC 2024-02-19 10:51:16 +01:00
Sam Brannen c6e6a3e44d Link to section in reference manual 2024-02-18 18:19:59 +01:00
Sam Brannen bc2895a30b Support backticks for quoted identifiers in spring-r2dbc
NamedParameterUtils in spring-r2dbc now supports MySQL-style backticks
for quoted identifiers for consistency with spring-jdbc.

See gh-31944
Closes gh-32285
2024-02-17 16:05:40 +01:00
Sam Brannen d86af57e0f Polishing 2024-02-17 16:00:58 +01:00
Sam Brannen d4cde29f75 Clean up TODOs in SpEL 2024-02-17 15:33:05 +01:00
Sam Brannen 5f1e25a61f Polishing 2024-02-17 15:32:43 +01:00
Juergen Hoeller 0ddfe3977a Merge branch '6.1.x' 2024-02-16 22:50:04 +01:00
Juergen Hoeller c6146ea2db Introduce shortcut for declared dependency name matching target bean name
Closes gh-28122
2024-02-16 21:28:04 +01:00
Sam Brannen eefdee7983 Fix syntax in Selection/Projection examples 2024-02-16 18:44:28 +01:00
Sam Brannen ab48ac36e9 Deprecate local variable support in SpEL's internal ExpressionState
Since the Spring Expression Language does not actually support local
variables in expressions, this commit deprecates all public APIs
related to local variables in ExpressionState (namely, the two
enterScope(...) variants that accept local variable data,
setLocalVariable(), and lookupLocalVariable()).

In addition, we no longer invoke `state.enterScope("index", ...)` in
the Projection and Selection AST nodes since the $index local variable
was never accessible within expressions anyway.

See gh-23202
Closes gh-32004
2024-02-16 18:29:00 +01:00
Sam Brannen c1f0faade7 Polish ExpressionState 2024-02-16 18:25:14 +01:00
rstoyanchev cd2a3fdd8d Remove deprecations in HandlerResult
See gh-30608
2024-02-16 16:16:08 +00:00
Sam Brannen 71dfebbfe5 Polishing 2024-02-16 16:45:18 +01:00
Sam Brannen a85bf3185e Remove APIs deprecated for removal in 6.2
This commit removes the following obsolete and deprecated APIs.

- org.springframework.util.Base64Utils

- org.springframework.cache.jcache.interceptor.JCacheOperationSourcePointcut

- org.springframework.http.client.AbstractClientHttpResponse

- org.springframework.http.client.ClientHttpResponse.getRawStatusCode()

- org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME

- org.springframework.web.reactive.function.client.ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME

- org.springframework.web.filter.reactive.ServerWebExchangeContextFilter.get(Context)

- org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleBindException(...)

- org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleBindException(...)

Closes gh-30608
2024-02-16 16:45:18 +01:00
Sam Brannen 6d5bf6d9b3 Ensure alias resolution in SimpleAliasRegistry depends on registration order
Closes gh-32024
2024-02-16 15:22:27 +01:00
Sam Brannen 6b482df6fa Clean up warning in Gradle build 2024-02-16 15:04:41 +01:00
Sam Brannen ea4e7df9ca Consistently declare ignoreUnresolvablePlaceholders as last argument 2024-02-16 15:00:32 +01:00
Sam Brannen 7c07c43201 Polishing 2024-02-16 15:00:06 +01:00
Juergen Hoeller 6791ea94a0 Change executor phase to MAX_VALUE/2 and reduce timeout to 10 seconds
Closes gh-32152
2024-02-16 14:16:32 +01:00
Juergen Hoeller 7ee8e66c7f Avoid internal lifecycle synchronization in favor of lifecycle lock
Closes gh-32284
2024-02-16 12:42:39 +01:00
Juergen Hoeller 34372ee32b Introduce lock-based lifecycle waiting and default virtual threads flag
Closes gh-32252
2024-02-16 12:42:27 +01:00
Sam Brannen b6df5a677e Polishing 2024-02-16 11:41:22 +01:00
Sam Brannen fc9a118406 Polish SimpleCommandLinePropertySource support 2024-02-16 11:41:22 +01:00
Sam Brannen 87e6d1b7da Update Eclipse template to 6.2 2024-02-16 11:41:22 +01:00
Juergen Hoeller ea3573176a Avoid infinite recursion for self-referencing generic type
Closes gh-32282
See gh-30079
2024-02-16 11:15:02 +01:00
Stéphane Nicoll bcf235cc66 Merge branch '6.1.x' 2024-02-16 08:36:26 +01:00
Juergen Hoeller 7ad197e8e1 Deprecate LobHandler and SqlXmlHandler abstractions
Including SqlLobValue and related support classes.

Closes gh-32179
2024-02-15 17:26:49 +01:00
Juergen Hoeller 7e67da8a26 Support for matching partial generics
Closes gh-20727
2024-02-15 16:51:09 +01:00
Juergen Hoeller d4e8daaede Add javadoc note on recursive resolution as of 6.2
See gh-30079
2024-02-15 16:50:53 +01:00
Yanming Zhou e788aeb25b Improve GenericTypeResolver to resolve type variable recursively
Fix GH-24963
2024-02-15 16:28:45 +01:00
Stéphane Nicoll 4b2e40153a Merge pull request #32243 from ttddyy
* pr/32243:
  Polish "Add ThreadLocalAccessor for LocaleContext and RequestAttributes"
  Add ThreadLocalAccessor for LocaleContext and RequestAttributes

Closes gh-32243
2024-02-15 15:58:06 +01:00
Stéphane Nicoll aef4b21f19 Polish "Add ThreadLocalAccessor for LocaleContext and RequestAttributes"
See gh-32243
2024-02-15 15:57:43 +01:00
Tadaya Tsuyukubo 5bd1c1fddb Add ThreadLocalAccessor for LocaleContext and RequestAttributes
Add `ThreadLocalAccessor` implementations:
- `LocaleThreadLocalAccessor`
- `RequestAttributesThreadLocalAccessor`

See gh-32243
2024-02-15 15:49:55 +01:00
Stéphane Nicoll 5d22aa9770 Add support for escaping prefix and separator in property placeholders
Closes gh-9628
Closes gh-26268
2024-02-15 15:28:36 +01:00
Stéphane Nicoll e3aa5b6b11 Use new implementation in PropertyPlaceholderHelper
This commit removes the previous implementation in favor of the new
PlaceholderParser. The only noticeable side effect is that the exception
is no longer an IllegalArgumentException, but rather the dedicated
PlaceholderResolutionException.

See gh-9628
2024-02-15 15:27:13 +01:00
Stéphane Nicoll 00e05e603d Add new property placeholder implementation
This commit provides a rewrite of the parser for properties containing
potentially placeholders.

Assuming a source where `firstName` = `John` and `lastName` = `Smith`,
the "${firstName}-${lastName}" property is evaluated as "John-Smith".

Compared with the existing implementation in PropertyPlaceholderHelper,
the new implementation offers the following extra features:

1. Placeholder can be escaped using a configurable escape character.
When a placeholder is escaped it is rendered as is. This does apply to
any nested placeholder that wouldn't be escaped. For instance,
"\${firstName}" is evaluated as "${firstName}".
2. The default separator can also be escaped the same way. When the
separator is escaped, the left and right parts are not considered as
the key and the default value respectively. Rather the two parts
combined, including the separator (but not the escape separator) are
used for resolution. For instance, ${java\:comp/env/test} is looking
for a "java:comp/env/test" property.
3. Placeholders are resolved lazily. Previously, all nested placeholders
were resolved before considering if a separator was present. This
implementation only attempts the resolution of the default value if the
key does not provide a value.
4. Failure to resolve a placeholder are more rich, with a dedicated
PlaceholderResolutionException that contains the resolution chain.

See gh-9628
See gh-26268
2024-02-15 15:27:13 +01:00
Stéphane Nicoll 0fbfecd392 Merge pull request #31513 from bclozel
* pr/31513:
  Support "--" end of options in SimpleCommandLineArgsParser

Closes gh-31513
2024-02-15 15:09:39 +01:00
Brian Clozel b4131ce131 Support "--" end of options in SimpleCommandLineArgsParser
Prior to this commit, the `SimpleCommandLineArgsParser` would reject
"--" arguments as invalid. As reported by the community, the POSIX
utility conventions (Guideline 10) state that

> The first -- argument that is not an option-argument should be
> accepted as a delimiter indicating the end of options.
> Any following arguments should be treated as operands, even if they
> begin with the '-' character.

This commit updates `SimpleCommandLineArgsParser` to not reject "--"
arguments and instead to consider remaining arguments as non-optional.

See gh-31513
2024-02-15 15:06:17 +01:00
Stéphane Nicoll 0f707706f1 Stop setting a thread name prefix for externally defined Executors
This commit updates the WebSocket message broker configuration to stop
setting a thread name prefix for externally defined Executors.

This used to apply to:

* clientInboundChannel with a thread name prefix of
"clientInboundChannel-".
* clientOutboundChannel with a thread name prefix of
"clientOutboundChannel-".
* brokerChannel with a thread name prefix of "brokerChannel-".

Closes gh-32132
2024-02-15 14:59:42 +01:00
Stéphane Nicoll f526b23fd7 Harmonize WebSocket message broker to use Executor
This commit harmonizes the configuration of the WebSocket message
broker to use Executor rather than TaskExecutor as only the former
is enforced. This lets custom configuration to use a wider range
of implementations.

Closes gh-32129
2024-02-15 14:59:42 +01:00
Stéphane Nicoll 2fc8b13dd5 Add support for MySQL backticks
This commit makes sure that content within backticks are skipped
when parsing a SQL statement using NamedParameterUtils. This harmonizes
the current behavior of ignoring special characters that are wrapped
in backticks.

Closes gh-31944
2024-02-15 14:41:30 +01:00
Stéphane Nicoll e73bbd4ad3 Configure jsonpath MappingProvider in WebTestClient
This commit improves jsonpath support in WebTestClient by detecting
a suitable json encoder/decoder that can be applied to assert more
complex data structure.

Closes gh-31653
2024-02-15 14:41:30 +01:00
Stéphane Nicoll 9f8038963f Allow JsonPathExpectationsHelper to use a custom configuration
This commit improves JsonPathExpectationsHelper to allow a custom json
path configuration to be defined. The primary objective of a custom
configuration is to specify a custom mapper that can deserialize complex
object structure.

As part of this commit, it is now possible to invoke a Matcher against
a type that holds generic information, using a regular
ParameterizedTypeReference.

Given that the existing constructor takes a vararg of Object, this
commit also deprecates this constructor in favor of formatting the
expression String upfront.

Closes gh-31651
2024-02-15 13:57:40 +01:00
Stéphane Nicoll 4f8eca1350 Order methods that take a type as a lambda consistently
Closes gh-32062
2024-02-15 13:57:17 +01:00
Stéphane Nicoll 18ea43c905 Allow customizations of embedded database connections
This commit allows EmbeddedDatabaseConfigurer instances to be further
customized if necessary. EmbeddedDatabaseBuilder has a way now to set
a DatabaseConfigurer rather than just a type to provide full control,
or customize an existing supported database type using the new
EmbeddedDatabaseConfigurers#customizeConfigurer callback.

Closes gh-21160
2024-02-15 13:46:49 +01:00
Stéphane Nicoll bcccba50c1 Merge branch '6.1.x' 2024-02-15 13:07:47 +01:00
Stéphane Nicoll 8288db496d Initiate Spring Framework 6.2.0 snapshots 2024-02-15 13:03:54 +01:00
3031 changed files with 98238 additions and 25858 deletions
-17
View File
@@ -1,17 +0,0 @@
<!--
!!! For Security Vulnerabilities, please go to https://spring.io/security-policy !!!
-->
**Affects:** \<Spring Framework version>
---
<!--
Thanks for taking the time to create an issue. Please read the following:
- Questions should be asked on Stack Overflow.
- For bugs, specify affected versions and explain what you are trying to do.
- For enhancements, provide context and describe the problem.
Issue or Pull Request? Create only one, not both. GitHub treats them as the same.
If unsure, start with an issue, and if you submit a pull request later, the
issue will be closed as superseded.
-->
+6
View File
@@ -0,0 +1,6 @@
blank_issues_enabled: false
contact_links:
- name: Community Support
url: https://stackoverflow.com/tags/spring
about: Please ask and answer questions on StackOverflow with the tag `spring`.
+23
View File
@@ -0,0 +1,23 @@
---
name: General
about: Bugs, enhancements, documentation, tasks.
title: ''
labels: ''
assignees: ''
---
<!--
Have you considered asking for help on stackoverflow.com?
** Bug Reports **
Please submit issues against OSS supported versions, see https://spring.io/projects/spring-framework#support
Please provide a minimal sample application that reproduces the problem for faster issue triage.
** Enhancements requests **
Before explaining how you would like things to work,
please describe a concrete use case for this feature and how you have tried to solve this so far.
-->
@@ -4,6 +4,10 @@ inputs:
milestone:
description: 'Name of the GitHub milestone for which a release will be created'
required: true
pre-release:
description: 'Whether the release is a pre-release (a milestone or release candidate)'
required: false
default: 'false'
token:
description: 'Token to use for authentication with GitHub'
required: true
@@ -20,4 +24,4 @@ runs:
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md
run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || '' }}
@@ -31,10 +31,11 @@ runs:
${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '17' || '' }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1
with:
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
develocity-token-expiry: 4
- name: Configure Gradle Properties
shell: bash
run: |
@@ -20,7 +20,7 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@9fe0f98bd45b19e6e931d457f4e98f8f84461fb5 # v4.4.1
uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Release Artifacts
@@ -2,7 +2,7 @@ name: Build and Deploy Snapshot
on:
push:
branches:
- 6.1.x
- 6.2.x
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -21,13 +21,13 @@ jobs:
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
publish: true
- name: Deploy
uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1
uses: spring-io/artifactory-deploy-action@dc1913008c0599f0c4b1fdafb6ff3c502b3565ea # v0.0.2
with:
artifact-properties: |
/**/framework-api-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-api-*-docs.zip::zip.type=docs
/**/framework-api-*-schema.zip::zip.type=schema
build-name: 'spring-framework-6.1.x'
build-name: 'spring-framework-6.2.x'
folder: 'deployment-repository'
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository: 'libs-snapshot-local'
+3 -14
View File
@@ -9,22 +9,11 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Set Up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'liberica'
java-version: '17'
- name: Check Out
- name: Check Out Code
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
- name: Build
env:
CI: 'true'
GRADLE_ENTERPRISE_URL: 'https://ge.spring.io'
run: ./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --no-parallel --continue build
id: build
uses: ./.github/actions/build
- name: Print JVM Thread Dumps When Cancelled
if: cancelled()
uses: ./.github/actions/print-jvm-thread-dumps
+1 -3
View File
@@ -2,7 +2,7 @@ name: CI
on:
push:
branches:
- 6.1.x
- 6.2.x
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -21,8 +21,6 @@ jobs:
toolchain: false
- version: 21
toolchain: true
- version: 22
toolchain: true
- version: 23
toolchain: true
exclude:
+1 -1
View File
@@ -15,7 +15,7 @@ permissions:
jobs:
build:
name: Dispatch docs deployment
if: ${{ github.repository == 'spring-projects/spring-framework' }}
if: github.repository_owner == 'spring-projects'
runs-on: ubuntu-latest
steps:
- name: Check out code
+2 -2
View File
@@ -2,7 +2,7 @@ name: Release
on:
push:
tags:
- v6.1.[0-9]+
- v6.2.[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -73,7 +73,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@9fe0f98bd45b19e6e931d457f4e98f8f84461fb5 # v4.4.1
uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build
@@ -0,0 +1,37 @@
name: Update Antora UI Spring
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions:
pull-requests: write
issues: write
contents: write
jobs:
update-antora-ui-spring:
name: Update on Supported Branches
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
strategy:
matrix:
branch: [ '6.1.x' ]
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@5a57bcc6a0da2a1474136cf29571b277850432bc
name: Update
with:
docs-branch: ${{ matrix.branch }}
token: ${{ secrets.GITHUB_TOKEN }}
antora-file-path: 'framework-docs/antora-playbook.yml'
update-antora-ui-spring-docs-build:
name: Update on docs-build
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@5a57bcc6a0da2a1474136cf29571b277850432bc
name: Update
with:
docs-branch: 'docs-build'
token: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -46,7 +46,7 @@ jobs:
distribution: 'liberica'
java-version: 17
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1
with:
cache-read-only: false
- name: Configure Gradle Properties
+7 -6
View File
@@ -16,7 +16,7 @@ First off, thank you for taking the time to contribute! :+1: :tada:
### Code of Conduct
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc).
This project is governed by the [Spring Code of Conduct](https://github.com/spring-projects/spring-framework#coc-ov-file).
By participating you are expected to uphold this code.
Please report unacceptable behavior to spring-code-of-conduct@spring.io.
@@ -65,10 +65,6 @@ follow-up reports will need to be created as new issues with a fresh description
#### Submit a Pull Request
1. If you have not previously done so, please sign the
[Contributor License Agreement](https://cla.spring.io/sign/spring). You will be reminded
automatically when you submit the PR.
1. Should you create an issue first? No, just create the pull request and use the
description to provide context and motivation, as you would for an issue. If you want
to start a discussion first or have already created an issue, once a pull request is
@@ -85,8 +81,13 @@ multiple edits or corrections of the same logical change. See
[Rewriting History section of Pro Git](https://git-scm.com/book/en/Git-Tools-Rewriting-History)
for an overview of streamlining the commit history.
1. All commits must include a _Signed-off-by_ trailer at the end of each commit message
to indicate that the contributor agrees to the Developer Certificate of Origin.
For additional details, please refer to the blog post
[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring](https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring).
1. Format commit messages using 55 characters for the subject line, 72 characters per line
for the description, followed by the issue fixed, e.g. `Closes gh-22276`. See the
for the description, followed by the issue fixed, for example, `Closes gh-22276`. See the
[Commit Guidelines section of Pro Git](https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines)
for best practices around commit messages, and use `git log` to see some examples.
+2 -2
View File
@@ -1,4 +1,4 @@
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=6.1.x)](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3A6.1.x) [![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.spring.io/scans?search.rootProjectNames=spring)
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=main)](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3Amain) [![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](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@spring.io.
This project is governed by the [Spring Code of Conduct](https://github.com/spring-projects/spring-framework/?tab=coc-ov-file#contributor-code-of-conduct). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@spring.io.
## Access to Binaries
+5 -11
View File
@@ -1,16 +1,10 @@
# Security Policy
# Reporting a Vulnerability
Please, [open a draft security advisory](https://github.com/spring-projects/security-advisories/security/advisories/new) if you need to disclose and discuss a security issue in private with the Spring Framework team. Note that we only accept reports against [supported versions](https://spring.io/projects/spring-framework#support).
For more details, check out our [security policy](https://spring.io/security-policy).
## JAR signing
Spring Framework JARs released on Maven Central are signed.
You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt
## Supported Versions
Please see the
[Spring Framework Versions](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions)
wiki page.
## Reporting a Vulnerability
Please see https://spring.io/security-policy.
+6 -5
View File
@@ -2,13 +2,14 @@ plugins {
id 'io.freefair.aspectj' version '8.4' apply false
// kotlinVersion is managed in gradle.properties
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka' version '1.8.20'
id 'org.jetbrains.dokka' version '1.9.20'
id 'com.github.ben-manes.versions' version '0.51.0'
id 'com.github.bjornvester.xjc' version '1.8.2' apply false
id 'de.undercouch.download' version '5.4.0'
id 'io.github.goooler.shadow' version '8.1.8' apply false
id 'me.champeau.jmh' version '0.7.2' apply false
id 'me.champeau.mrjar' version '0.1.1'
id "net.ltgt.errorprone" version "3.1.0" apply false
}
ext {
@@ -24,17 +25,17 @@ configure(allprojects) { project ->
repositories {
mavenCentral()
maven {
url "https://repo.spring.io/milestone"
url = "https://repo.spring.io/milestone"
content {
// Netty 5 optional support
includeGroup 'io.projectreactor.netty'
}
}
if (version.contains('-')) {
maven { url "https://repo.spring.io/milestone" }
maven { url = "https://repo.spring.io/milestone" }
}
if (version.endsWith('-SNAPSHOT')) {
maven { url "https://repo.spring.io/snapshot" }
maven { url = "https://repo.spring.io/snapshot" }
}
}
configurations.all {
@@ -101,7 +102,7 @@ configure([rootProject] + javaProjects) { project ->
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
// See https://github.com/spring-projects/spring-framework/issues/27497
//
// "https://junit.org/junit5/docs/5.10.4/api/",
// "https://junit.org/junit5/docs/5.11.4/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
//"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/",
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
@@ -50,7 +50,7 @@ public class CheckstyleConventions {
project.getPlugins().apply(CheckstylePlugin.class);
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g"));
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.setToolVersion("10.21.2");
checkstyle.setToolVersion("10.21.1");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
+2 -2
View File
@@ -9,7 +9,7 @@ apply from: "${rootDir}/gradle/publications.gradle"
repositories {
maven {
url "https://repo.spring.io/release"
url = "https://repo.spring.io/release"
}
}
@@ -87,7 +87,7 @@ tasks.register('schemaZip', Zip) {
archiveClassifier.set("schema")
description = "Builds -${archiveClassifier} archive containing all " +
"XSDs for deployment at https://springframework.org/schema."
duplicatesStrategy DuplicatesStrategy.EXCLUDE
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
moduleProjects.each { module ->
def Properties schemas = new Properties();
+3 -1
View File
@@ -21,6 +21,7 @@ asciidoc:
table-stripes: 'odd'
include-java: 'example$docs-src/main/java/org/springframework/docs'
include-kotlin: 'example$docs-src/main/kotlin/org/springframework/docs'
include-xml: 'example$docs-src/main/resources/org/springframework/docs'
spring-site: 'https://spring.io'
spring-site-blog: '{spring-site}/blog'
spring-site-cve: "{spring-site}/security"
@@ -41,7 +42,8 @@ asciidoc:
spring-framework-reference: '{spring-framework-docs-root}/{spring-version}/reference'
#
# Other Spring portfolio projects
spring-boot-docs: '{docs-site}/spring-boot/docs/current/reference/html'
spring-boot-docs: '{docs-site}/spring-boot'
spring-boot-docs-ref: '{spring-boot-docs}/reference'
spring-boot-issues: '{spring-github-org}/spring-boot/issues'
# TODO add more projects / links or just build up on {docs-site}?
# TODO rename the below using new conventions
+17 -1
View File
@@ -37,20 +37,36 @@ javadoc {
repositories {
maven {
url "https://repo.spring.io/release"
url = "https://repo.spring.io/release"
}
}
dependencies {
api(project(":spring-aspects"))
api(project(":spring-context"))
api(project(":spring-context-support"))
api(project(":spring-jdbc"))
api(project(":spring-jms"))
api(project(":spring-test"))
api(project(":spring-web"))
api(project(":spring-webflux"))
api(project(":spring-webmvc"))
api(project(":spring-websocket"))
api("com.fasterxml.jackson.core:jackson-databind")
api("com.fasterxml.jackson.module:jackson-module-parameter-names")
api("com.mchange:c3p0:0.9.5.5")
api("com.oracle.database.jdbc:ojdbc11")
api("io.projectreactor.netty:reactor-netty-http")
api("jakarta.jms:jakarta.jms-api")
api("jakarta.servlet:jakarta.servlet-api")
api("jakarta.resource:jakarta.resource-api")
api("jakarta.validation:jakarta.validation-api")
api("javax.cache:cache-api")
api("org.apache.activemq:activemq-ra:6.1.2")
api("org.apache.commons:commons-dbcp2:2.11.0")
api("org.aspectj:aspectjweaver")
api("org.eclipse.jetty.websocket:jetty-websocket-jetty-api")
api("org.jetbrains.kotlin:kotlin-stdlib")
implementation(project(":spring-core-test"))
+97 -83
View File
@@ -60,6 +60,7 @@
**** xref:core/expressions/language-ref/constructors.adoc[]
**** xref:core/expressions/language-ref/variables.adoc[]
**** xref:core/expressions/language-ref/functions.adoc[]
**** xref:core/expressions/language-ref/varargs.adoc[]
**** xref:core/expressions/language-ref/bean-references.adoc[]
**** xref:core/expressions/language-ref/operator-ternary.adoc[]
**** xref:core/expressions/language-ref/operator-elvis.adoc[]
@@ -106,87 +107,6 @@
*** xref:core/appendix/xsd-schemas.adoc[]
*** xref:core/appendix/xml-custom.adoc[]
*** xref:core/appendix/application-startup-steps.adoc[]
* xref:testing.adoc[]
** xref:testing/introduction.adoc[]
** xref:testing/unit.adoc[]
** xref:testing/integration.adoc[]
** xref:testing/support-jdbc.adoc[]
** xref:testing/testcontext-framework.adoc[]
*** xref:testing/testcontext-framework/key-abstractions.adoc[]
*** xref:testing/testcontext-framework/bootstrapping.adoc[]
*** xref:testing/testcontext-framework/tel-config.adoc[]
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/inheritance.adoc[]
**** xref:testing/testcontext-framework/ctx-management/env-profiles.adoc[]
**** xref:testing/testcontext-framework/ctx-management/property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web-mocks.adoc[]
**** xref:testing/testcontext-framework/ctx-management/caching.adoc[]
**** xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[]
**** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[]
*** xref:testing/testcontext-framework/fixture-di.adoc[]
*** xref:testing/testcontext-framework/web-scoped-beans.adoc[]
*** xref:testing/testcontext-framework/tx.adoc[]
*** xref:testing/testcontext-framework/executing-sql.adoc[]
*** xref:testing/testcontext-framework/parallel-test-execution.adoc[]
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/spring-mvc-test-framework.adoc[]
*** xref:testing/spring-mvc-test-framework/server.adoc[]
*** xref:testing/spring-mvc-test-framework/server-static-imports.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-options.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-steps.adoc[]
*** xref:testing/spring-mvc-test-framework/server-performing-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-defining-expectations.adoc[]
*** xref:testing/spring-mvc-test-framework/async-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-streaming-response.adoc[]
*** xref:testing/spring-mvc-test-framework/server-filters.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-resources.adoc[]
*** xref:testing/spring-mvc-test-framework/server-htmlunit.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/geb.adoc[]
** xref:testing/spring-mvc-test-client.adoc[]
** xref:testing/appendix.adoc[]
*** xref:testing/annotations.adoc[]
**** xref:testing/annotations/integration-standard.adoc[]
**** xref:testing/annotations/integration-spring.adoc[]
***** xref:testing/annotations/integration-spring/annotation-bootstrapwith.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-webappconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contexthierarchy.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextcustomizerfactories.adoc[]
***** xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[]
***** xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[]
***** xref:testing/annotations/integration-spring/annotation-commit.adoc[]
***** xref:testing/annotations/integration-spring/annotation-rollback.adoc[]
***** xref:testing/annotations/integration-spring/annotation-beforetransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-aftertransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sql.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlconfig.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[]
***** xref:testing/annotations/integration-spring/annotation-disabledinaotmode.adoc[]
**** xref:testing/annotations/integration-junit4.adoc[]
**** xref:testing/annotations/integration-junit-jupiter.adoc[]
**** xref:testing/annotations/integration-meta.adoc[]
*** xref:testing/resources.adoc[]
* xref:data-access.adoc[]
** xref:data-access/transaction.adoc[]
*** xref:data-access/transaction/motivation.adoc[]
@@ -245,6 +165,7 @@
**** xref:web/webmvc/mvc-servlet/multipart.adoc[]
**** xref:web/webmvc/mvc-servlet/logging.adoc[]
*** xref:web/webmvc/filters.adoc[]
*** xref:web/webmvc/message-converters.adoc[]
*** xref:web/webmvc/mvc-controller.adoc[]
**** xref:web/webmvc/mvc-controller/ann.adoc[]
**** xref:web/webmvc/mvc-controller/ann-requestmapping.adoc[]
@@ -285,6 +206,7 @@
**** xref:web/webmvc-view/mvc-freemarker.adoc[]
**** xref:web/webmvc-view/mvc-groovymarkup.adoc[]
**** xref:web/webmvc-view/mvc-script.adoc[]
**** xref:web/webmvc-view/mvc-fragments.adoc[]
**** xref:web/webmvc-view/mvc-jsp.adoc[]
**** xref:web/webmvc-view/mvc-feeds.adoc[]
**** xref:web/webmvc-view/mvc-document.adoc[]
@@ -392,6 +314,97 @@
** xref:web/webflux-test.adoc[]
** xref:rsocket.adoc[]
** xref:web/webflux-reactive-libraries.adoc[]
* xref:testing.adoc[]
** xref:testing/introduction.adoc[]
** xref:testing/unit.adoc[]
** xref:testing/integration.adoc[]
** xref:testing/support-jdbc.adoc[]
** xref:testing/testcontext-framework.adoc[]
*** xref:testing/testcontext-framework/key-abstractions.adoc[]
*** xref:testing/testcontext-framework/bootstrapping.adoc[]
*** xref:testing/testcontext-framework/tel-config.adoc[]
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/inheritance.adoc[]
**** xref:testing/testcontext-framework/ctx-management/env-profiles.adoc[]
**** xref:testing/testcontext-framework/ctx-management/property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web-mocks.adoc[]
**** xref:testing/testcontext-framework/ctx-management/caching.adoc[]
**** xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[]
**** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[]
*** xref:testing/testcontext-framework/fixture-di.adoc[]
*** xref:testing/testcontext-framework/bean-overriding.adoc[]
*** xref:testing/testcontext-framework/web-scoped-beans.adoc[]
*** xref:testing/testcontext-framework/tx.adoc[]
*** xref:testing/testcontext-framework/executing-sql.adoc[]
*** xref:testing/testcontext-framework/parallel-test-execution.adoc[]
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/mockmvc.adoc[]
*** xref:testing/mockmvc/overview.adoc[]
*** xref:testing/mockmvc/setup-options.adoc[]
*** xref:testing/mockmvc/hamcrest.adoc[]
**** xref:testing/mockmvc/hamcrest/static-imports.adoc[]
**** xref:testing/mockmvc/hamcrest/setup.adoc[]
**** xref:testing/mockmvc/hamcrest/setup-steps.adoc[]
**** xref:testing/mockmvc/hamcrest/requests.adoc[]
**** xref:testing/mockmvc/hamcrest/expectations.adoc[]
**** xref:testing/mockmvc/hamcrest/async-requests.adoc[]
**** xref:testing/mockmvc/hamcrest/vs-streaming-response.adoc[]
**** xref:testing/mockmvc/hamcrest/filters.adoc[]
*** xref:testing/mockmvc/assertj.adoc[]
**** xref:testing/mockmvc/assertj/setup.adoc[]
**** xref:testing/mockmvc/assertj/requests.adoc[]
**** xref:testing/mockmvc/assertj/assertions.adoc[]
**** xref:testing/mockmvc/assertj/integration.adoc[]
*** xref:testing/mockmvc/htmlunit.adoc[]
**** xref:testing/mockmvc/htmlunit/why.adoc[]
**** xref:testing/mockmvc/htmlunit/mah.adoc[]
**** xref:testing/mockmvc/htmlunit/webdriver.adoc[]
**** xref:testing/mockmvc/htmlunit/geb.adoc[]
*** xref:testing/mockmvc/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/mockmvc/resources.adoc[]
** xref:testing/spring-mvc-test-client.adoc[]
** xref:testing/appendix.adoc[]
*** xref:testing/annotations.adoc[]
**** xref:testing/annotations/integration-standard.adoc[]
**** xref:testing/annotations/integration-spring.adoc[]
***** xref:testing/annotations/integration-spring/annotation-bootstrapwith.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-webappconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contexthierarchy.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextcustomizerfactories.adoc[]
***** xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testbean.adoc[]
***** xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[]
***** xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[]
***** xref:testing/annotations/integration-spring/annotation-commit.adoc[]
***** xref:testing/annotations/integration-spring/annotation-rollback.adoc[]
***** xref:testing/annotations/integration-spring/annotation-beforetransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-aftertransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sql.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlconfig.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[]
***** xref:testing/annotations/integration-spring/annotation-disabledinaotmode.adoc[]
**** xref:testing/annotations/integration-junit4.adoc[]
**** xref:testing/annotations/integration-junit-jupiter.adoc[]
**** xref:testing/annotations/integration-meta.adoc[]
*** xref:testing/resources.adoc[]
* xref:integration.adoc[]
** xref:integration/rest-clients.adoc[]
** xref:integration/jms.adoc[]
@@ -439,5 +452,6 @@
** xref:languages/groovy.adoc[]
** xref:languages/dynamic.adoc[]
* xref:appendix.adoc[]
* {spring-framework-wiki}[Wiki]
* {spring-framework-docs-root}/{spring-version}/javadoc-api/[Java API,window=_blank, role=link-external]
* {spring-framework-api-kdoc}/[Kotlin API,window=_blank, role=link-external]
* {spring-framework-wiki}[Wiki, window=_blank, role=link-external]
@@ -33,11 +33,11 @@ arbitrary advice types. This section describes the basic concepts and standard a
[[aop-api-advice-around]]
=== Interception Around Advice
The most fundamental advice type in Spring is interception around advice.
The most fundamental advice type in Spring is _interception around advice_.
Spring is compliant with the AOP `Alliance` interface for around advice that uses method
interception. Classes that implement `MethodInterceptor` and that implement around advice should also implement the
following interface:
Spring is compliant with the AOP Alliance interface for around advice that uses method
interception. Classes that implement around advice should therefore implement the
following `MethodInterceptor` interface from the `org.aopalliance.intercept` package:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -49,8 +49,8 @@ following interface:
The `MethodInvocation` argument to the `invoke()` method exposes the method being
invoked, the target join point, the AOP proxy, and the arguments to the method. The
`invoke()` method should return the invocation's result: the return value of the join
point.
`invoke()` method should return the invocation's result: typically the return value of
the join point.
The following example shows a simple `MethodInterceptor` implementation:
@@ -58,30 +58,30 @@ The following example shows a simple `MethodInterceptor` implementation:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
Object result = invocation.proceed();
System.out.println("Invocation returned");
return rval;
return result;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class DebugInterceptor : MethodInterceptor {
override fun invoke(invocation: MethodInvocation): Any {
println("Before: invocation=[$invocation]")
val rval = invocation.proceed()
val result = invocation.proceed()
println("Invocation returned")
return rval
return result
}
}
----
@@ -105,7 +105,7 @@ currently define pointcut interfaces.
[[aop-api-advice-before]]
=== Before Advice
A simpler advice type is a before advice. This does not need a `MethodInvocation`
A simpler advice type is a _before advice_. This does not need a `MethodInvocation`
object, since it is called only before entering the method.
The main advantage of a before advice is that there is no need to invoke the `proceed()`
@@ -122,10 +122,6 @@ The following listing shows the `MethodBeforeAdvice` interface:
}
----
(Spring's API design would allow for
field before advice, although the usual objects apply to field interception and it is
unlikely for Spring to ever implement it.)
Note that the return type is `void`. Before advice can insert custom behavior before the join
point runs but cannot change the return value. If a before advice throws an
exception, it stops further execution of the interceptor chain. The exception
@@ -139,7 +135,7 @@ The following example shows a before advice in Spring, which counts all method i
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class CountingBeforeAdvice implements MethodBeforeAdvice {
@@ -157,7 +153,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class CountingBeforeAdvice : MethodBeforeAdvice {
@@ -176,10 +172,10 @@ TIP: Before advice can be used with any pointcut.
[[aop-api-advice-throws]]
=== Throws Advice
Throws advice is invoked after the return of the join point if the join point threw
_Throws advice_ is invoked after the return of the join point if the join point threw
an exception. Spring offers typed throws advice. Note that this means that the
`org.springframework.aop.ThrowsAdvice` interface does not contain any methods. It is a
tag interface identifying that the given object implements one or more typed throws
marker interface identifying that the given object implements one or more typed throws
advice methods. These should be in the following form:
[source,java,indent=0,subs="verbatim,quotes"]
@@ -189,15 +185,16 @@ advice methods. These should be in the following form:
Only the last argument is required. The method signatures may have either one or four
arguments, depending on whether the advice method is interested in the method and
arguments. The next two listing show classes that are examples of throws advice.
arguments. The next two listings show classes that are examples of throws advice.
The following advice is invoked if a `RemoteException` is thrown (including from subclasses):
The following advice is invoked if a `RemoteException` is thrown (including subclasses of
`RemoteException`):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class RemoteThrowsAdvice implements ThrowsAdvice {
@@ -209,7 +206,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class RemoteThrowsAdvice : ThrowsAdvice {
@@ -220,15 +217,15 @@ Kotlin::
----
======
Unlike the preceding
advice, the next example declares four arguments, so that it has access to the invoked method, method
arguments, and target object. The following advice is invoked if a `ServletException` is thrown:
Unlike the preceding advice, the next example declares four arguments, so that it has
access to the invoked method, method arguments, and target object. The following advice
is invoked if a `ServletException` is thrown:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
@@ -240,7 +237,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ServletThrowsAdviceWithArguments : ThrowsAdvice {
@@ -259,7 +256,7 @@ methods can be combined in a single class. The following listing shows the final
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static class CombinedThrowsAdvice implements ThrowsAdvice {
@@ -275,7 +272,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class CombinedThrowsAdvice : ThrowsAdvice {
@@ -304,7 +301,7 @@ TIP: Throws advice can be used with any pointcut.
[[aop-api-advice-after-returning]]
=== After Returning Advice
An after returning advice in Spring must implement the
An _after returning advice_ in Spring must implement the
`org.springframework.aop.AfterReturningAdvice` interface, which the following listing shows:
[source,java,indent=0,subs="verbatim,quotes"]
@@ -326,7 +323,7 @@ not thrown exceptions:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
@@ -345,7 +342,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class CountingAfterReturningAdvice : AfterReturningAdvice {
@@ -368,7 +365,7 @@ TIP: After returning advice can be used with any pointcut.
[[aop-api-advice-introduction]]
=== Introduction Advice
Spring treats introduction advice as a special kind of interception advice.
Spring treats _introduction advice_ as a special kind of interception advice.
Introduction requires an `IntroductionAdvisor` and an `IntroductionInterceptor` that
implement the following interface:
@@ -420,7 +417,7 @@ introduce the following interface to one or more objects:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface Lockable {
void lock();
@@ -431,7 +428,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
interface Lockable {
fun lock()
@@ -480,7 +477,7 @@ The following example shows the example `LockMixin` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
@@ -510,7 +507,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class LockMixin : DelegatingIntroductionInterceptor(), Lockable {
@@ -556,7 +553,7 @@ The following example shows our `LockMixinAdvisor` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
@@ -568,7 +565,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class LockMixinAdvisor : DefaultIntroductionAdvisor(LockMixin(), Lockable::class.java)
----
@@ -10,7 +10,7 @@ following methods:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Advisor[] getAdvisors();
@@ -35,7 +35,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun getAdvisors(): Array<Advisor>
@@ -90,7 +90,7 @@ manipulating its advice:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
@@ -110,7 +110,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val advised = myObject as Advised
val advisors = advised.advisors
@@ -196,16 +196,16 @@ follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Person person = (Person) factory.getBean("person");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val person = factory.getBean("person") as Person;
val person = factory.getBean("person") as Person
----
======
@@ -128,18 +128,7 @@ the resulting pointcut is effectively the union of the specified patterns.)
The following example shows how to use `JdkRegexpMethodPointcut`:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="settersAndAbsquatulatePointcut"
class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
----
include-code::./JdkRegexpConfiguration[tag=snippet,indent=0]
Spring provides a convenience class named `RegexpMethodPointcutAdvisor`, which lets us
also reference an `Advice` (remember that an `Advice` can be an interceptor, before advice,
@@ -147,21 +136,7 @@ throws advice, and others). Behind the scenes, Spring uses a `JdkRegexpMethodPoi
Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both
pointcut and advice, as the following example shows:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="settersAndAbsquatulateAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="beanNameOfAopAllianceInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
----
include-code::./RegexpConfiguration[tag=snippet,indent=0]
You can use `RegexpMethodPointcutAdvisor` with any `Advice` type.
@@ -212,7 +187,7 @@ following example shows how to subclass `StaticMethodMatcherPointcut`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
class TestStaticPointcut extends StaticMethodMatcherPointcut {
@@ -224,7 +199,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class TestStaticPointcut : StaticMethodMatcherPointcut() {
@@ -12,7 +12,7 @@ interceptor and one advisor:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.addAdvice(myMethodInterceptor);
@@ -22,7 +22,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val factory = ProxyFactory(myBusinessInterfaceImpl)
factory.addAdvice(myMethodInterceptor)
@@ -38,7 +38,7 @@ You can change the target by using the `swap()` method on HotSwappableTargetSour
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
@@ -46,7 +46,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
val oldTarget = swapper.swap(newTarget)
@@ -152,7 +152,7 @@ The cast is defined as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
System.out.println("Max pool size is " + conf.getMaxSize());
@@ -160,7 +160,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val conf = beanFactory.getBean("businessObject") as PoolingConfig
println("Max pool size is " + conf.maxSize)
@@ -15,7 +15,7 @@ The basic usage for this class is very simple, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
@@ -34,7 +34,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
// create a factory that can generate a proxy for the given target object
val factory = AspectJProxyFactory(targetObject)
@@ -17,7 +17,7 @@ The following example uses an inline pointcut expression.
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@@ -34,7 +34,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@@ -57,7 +57,7 @@ as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@@ -74,7 +74,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@@ -101,7 +101,7 @@ You can declare it by using the `@AfterReturning` annotation.
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@@ -118,7 +118,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@@ -146,7 +146,7 @@ access, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@@ -165,7 +165,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@@ -204,7 +204,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@@ -221,7 +221,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@@ -247,7 +247,7 @@ The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@@ -266,7 +266,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@@ -311,7 +311,7 @@ purposes. The following example shows how to use after finally advice:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@@ -328,7 +328,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.After
@@ -417,7 +417,7 @@ The following example shows how to use around advice:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
@@ -438,7 +438,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Around
@@ -500,7 +500,7 @@ You could write the following:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
public void validateAccount(Account account) {
@@ -510,7 +510,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
fun validateAccount(account: Account) {
@@ -533,7 +533,7 @@ from the advice. This would look as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@@ -546,7 +546,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private fun accountDataAccessOperation(account: Account) {
@@ -572,7 +572,7 @@ The following shows the definition of the `@Auditable` annotation:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@@ -583,7 +583,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@@ -597,7 +597,7 @@ The following shows the advice that matches the execution of `@Auditable` method
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
public void audit(Auditable auditable) {
@@ -609,7 +609,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
fun audit(auditable: Auditable) {
@@ -630,7 +630,7 @@ you have a generic type like the following:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public interface Sample<T> {
void sampleGenericMethod(T param);
@@ -640,7 +640,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
interface Sample<T> {
fun sampleGenericMethod(param: T)
@@ -656,7 +656,7 @@ tying the advice parameter to the parameter type for which you want to intercept
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
@@ -666,7 +666,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
fun beforeSampleMethod(param: MyType) {
@@ -682,7 +682,7 @@ pointcut as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
@@ -692,7 +692,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
fun beforeSampleMethod(param: Collection<MyType>) {
@@ -756,7 +756,7 @@ The following example shows how to use the `argNames` attribute:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@@ -771,7 +771,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@@ -794,7 +794,7 @@ point object, the `argNames` attribute does not need to include it:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@@ -809,7 +809,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@@ -833,7 +833,7 @@ the `argNames` attribute:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
public void audit(JoinPoint jp) {
@@ -844,7 +844,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
fun audit(jp: JoinPoint) {
@@ -867,7 +867,7 @@ The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
@@ -882,7 +882,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
@@ -923,7 +923,7 @@ Each of the distinct advice types of a particular aspect is conceptually meant t
to the join point directly. As a consequence, an `@AfterThrowing` advice method is not
supposed to receive an exception from an accompanying `@After`/`@AfterReturning` method.
As of Spring Framework 5.2.7, advice methods defined in the same `@Aspect` class that
Advice methods defined in the same `@Aspect` class that
need to run at the same join point are assigned precedence based on their advice type in
the following order, from highest to lowest precedence: `@Around`, `@Before`, `@After`,
`@AfterReturning`, `@AfterThrowing`. Note, however, that an `@After` advice method will
@@ -8,54 +8,8 @@ determines that a bean is advised by one or more aspects, it automatically gener
a proxy for that bean to intercept method invocations and ensures that advice is run
as needed.
The @AspectJ support can be enabled with XML- or Java-style configuration. In either
case, you also need to ensure that AspectJ's `aspectjweaver.jar` library is on the
classpath of your application (version 1.9 or later). This library is available in the
`lib` directory of an AspectJ distribution or from the Maven Central repository.
[[aop-enable-aspectj-java]]
== Enabling @AspectJ Support with Java Configuration
To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy`
annotation, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Configuration
@EnableAspectJAutoProxy
class AppConfig
----
======
[[aop-enable-aspectj-xml]]
== Enabling @AspectJ Support with XML Configuration
To enable @AspectJ support with XML-based configuration, use the `aop:aspectj-autoproxy`
element, as the following example shows:
[source,xml,indent=0,subs="verbatim"]
----
<aop:aspectj-autoproxy/>
----
This assumes that you use schema support as described in
xref:core/appendix/xsd-schemas.adoc[XML Schema-based configuration].
See xref:core/appendix/xsd-schemas.adoc#aop[the AOP schema] for how to
import the tags in the `aop` namespace.
The @AspectJ support can be enabled with programmatic or XML configuration. In either
case, you also need to ensure that AspectJ's `org.aspectj:aspectjweaver` library is on the
classpath of your application (version 1.9 or later).
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
@@ -9,43 +9,12 @@ minimal steps required for a not-very-useful aspect.
The first of the two examples shows a regular bean definition in the application context
that points to a bean class that is annotated with `@Aspect`:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="myAspect" class="com.xyz.NotVeryUsefulAspect">
<!-- configure properties of the aspect here -->
</bean>
----
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is
annotated with `@Aspect`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
----
package com.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
----
package com.xyz
import org.aspectj.lang.annotation.Aspect
@Aspect
class NotVeryUsefulAspect
----
======
include-code::./NotVeryUsefulAspect[tag=snippet,indent=0]
Aspects (classes annotated with `@Aspect`) can have methods and fields, the same as any
other class. They can also contain pointcut, advice, and introduction (inter-type)
@@ -16,93 +16,9 @@ aspect.
Because we want to retry the operation, we need to use around advice so that we can
call `proceed` multiple times. The following listing shows the basic aspect implementation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Aspect
public class ConcurrentOperationExecutor implements Ordered {
include-code::./ConcurrentOperationExecutor[tag=snippet,indent=0]
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
@Around("com.xyz.CommonPointcuts.businessService()") // <1>
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
} while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
----
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Aspect
class ConcurrentOperationExecutor : Ordered {
private val DEFAULT_MAX_RETRIES = 2
private var maxRetries = DEFAULT_MAX_RETRIES
private var order = 1
fun setMaxRetries(maxRetries: Int) {
this.maxRetries = maxRetries
}
override fun getOrder(): Int {
return this.order
}
fun setOrder(order: Int) {
this.order = order
}
@Around("com.xyz.CommonPointcuts.businessService()") // <1>
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any? {
var numAttempts = 0
var lockFailureException: PessimisticLockingFailureException
do {
numAttempts++
try {
return pjp.proceed()
} catch (ex: PessimisticLockingFailureException) {
lockFailureException = ex
}
} while (numAttempts <= this.maxRetries)
throw lockFailureException
}
}
----
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
======
`@Around("com.xyz.CommonPointcuts.businessService()")` references the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Note that the aspect implements the `Ordered` interface so that we can set the precedence of
the aspect higher than the transaction advice (we want a fresh transaction each time we
@@ -114,70 +30,15 @@ we have exhausted all of our retry attempts.
The corresponding Spring configuration follows:
[source,xml,indent=0,subs="verbatim"]
----
<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor"
class="com.xyz.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
----
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
To refine the aspect so that it retries only idempotent operations, we might define the following
`Idempotent` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Retention(RetentionPolicy.RUNTIME)
// marker annotation
public @interface Idempotent {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Retention(AnnotationRetention.RUNTIME)
// marker annotation
annotation class Idempotent
----
======
include-code::./service/Idempotent[tag=snippet,indent=0]
We can then use the annotation to annotate the implementation of service operations. The change
to the aspect to retry only idempotent operations involves refining the pointcut
expression so that only `@Idempotent` operations match, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any? {
// ...
}
----
======
include-code::./service/SampleService[tag=snippet,indent=0]
@@ -17,7 +17,7 @@ annotation. Consider the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
public class MyAspect {
@@ -33,7 +33,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
class MyAspect {
@@ -9,13 +9,13 @@ You can make an introduction by using the `@DeclareParents` annotation. This ann
is used to declare that matching types have a new parent (hence the name). For example,
given an interface named `UsageTracked` and an implementation of that interface named
`DefaultUsageTracked`, the following aspect declares that all implementors of service
interfaces also implement the `UsageTracked` interface (e.g. for statistics via JMX):
interfaces also implement the `UsageTracked` interface (for example, for statistics via JMX):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Aspect
public class UsageTracking {
@@ -33,7 +33,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Aspect
class UsageTracking {
@@ -63,16 +63,16 @@ you would write the following:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
val usageTracked = context.getBean("myService", UsageTracked.class)
val usageTracked = context.getBean<UsageTracked>("myService")
----
======
@@ -19,7 +19,7 @@ matches the execution of any method named `transfer`:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature
@@ -27,7 +27,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Pointcut("execution(* transfer(..))") // the pointcut expression
private fun anyOldTransfer() {} // the pointcut signature
@@ -150,7 +150,7 @@ pointcut expressions by name. The following example shows three pointcut express
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz;
@@ -174,7 +174,7 @@ trading module.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz
@@ -217,7 +217,7 @@ expressions for this purpose. Such a class typically resembles the following
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
[source,java,indent=0,subs="verbatim",chomp="-packages",fold="none"]
----
package com.xyz;
@@ -279,7 +279,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages",fold="none"]
----
package com.xyz
@@ -59,7 +59,7 @@ For example, in the @AspectJ style you can write something like the following:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Pointcut("execution(* get*())")
public void propertyAccess() {}
@@ -73,7 +73,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Pointcut("execution(* get*())")
fun propertyAccess() {}
@@ -65,7 +65,7 @@ with less potential for errors. For example, you do not need to invoke the `proc
method on the `JoinPoint` used for around advice, and, hence, you cannot fail to invoke it.
All advice parameters are statically typed so that you work with advice parameters of
the appropriate type (e.g. the type of the return value from a method execution) rather
the appropriate type (for example, the type of the return value from a method execution) rather
than `Object` arrays.
The concept of join points matched by pointcuts is the key to AOP, which distinguishes
@@ -6,22 +6,26 @@ target object. JDK dynamic proxies are built into the JDK, whereas CGLIB is a co
open-source class definition library (repackaged into `spring-core`).
If the target object to be proxied implements at least one interface, a JDK dynamic
proxy is used. All of the interfaces implemented by the target type are proxied.
If the target object does not implement any interfaces, a CGLIB proxy is created.
proxy is used, and all of the interfaces implemented by the target type are proxied.
If the target object does not implement any interfaces, a CGLIB proxy is created which
is a runtime-generated subclass of the target type.
If you want to force the use of CGLIB proxying (for example, to proxy every method
defined for the target object, not only those implemented by its interfaces),
you can do so. However, you should consider the following issues:
* With CGLIB, `final` methods cannot be advised, as they cannot be overridden in
runtime-generated subclasses.
* As of Spring 4.0, the constructor of your proxied object is NOT called twice anymore,
since the CGLIB proxy instance is created through Objenesis. Only if your JVM does
not allow for constructor bypassing, you might see double invocations and
corresponding debug log entries from Spring's AOP support.
* Your CGLIB proxy usage may face limitations with the JDK 9+ platform module system.
As a typical case, you cannot create a CGLIB proxy for a class from the `java.lang`
package when deploying on the module path. Such cases require a JVM bootstrap flag
* `final` classes cannot be proxied, because they cannot be extended.
* `final` methods cannot be advised, because they cannot be overridden.
* `private` methods cannot be advised, because they cannot be overridden.
* Methods that are not visible for example, package-private methods in a parent class
from a different package cannot be advised because they are effectively private.
* The constructor of your proxied object will not be called twice, since the CGLIB proxy
instance is created through Objenesis. However, if your JVM does not allow for
constructor bypassing, you might see double invocations and corresponding debug log
entries from Spring's AOP support.
* Your CGLIB proxy usage may face limitations with the Java Module System. As a typical
case, you cannot create a CGLIB proxy for a class from the `java.lang` package when
deploying on the module path. Such cases require a JVM bootstrap flag
`--add-opens=java.base/java.lang=ALL-UNNAMED` which is not available for modules.
To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute
@@ -65,15 +69,14 @@ Spring AOP is proxy-based. It is vitally important that you grasp the semantics
what that last statement actually means before you write your own aspects or use any of
the Spring AOP-based aspects supplied with the Spring Framework.
Consider first the scenario where you have a plain-vanilla, un-proxied,
nothing-special-about-it, straight object reference, as the following
code snippet shows:
Consider first the scenario where you have a plain-vanilla, un-proxied object reference,
as the following code snippet shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class SimplePojo implements Pojo {
@@ -90,7 +93,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
class SimplePojo : Pojo {
@@ -115,7 +118,7 @@ image::aop-proxy-plain-pojo-call.png[]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class Main {
@@ -129,7 +132,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun main() {
val pojo = SimplePojo()
@@ -148,7 +151,7 @@ image::aop-proxy-call.png[]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class Main {
@@ -166,7 +169,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun main() {
val factory = ProxyFactory(SimplePojo())
@@ -187,26 +190,35 @@ the interceptors (advice) that are relevant to that particular method call. Howe
once the call has finally reached the target object (the `SimplePojo` reference in
this case), any method calls that it may make on itself, such as `this.bar()` or
`this.foo()`, are going to be invoked against the `this` reference, and not the proxy.
This has important implications. It means that self-invocation is not going to result
in the advice associated with a method invocation getting a chance to run.
This has important implications. It means that self invocation is not going to result
in the advice associated with a method invocation getting a chance to run. In other words,
self invocation via an explicit or implicit `this` reference will bypass the advice.
Okay, so what is to be done about this? The best approach (the term "best" is used
loosely here) is to refactor your code such that the self-invocation does not happen.
This does entail some work on your part, but it is the best, least-invasive approach.
The next approach is absolutely horrendous, and we hesitate to point it out, precisely
because it is so horrendous. You can (painful as it is to us) totally tie the logic
within your class to Spring AOP, as the following example shows:
To address that, you have the following options.
Avoid self invocation ::
The best approach (the term "best" is used loosely here) is to refactor your code such
that the self invocation does not happen. This does entail some work on your part, but
it is the best, least-invasive approach.
Inject a self reference ::
An alternative approach is to make use of
xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-self-injection[self injection],
and invoke methods on the proxy via the self reference instead of via `this`.
Use `AopContext.currentProxy()` ::
This last approach is highly discouraged, and we hesitate to point it out, in favor of
the previous options. However, as a last resort you can choose to tie the logic within
your class to Spring AOP, as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class SimplePojo implements Pojo {
public void foo() {
// this works, but... gah!
// This works, but it should be avoided if possible.
((Pojo) AopContext.currentProxy()).bar();
}
@@ -218,12 +230,12 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
class SimplePojo : Pojo {
fun foo() {
// this works, but... gah!
// This works, but it should be avoided if possible.
(AopContext.currentProxy() as Pojo).bar()
}
@@ -234,16 +246,16 @@ Kotlin::
----
======
This totally couples your code to Spring AOP, and it makes the class itself aware of
the fact that it is being used in an AOP context, which flies in the face of AOP. It
also requires some additional configuration when the proxy is being created, as the
following example shows:
The use of `AopContext.currentProxy()` totally couples your code to Spring AOP, and it
makes the class itself aware of the fact that it is being used in an AOP context, which
reduces some of the benefits of AOP. It also requires that the `ProxyFactory` is
configured to expose the proxy, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class Main {
@@ -262,7 +274,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun main() {
val factory = ProxyFactory(SimplePojo())
@@ -277,9 +289,6 @@ Kotlin::
----
======
Finally, it must be noted that AspectJ does not have this self-invocation issue because
it is not a proxy-based AOP framework.
NOTE: AspectJ compile-time weaving and load-time weaving do not have this self-invocation
issue because they apply advice within the bytecode instead of via a proxy.
@@ -136,7 +136,7 @@ parameters of the matching names, as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public void monitor(Object service) {
// ...
@@ -145,7 +145,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun monitor(service: Any) {
// ...
@@ -282,14 +282,14 @@ example, you can declare the method signature as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public void doAccessCheck(Object retVal) {...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun doAccessCheck(retVal: Any) {...
----
@@ -340,14 +340,14 @@ The type of this parameter constrains matching in the same way as described for
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public void doRecoveryActions(DataAccessException dataAccessEx) {...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun doRecoveryActions(dataAccessEx: DataAccessException) {...
----
@@ -421,7 +421,7 @@ The implementation of the `doBasicProfiling` advice can be exactly the same as i
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
@@ -433,7 +433,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any? {
// start stopwatch
@@ -475,7 +475,7 @@ some around advice used in conjunction with a number of strongly typed parameter
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.service;
@@ -494,7 +494,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.service
@@ -521,7 +521,7 @@ proceed with the method call. The presence of this parameter is an indication th
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz;
@@ -545,7 +545,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz
@@ -610,7 +610,7 @@ Consider the following driver script:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class Boot {
@@ -624,7 +624,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun main() {
val ctx = ClassPathXmlApplicationContext("beans.xml")
@@ -714,7 +714,7 @@ The class that backs the `usageTracking` bean would then contain the following m
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
@@ -723,7 +723,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
fun recordUsage(usageTracked: UsageTracked) {
usageTracked.incrementUseCount()
@@ -742,14 +742,14 @@ following:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
val usageTracked = context.getBean("myService", UsageTracked.class)
----
@@ -829,7 +829,7 @@ call `proceed` multiple times. The following listing shows the basic aspect impl
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
public class ConcurrentOperationExecutor implements Ordered {
@@ -869,7 +869,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
class ConcurrentOperationExecutor : Ordered {
@@ -953,7 +953,7 @@ to annotate the implementation of service operations, as the following example s
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Retention(RetentionPolicy.RUNTIME)
// marker annotation
@@ -963,7 +963,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Retention(AnnotationRetention.RUNTIME)
// marker annotation
@@ -36,7 +36,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.domain;
@@ -50,7 +50,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.domain
@@ -66,7 +66,7 @@ Kotlin::
When used as a marker interface in this way, Spring configures new instances of the
annotated type (`Account`, in this case) by using a bean definition (typically
prototype-scoped) with the same name as the fully-qualified type name
(`com.xyz.domain.Account`). Since the default name for a bean is the
(`com.xyz.domain.Account`). Since the default name for a bean defined via XML is the
fully-qualified name of its type, a convenient way to declare the prototype definition
is to omit the `id` attribute, as the following example shows:
@@ -84,7 +84,7 @@ can do so directly in the annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.domain;
@@ -98,7 +98,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz.domain
@@ -153,14 +153,14 @@ available for use in the body of the constructors, you need to define this on th
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
[source,java,indent=0,subs="verbatim"]
----
@Configurable(preConstruction = true)
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
@Configurable(preConstruction = true)
----
@@ -177,41 +177,10 @@ either use a build-time Ant or Maven task to do this (see, for example, the
{aspectj-docs-devguide}/antTasks.html[AspectJ Development
Environment Guide]) or load-time weaving (see xref:core/aop/using-aspectj.adoc#aop-aj-ltw[Load-time Weaving with AspectJ in the Spring Framework]). The
`AnnotationBeanConfigurerAspect` itself needs to be configured by Spring (in order to obtain
a reference to the bean factory that is to be used to configure new objects). If you
use Java-based configuration, you can add `@EnableSpringConfigured` to any
`@Configuration` class, as follows:
a reference to the bean factory that is to be used to configure new objects). You can define
the related configuration as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Configuration
@EnableSpringConfigured
public class AppConfig {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Configuration
@EnableSpringConfigured
class AppConfig {
}
----
======
If you prefer XML based configuration, the Spring
xref:core/appendix/xsd-schemas.adoc#context[`context` namespace]
defines a convenient `context:spring-configured` element, which you can use as follows:
[source,xml,indent=0,subs="verbatim"]
----
<context:spring-configured/>
----
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
Instances of `@Configurable` objects created before the aspect has been configured
result in a message being issued to the debug log and no configuration of the
@@ -444,7 +413,7 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz;
@@ -477,7 +446,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz
@@ -575,7 +544,7 @@ driver class with a `main(..)` method to demonstrate the LTW in action:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz;
@@ -597,7 +566,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz
@@ -656,7 +625,7 @@ result:
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz;
@@ -678,7 +647,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim",chomp="-packages"]
----
package com.xyz
@@ -783,52 +752,9 @@ adding one line. (Note that you almost certainly need to use an
`ApplicationContext` as your Spring container -- typically, a `BeanFactory` is not
enough because the LTW support uses `BeanFactoryPostProcessors`.)
To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver`,
which typically is done by using the `@EnableLoadTimeWeaving` annotation, as follows:
To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver` as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Configuration
@EnableLoadTimeWeaving
class AppConfig {
}
----
======
Alternatively, if you prefer XML-based configuration, use the
`<context:load-time-weaver/>` element. Note that the element is defined in the
`context` namespace. The following example shows how to use `<context:load-time-weaver/>`:
[source,xml,indent=0,subs="verbatim"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:load-time-weaver/>
</beans>
----
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
The preceding configuration automatically defines and registers a number of LTW-specific
infrastructure beans, such as a `LoadTimeWeaver` and an `AspectJWeavingEnabler`, for you.
@@ -864,63 +790,12 @@ Note that the table lists only the `LoadTimeWeavers` that are autodetected when
use the `DefaultContextLoadTimeWeaver`. You can specify exactly which `LoadTimeWeaver`
implementation to use.
To specify a specific `LoadTimeWeaver` with Java configuration, implement the
`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method.
To configure a specific `LoadTimeWeaver`, implement the
`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method
(or use the XML equivalent).
The following example specifies a `ReflectiveLoadTimeWeaver`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Configuration
@EnableLoadTimeWeaving
public class AppConfig implements LoadTimeWeavingConfigurer {
@Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new ReflectiveLoadTimeWeaver();
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Configuration
@EnableLoadTimeWeaving
class AppConfig : LoadTimeWeavingConfigurer {
override fun getLoadTimeWeaver(): LoadTimeWeaver {
return ReflectiveLoadTimeWeaver()
}
}
----
======
If you use XML-based configuration, you can specify the fully qualified class name
as the value of the `weaver-class` attribute on the `<context:load-time-weaver/>`
element. Again, the following example specifies a `ReflectiveLoadTimeWeaver`:
[source,xml,indent=0,subs="verbatim"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:load-time-weaver
weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</beans>
----
include-code::./CustomWeaverConfiguration[tag=snippet,indent=0]
The `LoadTimeWeaver` that is defined and registered by the configuration can be later
retrieved from the Spring container by using the well known name, `loadTimeWeaver`.
+139 -37
View File
@@ -140,7 +140,7 @@ Taking our previous example, let's assume that `DataSourceConfiguration` is as f
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
public class DataSourceConfiguration {
@@ -155,7 +155,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
class DataSourceConfiguration {
@@ -176,7 +176,7 @@ The AOT engine will convert the configuration class above to code similar to the
======
Java::
+
[source,java,indent=0,role="primary"]
[source,java,indent=0]
----
/**
* Bean definitions for {@link DataSourceConfiguration}
@@ -278,7 +278,7 @@ Consider the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
public class UserConfiguration {
@@ -290,6 +290,19 @@ Java::
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
class UserConfiguration {
@Bean
fun myInterface(): MyInterface = MyImplementation()
}
----
======
In the example above, the declared type for the `myInterface` bean is `MyInterface`.
@@ -302,7 +315,7 @@ The example above should be rewritten as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
public class UserConfiguration {
@@ -314,6 +327,19 @@ Java::
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
class UserConfiguration {
@Bean
fun myInterface() = MyImplementation()
}
----
======
If you are registering bean definitions programmatically, consider using `RootBeanBefinition` as it allows to specify a `ResolvableType` that handles generics.
@@ -379,12 +405,21 @@ Consider the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ClientFactoryBean<T extends AbstractClient> implements FactoryBean<T> {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ClientFactoryBean<T : AbstractClient> : FactoryBean<T> {
// ...
}
----
======
A concrete client declaration should provide a resolved generic for the client, as shown in the following example:
@@ -393,7 +428,7 @@ A concrete client declaration should provide a resolved generic for the client,
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
public class UserConfiguration {
@@ -405,6 +440,19 @@ Java::
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration(proxyBeanMethods = false)
class UserConfiguration {
@Bean
fun myClient() = ClientFactoryBean<MyClient>(...)
}
----
======
If the `FactoryBean` bean definition is registered programmatically, make sure to follow these steps:
@@ -419,13 +467,23 @@ The following example showcases a basic definition:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
RootBeanDefinition beanDefinition = new RootBeanDefinition(ClientFactoryBean.class);
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean.class, MyClient.class));
// ...
registry.registerBeanDefinition("myClient", beanDefinition);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val beanDefinition = RootBeanDefinition(ClientFactoryBean::class.java)
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean::class.java, MyClient::class.java));
// ...
registry.registerBeanDefinition("myClient", beanDefinition)
----
======
[[aot.bestpractices.jpa]]
@@ -437,7 +495,7 @@ The JPA persistence unit has to be known upfront for certain optimizations to ap
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean
LocalContainerEntityManagerFactoryBean customDBEntityManagerFactory(DataSource dataSource) {
@@ -447,6 +505,19 @@ Java::
return factoryBean;
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean
fun customDBEntityManagerFactory(dataSource: DataSource): LocalContainerEntityManagerFactoryBean {
val factoryBean = LocalContainerEntityManagerFactoryBean()
factoryBean.dataSource = dataSource
factoryBean.setPackagesToScan("com.example.app")
return factoryBean
}
----
======
To make sure the scanning occurs ahead of time, a `PersistenceManagedTypes` bean must be declared and used by the
@@ -456,7 +527,7 @@ factory bean definition, as shown by the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean
PersistenceManagedTypes persistenceManagedTypes(ResourceLoader resourceLoader) {
@@ -472,6 +543,25 @@ Java::
return factoryBean;
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean
fun persistenceManagedTypes(resourceLoader: ResourceLoader): PersistenceManagedTypes {
return PersistenceManagedTypesScanner(resourceLoader)
.scan("com.example.app")
}
@Bean
fun customDBEntityManagerFactory(dataSource: DataSource, managedTypes: PersistenceManagedTypes): LocalContainerEntityManagerFactoryBean {
val factoryBean = LocalContainerEntityManagerFactoryBean()
factoryBean.dataSource = dataSource
factoryBean.setManagedTypes(managedTypes)
return factoryBean
}
----
======
[[aot.hints]]
@@ -489,10 +579,17 @@ The following example makes sure that `config/app.properties` can be loaded from
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
runtimeHints.resources().registerPattern("config/app.properties");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
runtimeHints.resources().registerPattern("config/app.properties")
----
======
A number of contracts are handled automatically during AOT processing.
@@ -523,40 +620,45 @@ It is also possible to register an implementation statically by adding an entry
{spring-framework-api}/aot/hint/annotation/Reflective.html[`@Reflective`] provides an idiomatic way to flag the need for reflection on an annotated element.
For instance, `@EventListener` is meta-annotated with `@Reflective` since the underlying implementation invokes the annotated method using reflection.
By default, only Spring beans are considered, and an invocation hint is registered for the annotated element.
This can be tuned by specifying a custom `ReflectiveProcessor` implementation via the
`@Reflective` annotation.
Out-of-the-box, only Spring beans are considered but you can opt-in for scanning using `@ReflectiveScan`.
In the example below, all types of the package `com.example.app` and their subpackages are considered:
include-code::./MyConfiguration[]
Scanning happens during AOT processing and the types in the target packages do not need to have a class-level annotation to be considered.
This performs a "deep scan" and the presence of `@Reflective`, either directly or as a meta-annotation, is checked on types, fields, constructors, methods, and enclosed elements.
By default, `@Reflective` registers an invocation hint for the annotated element.
This can be tuned by specifying a custom `ReflectiveProcessor` implementation via the `@Reflective` annotation.
Library authors can reuse this annotation for their own purposes.
If components other than Spring beans need to be processed, a `BeanFactoryInitializationAotProcessor` can detect the relevant types and use `ReflectiveRuntimeHintsRegistrar` to process them.
An example of such customization is covered in the next section.
[[aot.hints.register-reflection-for-binding]]
=== `@RegisterReflectionForBinding`
[[aot.hints.register-reflection]]
=== `@RegisterReflection`
{spring-framework-api}/aot/hint/annotation/RegisterReflectionForBinding.html[`@RegisterReflectionForBinding`] is a specialization of `@Reflective` that registers the need for serializing arbitrary types.
{spring-framework-api}/aot/hint/annotation/RegisterReflection.html[`@RegisterReflection`] is a specialization of `@Reflective` that provides a declarative way of registering reflection for arbitrary types.
NOTE: As a specialization of `@Reflective`, this is also detected if you're using `@ReflectiveScan`.
In the following example, public constructors and public methods can be invoked via reflection on `AccountService`:
include-code::./MyConfiguration[tag=snippet,indent=0]
`@RegisterReflection` can be applied to any target type at the class level, but it can also be applied directly to a method to better indicate where the hints are actually required.
`@RegisterReflection` can be used as a meta-annotation to provide more specific needs.
{spring-framework-api}/aot/hint/annotation/RegisterReflectionForBinding.html[`@RegisterReflectionForBinding`] is such composed annotation and registers the need for serializing arbitrary types.
A typical use case is the use of DTOs that the container cannot infer, such as using a web client within a method body.
`@RegisterReflectionForBinding` can be applied to any Spring bean at the class level, but it can also be applied directly to a method, field, or constructor to better indicate where the hints are actually required.
The following example registers `Account` for serialization.
The following example registers `Order` for serialization.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@Component
public class OrderService {
include-code::./OrderService[tag=snippet,indent=0]
@RegisterReflectionForBinding(Account.class)
public void process(Order order) {
// ...
}
}
----
======
This registers hints for constructors, fields, properties, and record components of `Order`.
Hints are also registered for types transitively used on properties and record components.
In other words, if `Order` exposes others types, hints are registered for those as well.
[[aot.hints.testing]]
=== Testing Runtime Hints
@@ -588,7 +690,7 @@ If you forgot to contribute a hint, the test will fail and provide some details
[source,txt,indent=0,subs="verbatim,quotes"]
----
org.springframework.docs.core.aot.hints.testing.SampleReflection performReflection
INFO: Spring version:6.0.0-SNAPSHOT
INFO: Spring version: 6.2.0
Missing <"ReflectionHints"> for invocation <java.lang.Class#forName>
with arguments ["org.springframework.core.SpringVersion",
@@ -145,7 +145,7 @@ use the `NamespaceHandlerSupport` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.samples.xml;
@@ -161,7 +161,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.samples.xml
@@ -202,7 +202,7 @@ we can parse our custom XML content, as you can see in the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.samples.xml;
@@ -240,7 +240,7 @@ single `BeanDefinition` represents.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.samples.xml
@@ -416,7 +416,7 @@ The following listing shows the `Component` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -449,7 +449,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -480,7 +480,7 @@ setter property for the `components` property. The following listing shows such
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -522,7 +522,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -598,7 +598,7 @@ we then create a custom `NamespaceHandler`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -614,7 +614,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -637,7 +637,7 @@ listing shows our custom `BeanDefinitionParser` implementation:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -688,7 +688,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -787,7 +787,7 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -807,7 +807,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -843,7 +843,7 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -861,7 +861,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -886,7 +886,7 @@ The following listing shows our `BeanDefinitionDecorator` implementation:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo;
@@ -942,7 +942,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo
@@ -121,7 +121,7 @@ The following example enumeration shows how easy injecting an enum value is:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package jakarta.persistence;
@@ -134,7 +134,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package jakarta.persistence
@@ -152,7 +152,7 @@ Now consider the following setter of type `PersistenceContextType` and the corre
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example;
@@ -168,7 +168,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example
@@ -20,7 +20,7 @@ can be found in the xref:core/beans/standard-annotations.adoc[relevant section].
[NOTE]
====
Annotation injection is performed before external property injection. Thus, external
configuration (e.g. XML-specified bean properties) effectively overrides the annotations
configuration (for example, XML-specified bean properties) effectively overrides the annotations
for properties when wired through mixed approaches.
====
@@ -1,5 +1,5 @@
[[beans-autowired-annotation-primary]]
= Fine-tuning Annotation-based Autowiring with `@Primary`
= Fine-tuning Annotation-based Autowiring with `@Primary` or `@Fallback`
Because autowiring by type may lead to multiple candidates, it is often necessary to have
more control over the selection process. One way to accomplish this is with Spring's
@@ -15,7 +15,7 @@ primary `MovieCatalog`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class MovieConfiguration {
@@ -33,7 +33,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class MovieConfiguration {
@@ -50,14 +50,57 @@ Kotlin::
----
======
With the preceding configuration, the following `MovieRecommender` is autowired with the
`firstMovieCatalog`:
Alternatively, as of 6.2, there is a `@Fallback` annotation for demarcating
any beans other than the regular ones to be injected. If only one regular
bean is left, it is effectively primary as well:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class MovieConfiguration {
@Bean
public MovieCatalog firstMovieCatalog() { ... }
@Bean
@Fallback
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class MovieConfiguration {
@Bean
fun firstMovieCatalog(): MovieCatalog { ... }
@Bean
@Fallback
fun secondMovieCatalog(): MovieCatalog { ... }
// ...
}
----
======
With both variants of the preceding configuration, the following
`MovieRecommender` is autowired with the `firstMovieCatalog`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -70,7 +113,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -1,19 +1,20 @@
[[beans-autowired-annotation-qualifiers]]
= Fine-tuning Annotation-based Autowiring with Qualifiers
`@Primary` is an effective way to use autowiring by type with several instances when one
primary candidate can be determined. When you need more control over the selection process,
you can use Spring's `@Qualifier` annotation. You can associate qualifier values
with specific arguments, narrowing the set of type matches so that a specific bean is
chosen for each argument. In the simplest case, this can be a plain descriptive value, as
shown in the following example:
`@Primary` and `@Fallback` are effective ways to use autowiring by type with several
instances when one primary (or non-fallback) candidate can be determined.
When you need more control over the selection process, you can use Spring's `@Qualifier`
annotation. You can associate qualifier values with specific arguments, narrowing the set
of type matches so that a specific bean is chosen for each argument. In the simplest case,
this can be a plain descriptive value, as shown in the following example:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -27,7 +28,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -49,7 +50,7 @@ method parameters, as shown in the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -70,7 +71,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -157,44 +158,31 @@ for a non-unique dependency situation, Spring matches the injection point name
the same-named candidate, if any (either by bean name or by associated alias).
Since version 6.1, this requires the `-parameters` Java compiler flag to be present.
As of 6.2, the container applies fast shortcut resolution for bean name matches,
bypassing the full type matching algorithm when the parameter name matches the
bean name and no type, qualifier or primary conditions override the match. It is
therefore recommendable for your parameter names to match the target bean names.
====
As an alternative for injection by name, consider the JSR-250 `@Resource` annotation
which is semantically defined to identify a specific target component by its unique name,
with the declared type being irrelevant for the matching process. `@Autowired` has rather
different semantics: After selecting candidate beans by type, the specified `String`
different semantics: after selecting candidate beans by type, the specified `String`
qualifier value is considered within those type-selected candidates only (for example,
matching an `account` qualifier against beans marked with the same qualifier label).
For beans that are themselves defined as a collection, `Map`, or array type, `@Resource`
is a fine solution, referring to the specific collection or array bean by unique name.
That said, as of 4.3, you can match collection, `Map`, and array types through Spring's
That said, you can match collection, `Map`, and array types through Spring's
`@Autowired` type matching algorithm as well, as long as the element type information
is preserved in `@Bean` return type signatures or collection inheritance hierarchies.
In this case, you can use qualifier values to select among same-typed collections,
as outlined in the previous paragraph.
As of 4.3, `@Autowired` also considers self references for injection (that is, references
back to the bean that is currently injected). Note that self injection is a fallback.
Regular dependencies on other components always have precedence. In that sense, self
references do not participate in regular candidate selection and are therefore in
particular never primary. On the contrary, they always end up as lowest precedence.
In practice, you should use self references as a last resort only (for example, for
calling other methods on the same instance through the bean's transactional proxy).
Consider factoring out the affected methods to a separate delegate bean in such a scenario.
Alternatively, you can use `@Resource`, which may obtain a proxy back to the current bean
by its unique name.
[NOTE]
====
Trying to inject the results from `@Bean` methods on the same configuration class is
effectively a self-reference scenario as well. Either lazily resolve such references
in the method signature where it is actually needed (as opposed to an autowired field
in the configuration class) or declare the affected `@Bean` methods as `static`,
decoupling them from the containing configuration class instance and its lifecycle.
Otherwise, such beans are only considered in the fallback phase, with matching beans
on other configuration classes selected as primary candidates instead (if available).
====
`@Autowired` also considers self references for injection (that is, references back to
the bean that is currently injected). See
xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-self-injection[Self Injection]
for details.
`@Autowired` applies to fields, constructors, and multi-argument methods, allowing for
narrowing through qualifier annotations at the parameter level. In contrast, `@Resource`
@@ -210,7 +198,7 @@ provide the `@Qualifier` annotation within your definition, as the following exa
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@@ -223,7 +211,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@@ -241,7 +229,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -262,7 +250,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -334,7 +322,7 @@ the simple annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@@ -345,7 +333,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@@ -363,7 +351,7 @@ following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -378,7 +366,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -418,7 +406,7 @@ consider the following annotation definition:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@@ -433,7 +421,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@@ -450,7 +438,7 @@ In this case `Format` is an enum, defined as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public enum Format {
VHS, DVD, BLURAY
@@ -459,7 +447,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
enum class Format {
VHS, DVD, BLURAY
@@ -476,7 +464,7 @@ for both attributes: `genre` and `format`, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -502,7 +490,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -13,7 +13,7 @@ You can apply the `@Autowired` annotation to constructors, as the following exam
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -30,7 +30,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao)
@@ -54,7 +54,7 @@ as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -71,7 +71,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -91,7 +91,7 @@ arguments, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -112,7 +112,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -139,7 +139,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -159,7 +159,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao) {
@@ -186,14 +186,37 @@ implementation type, consider declaring the most specific return type on your fa
method (at least as specific as required by the injection points referring to your bean).
====
.[[beans-autowired-annotation-self-injection]]Self Injection
****
`@Autowired` also considers self references for injection (that is, references back to
the bean that is currently injected).
Note, however, that self injection is a fallback mechanism. Regular dependencies on other
components always have precedence. In that sense, self references do not participate in
regular autowiring candidate selection and are therefore in particular never primary. On
the contrary, they always end up as lowest precedence.
In practice, you should use self references as a last resort only for example, for
calling other methods on the same instance through the bean's transactional proxy. As an
alternative, consider factoring out the affected methods to a separate delegate bean in
such a scenario.
Another alternative is to use `@Resource`, which may obtain a proxy back to the current
bean by its unique name.
======
[NOTE]
====
As of 4.3, `@Autowired` also considers self references for injection (that is, references
back to the bean that is currently injected). Note that self injection is a fallback.
In practice, you should use self references as a last resort only (for example, for
calling other methods on the same instance through the bean's transactional proxy).
Consider factoring out the affected methods to a separate delegate bean in such a scenario.
Trying to inject the results from `@Bean` methods in the same `@Configuration` class is
effectively a self-reference scenario as well. Either lazily resolve such references
in the method signature where it is actually needed (as opposed to an autowired field
in the configuration class) or declare the affected `@Bean` methods as `static`,
decoupling them from the containing configuration class instance and its lifecycle.
Otherwise, such beans are only considered in the fallback phase, with matching beans
on other configuration classes selected as primary candidates instead (if available).
====
======
****
You can also instruct Spring to provide all beans of a particular type from the
`ApplicationContext` by adding the `@Autowired` annotation to a field or method that
@@ -203,7 +226,7 @@ expects an array of that type, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -216,7 +239,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -234,7 +257,7 @@ The same applies for typed collections, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -251,7 +274,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -296,7 +319,7 @@ corresponding bean names, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -313,7 +336,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -338,7 +361,7 @@ non-required (i.e., by setting the `required` attribute in `@Autowired` to `fals
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -355,7 +378,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -421,15 +444,15 @@ through Java 8's `java.util.Optional`, as the following example shows:
}
----
As of Spring Framework 5.0, you can also use a `@Nullable` annotation (of any kind
in any package -- for example, `javax.annotation.Nullable` from JSR-305) or just leverage
Kotlin built-in null-safety support:
You can also use a `@Nullable` annotation (of any kind in any package -- for example,
`javax.annotation.Nullable` from JSR-305) or just leverage Kotlin built-in null-safety
support:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -442,7 +465,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -465,7 +488,7 @@ an `ApplicationContext` object:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -481,7 +504,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -9,7 +9,7 @@ configuration:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class MyConfiguration {
@@ -28,7 +28,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class MyConfiguration {
@@ -50,7 +50,7 @@ used as a qualifier, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
@@ -61,7 +61,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Autowired
private lateinit var s1: Store<String> // <String> qualifier, injects the stringStore bean
@@ -78,7 +78,7 @@ following example autowires a generic `List`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@@ -88,7 +88,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@@ -17,7 +17,7 @@ cleared upon destruction:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class CachingMovieLister {
@@ -35,7 +35,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class CachingMovieLister {
@@ -15,7 +15,7 @@ as demonstrated in the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -31,7 +31,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -54,7 +54,7 @@ named `movieFinder` injected into its setter method:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -69,7 +69,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -103,7 +103,7 @@ named "customerPreferenceDao" and then falls back to a primary type match for th
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MovieRecommender {
@@ -124,7 +124,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MovieRecommender {
@@ -7,7 +7,7 @@
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@@ -22,7 +22,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MovieRecommender(@Value("\${catalog.name}") private val catalog: String)
@@ -35,7 +35,7 @@ With the following configuration:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:application.properties")
@@ -44,7 +44,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:application.properties")
@@ -71,7 +71,7 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -85,7 +85,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -101,8 +101,8 @@ NOTE: When configuring a `PropertySourcesPlaceholderConfigurer` using JavaConfig
Using the above configuration ensures Spring initialization failure if any `${}`
placeholder could not be resolved. It is also possible to use methods like
`setPlaceholderPrefix`, `setPlaceholderSuffix`, or `setValueSeparator` to customize
placeholders.
`setPlaceholderPrefix`, `setPlaceholderSuffix`, `setValueSeparator`, or
`setEscapeCharacter` to customize placeholders.
NOTE: Spring Boot configures by default a `PropertySourcesPlaceholderConfigurer` bean that
will get properties from `application.properties` and `application.yml` files.
@@ -117,7 +117,7 @@ It is possible to provide a default value as following:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@@ -132,7 +132,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MovieRecommender(@Value("\${catalog.name:defaultCatalog}") private val catalog: String)
@@ -148,7 +148,7 @@ provide conversion support for your own custom type, you can provide your own
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -164,7 +164,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -186,7 +186,7 @@ computed at runtime as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@@ -201,7 +201,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MovieRecommender(
@@ -215,7 +215,7 @@ SpEL also enables the use of more complex data structures:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@@ -231,7 +231,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MovieRecommender(
@@ -110,14 +110,14 @@ as the local file system, the Java `CLASSPATH`, and so on.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
----
@@ -294,7 +294,7 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
@@ -308,7 +308,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -331,14 +331,14 @@ The following example shows Groovy configuration:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
----
@@ -352,7 +352,7 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
@@ -361,7 +361,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
@@ -376,7 +376,7 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
@@ -385,7 +385,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
@@ -90,7 +90,7 @@ you need to programmatically call `addBeanPostProcessor`, as the following examp
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// populate the factory with bean definitions
@@ -104,7 +104,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val factory = DefaultListableBeanFactory()
// populate the factory with bean definitions
@@ -124,7 +124,7 @@ you need to call its `postProcessBeanFactory` method, as the following example s
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
@@ -140,7 +140,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val factory = DefaultListableBeanFactory()
val reader = XmlBeanDefinitionReader(factory)
@@ -59,7 +59,7 @@ is meta-annotated with `@Component`, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@@ -74,7 +74,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@@ -103,7 +103,7 @@ customization of the `proxyMode`. The following listing shows the definition of
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@@ -123,7 +123,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@@ -142,7 +142,7 @@ You can then use `@SessionScope` without declaring the `proxyMode` as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service
@SessionScope
@@ -153,7 +153,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service
@SessionScope
@@ -169,7 +169,7 @@ You can also override the value for the `proxyMode`, as the following example sh
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
@@ -180,7 +180,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
@@ -207,7 +207,7 @@ are eligible for such autodetection:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service
public class SimpleMovieLister {
@@ -222,7 +222,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service
class SimpleMovieLister(private val movieFinder: MovieFinder)
@@ -233,7 +233,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Repository
public class JpaMovieFinder implements MovieFinder {
@@ -243,7 +243,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Repository
class JpaMovieFinder : MovieFinder {
@@ -262,7 +262,7 @@ comma- or semicolon- or space-separated list that includes the parent package of
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example")
@@ -273,7 +273,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"])
@@ -380,7 +380,7 @@ and using "`stub`" repositories instead:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example",
@@ -393,7 +393,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"],
@@ -438,7 +438,7 @@ annotated classes. The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class FactoryMethodComponent {
@@ -457,7 +457,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class FactoryMethodComponent {
@@ -497,7 +497,7 @@ support for autowiring of `@Bean` methods. The following example shows how to do
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class FactoryMethodComponent {
@@ -536,7 +536,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class FactoryMethodComponent {
@@ -589,7 +589,7 @@ The following example shows how to use `InjectionPoint`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class FactoryMethodComponent {
@@ -603,7 +603,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class FactoryMethodComponent {
@@ -703,7 +703,7 @@ following component classes were detected, the names would be `myMovieLister` an
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
public class SimpleMovieLister {
@@ -713,7 +713,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
class SimpleMovieLister {
@@ -726,7 +726,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Repository
public class MovieFinderImpl implements MovieFinder {
@@ -736,7 +736,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Repository
class MovieFinderImpl : MovieFinder {
@@ -763,7 +763,7 @@ fully qualified class name for the generated bean name. The
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
@@ -774,7 +774,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
@@ -810,7 +810,7 @@ scope within the annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
@@ -821,7 +821,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
@@ -853,7 +853,7 @@ an annotation and a bean definition shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
@@ -864,7 +864,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
@@ -891,7 +891,7 @@ the following configuration results in standard JDK dynamic proxies:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
@@ -902,7 +902,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
@@ -939,7 +939,7 @@ technique:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
@@ -950,7 +950,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
@@ -962,7 +962,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
@@ -973,7 +973,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
@@ -987,7 +987,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
@@ -998,7 +998,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
@@ -102,7 +102,7 @@ implementations and so can be cast to the `MessageSource` interface.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
@@ -113,7 +113,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun main() {
val resources = ClassPathXmlApplicationContext("beans.xml")
@@ -161,7 +161,7 @@ converted into `String` objects and inserted into placeholders in the lookup mes
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class Example {
@@ -181,7 +181,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class Example {
@@ -224,7 +224,7 @@ argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(final String[] args) {
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
@@ -236,7 +236,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun main() {
val resources = ClassPathXmlApplicationContext("beans.xml")
@@ -344,7 +344,7 @@ simple class that extends Spring's `ApplicationEvent` base class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class BlockedListEvent extends ApplicationEvent {
@@ -363,7 +363,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class BlockedListEvent(source: Any,
val address: String,
@@ -380,7 +380,7 @@ example shows such a class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class EmailService implements ApplicationEventPublisherAware {
@@ -407,7 +407,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class EmailService : ApplicationEventPublisherAware {
@@ -447,7 +447,7 @@ shows such a class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
@@ -465,7 +465,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class BlockedListNotifier : ApplicationListener<BlockedListEvent> {
@@ -484,7 +484,7 @@ You can register as many event listeners as you wish, but note that, by default,
This means that the `publishEvent()` method blocks until all listeners have finished processing the event.
One advantage of this synchronous and single-threaded approach is that, when a listener receives an event,
it operates inside the transaction context of the publisher if a transaction context is available.
If another strategy for event publication becomes necessary, e.g. asynchronous event processing by default,
If another strategy for event publication becomes necessary, for example, asynchronous event processing by default,
see the javadoc for Spring's {spring-framework-api}/context/event/ApplicationEventMulticaster.html[`ApplicationEventMulticaster`] interface
and {spring-framework-api}/context/event/SimpleApplicationEventMulticaster.html[`SimpleApplicationEventMulticaster`] implementation
for configuration options which can be applied to a custom "applicationEventMulticaster" bean definition.
@@ -545,7 +545,7 @@ You can register an event listener on any method of a managed bean by using the
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class BlockedListNotifier {
@@ -564,7 +564,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class BlockedListNotifier {
@@ -578,6 +578,8 @@ Kotlin::
----
======
NOTE: Do not define such beans to be lazy as the `ApplicationContext` will honour that and will not register the method to listen to events.
The method signature once again declares the event type to which it listens,
but, this time, with a flexible name and without implementing a specific listener interface.
The event type can also be narrowed through generics as long as the actual event type
@@ -591,7 +593,7 @@ following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
@@ -601,7 +603,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener(ContextStartedEvent::class, ContextRefreshedEvent::class)
fun handleContextStart() {
@@ -621,7 +623,7 @@ The following example shows how our notifier can be rewritten to be invoked only
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlockedListEvent(BlockedListEvent blEvent) {
@@ -631,7 +633,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener(condition = "#blEvent.content == 'my-event'")
fun processBlockedListEvent(blEvent: BlockedListEvent) {
@@ -677,7 +679,7 @@ method signature to return the event that should be published, as the following
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener
public ListUpdateEvent handleBlockedListEvent(BlockedListEvent event) {
@@ -688,7 +690,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener
fun handleBlockedListEvent(event: BlockedListEvent): ListUpdateEvent {
@@ -717,7 +719,7 @@ The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener
@Async
@@ -728,7 +730,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener
@Async
@@ -763,7 +765,7 @@ annotation to the method declaration, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener
@Order(42)
@@ -774,7 +776,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener
@Order(42)
@@ -797,7 +799,7 @@ can create the following listener definition to receive only `EntityCreatedEvent
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
@@ -807,7 +809,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@EventListener
fun onPersonCreated(event: EntityCreatedEvent<Person>) {
@@ -829,7 +831,7 @@ environment provides. The following event shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
@@ -846,7 +848,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class EntityCreatedEvent<T>(entity: T) : ApplicationEvent(entity), ResolvableTypeProvider {
@@ -864,7 +866,7 @@ Finally, as with classic `ApplicationListener` implementations, the actual multi
happens via a context-wide `ApplicationEventMulticaster` at runtime. By default, this is a
`SimpleApplicationEventMulticaster` with synchronous event publication in the caller thread.
This can be replaced/customized through an "applicationEventMulticaster" bean definition,
e.g. for processing all events asynchronously and/or for handling listener exceptions:
for example, for processing all events asynchronously and/or for handling listener exceptions:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -936,7 +938,7 @@ Here is an example of instrumentation in the `AnnotationConfigApplicationContext
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// create a startup step and start recording
StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan");
@@ -950,7 +952,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// create a startup step and start recording
val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
@@ -11,7 +11,7 @@ To enable load-time weaving, you can add the `@EnableLoadTimeWeaving` to one of
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@EnableLoadTimeWeaving
@@ -21,7 +21,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@EnableLoadTimeWeaving
@@ -78,19 +78,20 @@ lead to concurrent access exceptions, inconsistent state in the bean container,
[[beans-definition-overriding]]
== Overriding Beans
Bean overriding is happening when a bean is registered using an identifier that is
already allocated. While bean overriding is possible, it makes the configuration harder
to read and this feature will be deprecated in a future release.
Bean overriding occurs when a bean is registered using an identifier that is already
allocated. While bean overriding is possible, it makes the configuration harder to read.
WARNING: Bean overriding will be deprecated in a future release.
To disable bean overriding altogether, you can set the `allowBeanDefinitionOverriding`
flag to `false` on the `ApplicationContext` before it is refreshed. In such setup, an
flag to `false` on the `ApplicationContext` before it is refreshed. In such a setup, an
exception is thrown if bean overriding is used.
By default, the container logs every bean overriding at `INFO` level so that you can
adapt your configuration accordingly. While not recommended, you can silence those logs
by setting the `allowBeanDefinitionOverriding` flag to `true`.
By default, the container logs every attempt to override a bean at `INFO` level so that
you can adapt your configuration accordingly. While not recommended, you can silence
those logs by setting the `allowBeanDefinitionOverriding` flag to `true`.
.Java-configuration
.Java Configuration
****
If you use Java Configuration, a corresponding `@Bean` method always silently overrides
a scanned bean class with the same component name as long as the return type of the
@@ -98,6 +99,10 @@ a scanned bean class with the same component name as long as the return type of
the `@Bean` factory method in favor of any pre-declared constructor on the bean class.
****
NOTE: We acknowledge that overriding beans in test scenarios is convenient, and there is
explicit support for this as of Spring Framework 6.2. Please refer to
xref:testing/testcontext-framework/bean-overriding.adoc[this section] for more details.
[[beans-beanname]]
@@ -293,7 +298,7 @@ The following example shows a class that would work with the preceding bean defi
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ClientService {
private static ClientService clientService = new ClientService();
@@ -307,7 +312,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ClientService private constructor() {
companion object {
@@ -373,7 +378,7 @@ The following example shows the corresponding class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class DefaultServiceLocator {
@@ -387,7 +392,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class DefaultServiceLocator {
companion object {
@@ -423,7 +428,7 @@ The following example shows the corresponding class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class DefaultServiceLocator {
@@ -443,7 +448,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class DefaultServiceLocator {
companion object {
@@ -124,5 +124,21 @@ These techniques are useful for beans that you never want to be injected into ot
by autowiring. It does not mean that an excluded bean cannot itself be configured by
using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
[NOTE]
====
As of 6.2, `@Bean` methods support two variants of the autowire candidate flag:
`autowireCandidate` and `defaultCandidate`.
When using xref:core/beans/annotation-config/autowired-qualifiers.adoc[qualifiers],
a bean marked with `defaultCandidate=false` is only available for injection points
where an additional qualifier indication is present. This is useful for restricted
delegates that are supposed to be injectable in certain areas but are not meant to
get in the way of beans of the same type in other places. Such a bean will never
get injected by plain declared type only, rather by type plus specific qualifier.
In contrast, `autowireCandidate=false` behaves exactly like the `autowire-candidate`
attribute as explained above: Such a bean will never get injected by type at all.
====
@@ -34,7 +34,7 @@ injection:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -52,7 +52,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// a constructor so that the Spring container can inject a MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
@@ -77,7 +77,7 @@ being instantiated. Consider the following class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package x.y;
@@ -91,7 +91,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package x.y
@@ -127,7 +127,7 @@ by type without help. Consider the following class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package examples;
@@ -148,7 +148,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package examples
@@ -221,7 +221,7 @@ then have to look as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package examples;
@@ -239,7 +239,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package examples
@@ -265,7 +265,7 @@ on container specific interfaces, base classes, or annotations.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -283,7 +283,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -440,7 +440,7 @@ The following example shows the corresponding `ExampleBean` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ExampleBean {
@@ -466,7 +466,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ExampleBean {
lateinit var beanOne: AnotherBean
@@ -503,7 +503,7 @@ The following example shows the corresponding `ExampleBean` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ExampleBean {
@@ -524,7 +524,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ExampleBean(
private val beanOne: AnotherBean,
@@ -557,7 +557,7 @@ The following example shows the corresponding `ExampleBean` class:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ExampleBean {
@@ -581,7 +581,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ExampleBean private constructor() {
companion object {
@@ -3,7 +3,7 @@
If a bean is a dependency of another bean, that usually means that one bean is set as a
property of another. Typically you accomplish this with the
xref:core/beans/dependencies/factory-properties-detailed.adoc#beans-ref-element[`<ref/>` element>]
xref:core/beans/dependencies/factory-properties-detailed.adoc#beans-ref-element[`<ref/>` element]
in XML-based metadata or through xref:core/beans/dependencies/factory-autowire.adoc[autowiring].
However, sometimes dependencies between beans are less direct. An example is when a static
@@ -10,33 +10,25 @@ pre-instantiation of a singleton bean by marking the bean definition as being
lazy-initialized. A lazy-initialized bean tells the IoC container to create a bean
instance when it is first requested, rather than at startup.
In XML, this behavior is controlled by the `lazy-init` attribute on the `<bean/>`
element, as the following example shows:
This behavior is controlled by the `@Lazy` annotation or in XML the `lazy-init` attribute on the `<bean/>` element, as
the following example shows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
----
include-code::./ApplicationConfiguration[tag=snippet,indent=0]
When the preceding configuration is consumed by an `ApplicationContext`, the `lazy` bean
is not eagerly pre-instantiated when the `ApplicationContext` starts,
whereas the `not.lazy` bean is eagerly pre-instantiated.
whereas the `notLazy` one is eagerly pre-instantiated.
However, when a lazy-initialized bean is a dependency of a singleton bean that is
not lazy-initialized, the `ApplicationContext` creates the lazy-initialized bean at
startup, because it must satisfy the singleton's dependencies. The lazy-initialized bean
is injected into a singleton bean elsewhere that is not lazy-initialized.
You can also control lazy-initialization at the container level by using the
`default-lazy-init` attribute on the `<beans/>` element, as the following example shows:
You can also control lazy-initialization for a set of beans by using the `@Lazy` annotation on your `@Configuration`
annotated class or in XML using the `default-lazy-init` attribute on the `<beans/>` element, as the following example
shows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
----
include-code::./LazyConfiguration[tag=snippet,indent=0]
@@ -21,7 +21,7 @@ shows this approach:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
package fiona.apple;
@@ -60,7 +60,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
package fiona.apple
@@ -120,6 +120,8 @@ dynamically generate a subclass that overrides the method.
subclasses cannot be `final`, and the method to be overridden cannot be `final`, either.
* Unit-testing a class that has an `abstract` method requires you to subclass the class
yourself and to supply a stub implementation of the `abstract` method.
* Concrete methods are also necessary for component scanning, which requires concrete
classes to pick up.
* A further key limitation is that lookup methods do not work with factory methods and
in particular not with `@Bean` methods in configuration classes, since, in that case,
the container is not in charge of creating the instance and therefore cannot create
@@ -135,7 +137,7 @@ the reworked example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
package fiona.apple;
@@ -158,7 +160,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
package fiona.apple
@@ -218,7 +220,7 @@ method through the `@Lookup` annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public abstract class CommandManager {
@@ -235,7 +237,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
abstract class CommandManager {
@@ -258,7 +260,7 @@ declared return type of the lookup method:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public abstract class CommandManager {
@@ -275,7 +277,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
abstract class CommandManager {
@@ -291,6 +293,11 @@ Kotlin::
----
======
Note that you should typically declare such annotated lookup methods with a concrete
stub implementation, in order for them to be compatible with Spring's component
scanning rules where abstract classes get ignored by default. This limitation does not
apply to explicitly registered or explicitly imported bean classes.
[TIP]
====
Another way of accessing differently scoped target beans is an `ObjectFactory`/
@@ -317,7 +324,7 @@ the following class, which has a method called `computeValue` that we want to ov
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MyValueCalculator {
@@ -331,7 +338,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MyValueCalculator {
@@ -351,7 +358,7 @@ interface provides the new method definition, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
/**
* meant to be used to override the existing computeValue(String)
@@ -370,7 +377,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
/**
* meant to be used to override the existing computeValue(String)
@@ -168,8 +168,8 @@ listings shows how to use the `parent` attribute:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
<!-- in the child (descendant) context, bean name is the same as the parent bean -->
<bean id="accountService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
@@ -354,7 +354,7 @@ The following Java class and bean definition show how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SomeClass {
@@ -368,7 +368,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SomeClass {
lateinit var accounts: Map<String, Float>
@@ -418,14 +418,14 @@ The preceding example is equivalent to the following Java code:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
exampleBean.setEmail("");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
exampleBean.email = ""
----
@@ -449,14 +449,14 @@ The preceding configuration is equivalent to the following Java code:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
exampleBean.setEmail(null);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
exampleBean.email = null
----
@@ -43,7 +43,7 @@ Consider the first use case in a practical application that requires a
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean
public DataSource dataSource() {
@@ -57,7 +57,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean
fun dataSource(): DataSource {
@@ -79,7 +79,7 @@ now looks like the following listing:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean(destroyMethod = "")
public DataSource dataSource() throws Exception {
@@ -90,7 +90,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
@@ -128,7 +128,7 @@ can rewrite the `dataSource` configuration as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("development")
@@ -147,7 +147,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("development")
@@ -171,7 +171,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("production")
@@ -188,7 +188,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("production")
@@ -233,7 +233,7 @@ of creating a custom composed annotation. The following example defines a custom
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@@ -244,7 +244,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@@ -272,7 +272,7 @@ the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -300,7 +300,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -454,7 +454,7 @@ it programmatically against the `Environment` API which is available through an
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
@@ -464,7 +464,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = AnnotationConfigApplicationContext().apply {
environment.setActiveProfiles("development")
@@ -491,14 +491,14 @@ activates multiple profiles:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
ctx.getEnvironment().setActiveProfiles("profile1", "profile2")
----
@@ -523,7 +523,7 @@ the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("default")
@@ -541,7 +541,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@Profile("default")
@@ -578,7 +578,7 @@ hierarchy of property sources. Consider the following listing:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
@@ -588,7 +588,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = GenericApplicationContext()
val env = ctx.environment
@@ -643,7 +643,7 @@ current `Environment`. The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
@@ -652,7 +652,7 @@ sources.addFirst(new MyPropertySource());
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = GenericApplicationContext()
val sources = ctx.environment.propertySources
@@ -684,7 +684,7 @@ a call to `testBean.getName()` returns `myTestBean`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:/com/myco/app.properties")
@@ -704,7 +704,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:/com/myco/app.properties")
@@ -729,7 +729,7 @@ environment, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
@@ -749,7 +749,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:/com/\${my.placeholder:default/path}/app.properties")
@@ -123,7 +123,7 @@ The following listing shows the custom `BeanPostProcessor` implementation class
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package scripting;
@@ -145,7 +145,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package scripting
@@ -205,7 +205,7 @@ The following Java application runs the preceding code and configuration:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -224,7 +224,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -72,7 +72,7 @@ no-argument signature. With Java configuration, you can use the `initMethod` att
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ExampleBean {
@@ -84,7 +84,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ExampleBean {
@@ -107,7 +107,7 @@ The preceding example has almost exactly the same effect as the following exampl
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class AnotherExampleBean implements InitializingBean {
@@ -120,7 +120,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class AnotherExampleBean : InitializingBean {
@@ -144,7 +144,7 @@ based on the given configuration but no further activity with external bean acce
Otherwise there is a risk for an initialization deadlock.
For a scenario where expensive post-initialization activity is to be triggered,
e.g. asynchronous database preparation steps, your bean should either implement
for example, asynchronous database preparation steps, your bean should either implement
`SmartInitializingSingleton.afterSingletonsInstantiated()` or rely on the context
refresh event: implementing `ApplicationListener<ContextRefreshedEvent>` or
declaring its annotation equivalent `@EventListener(ContextRefreshedEvent.class)`.
@@ -187,7 +187,7 @@ xref:core/beans/java/bean-annotation.adoc#beans-java-lifecycle-callbacks[Receivi
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class ExampleBean {
@@ -199,7 +199,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class ExampleBean {
@@ -221,7 +221,7 @@ The preceding definition has almost exactly the same effect as the following def
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class AnotherExampleBean implements DisposableBean {
@@ -234,7 +234,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class AnotherExampleBean : DisposableBean {
@@ -295,7 +295,7 @@ following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class DefaultBlogService implements BlogService {
@@ -316,7 +316,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class DefaultBlogService : BlogService {
@@ -551,7 +551,7 @@ declared on the `ConfigurableApplicationContext` interface, as the following exa
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -573,7 +573,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.context.support.ClassPathXmlApplicationContext
@@ -607,7 +607,7 @@ bean creation phase and its subsequent initial publication, they need to be decl
`volatile` or guarded by a common lock whenever accessed.
Note that concurrent access to such configuration state in singleton bean instances,
e.g. for controller instances or repository instances, is perfectly thread-safe after
for example, for controller instances or repository instances, is perfectly thread-safe after
such safe initial publication from the container side. This includes common singleton
`FactoryBean` instances which are processed within the general singleton lock as well.
@@ -617,7 +617,7 @@ structures (or in `volatile` fields for simple cases) as per common Java guideli
Deeper `Lifecycle` integration as shown above involves runtime-mutable state such as
a `runnable` field which will have to be declared as `volatile`. While the common
lifecycle callbacks follow a certain order, e.g. a start callback is guaranteed to
lifecycle callbacks follow a certain order, for example, a start callback is guaranteed to
only happen after full initialization and a stop callback only after an initial start,
there is a special case with the common stop before destroy arrangement: It is strongly
recommended that the internal state in any such bean also allows for an immediate
@@ -251,7 +251,7 @@ to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@RequestScope
@Component
@@ -262,7 +262,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@RequestScope
@Component
@@ -301,7 +301,7 @@ When using annotation-driven components or Java configuration, you can use the
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@SessionScope
@Component
@@ -312,7 +312,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@SessionScope
@Component
@@ -350,7 +350,7 @@ following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@ApplicationScope
@Component
@@ -361,7 +361,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@ApplicationScope
@Component
@@ -584,14 +584,14 @@ underlying scope:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Object get(String name, ObjectFactory<?> objectFactory)
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun get(name: String, objectFactory: ObjectFactory<*>): Any
----
@@ -606,14 +606,14 @@ the underlying scope:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Object remove(String name)
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun remove(name: String): Any
----
@@ -626,14 +626,14 @@ destroyed or when the specified object in the scope is destroyed:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
void registerDestructionCallback(String name, Runnable destructionCallback)
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
----
@@ -648,14 +648,14 @@ The following method obtains the conversation identifier for the underlying scop
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
String getConversationId()
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun getConversationId(): String
----
@@ -677,14 +677,14 @@ method to register a new `Scope` with the Spring container:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
void registerScope(String scopeName, Scope scope);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun registerScope(scopeName: String, scope: Scope)
----
@@ -710,7 +710,7 @@ implementations.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
@@ -718,7 +718,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)
@@ -19,7 +19,7 @@ The simplest possible `@Configuration` class reads as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -33,7 +33,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -64,7 +64,7 @@ This prevents the same `@Bean` method from accidentally being invoked through a
Java method call, which helps to reduce subtle bugs that can be hard to track down.
When `@Bean` methods are declared within classes that are not annotated with
`@Configuration` - or when `@Configuration(proxyBeanMethods=false)` is declared -,
`@Configuration`, or when `@Configuration(proxyBeanMethods=false)` is declared,
they are referred to as being processed in a "lite" mode. In such scenarios,
`@Bean` methods are effectively a general-purpose factory method mechanism without
special runtime processing (that is, without generating a CGLIB subclass for it).
@@ -25,7 +25,7 @@ the method name. The following example shows a `@Bean` method declaration:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -39,7 +39,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -75,7 +75,7 @@ configurations by implementing interfaces with bean definitions on default metho
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface BaseConfig {
@@ -99,7 +99,7 @@ return type, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -113,7 +113,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -153,7 +153,7 @@ parameter, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -167,7 +167,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -211,7 +211,7 @@ on the `bean` element, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class BeanOne {
@@ -244,7 +244,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class BeanOne {
@@ -291,7 +291,7 @@ The following example shows how to prevent an automatic destruction callback for
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
@@ -301,7 +301,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
@@ -326,7 +326,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -344,7 +344,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -382,7 +382,7 @@ as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class MyConfiguration {
@@ -397,7 +397,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class MyConfiguration {
@@ -431,7 +431,7 @@ it resembles the following:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@@ -451,7 +451,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@@ -479,7 +479,7 @@ as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -493,7 +493,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -517,7 +517,7 @@ The following example shows how to set a number of aliases for a bean:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -531,7 +531,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -559,7 +559,7 @@ annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -574,7 +574,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -16,7 +16,7 @@ another configuration class, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class ConfigA {
@@ -40,7 +40,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class ConfigA {
@@ -67,7 +67,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
@@ -80,7 +80,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -123,7 +123,7 @@ classes, each depending on beans declared in the others:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class ServiceConfig {
@@ -163,7 +163,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -219,7 +219,7 @@ parameter-based injection, as in the preceding example.
Avoid access to locally defined beans within a `@PostConstruct` method on the same configuration
class. This effectively leads to a circular reference since non-static `@Bean` methods semantically
require a fully initialized configuration class instance to be called on. With circular references
disallowed (e.g. in Spring Boot 2.6+), this may trigger a `BeanCurrentlyInCreationException`.
disallowed (for example, in Spring Boot 2.6+), this may trigger a `BeanCurrentlyInCreationException`.
Also, be particularly careful with `BeanPostProcessor` and `BeanFactoryPostProcessor` definitions
through `@Bean`. Those should usually be declared as `static @Bean` methods, not triggering the
@@ -234,7 +234,7 @@ The following example shows how one bean can be autowired to another bean:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class ServiceConfig {
@@ -283,7 +283,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -353,7 +353,7 @@ configuration classes themselves. The following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class ServiceConfig {
@@ -371,7 +371,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class ServiceConfig {
@@ -397,7 +397,7 @@ abstract class-based `@Configuration` classes. Consider the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class ServiceConfig {
@@ -447,7 +447,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -504,10 +504,47 @@ get a type hierarchy of `RepositoryConfig` implementations. In this
way, navigating `@Configuration` classes and their dependencies becomes no different
than the usual process of navigating interface-based code.
TIP: If you want to influence the startup creation order of certain beans, consider
declaring some of them as `@Lazy` (for creation on first access instead of on startup)
or as `@DependsOn` certain other beans (making sure that specific other beans are
created before the current bean, beyond what the latter's direct dependencies imply).
[[beans-java-startup]]
== Influencing the Startup of `@Bean`-defined Singletons
If you want to influence the startup creation order of certain singleton beans, consider
declaring some of them as `@Lazy` for creation on first access instead of on startup.
`@DependsOn` forces certain other beans to be initialized first, making sure that
the specified beans are created before the current bean, beyond what the latter's
direct dependencies imply.
[[beans-java-startup-background]]
=== Background Initialization
As of 6.2, there is a background initialization option: `@Bean(bootstrap=BACKGROUND)`
allows for singling out specific beans for background initialization, covering the
entire bean creation step for each such bean on context startup.
Dependent beans with non-lazy injection points automatically wait for the bean instance
to be completed. All regular background initializations are forced to complete at the end
of context startup. Only beans additionally marked as `@Lazy` are allowed to be completed
later (up until the first actual access).
Background initialization typically goes together with `@Lazy` (or `ObjectProvider`)
injection points in dependent beans. Otherwise, the main bootstrap thread is going to
block when an actual background-initialized bean instance needs to be injected early.
This form of concurrent startup applies to individual beans: if such a bean depends on
other beans, they need to have been initialized already, either simply through being
declared earlier or through `@DependsOn` which enforces initialization in the main
bootstrap thread before background initialization for the affected bean is triggered.
[NOTE]
====
A `bootstrapExecutor` bean of type `Executor` must be declared for background
bootstrapping to be actually active. Otherwise, the background markers will be ignored at
runtime.
The bootstrap executor may be a bounded executor just for startup purposes or a shared
thread pool which serves for other purposes as well.
====
[[beans-java-conditional]]
@@ -533,7 +570,7 @@ method that returns `true` or `false`. For example, the following listing shows
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
@@ -553,7 +590,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean {
// Read the @Profile annotation attributes
@@ -612,7 +649,7 @@ The following example shows the `AppConfig` configuration class in Java and Kotl
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -634,7 +671,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -686,7 +723,7 @@ jdbc.password=
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
@@ -697,7 +734,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun main() {
val ctx = ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml")
@@ -757,7 +794,7 @@ annotation to achieve "`Java-centric`" configuration that uses XML as needed:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
@@ -792,7 +829,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
@@ -846,7 +883,7 @@ jdbc.password=
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
@@ -857,7 +894,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -17,7 +17,7 @@ as having one bean method call another, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -36,7 +36,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -72,7 +72,7 @@ following example shows how to use lookup method injection:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public abstract class CommandManager {
public Object process(Object commandState) {
@@ -90,7 +90,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
abstract class CommandManager {
fun process(commandState: Any): Any {
@@ -115,7 +115,7 @@ the abstract `createCommand()` method is overridden in such a way that it looks
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Bean
@Scope("prototype")
@@ -139,7 +139,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Bean
@Scope("prototype")
@@ -172,7 +172,7 @@ Consider the following example, which shows a `@Bean` annotated method being cal
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@@ -200,7 +200,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
class AppConfig {
@@ -27,7 +27,7 @@ XML-free usage of the Spring container, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
@@ -38,7 +38,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -58,7 +58,7 @@ as input to the constructor, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
@@ -69,7 +69,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -97,7 +97,7 @@ example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -111,7 +111,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
@@ -136,7 +136,7 @@ To enable component scanning, you can annotate your `@Configuration` class as fo
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "com.acme") // <1>
@@ -148,7 +148,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["com.acme"]) // <1>
@@ -183,7 +183,7 @@ following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -195,7 +195,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun main() {
val ctx = AnnotationConfigApplicationContext()
@@ -33,7 +33,7 @@ Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject;
@@ -55,7 +55,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject
@@ -83,7 +83,7 @@ preceding example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject;
import jakarta.inject.Provider;
@@ -106,7 +106,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject
@@ -131,7 +131,7 @@ you should use the `@Named` annotation, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -151,7 +151,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@@ -190,7 +190,7 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SimpleMovieLister {
@@ -203,7 +203,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SimpleMovieLister {
@@ -225,7 +225,7 @@ as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -246,7 +246,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@@ -269,7 +269,7 @@ It is very common to use `@Component` without specifying a name for the componen
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -290,7 +290,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@@ -313,7 +313,7 @@ exact same way as when you use Spring annotations, as the following example show
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example")
@@ -324,7 +324,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"])
@@ -29,7 +29,7 @@ a `DataBuffer` implementation and that does not involve allocation.
Note that WebFlux applications do not create a `DataBufferFactory` directly but instead
access it through the `ServerHttpResponse` or the `ClientHttpRequest` on the client side.
The type of factory depends on the underlying client or server, e.g.
The type of factory depends on the underlying client or server, for example,
`NettyDataBufferFactory` for Reactor Netty, `DefaultDataBufferFactory` for others.
@@ -82,7 +82,7 @@ to use the convenience methods in `DataBufferUtils` that apply release or retain
`DataBufferUtils` offers a number of utility methods to operate on data buffers:
* Join a stream of data buffers into a single buffer possibly with zero copy, e.g. via
* Join a stream of data buffers into a single buffer possibly with zero copy, for example, via
composite buffers, if that's supported by the underlying byte buffer API.
* Turn `InputStream` or NIO `Channel` into `Flux<DataBuffer>`, and vice versa a
`Publisher<DataBuffer>` into `OutputStream` or NIO `Channel`.
@@ -144,7 +144,7 @@ a serialization error occurs while populating the buffer with data. For example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
DataBuffer buffer = factory.allocateBuffer();
boolean release = true;
@@ -162,7 +162,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val buffer = factory.allocateBuffer()
var release = true
@@ -1,219 +1,34 @@
[[expressions-beandef]]
= Expressions in Bean Definitions
You can use SpEL expressions with XML-based or annotation-based configuration metadata for
defining `BeanDefinition` instances. In both cases, the syntax to define the expression is of the
form `#{ <expression string> }`.
[[expressions-beandef-xml-based]]
== XML Configuration
A property or constructor argument value can be set by using expressions, as the following
example shows:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
<!-- other properties -->
</bean>
----
You can use SpEL expressions with configuration metadata for defining bean instances. In both
cases, the syntax to define the expression is of the form `#{ <expression string> }`.
All beans in the application context are available as predefined variables with their
common bean name. This includes standard context beans such as `environment` (of type
`org.springframework.core.env.Environment`) as well as `systemProperties` and
`systemEnvironment` (of type `Map<String, Object>`) for access to the runtime environment.
The following example shows access to the `systemProperties` bean as a SpEL variable:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
<!-- other properties -->
</bean>
----
Note that you do not have to prefix the predefined variable with the `#` symbol here.
You can also refer to other bean properties by name, as the following example shows:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
<!-- other properties -->
</bean>
<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
<!-- other properties -->
</bean>
----
[[expressions-beandef-annotation-based]]
== Annotation Configuration
To specify a default value, you can place the `@Value` annotation on fields, methods,
and method or constructor parameters.
and method or constructor parameters (or XML equivalent).
The following example sets the default value of a field:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class FieldValueTestBean {
include-code::./FieldValueTestBean[tag=snippet,indent=0]
@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class FieldValueTestBean {
@Value("#{ systemProperties['user.region'] }")
var defaultLocale: String? = null
}
----
======
Note that you do not have to prefix the predefined variable with the `#` symbol here.
The following example shows the equivalent but on a property setter method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class PropertyValueTestBean {
private String defaultLocale;
@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class PropertyValueTestBean {
@Value("#{ systemProperties['user.region'] }")
var defaultLocale: String? = null
}
----
======
include-code::./PropertyValueTestBean[tag=snippet,indent=0]
Autowired methods and constructors can also use the `@Value` annotation, as the following
examples show:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class SimpleMovieLister {
private lateinit var movieFinder: MovieFinder
private lateinit var defaultLocale: String
@Autowired
fun configure(movieFinder: MovieFinder,
@Value("#{ systemProperties['user.region'] }") defaultLocale: String) {
this.movieFinder = movieFinder
this.defaultLocale = defaultLocale
}
// ...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class MovieRecommender {
private String defaultLocale;
private CustomerPreferenceDao customerPreferenceDao;
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
@Value("#{systemProperties['user.country']}") String defaultLocale) {
this.customerPreferenceDao = customerPreferenceDao;
this.defaultLocale = defaultLocale;
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class MovieRecommender(private val customerPreferenceDao: CustomerPreferenceDao,
@Value("#{systemProperties['user.country']}") private val defaultLocale: String) {
// ...
}
----
======
include-code::./SimpleMovieLister[tag=snippet,indent=0]
include-code::./MovieRecommender[tag=snippet,indent=0]
You can also refer to other bean properties by name, as the following example shows:
include-code::./ShapeGuess[tag=snippet,indent=0]
@@ -12,7 +12,7 @@ expression, `Hello World`.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'"); // <1>
@@ -22,7 +22,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val exp = parser.parseExpression("'Hello World'") // <1>
@@ -51,7 +51,7 @@ literal, `Hello World`.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
@@ -61,7 +61,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val exp = parser.parseExpression("'Hello World'.concat('!')") // <1>
@@ -77,7 +77,7 @@ string literal, `Hello World`.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
@@ -89,7 +89,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
@@ -110,7 +110,7 @@ The following example shows how to use dot notation to get the length of a strin
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
@@ -122,7 +122,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
@@ -140,7 +140,7 @@ example shows.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
@@ -150,7 +150,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val exp = parser.parseExpression("new String('hello world').toUpperCase()") // <1>
@@ -173,7 +173,7 @@ reference the `name` property in a boolean expression.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
@@ -195,7 +195,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Create and set a calendar
val c = GregorianCalendar()
@@ -275,7 +275,7 @@ being placed in it. The following example shows how to do so.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
class Simple {
public List<Boolean> booleanList = new ArrayList<>();
@@ -296,7 +296,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class Simple {
var booleanList: MutableList<Boolean> = ArrayList()
@@ -339,7 +339,7 @@ automatically grow a `List`.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
class Demo {
public List<String> list;
@@ -364,7 +364,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class Demo {
var list: List<String>? = null
@@ -444,18 +444,27 @@ component. This section discusses both of these options.
The compiler can operate in one of three modes, which are captured in the
`org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows.
* `OFF` (default): The compiler is switched off.
* `IMMEDIATE`: In immediate mode, the expressions are compiled as soon as possible. This
is typically after the first interpreted evaluation. If the compiled expression fails
(typically due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception.
* `MIXED`: In mixed mode, the expressions silently switch between interpreted and
compiled mode over time. After some number of interpreted runs, they switch to compiled
form and, if something goes wrong with the compiled form (such as a type changing, as
described earlier), the expression automatically switches back to interpreted form
again. Sometime later, it may generate another compiled form and switch to it.
Basically, the exception that the user gets in `IMMEDIATE` mode is instead handled
internally.
`OFF` ::
The compiler is switched off, and all expressions will be evaluated in _interpreted_
mode. This is the default mode.
`IMMEDIATE` ::
In immediate mode, expressions are compiled as soon as possible, typically after the
first interpreted evaluation. If evaluation of the compiled expression fails (for
example, due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception. If the types of various expression elements change
over time, consider switching to `MIXED` mode or turning off the compiler.
`MIXED` ::
In mixed mode, expression evaluation silently switches between _interpreted_ and
_compiled_ over time. After some number of successful interpreted runs, the expression
gets compiled. If evaluation of the compiled expression fails (for example, due to a
type changing), that failure will be caught internally, and the system will switch back
to interpreted mode for the given expression. Basically, the exception that the caller
receives in `IMMEDIATE` mode is instead handled internally. Sometime later, the
compiler may generate another compiled form and switch to it. This cycle of switching
between interpreted and compiled mode will continue until the system determines that it
does not make sense to continue trying — for example, when a certain failure threshold
has been reached — at which point the system will permanently switch to interpreted
mode for the given expression.
`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that
have side effects. If a compiled expression blows up after partially succeeding, it
@@ -470,7 +479,7 @@ following example shows how to do so.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
this.getClass().getClassLoader());
@@ -486,7 +495,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val config = SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
this.javaClass.classLoader)
@@ -525,10 +534,11 @@ following kinds of expressions cannot be compiled.
* Expressions involving assignment
* Expressions relying on the conversion service
* Expressions using custom resolvers or accessors
* Expressions using custom resolvers
* Expressions using overloaded operators
* Expressions using array construction syntax
* Expressions using selection or projection
* Expressions using bean references
Compilation of additional kinds of expressions may be supported in the future.
@@ -9,7 +9,7 @@ This section lists the classes used in the examples throughout this chapter.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor;
@@ -84,7 +84,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor
@@ -103,7 +103,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor;
@@ -141,7 +141,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor
@@ -155,7 +155,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor;
@@ -200,7 +200,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.spring.samples.spel.inventor
@@ -8,7 +8,7 @@ to have the array populated at construction time. The following example shows ho
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
@@ -21,7 +21,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val numbers1 = parser.parseExpression("new int[4]").getValue(context) as IntArray
@@ -1,65 +1,73 @@
[[expressions-bean-references]]
= Bean References
If the evaluation context has been configured with a bean resolver, you can
look up beans from an expression by using the `@` symbol. The following example shows how
If the evaluation context has been configured with a bean resolver, you can look up beans
from an expression by using the `@` symbol as a prefix. The following example shows how
to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("@something").getValue(context);
// This will end up calling resolve(context, "someBean") on MyBeanResolver
// during evaluation.
Object bean = parser.parseExpression("@someBean").getValue(context);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = StandardEvaluationContext()
context.setBeanResolver(MyBeanResolver())
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
val bean = parser.parseExpression("@something").getValue(context)
// This will end up calling resolve(context, "someBean") on MyBeanResolver
// during evaluation.
val bean = parser.parseExpression("@someBean").getValue(context)
----
======
To access a factory bean itself, you should instead prefix the bean name with an `&` symbol.
The following example shows how to do so:
[NOTE]
====
If a bean name contains a dot (`.`) or other special characters, you must provide the
name of the bean as a _string literal_ for example, `@'order.service'`.
====
To access a factory bean itself, you should instead prefix the bean name with an `&`
symbol. The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("&foo").getValue(context);
// This will end up calling resolve(context, "&someFactoryBean") on
// MyBeanResolver during evaluation.
Object factoryBean = parser.parseExpression("&someFactoryBean").getValue(context);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = StandardEvaluationContext()
context.setBeanResolver(MyBeanResolver())
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
val bean = parser.parseExpression("&foo").getValue(context)
// This will end up calling resolve(context, "&someFactoryBean") on
// MyBeanResolver during evaluation.
val factoryBean = parser.parseExpression("&someFactoryBean").getValue(context)
----
======
@@ -11,7 +11,7 @@ list. The following example uses projection to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to ["Smiljan", "Idvor"]
List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
@@ -20,7 +20,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to ["Smiljan", "Idvor"]
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
@@ -12,7 +12,7 @@ selection lets us easily get a list of Serbian inventors, as the following examp
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"members.?[nationality == 'Serbian']").getValue(societyContext);
@@ -20,7 +20,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val list = parser.parseExpression(
"members.?[nationality == 'Serbian']").getValue(societyContext) as List<Inventor>
@@ -41,14 +41,14 @@ than 27:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Map newMap = parser.parseExpression("#map.?[value < 27]").getValue(Map.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val newMap = parser.parseExpression("#map.?[value < 27]").getValue() as Map
----
@@ -3,14 +3,16 @@
You can invoke constructors by using the `new` operator. You should use the fully
qualified class name for all types except those located in the `java.lang` package
(`Integer`, `Float`, `String`, and so on). The following example shows how to use the
`new` operator to invoke constructors:
(`Integer`, `Float`, `String`, and so on).
xref:core/expressions/language-ref/varargs.adoc[Varargs] are also supported.
The following example shows how to use the `new` operator to invoke constructors.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Inventor einstein = parser.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
@@ -24,7 +26,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val einstein = parser.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
@@ -38,4 +40,3 @@ Kotlin::
======
@@ -2,8 +2,12 @@
= Functions
You can extend SpEL by registering user-defined functions that can be called within
expressions by using the `#functionName(...)` syntax. Functions can be registered as
variables in `EvaluationContext` implementations via the `setVariable()` method.
expressions by using the `#functionName(...)` syntax, and like with standard method
invocations, xref:core/expressions/language-ref/varargs.adoc[varargs] are also supported
for function invocations.
Functions can be registered as _variables_ in `EvaluationContext` implementations via the
`setVariable()` method.
[TIP]
====
@@ -26,7 +30,7 @@ reflection using a `java.lang.reflect.Method`:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Method method = ...;
@@ -36,7 +40,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val method: Method = ...
@@ -51,7 +55,7 @@ For example, consider the following utility method that reverses a string:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public abstract class StringUtils {
@@ -63,7 +67,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
fun reverseString(input: String): String {
return StringBuilder(input).reverse().toString()
@@ -77,7 +81,7 @@ You can register and use the preceding method, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
@@ -92,7 +96,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
@@ -111,7 +115,8 @@ been fully bound prior to registration; however, partially bound handles are als
supported.
Consider the `String#formatted(Object...)` instance method, which produces a message
according to a template and a variable number of arguments.
according to a template and a variable number of arguments
(xref:core/expressions/language-ref/varargs.adoc[varargs]).
You can register and use the `formatted` method as a `MethodHandle`, as the following
example shows:
@@ -120,7 +125,7 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@@ -136,7 +141,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
@@ -160,7 +165,7 @@ the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@@ -181,7 +186,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
@@ -203,4 +208,3 @@ Kotlin::
======
@@ -7,7 +7,7 @@ You can directly express lists in an expression by using `{}` notation.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to a Java list containing the four numbers
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
@@ -17,7 +17,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to a Java list containing the four numbers
val numbers = parser.parseExpression("{1,2,3,4}").getValue(context) as List<*>
@@ -8,7 +8,7 @@ following example shows how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
@@ -18,7 +18,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim"]
----
// evaluates to a Java map containing the two entries
val inventorInfo = parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context) as Map<*, *>
@@ -53,7 +53,7 @@ method.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
@@ -75,7 +75,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
@@ -1,15 +1,17 @@
[[expressions-methods]]
= Methods
You can invoke methods by using typical Java programming syntax. You can also invoke methods
on literals. Variable arguments are also supported. The following examples show how to
invoke methods:
You can invoke methods by using the typical Java programming syntax. You can also invoke
methods directly on literals such as strings or numbers.
xref:core/expressions/language-ref/varargs.adoc[Varargs] are supported as well.
The following examples show how to invoke methods.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// string literal, evaluates to "bc"
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
@@ -21,7 +23,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// string literal, evaluates to "bc"
val bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String::class.java)
@@ -19,7 +19,7 @@ The following example shows how to use the Elvis operator:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
@@ -29,7 +29,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
@@ -48,7 +48,7 @@ The following listing shows a more complex example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@@ -64,7 +64,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
@@ -1,7 +1,7 @@
[[expressions-operator-safe-navigation]]
= Safe Navigation Operator
The safe navigation operator (`?`) is used to avoid a `NullPointerException` and comes
The safe navigation operator (`?.`) is used to avoid a `NullPointerException` and comes
from the https://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy]
language. Typically, when you have a reference to an object, you might need to verify
that it is not `null` before accessing methods or properties of the object. To avoid
@@ -27,7 +27,7 @@ The following example shows how to use the safe navigation operator for property
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@@ -50,7 +50,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
@@ -81,6 +81,65 @@ For example, the expression `#calculator?.max(4, 2)` evaluates to `null` if the
`max(int, int)` method will be invoked on the `#calculator`.
====
[[expressions-operator-safe-navigation-indexing]]
== Safe Index Access
Since Spring Framework 6.2, the Spring Expression Language supports safe navigation for
indexing into the following types of structures.
* xref:core/expressions/language-ref/properties-arrays.adoc#expressions-indexing-arrays-and-collections[arrays and collections]
* xref:core/expressions/language-ref/properties-arrays.adoc#expressions-indexing-strings[strings]
* xref:core/expressions/language-ref/properties-arrays.adoc#expressions-indexing-maps[maps]
* xref:core/expressions/language-ref/properties-arrays.adoc#expressions-indexing-objects[objects]
* xref:core/expressions/language-ref/properties-arrays.adoc#expressions-indexing-custom[custom]
The following example shows how to use the safe navigation operator for indexing into
a list (`?.[]`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
EvaluationContext context = new StandardEvaluationContext(society);
// evaluates to Inventor("Nikola Tesla")
Inventor inventor = parser.parseExpression("members?.[0]") // <1>
.getValue(context, Inventor.class);
society.members = null;
// evaluates to null - does not throw an exception
inventor = parser.parseExpression("members?.[0]") // <2>
.getValue(context, Inventor.class);
----
<1> Use null-safe index operator on a non-null `members` list
<2> Use null-safe index operator on a null `members` list
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
// evaluates to Inventor("Nikola Tesla")
var inventor = parser.parseExpression("members?.[0]") // <1>
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw an exception
inventor = parser.parseExpression("members?.[0]") // <2>
.getValue(context, Inventor::class.java)
----
<1> Use null-safe index operator on a non-null `members` list
<2> Use null-safe index operator on a null `members` list
======
[[expressions-operator-safe-navigation-selection-and-projection]]
== Safe Collection Selection and Projection
@@ -102,7 +161,7 @@ selection (`?.?`).
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
@@ -123,7 +182,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
@@ -150,7 +209,7 @@ collections (`?.^`).
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
@@ -172,7 +231,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
@@ -201,7 +260,7 @@ collections (`?.$`).
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
@@ -223,7 +282,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
@@ -251,7 +310,7 @@ projection (`?.!`).
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
@@ -272,7 +331,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
@@ -321,7 +380,7 @@ evaluates to `null` instead of throwing an exception.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
@@ -342,7 +401,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val society = IEEE()
@@ -8,7 +8,7 @@ the expression. The following listing shows a minimal example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
String falseString = parser.parseExpression(
"false ? 'trueExp' : 'falseExp'").getValue(String.class);
@@ -16,7 +16,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val falseString = parser.parseExpression(
"false ? 'trueExp' : 'falseExp'").getValue(String::class.java)
@@ -30,7 +30,7 @@ realistic example follows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
parser.parseExpression("name").setValue(societyContext, "IEEE");
societyContext.setVariable("queryName", "Nikola Tesla");
@@ -45,7 +45,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
parser.parseExpression("name").setValue(societyContext, "IEEE")
societyContext.setVariable("queryName", "Nikola Tesla")
@@ -24,7 +24,7 @@ The following listing shows a few examples of relational operators:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
@@ -41,7 +41,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to true
val trueValue = parser.parseExpression("2 == 2").getValue(Boolean::class.java)
@@ -89,7 +89,7 @@ shows examples of all three:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
boolean result;
@@ -128,7 +128,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to true
var result = parser.parseExpression(
@@ -195,7 +195,7 @@ The following example shows how to use the logical operators:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// -- AND --
@@ -228,7 +228,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// -- AND --
@@ -277,7 +277,7 @@ The following example shows the `String` operators in use:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// -- Concatenation --
@@ -300,7 +300,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// -- Concatenation --
@@ -358,7 +358,7 @@ The following example shows the mathematical operators in use:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
@@ -424,7 +424,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val inventor = Inventor()
val context = SimpleEvaluationContext.forReadWriteDataBinding().build()
@@ -501,7 +501,7 @@ listing shows both ways to use the assignment operator:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
@@ -515,7 +515,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val inventor = Inventor()
val context = SimpleEvaluationContext.forReadWriteDataBinding().build()
@@ -541,7 +541,7 @@ For example, if we want to overload the `ADD` operator to allow two lists to be
concatenated using the `+` sign, we can implement a custom `OperatorOverloader` as
follows.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
pubic class ListConcatenation implements OperatorOverloader {
@@ -576,7 +576,7 @@ as demonstrated in the following example.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
StandardEvaluationContext context = new StandardEvaluationContext();
context.setOperatorOverloader(new ListConcatenation());
@@ -587,7 +587,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
StandardEvaluationContext context = StandardEvaluationContext()
context.setOperatorOverloader(ListConcatenation())
@@ -1,31 +1,47 @@
[[expressions-properties-arrays]]
= Properties, Arrays, Lists, Maps, and Indexers
Navigating with property references is easy. To do so, use a period to indicate a nested
property value. The instances of the `Inventor` class, `pupin` and `tesla`, were
populated with data listed in the xref:core/expressions/example-classes.adoc[Classes used in the examples]
section. To navigate "down" the object graph and get Tesla's year of birth and
Pupin's city of birth, we use the following expressions:
The Spring Expression Language provides support for navigating object graphs and indexing
into various structures.
NOTE: Numerical index values are zero-based, such as when accessing the n^th^ element of
an array in Java.
TIP: See the xref:core/expressions/language-ref/operator-safe-navigation.adoc[Safe Navigation Operator]
section for details on how to navigate object graphs and index into various structures
using the null-safe operator.
[[expressions-property-navigation]]
== Property Navigation
You can navigate property references within an object graph by using a period to indicate
a nested property value. The instances of the `Inventor` class, `pupin` and `tesla`, were
populated with data listed in the
xref:core/expressions/example-classes.adoc[Classes used in the examples] section. To
navigate _down_ the object graph and get Tesla's year of birth and Pupin's city of birth,
we use the following expressions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
// evaluates to "Smiljan"
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to 1856
val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int
// evaluates to "Smiljan"
val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String
----
======
@@ -39,14 +55,26 @@ method invocations -- for example, `getPlaceOfBirth().getCity()` instead of
`placeOfBirth.city`.
====
The contents of arrays and lists are obtained by using square bracket notation, as the
following example shows:
[[expressions-indexing-arrays-and-collections]]
== Indexing into Arrays and Collections
The n^th^ element of an array or collection (for example, a `Set` or `List`) can be
obtained by using square bracket notation, as the following example shows.
[NOTE]
====
If the indexed collection is a `java.util.List`, the n^th^ element will be accessed
directly via `list.get(n)`.
For any other type of `Collection`, the n^th^ element will be accessed by iterating over
the collection using its `Iterator` and returning the n^th^ element encountered.
====
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@@ -63,7 +91,8 @@ Java::
String name = parser.parseExpression("members[0].name").getValue(
context, ieee, String.class);
// List and Array navigation
// List and Array Indexing
// evaluates to "Wireless communication"
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
context, ieee, String.class);
@@ -71,7 +100,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
@@ -88,55 +117,248 @@ Kotlin::
val name = parser.parseExpression("members[0].name").getValue(
context, ieee, String::class.java)
// List and Array navigation
// List and Array Indexing
// evaluates to "Wireless communication"
val invention = parser.parseExpression("members[0].inventions[6]").getValue(
context, ieee, String::class.java)
----
======
The contents of maps are obtained by specifying the literal key value within the
brackets. In the following example, because keys for the `officers` map are strings, we can specify
string literals:
[[expressions-indexing-strings]]
== Indexing into Strings
The n^th^ character of a string can be obtained by specifying the index within square
brackets, as demonstrated in the following example.
NOTE: The n^th^ character of a string will evaluate to a `java.lang.String`, not a
`java.lang.Character`.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// Officer's Dictionary
Inventor pupin = parser.parseExpression("officers['president']").getValue(
societyContext, Inventor.class);
// evaluates to "Idvor"
String city = parser.parseExpression("officers['president'].placeOfBirth.city").getValue(
societyContext, String.class);
// setting values
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
societyContext, "Croatia");
// evaluates to "T" (8th letter of "Nikola Tesla")
String character = parser.parseExpression("members[0].name[7]")
.getValue(societyContext, String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Officer's Dictionary
val pupin = parser.parseExpression("officers['president']").getValue(
societyContext, Inventor::class.java)
// evaluates to "Idvor"
val city = parser.parseExpression("officers['president'].placeOfBirth.city").getValue(
societyContext, String::class.java)
// setting values
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
societyContext, "Croatia")
// evaluates to "T" (8th letter of "Nikola Tesla")
val character = parser.parseExpression("members[0].name[7]")
.getValue(societyContext, String::class.java)
----
======
[[expressions-indexing-maps]]
== Indexing into Maps
The contents of maps are obtained by specifying the key value within square brackets. In
the following example, because keys for the `officers` map are strings, we can specify
string literals such as `'president'`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// Officer's Map
// evaluates to Inventor("Pupin")
Inventor pupin = parser.parseExpression("officers['president']")
.getValue(societyContext, Inventor.class);
// evaluates to "Idvor"
String city = parser.parseExpression("officers['president'].placeOfBirth.city")
.getValue(societyContext, String.class);
String countryExpression = "officers['advisors'][0].placeOfBirth.country";
// setting values
parser.parseExpression(countryExpression)
.setValue(societyContext, "Croatia");
// evaluates to "Croatia"
String country = parser.parseExpression(countryExpression)
.getValue(societyContext, String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Officer's Map
// evaluates to Inventor("Pupin")
val pupin = parser.parseExpression("officers['president']")
.getValue(societyContext, Inventor::class.java)
// evaluates to "Idvor"
val city = parser.parseExpression("officers['president'].placeOfBirth.city")
.getValue(societyContext, String::class.java)
val countryExpression = "officers['advisors'][0].placeOfBirth.country"
// setting values
parser.parseExpression(countryExpression)
.setValue(societyContext, "Croatia")
// evaluates to "Croatia"
val country = parser.parseExpression(countryExpression)
.getValue(societyContext, String::class.java)
----
======
[[expressions-indexing-objects]]
== Indexing into Objects
A property of an object can be obtained by specifying the name of the property within
square brackets. This is analogous to accessing the value of a map based on its key. The
following example demonstrates how to _index_ into an object to retrieve a specific
property.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// Create an inventor to use as the root context object.
Inventor tesla = new Inventor("Nikola Tesla");
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("#root['name']")
.getValue(context, tesla, String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Create an inventor to use as the root context object.
val tesla = Inventor("Nikola Tesla")
// evaluates to "Nikola Tesla"
val name = parser.parseExpression("#root['name']")
.getValue(context, tesla, String::class.java)
----
======
[[expressions-indexing-custom]]
== Indexing into Custom Structures
Since Spring Framework 6.2, the Spring Expression Language supports indexing into custom
structures by allowing developers to implement and register an `IndexAccessor` with the
`EvaluationContext`. If you would like to support
xref:core/expressions/evaluation.adoc#expressions-spel-compilation[compilation] of
expressions that rely on a custom index accessor, that index accessor must implement the
`CompilableIndexAccessor` SPI.
To support common use cases, Spring provides a built-in `ReflectiveIndexAccessor` which
is a flexible `IndexAccessor` that uses reflection to read from and optionally write to
an indexed structure of a target object. The indexed structure can be accessed through a
`public` read-method (when being read) or a `public` write-method (when being written).
The relationship between the read-method and write-method is based on a convention that
is applicable for typical implementations of indexed structures.
NOTE: `ReflectiveIndexAccessor` also implements `CompilableIndexAccessor` in order to
support xref:core/expressions/evaluation.adoc#expressions-spel-compilation[compilation]
to bytecode for read access. Note, however, that the configured read-method must be
invokable via a `public` class or `public` interface for compilation to succeed.
The following code listings define a `Color` enum and `FruitMap` type that behaves like a
map but does not implement the `java.util.Map` interface. Thus, if you want to index into
a `FruitMap` within a SpEL expression, you will need to register an `IndexAccessor`.
[source,java,indent=0,subs="verbatim,quotes"]
----
package example;
public enum Color {
RED, ORANGE, YELLOW
}
----
[source,java,indent=0,subs="verbatim,quotes"]
----
public class FruitMap {
private final Map<Color, String> map = new HashMap<>();
public FruitMap() {
this.map.put(Color.RED, "cherry");
this.map.put(Color.ORANGE, "orange");
this.map.put(Color.YELLOW, "banana");
}
public String getFruit(Color color) {
return this.map.get(color);
}
public void setFruit(Color color, String fruit) {
this.map.put(color, fruit);
}
}
----
A read-only `IndexAccessor` for `FruitMap` can be created via `new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit")`. With that accessor
registered and a `FruitMap` registered as a variable named `#fruitMap`, the SpEL
expression `#fruitMap[T(example.Color).RED]` will evaluate to `"cherry"`.
A read-write `IndexAccessor` for `FruitMap` can be created via `new
ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit", "setFruit")`. With that
accessor registered and a `FruitMap` registered as a variable named `#fruitMap`, the SpEL
expression `#fruitMap[T(example.Color).RED] = 'strawberry'` can be used to change the
fruit mapping for the color red from `"cherry"` to `"strawberry"`.
The following example demonstrates how to register a `ReflectiveIndexAccessor` to index
into a `FruitMap` and then index into the `FruitMap` within a SpEL expression.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// Create a ReflectiveIndexAccessor for FruitMap
IndexAccessor fruitMapAccessor = new ReflectiveIndexAccessor(
FruitMap.class, Color.class, "getFruit", "setFruit");
// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor);
// Register the fruitMap variable
context.setVariable("fruitMap", new FruitMap());
// evaluates to "cherry"
String fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
.getValue(context, String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Create a ReflectiveIndexAccessor for FruitMap
val fruitMapAccessor = ReflectiveIndexAccessor(
FruitMap::class.java, Color::class.java, "getFruit", "setFruit")
// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor)
// Register the fruitMap variable
context.setVariable("fruitMap", FruitMap())
// evaluates to "cherry"
val fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
.getValue(context, String::class.java)
----
======
@@ -3,14 +3,14 @@
Expression templates allow mixing literal text with one or more evaluation blocks.
Each evaluation block is delimited with prefix and suffix characters that you can
define. A common choice is to use `#{ }` as the delimiters, as the following example
define. A common choice is to use `+#{ }+` as the delimiters, as the following example
shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
String randomPhrase = parser.parseExpression(
"random number is #{T(java.lang.Math).random()}",
@@ -21,7 +21,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val randomPhrase = parser.parseExpression(
"random number is #{T(java.lang.Math).random()}",
@@ -32,7 +32,7 @@ Kotlin::
======
The string is evaluated by concatenating the literal text `'random number is '` with the
result of evaluating the expression inside the `#{ }` delimiters (in this case, the
result of evaluating the expression inside the `+#{ }+` delimiters (in this case, the
result of calling that `random()` method). The second argument to the `parseExpression()`
method is of the type `ParserContext`. The `ParserContext` interface is used to influence
how the expression is parsed in order to support the expression templating functionality.
@@ -13,7 +13,7 @@ following example shows how to use the `T` operator:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
@@ -26,7 +26,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class::class.java)
@@ -0,0 +1,151 @@
[[expressions-varargs]]
= Varargs Invocations
The Spring Expression Language supports
https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html[varargs]
invocations for xref:core/expressions/language-ref/constructors.adoc[constructors],
xref:core/expressions/language-ref/methods.adoc[methods], and user-defined
xref:core/expressions/language-ref/functions.adoc[functions].
The following example shows how to invoke the `java.lang.String#formatted(Object...)`
_varargs_ method within an expression by supplying the variable argument list as separate
arguments (`'blue', 1`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
String expression = "'%s is color #%d'.formatted('blue', 1)";
String message = parser.parseExpression(expression).getValue(String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
val expression = "'%s is color #%d'.formatted('blue', 1)"
val message = parser.parseExpression(expression).getValue(String::class.java)
----
======
A variable argument list can also be supplied as an array, as demonstrated in the
following example (`new Object[] {'blue', 1}`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
String expression = "'%s is color #%d'.formatted(new Object[] {'blue', 1})";
String message = parser.parseExpression(expression).getValue(String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
val expression = "'%s is color #%d'.formatted(new Object[] {'blue', 1})"
val message = parser.parseExpression(expression).getValue(String::class.java)
----
======
As an alternative, a variable argument list can be supplied as a `java.util.List` for
example, as an xref:core/expressions/language-ref/inline-lists.adoc[inline list]
(`{'blue', 1}`). The following example shows how to do that.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
String expression = "'%s is color #%d'.formatted({'blue', 1})";
String message = parser.parseExpression(expression).getValue(String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
val expression = "'%s is color #%d'.formatted({'blue', 1})"
val message = parser.parseExpression(expression).getValue(String::class.java)
----
======
[[expressions-varargs-type-conversion]]
== Varargs Type Conversion
In contrast to the standard support for varargs invocations in Java,
xref:core/expressions/evaluation.adoc#expressions-type-conversion[type conversion] may be
applied to the individual arguments when invoking varargs constructors, methods, or
functions in SpEL.
For example, if we have registered a custom
xref:core/expressions/language-ref/functions.adoc[function] in the `EvaluationContext`
under the name `#reverseStrings` for a method with the signature
`String reverseStrings(String... strings)`, we can invoke that function within a SpEL
expression with any argument that can be converted to a `String`, as demonstrated in the
following example.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to "3.0, 2.0, 1, SpEL"
String expression = "#reverseStrings('SpEL', 1, 10F / 5, 3.0000)";
String message = parser.parseExpression(expression)
.getValue(evaluationContext, String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to "3.0, 2.0, 1, SpEL"
val expression = "#reverseStrings('SpEL', 1, 10F / 5, 3.0000)"
val message = parser.parseExpression(expression)
.getValue(evaluationContext, String::class.java)
----
======
Similarly, any array whose component type is a subtype of the required varargs type can
be supplied as the variable argument list for a varargs invocation. For example, a
`String[]` array can be supplied to a varargs invocation that accepts an `Object...`
argument list.
The following listing demonstrates that we can supply a `String[]` array to the
`java.lang.String#formatted(Object...)` _varargs_ method. It also highlights that `1`
will be automatically converted to `"1"`.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
String expression = "'%s is color #%s'.formatted(new String[] {'blue', 1})";
String message = parser.parseExpression(expression).getValue(String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// evaluates to "blue is color #1"
val expression = "'%s is color #%s'.formatted(new String[] {'blue', 1})"
val message = parser.parseExpression(expression).getValue(String::class.java)
----
======
@@ -42,7 +42,7 @@ The following example shows how to use variables.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
@@ -55,7 +55,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val tesla = Inventor("Nikola Tesla", "Serbian")
@@ -83,7 +83,7 @@ xref:core/expressions/language-ref/collection-selection.adoc[collection selectio
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// Create a list of prime integers.
List<Integer> primes = List.of(2, 3, 5, 7, 11, 13, 17);
@@ -103,7 +103,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Create a list of prime integers.
val primes = listOf(2, 3, 5, 7, 11, 13, 17)
@@ -130,7 +130,7 @@ xref:core/expressions/language-ref/collection-projection.adoc[collection project
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// Create parser and evaluation context.
ExpressionParser parser = new SpelExpressionParser();
@@ -154,7 +154,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// Create parser and evaluation context.
val parser = SpelExpressionParser()
@@ -280,14 +280,14 @@ snippet of code was run against a `ClassPathXmlApplicationContext` instance:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val template = ctx.getResource("some/resource/path/myTemplate.txt")
----
@@ -309,14 +309,14 @@ example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val template = ctx.getResource("classpath:some/resource/path/myTemplate.txt")
----
@@ -329,14 +329,14 @@ Similarly, you can force a `UrlResource` to be used by specifying any of the sta
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val template = ctx.getResource("file:///some/resource/path/myTemplate.txt")
----
@@ -346,14 +346,14 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt")
----
@@ -505,7 +505,7 @@ property of type `Resource`.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
package example;
@@ -523,7 +523,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MyBean(var template: Resource)
----
@@ -571,7 +571,7 @@ The following example demonstrates how to achieve this.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MyBean {
@@ -588,7 +588,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MyBean(@Value("\${template.path}") private val template: Resource)
@@ -606,7 +606,7 @@ can be injected into the `MyBean` constructor.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MyBean {
@@ -623,7 +623,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
class MyBean(@Value("\${templates.path}") private val templates: Resource[])
@@ -657,14 +657,14 @@ specific application context. For example, consider the following example, which
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = ClassPathXmlApplicationContext("conf/appContext.xml")
----
@@ -677,7 +677,7 @@ used. However, consider the following example, which creates a `FileSystemXmlApp
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
@@ -685,7 +685,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = FileSystemXmlApplicationContext("conf/appContext.xml")
----
@@ -702,7 +702,7 @@ definitions. Consider the following example:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
@@ -710,7 +710,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = FileSystemXmlApplicationContext("classpath:conf/appContext.xml")
----
@@ -749,7 +749,7 @@ classpath) can be instantiated:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
@@ -757,7 +757,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = ClassPathXmlApplicationContext(arrayOf("services.xml", "repositories.xml"), MessengerService::class.java)
----
@@ -843,7 +843,7 @@ special `classpath*:` prefix, as the following example shows:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
@@ -851,7 +851,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = ClassPathXmlApplicationContext("classpath*:conf/appContext.xml")
----
@@ -905,8 +905,8 @@ policies in some environments -- for example, stand-alone applications on JDK 1.
and higher (which requires 'Trusted-Library' to be set up in your manifests. See
{stackoverflow-questions}/19394570/java-jre-7u45-breaks-classloader-getresources).
On JDK 9's module path (Jigsaw), Spring's classpath scanning generally works as expected.
Putting resources into a dedicated directory is highly recommendable here as well,
On the module path (Java Module System), Spring's classpath scanning generally works as
expected. Putting resources into a dedicated directory is highly recommendable here as well,
avoiding the aforementioned portability problems with searching the jar file root level.
====
@@ -955,7 +955,7 @@ In practice, this means the following examples are equivalent:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/context.xml");
@@ -963,7 +963,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = FileSystemXmlApplicationContext("conf/context.xml")
----
@@ -973,7 +973,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/conf/context.xml");
@@ -981,7 +981,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx = FileSystemXmlApplicationContext("/conf/context.xml")
----
@@ -994,7 +994,7 @@ case is relative and the other absolute):
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
@@ -1002,7 +1002,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx: FileSystemXmlApplicationContext = ...
ctx.getResource("some/resource/path/myTemplate.txt")
@@ -1013,7 +1013,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");
@@ -1021,7 +1021,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val ctx: FileSystemXmlApplicationContext = ...
ctx.getResource("/some/resource/path/myTemplate.txt")
@@ -1037,7 +1037,7 @@ show how to do so:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
@@ -1045,7 +1045,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt")
@@ -1056,7 +1056,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx =
@@ -1065,7 +1065,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
val ctx = FileSystemXmlApplicationContext("file:///conf/context.xml")
@@ -1,7 +1,7 @@
[[spring-jcl]]
= Logging
Since Spring Framework 5.0, Spring comes with its own Commons Logging bridge implemented
Spring comes with its own Commons Logging bridge implemented
in the `spring-jcl` module. The implementation checks for the presence of the Log4j 2.x
API and the SLF4J 1.7 API in the classpath and uses the first one of those found as the
logging implementation, falling back to the Java platform's core logging facilities (also
@@ -9,7 +9,7 @@ known as _JUL_ or `java.util.logging`) if neither Log4j 2.x nor SLF4J is availab
Put Log4j 2.x or Logback (or another SLF4J provider) in your classpath, without any extra
bridges, and let the framework auto-adapt to your choice. For further information see the
{spring-boot-docs}/features.html#features.logging[Spring
{spring-boot-docs-ref}/features/logging.html[Spring
Boot Logging Reference Documentation].
[NOTE]
@@ -27,7 +27,7 @@ the following example.
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MyBean {
private final Log log = LogFactory.getLog(getClass());
@@ -37,7 +37,7 @@ public class MyBean {
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MyBean {
private val log = LogFactory.getLog(javaClass)
@@ -27,15 +27,20 @@ The target class should have a single public constructor or a single non-public
with arguments. If there are multiple constructors, then a default constructor if present
is used.
By default, constructor parameter names are used to look up argument values, but you can
configure a `NameResolver`. Spring MVC and WebFlux both rely to allow customizing the name
of the value to bind through an `@BindParam` annotation on constructor parameters.
By default, argument values are looked up via constructor parameter names. Spring MVC and
WebFlux support a custom name mapping through the `@BindParam` annotation on constructor
parameters or fields if present. If necessary, you can also configure a `NameResolver` on
`DataBinder` to customize the argument name to use.
xref:beans-beans-conventions[Type conversion] is applied as needed to convert user input.
If the constructor parameter is an object, it is constructed recursively in the same
manner, but through a nested property path. That means constructor binding creates both
the target object and any objects it contains.
Constructor binding supports `List`, `Map`, and array arguments either converted from
a single string, for example, comma-separated list, or based on indexed keys such as
`accounts[2].name` or `account[KEY].name`.
Binding and conversion errors are reflected in the `BindingResult` of the `DataBinder`.
If the target is created successfully, then `target` is set to the created instance
after the call to `construct`.
@@ -90,13 +95,12 @@ details. The below table shows some examples of these conventions:
| Indicates the nested property `name` of the property `account` that corresponds to
(for example) the `getAccount().setName()` or `getAccount().getName()` methods.
| `account[2]`
| `accounts[2]`
| Indicates the _third_ element of the indexed property `account`. Indexed properties
can be of type `array`, `list`, or other naturally ordered collection.
| `account[COMPANYNAME]`
| Indicates the value of the map entry indexed by the `COMPANYNAME` key of the `account` `Map`
property.
| `accounts[KEY]`
| Indicates the value of the map entry indexed by the `KEY` value.
|===
(This next section is not vitally important to you if you do not plan to work with
@@ -111,7 +115,7 @@ properties:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class Company {
@@ -138,7 +142,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class Company {
var name: String? = null
@@ -151,7 +155,7 @@ Kotlin::
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class Employee {
@@ -179,7 +183,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class Employee {
var name: String? = null
@@ -195,7 +199,7 @@ the properties of instantiated ``Company``s and ``Employee``s:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
BeanWrapper company = new BeanWrapperImpl(new Company());
// setting the company name..
@@ -215,7 +219,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val company = BeanWrapperImpl(Company())
// setting the company name..
@@ -375,7 +379,7 @@ associates a `CustomNumberEditor` with the `age` property of the `Something` cla
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
public class SomethingBeanInfo extends SimpleBeanInfo {
@@ -399,7 +403,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class SomethingBeanInfo : SimpleBeanInfo() {
@@ -463,7 +467,7 @@ another class called `DependsOnExoticType`, which needs `ExoticType` set as a pr
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example;
@@ -488,7 +492,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example
@@ -518,7 +522,7 @@ The `PropertyEditor` implementation could look similar to the following:
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example;
@@ -535,7 +539,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example
@@ -589,7 +593,7 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo.editors.spring;
@@ -607,7 +611,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.foo.editors.spring
@@ -657,7 +661,7 @@ example uses a `PropertyEditorRegistrar` in the implementation of an `@InitBinde
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes"]
----
@Controller
public class RegisterUserController {
@@ -679,7 +683,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Controller
class RegisterUserController(

Some files were not shown because too many files have changed in this diff Show More