Compare commits

...

431 Commits

Author SHA1 Message Date
Stéphane Nicoll 9b59345547 Release v6.1.11 2024-07-11 09:40:59 +02:00
rstoyanchev 611d3e5551 Correct type names in docs on Validation in WebFlux
Closes gh-33061
2024-07-10 17:55:19 +01:00
Sam Brannen fa2a58b9db Ensure varargs component type for MethodHandle is not null in SpEL
This commit ensures that the varargs component type for a MethodHandle
cannot be null in ReflectionHelper's
convertAllMethodHandleArguments(...) method in SpEL.

Closes gh-33193
2024-07-10 16:46:47 +02:00
Sam Brannen 83ca2c0cff Support MethodHandle function invocation with varargs array in SpEL
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with an array containing the
variable arguments, although that is supported for a varargs Method
function. Attempting to do so resulted in the array being supplied as a
single argument to the MethodHandle.

This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference as
follows when the user supplies the varargs already packaged in an array.

- Creates a new array large enough to hold the non-varargs arguments
  and the unpackaged varargs arguments.

- Adds the non-varargs arguments to the beginning of that array and
  adds the unpackaged varargs arguments to the end of that array.

- Invokes the MethodHandle with the new arguments array.

Closes gh-33191
2024-07-10 16:16:41 +02:00
Sam Brannen dc16f3cffb Polish SpEL function invocation support 2024-07-10 16:16:41 +02:00
Juergen Hoeller f2b3263fff Polishing 2024-07-10 15:56:56 +02:00
Simon Baslé 1d890a8952 Make coroutines with custom AOP aspects work with @Transactional
Previous to this change, the transactional aspect would supersed the
user-defined AspectJ aspect, shortcircuiting to calling the original
Kotlin suspending function.

This change simplifies the TransactionAspectSupport way of dealing with
transactional coroutines, thanks to the fact that lower level support
for AOP has been introduced in c8169e5c.

Closes gh-33095
2024-07-10 15:35:43 +02:00
Juergen Hoeller 3ccaefe38f Polishing 2024-07-10 15:15:32 +02:00
Juergen Hoeller 300f4585be Update spring.jdbc.getParameterType.ignore note for 6.1.2
See gh-25679
2024-07-10 15:15:26 +02:00
Sam Brannen a0f5c16627 Support MethodHandle function invocation with zero varargs in SpEL
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with zero variable arguments,
even though the variable arguments are not required. Attempting to do
so resulted in a SpelEvaluationException with an
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION message.

This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference so that
it properly checks the required number of arguments for both varargs
and non-varargs MethodHandle invocations.

This commit also improves the error message for varargs invocations
with too few arguments. For example, if the MethodHandle requires at
least 1 argument plus a variable number of additional arguments and 0
arguments were supplied, the error message now states:

"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 1 or more"

Instead of:

"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 2"

Closes gh-33190
2024-07-10 13:39:48 +02:00
Stéphane Nicoll b5a86dec92 Retain previous factory method in case of nested invocation with AOT
This commit harmonizes the invocation of a bean supplier with what
SimpleInstantiationStrategy does. Previously, the current factory method
was set to `null` once the invocation completes. This did not take
into account recursive scenarios where an instance supplier triggers
another instance supplier.

For consistency, the thread local is removed now if we attempt to set
the current method to null. SimpleInstantiationStrategy itself uses
the shortcut to align the code as much as possible.

Closes gh-33180
2024-07-10 12:38:56 +02:00
Sam Brannen c55c64427c Support single String argument for varargs invocations in SpEL
Prior to this commit, the Spring Expression Language (SpEL) incorrectly
split single String arguments by comma for Object... varargs method and
constructor invocations.

This commit addresses this by checking if the single argument type is
already "assignable" to the varargs component type instead of "equal"
to the varargs component type.

Closes gh-33013
2024-07-10 11:51:55 +02:00
Sam Brannen a4fcd301f2 Polish SpEL's ReflectionHelper 2024-07-10 11:19:36 +02:00
Stéphane Nicoll ec4558dc14 Polish 2024-07-10 10:19:50 +02:00
Stéphane Nicoll d6c623be40 Release from GHA
This commit adds a workflow to release the Spring Framework from GitHub
Actions.

Closes gh-33179
2024-07-10 10:11:32 +02:00
Stéphane Nicoll 86da45ba15 Upgrade to Reactor 2023.0.8
Closes gh-33169
2024-07-09 15:52:09 +02:00
Stéphane Nicoll 6a60298024 Upgrade to Micrometer 1.12.8
Closes gh-33168
2024-07-09 14:39:10 +02:00
Sébastien Deleuze f8b448e949 Upgrade to Kotlin Serialization 1.6.3
Closes gh-33175
2024-07-09 14:31:56 +02:00
Sébastien Deleuze 52a0e6f900 Upgrade to Kotlin 1.9.24
Closes gh-33177
2024-07-09 14:31:47 +02:00
Stéphane Nicoll 3d2fb3af3d Add verification tests
In preparation for releasing Spring Framework from GitHub actions, this
commit adds a `verify` workflow that validates that the released bits
are correct by running sample projects against them.

Closes gh-33178
2024-07-09 14:23:44 +02:00
Sébastien Deleuze 4f38079042 Throw proper DecodingException in Kotlin Serialization decoders
Closes gh-33138
2024-07-09 12:05:24 +02:00
rstoyanchev 3008d97f93 Polishing contribution
Closes gh-33150
2024-07-09 06:53:14 +01:00
Sébastien NUSSBAUMER f0c758498b Allow validation of Set method parameters
See gh-33150
2024-07-09 06:53:14 +01:00
Juergen Hoeller bc2deef951 Upgrade to JRuby 9.4.8, Rhino 1.7.15, Moneta 1.4.4, JSONassert 1.5.3 2024-07-08 22:55:54 +02:00
Juergen Hoeller 7322a0d3c5 Upgrade to Groovy 4.0.22, Tomcat 10.1.25, Jetty 12.0.11, Undertow 2.3.14 2024-07-08 19:43:19 +02:00
Juergen Hoeller 7227c30917 Allow tests to pass on Windows JVM (non-UTF-8 default encoding)
See gh-33071
2024-07-08 19:42:28 +02:00
Stéphane Nicoll 7e7f55cb23 Merge pull request #33166 from hunhee98
* pr/33166:
  Polish contribution
  Harmonize phrasing in URI Encoding section

Closes gh-33166
2024-07-08 16:51:51 +02:00
Stéphane Nicoll 84f20cd0a7 Polish contribution
See gh-33166
2024-07-08 16:51:23 +02:00
Hunhee Lee 3d8f1fb00f Harmonize phrasing in URI Encoding section
See gh-33166
2024-07-08 16:51:09 +02:00
Stéphane Nicoll e06115c06f Merge pull request #33156 from
* pr/33156:
  Polish "Implement DefaultErrorResponseBuilder#headers(Consumer)"
  Implement DefaultErrorResponseBuilder#headers(Consumer)

Closes gh-33156
2024-07-08 13:15:29 +02:00
Stéphane Nicoll 69850cad27 Polish "Implement DefaultErrorResponseBuilder#headers(Consumer)"
See gh-33156
2024-07-08 13:11:31 +02:00
Harry Yang bbbc95f773 Implement DefaultErrorResponseBuilder#headers(Consumer)
See gh-33156
2024-07-08 13:09:26 +02:00
Sam Brannen 83f7996c79 Polishing 2024-07-05 19:00:39 +02:00
Stéphane Nicoll 0544dfe090 Enable building against Java 23-ea
This commit updates the CI workflow to build against Java 23-ea as
well, using the temurin distribution. For consistency, we're also
building against Java 22.

Closes gh-32090
2024-07-05 10:00:17 +02:00
Stéphane Nicoll eacfd77d6a Harmonize CI configuration
This commit harmonizes our CI configuration with Spring Boot, in
particular the clever use of reusable custom actions that simplify
the workflow definition quite a bit.

One main difference compared to Spring Boot is that we can now
specify a different distribution for a Java version to test, in
preparation for the support of building against 23-ea

See gh-32090
2024-07-05 09:46:45 +02:00
Sam Brannen 89338c91a9 Stop using using legacy locale data for Date/Time formatting tests
Commit 84714fbae9 introduced usage of the
-Djava.locale.providers=COMPAT command-line argument for javac in order
to allow our JDK 20 builds to pass by using legacy locale data.

That was done to ensure that Date/Time formats using AM/PM produced a
standard space (" ") before the "AM" or "PM" instead of a narrow
non-breaking space (NNBSP "\u202F"), which was introduced in Java 20
due to adoption of Unicode Common Locale Data Repository (CLDR-14032).

This commit removes usage of the -Djava.locale.providers=COMPAT
command-line argument and updates all affected tests to:

- Use an NNBSP before "AM" or "PM" in input text when running on Java 20
  or higher.

- Leniently match against any Unicode space character in formatted
  values containing "AM" or "PM".

See https://jdk.java.net/20/release-notes#JDK-8284840
See https://unicode-org.atlassian.net/browse/CLDR-14032
See gh-30185
Closes gh-33144
2024-07-04 17:03:15 +02:00
Stéphane Nicoll 51641ece72 Polish
See gh-33127
2024-07-04 16:51:10 +02:00
Simon Baslé 06d267f04e Improve WebClientResponseException message in case of 1xx/2xx/3xx status
When a response fails to be completely emitted by the remote (connection
termination during the transmission of the response for example), a
WebClientResponseException can be propagated with a confusing message
which mainly reflects the status code and reason phrase, leading to
messages like "200 OK" in such an exception.

This change improves the situation by appending a hint at the underlying
cause whenever getMessage() is called on a WebClientResponseException
which was created with a non-error status code.

Closes gh-33127
2024-07-04 15:20:46 +02:00
Stéphane Nicoll dfa6b4bd42 Upgrade to Gradle 8.8
Closes gh-33146
2024-07-04 10:23:15 +02:00
Stéphane Nicoll 099a97740e Downgrade Awaitility to 4.2.0
This is required to build against ea builds

Closes gh-33143
2024-07-04 04:20:43 +02:00
Juergen Hoeller daea3f0eae Apply fallback resolution for non-hierarchical URIs such as "file:."
Includes meaningful exception message for file system resolution.

Closes gh-33124
2024-07-03 16:36:18 +02:00
zizare 8974da2a5a Use error handler for reactive cache aspect
This change ensures that the cache error handler is used in case of
future-based or publisher-based asynchronous caching completing with an
exception.

Closes gh-33073
2024-07-02 11:29:53 +02:00
Brian Clozel ab236c7741 Re-enable async dispatches in Observation Filter
Prior to this commit, the fix for gh-32730 disabled the involvment of
the osbervation filter for async dispatches. Instead of relying on ASYNC
dispatches to close the observation for async requests, this is now
using an async listener instead: async dispatches are not guaranteed to
happen once the async request is handled.

This change caused another side-effect: because async dispatches are not
considered anymore by this filter, the observation scope is not
reinstated for async dispatches. For example, `ResponseBodyAdvice`
implementations do not have the observation scope opened during their
execution.

This commit re-enables async dispatches for this filter, but ensures
that observations are not closed during such dispatches as this will be
done by the async listener.

Fixes gh-33091
2024-07-01 11:42:48 +02:00
Juergen Hoeller 61adf2dd25 Formal null safety for exception message through String.valueOf
See gh-33117
2024-06-28 18:09:39 +02:00
Juergen Hoeller 61894af0bd Expose FactoryBean attribute exception as BeanDefinitionStoreException
Closes gh-33117
2024-06-28 17:55:45 +02:00
rstoyanchev c74666a883 Polishing contribution
Closes gh-33105
2024-06-28 15:32:43 +01:00
vatsal 976b4f3533 Fix return value validation
Fix argument in call to applyReturnValueValidation()
method in MethodValidationInterceptor.java. Method
argument was passed instead of the return value of the
method that was being validated.

See gh-33105
2024-06-28 15:00:11 +01:00
Juergen Hoeller 100da83913 Detect ajc markers in superclasses as well (for weaving check)
Closes gh-33113
2024-06-28 11:36:17 +02:00
Sam Brannen e881c70a93 Upgrade to JUnit 5.10.3 2024-06-27 17:00:43 +02:00
Juergen Hoeller fea237c065 Lazily start and retain HttpClient once resource factory is running
Closes gh-33093
2024-06-27 12:03:10 +02:00
Sam Brannen 8b11ee9ee2 Document that ModelMap is not a supported argument type in WebFlux
Prior to this commit, the "Method Arguments" documentation for WebFlux
in the reference manual stated that WebFlux controller methods can
accept arguments of type Map, Model, or ModelMap to access the model.
However, ModelMap is actually not supported and results in exception
due to a type mismatch.

This commit updates the documentation to reflect this.

In addition, this commit updates related Javadoc and tests to avoid
mentioning or using ModelMap in WebFlux.

Closes gh-33107
2024-06-27 11:33:50 +02:00
Sam Brannen 1cf5264163 Polishing 2024-06-27 10:46:00 +02:00
Sam Brannen c68c6faa03 Fix comment in Method Injection example in reference manual
Prior to this commit, the comment in the XML configuration example in
the Method Injection section of the reference manual referred to the
wrong bean names.

Closes gh-33096
2024-06-26 16:45:06 +02:00
Brian Clozel 6dd5c85ed0 Support byte array payloads in ProtobufMessageConverter
Prior to this commit, the `ProtobufMessageConverter` used in messaging
would try and serialize the message payload by calling "toString()" on
it in order to pass it to the Protobuf JSON encoder.
While this works for `String` payloads, this fails for `byte[]` types.

This commit ensures that such `byte[]` are first converted to `String`
instances using the given charset first.

Fixes gh-27408
2024-06-25 21:16:50 +02:00
Sam Brannen d133ab60ee Improve documentation regarding encoding in FreeMarker support
This commit also introduces integration tests to test the status quo
regarding encoding.

Closes gh-33071
2024-06-25 16:56:48 +02:00
Sam Brannen 5d6e143ff4 Remove invalid configuration in RequestMappingViewResolutionIntegrationTests
Prior to this commit, RequestMappingViewResolutionIntegrationTests
invoked the following:

configurer.setTemplateLoaderPath(
	"classpath*:org/springframework/web/reactive/view/freemarker/");

However, that configuration is invalid since `classpath*:` is not
supported for a `templateLoaderPath`.

Despite that, the tests still passed since FreeMarkerConfigurer already
registers a new ClassTemplateLoader(FreeMarkerConfigurer.class, ""),
which automatically finds template files in the same package as
FreeMarkerConfigurer (for the "spring.ftl" macro library support) and
coincidentally RequestMappingViewResolutionIntegrationTests as well
(which resides in the same package).

This commit therefore removes the invalid configuration and adds a
comment to explain what's going on.
2024-06-25 16:56:21 +02:00
Juergen Hoeller 4e2fb308f6 Document contentLength() behavior for InputStreamResource and custom subclasses
Closes gh-33089
2024-06-24 12:10:35 +02:00
Sam Brannen 5f765fc8ce Polishing 2024-06-23 13:22:08 +02:00
Sam Brannen 6b456b6157 Upgrade to FreeMarker 2.3.33 2024-06-22 16:55:56 +02:00
Sam Brannen 000b563e83 Use consistent formatting for view name in AbstractView 2024-06-22 16:51:37 +02:00
Sam Brannen c571ee1f95 Fix typo in comment 2024-06-22 16:51:28 +02:00
Stéphane Nicoll 899f6308d9 Fix name of GitHub actions bot
See gh-gh-33076
2024-06-21 14:14:05 +02:00
Juergen Hoeller a580d6d6fc Leniently ignore type mismatch for LoadTimeWeaverAware beans
Closes gh-33082
2024-06-21 11:22:48 +02:00
Juergen Hoeller 66eddf99af Include original exception if cause is null
Closes gh-33080
See gh-32952
2024-06-20 18:56:43 +02:00
Stéphane Nicoll e94ec80df4 Exclude GitHub Actions bot from changelog
Closes gh-33076
2024-06-20 14:15:54 +02:00
Juergen Hoeller 2861e570fd Catch and log LinkageError in getTypeForFactoryMethod
Closes gh-33075
2024-06-20 13:47:43 +02:00
Spring Builds ee7a1e8b7e Next development version (v6.1.11-SNAPSHOT) 2024-06-19 15:37:10 +00:00
Brian Clozel f7307c9e07 Avoid recording RestClient observations twice
Prior to this commit, the fix for gh-32575 introduced cases where the
client observation would be stopped twice.

This commit ensures that `RestClient` observations are stopped only once
when the response is closed, or before throwing an unhanlded exception.

Fixes gh-33068
2024-06-19 12:46:21 +02:00
Brian Clozel 098c4b1dd7 Use Sonatype S01 token in release pipeline 2024-06-18 19:25:20 +02:00
Juergen Hoeller 65dbfd09b4 Defensive PersistenceExceptionTranslator bean retrieval on shutdown
Closes gh-33067
2024-06-18 18:31:15 +02:00
Sam Brannen 203fa75196 Support all "connection reset" phrases in DisconnectedClientHelper
Prior to this commit, the isClientDisconnectedException() method in
DisconnectedClientHelper checked whether the message of the ultimate
exception in an exception chain contained one of the phrases "broken
pipe" or "connection reset by peer". However, that failed to match if
the exception message contained "Connection reset", which is the case
for the SocketException thrown by throwConnectionReset() in
sun.nio.ch.SocketChannelImpl.

This commit therefore replaces the "connection reset by peer" phrase
with "connection reset" in order to support all exception messages
containing "connection reset".

Closes gh-33064
2024-06-18 16:43:06 +02:00
Juergen Hoeller 9a56a8877f Polishing 2024-06-17 18:42:37 +02:00
Juergen Hoeller e79a9a5bff Correct and consistent event class names in constructor javadoc
Closes gh-33032
2024-06-17 18:42:30 +02:00
Juergen Hoeller 2c3c3831c1 Consistently ignore bridge method on generated subclass for visibility purposes
Closes gh-33030
2024-06-17 18:42:20 +02:00
Arjen Poutsma c38e9896c7 Remove use of ServletException in ModelFactory
This commit changes the use of HttpSessionRequiredException in
ModelFactory::initModel to an IllegalStateException, because the former
extends ServletException and cannot be used in WebFlux.

Closes gh-33043
2024-06-17 14:19:19 +02:00
Stéphane Nicoll 3e0849a566 Fix typo
Closes gh-33050
2024-06-17 13:39:18 +02:00
github-actions[bot] f3a605b92c Update Antora Spring UI to v0.4.16 2024-06-17 10:06:47 +00:00
Stéphane Nicoll 6fdff201e9 Fix property name in Container Extension Points section
Closes gh-33037
2024-06-16 16:47:36 +02:00
Stéphane Nicoll c42778a05b Merge pull request #33036 from tafjwr
* pr/33036:
  Polish "Fix typo in comment"
  Fix typo in comment

Closes gh-33036
2024-06-16 09:59:15 +02:00
Stéphane Nicoll f140df881d Polish "Fix typo in comment"
See gh-33036
2024-06-16 09:57:24 +02:00
tafjwr 12cf654c98 Fix typo in comment
See gh-33036
2024-06-16 09:56:58 +02:00
Juergen Hoeller 089e4e69f1 Do not attempt to load pre-enhanced class for reloadable classes
Closes gh-33024
2024-06-14 22:07:46 +02:00
Stéphane Nicoll 77755ff2fa Remove repo-specific code of conduct
This will allow us to inherit the org's CoC instead.

Closes gh-33031
2024-06-14 18:58:49 +02:00
Stéphane Nicoll d0aa7ad524 Fix invalid character in Javadoc of BeanFactory 2024-06-13 14:06:19 +02:00
Spring Builds 072fc80cdb Next development version (v6.1.10-SNAPSHOT) 2024-06-13 10:27:57 +00:00
Arjen Poutsma 6f32ff489a Use null stream in ReactorNettyClientResponse if no body is available
Closes gh-32805
2024-06-13 11:10:50 +02:00
Juergen Hoeller 24c8dfea1f Remove duplicated javadoc paragraph 2024-06-12 14:23:26 +02:00
Juergen Hoeller cdfe5816c8 Upgrade to Netty 4.1.111 and Awaitility 4.2.1 2024-06-12 14:23:14 +02:00
Juergen Hoeller 0ff200b2f1 Trigger cancellation on context close for non-managed objects only
Specifically for prototype/scoped beans and FactoryBean-exposed objects.

Closes gh-33009
2024-06-12 13:31:00 +02:00
Stéphane Nicoll 261dac87cc Upgrade to Reactor 2023.0.7
Closes gh-33007
2024-06-11 14:42:08 +02:00
Juergen Hoeller fce2f49e46 Polishing (aligned with main) 2024-06-11 09:07:09 +02:00
Juergen Hoeller eca2b9657e Documentation notes for @Bean overriding and bean name matching
Closes gh-32825
2024-06-11 09:06:33 +02:00
Juergen Hoeller e48f37d956 Upgrade to Micrometer 1.12.7
Closes gh-33001
2024-06-11 09:05:48 +02:00
Juergen Hoeller ddc397dd05 Upgrade to spring-javaformat-checkstyle 0.0.42 2024-06-11 09:04:30 +02:00
Stéphane Nicoll 6b7f0bd4b6 Fix typo 2024-06-11 06:47:42 +02:00
Sébastien Deleuze c97a895f09 Add support for double backslashes to StringUtils#cleanPath
Closes gh-32962
2024-06-10 22:25:31 +02:00
rstoyanchev 3b13f2ed38 Update code-of-conduct email 2024-06-10 10:48:06 +01:00
Stéphane Nicoll a0eebca0cf Merge pull request #32993 from hlmg
* pr/32993:
  Fix typo

Closes gh-32993
2024-06-10 10:02:36 +02:00
hlmg c6c64e6fe7 Fix typo
See gh-32993
2024-06-10 10:00:37 +02:00
Brian Clozel 0ca393c0dc Restrict memory allocation in ContentCachingRequestWrapper
Prior to this commit, the `ContentCachingRequestWrapper` could allocate
a `FastByteArrayOutputStream` block that was larger than the content
cache limit given as a consturctor argument. This was due to an
optimization applied in gh-31834 for allocating the right content cache
size when the request size is known.

Fixes gh-32987
2024-06-10 09:46:01 +02:00
Brian Clozel 6681394886 Stop observations for async requests in Servlet filter
Prior to this commit, the `ServerHttpObservationFilter` would support
async dispatches and would do the following:

1. start the observation
2. call the filter chain
3. if async has started, do nothing
4. if not in async mode, stop the observation

This behavior would effectively rely on Async implementations to
complete and dispatch the request back to the container for an async
dispatch. This is what Spring web frameworks do and guarantee.

Some implementations complete the async request but do not dispatch
back; as a result, observations could leak as they are never stopped.

This commit changes the support of async requests. The filter now
opts-out of async dispatches - the filter will not be called for those
anymore. Instead, if the application started async mode during the
initial container dispatch, the filter will register an AsyncListener to
be notified of the outcome of the async handling.

Fixes gh-32730
2024-06-07 19:01:57 +02:00
Sébastien Deleuze 172987c874 Ignore checkpointOnRefresh after restore
Closes gh-32978
2024-06-07 18:41:37 +02:00
Thomas Deblock 47a5ebfde6 Support canEncode() for JAXBElement in Jaxb2XmlEncoder
Commit d7970e4ab8 introduced support for JAXBElement in
Jaxb2XmlEncoder's encodeValue() method; however, canEncode() still
returned false for a JAXBElement element type.

This commit revises canEncode() so that it returns true for an element
type that is assignable from JAXBElement.

See gh-30552
See gh-32972
Closes gh-32977
2024-06-07 14:13:59 +02:00
Sébastien Deleuze 43a113f067 Polishing
See gh-32983
2024-06-07 13:45:09 +02:00
Sébastien Deleuze dc250e1cc1 Remove outdated copyright from index.adoc
Closes gh-32983
2024-06-07 13:35:21 +02:00
Sébastien Deleuze fe74fcfded Exclude node_modules from NoHttp checks
Closes gh-32980
2024-06-07 11:43:45 +02:00
Juergen Hoeller 2451bd62b0 Polishing 2024-06-06 20:43:31 +02:00
Juergen Hoeller 624d6dd167 Expose actual result value for @CacheEvict condition
Closes gh-32960
2024-06-06 20:43:04 +02:00
Juergen Hoeller 0ea96b4806 Skip ajc-compiled aspects for ajc-compiled target classes
Includes defensive ignoring of incompatible aspect types.

Closes gh-32970
2024-06-06 20:42:07 +02:00
Sébastien Deleuze c28a0d5627 Add missing hints for Hibernate @TenantId
Closes gh-32967
2024-06-06 10:04:35 +02:00
Juergen Hoeller 61d045ce52 Polishing 2024-06-06 08:54:37 +02:00
Juergen Hoeller c0bef2c693 Lazily start resources on demand (if necessary outside of lifecycle)
See gh-32945
2024-06-06 08:54:32 +02:00
Stéphane Nicoll c3a0eaa95e Merge pull request #32966 from ypyf
* pr/32966:
  Use HttpStatusCode consistently in reference guide

Closes gh-32966
2024-06-06 08:08:45 +02:00
ypyf e12d1259d1 Use HttpStatusCode consistently in reference guide
See gh-32966
2024-06-06 08:06:33 +02:00
Brian Clozel 404c4d9d92 Support @Valid on container elements for handler arguments
Prior to this commit, #31870 added support for constraint annotations on
container elements for handler method argument validation. Supporting
this use case:

```
public void addNames(List<@NotEmpty String> names)
```

This commit does the same for `@Valid` annotation:

```
public void addPeople(List<@Valid Person> people)
```

Fixes gh-32964
2024-06-05 20:02:46 +02:00
Juergen Hoeller 7785f94c4c Revise and align Reactor client lifecycle management
Closes gh-32945
2024-06-05 16:32:40 +02:00
Juergen Hoeller 4f6f2c0d41 Revert to separate get/put steps against method cache for concurrency
Closes gh-32958
2024-06-05 16:32:27 +02:00
Stéphane Nicoll e6da2a86fc Merge pull request #32957 from soglad
* pr/32957:
  Fix entity name in MappingSqlQuery example of reference guide

Closes gh-32957
2024-06-05 10:45:01 +02:00
Tony Wen 301087e510 Fix entity name in MappingSqlQuery example of reference guide
See gh-32957
2024-06-05 10:43:14 +02:00
Juergen Hoeller 6c054f88ea Defensively handle UncheckedIOException cause (for NullAway compliance) 2024-06-05 00:01:52 +02:00
Juergen Hoeller f58c7d80cc Upgrade to SLF4J 2.0.13, Jetty 12.0.10, Netty 4.1.110, JRuby 9.4.7 2024-06-04 23:44:54 +02:00
Juergen Hoeller e5be10d53d Consistently throw IOException from ReactorNettyClientResponse
Aligned with ReactorNettyClientRequest.

See gh-32952
2024-06-04 23:43:10 +02:00
Juergen Hoeller 524da905db Consistently throw IOException from ReactorNettyClientRequest
This commit renames ReactorNettyClientRequestFactoryTests.

Closes gh-32952
2024-06-04 22:59:29 +02:00
Juergen Hoeller 4323c60513 Common context lifecycle management for ReactorResourceFactory
This commit moves ReactorResourceFactoryTests to same package.

Closes gh-32945
2024-06-04 22:59:18 +02:00
Sébastien Deleuze f6b608eecb Consistently support Hibernate annotation hint inference on methods
See gh-32842
2024-06-04 16:46:25 +02:00
Sébastien Deleuze 4da1511ed3 Infer hints for Hibernate generators
This commit updates
PersistenceManagedTypesBeanRegistrationAotProcessor
in order to infer hints for Hibernate annotations meta
annotated with `@ValueGenerationType` (like `@CreationTimestamp`)
and `@IdGeneratorType`.

`@GenericGenerator` is not supported as it is deprecated as of
Hibernate 6.5.

Closes gh-32842
2024-06-04 16:46:25 +02:00
Stéphane Nicoll 7102c33661 Add section about using complex data structures with AOT
Closes gh-32273
2024-06-04 15:51:40 +02:00
Sébastien Deleuze 43409b00d0 Refine KotlinDetector.isKotlinType documentation
This commit documents changes in lambda detection
as of Kotlin 2.0.

Closes gh-32905
2024-06-03 18:58:13 +02:00
Sébastien Deleuze d55abc6cf9 Fix RegisterReflectionForBinding Javadoc
Closes gh-32947
2024-06-03 18:26:24 +02:00
Sébastien Deleuze 31806f3a6b Fix MethodValidationPostProcessor refdoc
Closes gh-32929
2024-06-03 18:20:52 +02:00
Juergen Hoeller 8a84241c1e Polishing 2024-06-03 12:46:31 +02:00
Juergen Hoeller 624be6d4e6 Report bean creation failure in sortAdvisors as AopConfigException
Closes gh-32230
2024-06-03 12:46:14 +02:00
Juergen Hoeller b08883b65c Avoid NoSuchMethodException for annotation attribute checks
Closes gh-32921
2024-06-03 12:45:11 +02:00
Cong-Xin Cynthia Qiu 542ba3517f Fix typo in Jakarta validation documentation
Closes gh-32928
2024-05-31 12:22:02 +02:00
Juergen Hoeller 8c6a7799be Upgrade to Checkstyle 10.17 2024-05-28 18:46:22 +02:00
Juergen Hoeller 557dbba585 Remove superfluous addToClassHierarchy call for Enum types
Closes gh-32906
2024-05-28 18:45:05 +02:00
Sam Brannen e9de426eb5 Support compilation of map indexing with primitive in SpEL
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into a Map using a primitive literal
(boolean, int, long, float, or double).

This commit adds support for compilation of such expressions by
ensuring that primitive literals are boxed into their corresponding
wrapper types in the compiled bytecode.

Closes gh-32903
2024-05-28 10:19:15 +02:00
Sam Brannen cda577d1aa 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.

See gh-32694
Closes gh-32908
2024-05-27 17:06:48 +02:00
Sam Brannen 8feb842df5 Upgrade to AssertJ 3.26.0
See https://github.com/assertj/assertj/issues/3322
2024-05-27 16:43:22 +02:00
Sam Brannen ea2931f24a Use Develocity Gradle plugin API to avoid deprecation warning
Prior to this commit, the Gradle build issued the following warning.

- The deprecated "gradleEnterprise.buildScan.value" API has been
  replaced by "develocity.buildScan.value"
2024-05-24 15:41:58 +02:00
Juergen Hoeller 26d1c38d84 Polishing 2024-05-24 13:05:49 +02:00
Juergen Hoeller 345daaabbc Detect original generic method for CGLIB bridge method
Closes gh-32888
2024-05-24 11:49:10 +02:00
Juergen Hoeller 6c08d93992 Polishing 2024-05-23 17:07:55 +02:00
Juergen Hoeller 6d7cd9c7dc Defensive handling of incompatible advice methods
This covers AspectJ transaction and caching aspects when encountered by Spring AOP.

Closes gh-32882
See gh-32793
2024-05-23 17:07:51 +02:00
Attacktive 73eb6f0660 Complete a Kotlin code snippet in the refdoc
Closes gh-32877
2024-05-23 16:03:34 +02:00
Stéphane Nicoll 31f298b929 Merge pull request #32874 from Seungpang
* pr/32874:
  Polish
  Document using ThreadLocal#remove instead of ThreadLocal#set(null)

Closes gh-32874
2024-05-23 08:14:00 +02:00
Stéphane Nicoll c01aab5850 Polish
See gh-32874
2024-05-23 08:12:30 +02:00
Seungrae 61ef5a8930 Document using ThreadLocal#remove instead of ThreadLocal#set(null)
See gh-32874
2024-05-23 08:10:54 +02:00
Spring Builds 3b53ee7038 Next development version (v6.1.9-SNAPSHOT) 2024-05-22 16:45:49 +00:00
rstoyanchev 89dd247b97 Improve docs on controller method validation
Closes gh-32807
2024-05-22 17:15:54 +01:00
Stéphane Nicoll 39dd1e4049 Remove outdated Javadoc links
Closes gh-32872
2024-05-22 14:40:25 +02:00
Rob Winch 34f4ad3b71 Modernize Antora Build
- Use same playbook as docs-build
- Use Env Variables to cause partial build (same as docs-build)
- Use package.json so that dependencies can be updated with dependabot
2024-05-22 10:20:20 +02:00
Juergen Hoeller ea596aa211 Select most specific advice method in case of override
Closes gh-32865
2024-05-22 10:00:31 +02:00
Juergen Hoeller 58da30cd30 Upgrade to Jetty Reactive HttpClient 4.0.4 2024-05-21 19:22:20 +02:00
Juergen Hoeller cd33b4e35a Polishing 2024-05-21 18:25:57 +02:00
Juergen Hoeller 20dea0dae2 Polishing 2024-05-21 17:39:11 +02:00
Juergen Hoeller fee17e11ba Default fallback parsing for UTC without milliseconds
Closes gh-32856
2024-05-21 17:39:06 +02:00
Juergen Hoeller 65e1337d35 Polishing 2024-05-21 11:16:25 +02:00
Juergen Hoeller a4c2f291d9 Avoid creation of SAXParserFactory for every read operation
Includes JAXBContext locking revision (avoiding synchronization) and consistent treatment of DocumentBuilderFactory (in terms of caching as well as locking).

Closes gh-32851
2024-05-21 11:16:19 +02:00
Stéphane Nicoll f26483d272 Detect deprecated element in generic types
This commit updates Spring AOT to suppress a deprecation warning for
a generic type that has a deprecated element. Previously we only were
checking for the raw class.

Closes gh-32850
2024-05-21 08:53:18 +02:00
Stéphane Nicoll 481d036f7a 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:58:36 +02:00
Sébastien Deleuze 2a2ef443a5 Refine CDS documentation
Closes gh-32843
2024-05-20 10:24:29 +02:00
Juergen Hoeller 617833bec9 Defensively catch and log pointcut parsing exceptions
Closes gh-32838
See gh-32793
2024-05-17 12:27:59 +02:00
Spring Builds 4d633c2ea8 Next development version (v6.1.8-SNAPSHOT) 2024-05-16 09:04:43 +00:00
rstoyanchev 010e8a303b Polishing contribution
Closes gh-32799
2024-05-15 20:06:48 +01:00
Matteo Cristoforo 78549d4963 Fix cookie management in reactive JdkClientHttpRequest
Prevent cookies to be set to empty in the HTTP request if no cookie
is present

See gh-32799
2024-05-15 20:02:04 +01:00
Juergen Hoeller e4e6910122 Polishing 2024-05-15 14:15:52 +02:00
Juergen Hoeller 2270df515b Enforce cleaned URL for root resource from ClassLoader
Closes gh-32828
2024-05-15 14:15:47 +02:00
Juergen Hoeller 70886e32c0 Upgrade to Reactor 2023.0.6
Includes AspectJ 1.9.22.1, Tomcat 10.1.24, Jetty 12.0.9, Mockito 5.12

Closes gh-32786
2024-05-14 22:01:07 +02:00
Juergen Hoeller e509385eae Add InputStreamResource(InputStreamSource) constructor for lambda expressions
Includes notes for reliable InputStream closing, in particular with Spring MVC.

Closes gh-32802
2024-05-14 21:59:42 +02:00
Juergen Hoeller b7aafda872 Polishing 2024-05-14 13:43:35 +02:00
Brian Clozel a89a88d17c Upgrade to Micrometer 1.12.6
Closes gh-32810
2024-05-13 21:25:09 +02:00
Brian Clozel c6b6ccdc89 Close ResponseBodyEmitter in case of write errors
Prior to this commit, the `ReactiveTypeHandler` would handle `Flux`-like
return types from controller methods and adapt them to SSE streams using
the `SseEmitter`/`ResponseBodyEmitter` APIs. In case an `IOException` is
thrown while writing to the HTTP response stream, the
`ReactiveTypeHandler` would rely on the Servlet container to call
`AsyncListener#onError` - this would be the signal for Spring MVC to
complete the async exchange. To prevent racing issues between this
signal and the actual handling of the exception, changes like  gh-20173
were applied. Since then, robust checks were added with gh-32340 in
`StandardServletAsyncWebRequest.LifecycleHttpServletResponse`.

With Jetty 12, `AsyncListener#onError` would not be called as the error
would happen while writing in blocking mode to the response (so, not
using the Servlet WriteListener contract). But still, such `IOException`
would still result in the closing of the HTTP connection. As of Jetty
12.0.4, this is no longer the case and the party managing the async
lifecycle is in charge of completing the exchange, as it should. This
means that the current behavior leaks HTTP connections for these cases
and causes memory issues.

This commit ensures that such exceptions happening during response
writes are caught and result in the completion of the `SSEEmitter` and
the closing of the exchange. Even if other Servlet containers still
propagate the error `AsyncListener#onError`, competing signals are still
managed with gh-32340.

Closes gh-32629
2024-05-13 20:30:13 +02:00
Brian Clozel 09b8feadc2 Document streaming/collecting behavior for Flux return values
Closes gh-32630
2024-05-13 13:12:53 +02:00
rstoyanchev d03ea0bf19 Update docs on HandlerInterceptor
Closes gh-32729
2024-05-13 11:40:32 +01:00
rstoyanchev a5a1ef6b30 Use instance field for ProblemDetail in ErrorResponse's
Closes gh-32644
2024-05-13 11:40:32 +01:00
rstoyanchev 1b60b86bb2 Update MockMvc section on Streaming in the docs
Closes gh-32687
2024-05-13 11:40:32 +01:00
Brian Clozel 89ce63f1f3 Replace RFC7807 by RFC9457 in documentation
This commit updates all references to RFC7807 by RFC9457 since the
former is now obsolete.

Closes gh-32806
2024-05-13 10:42:35 +02:00
Sam Brannen 7536980be9 Fix Dokka links to Spring Framework and Servlet APIs
This commit fixes links from Spring Framework's Dokka HTML to Javadoc
for Spring Framework and Servlet APIs by explicitly configuring the
`element-list` page as the `package-list` in the Dokka Gradle plugin.

Closes gh-32797
2024-05-12 12:29:52 +02:00
Sam Brannen c1229b03a7 Polishing 2024-05-11 16:01:08 +02:00
Juergen Hoeller a4135bac5c Leniently ignore unsupported pointcut expression
See gh-32793
2024-05-10 13:52:39 +02:00
Juergen Hoeller bf08e0c1b4 Polishing 2024-05-10 12:27:29 +02:00
Juergen Hoeller 9202c0ad41 Accept ajc-compiled @Aspect classes for Spring AOP proxy usage
Closes gh-32793
2024-05-10 12:27:12 +02:00
Juergen Hoeller 22b6d66a28 Document @Order behavior on @Configuration classes versus @Bean methods
Includes brief note on self injection (extracted from qualifiers section).

Closes gh-30177
Closes gh-28299
2024-05-08 17:52:02 +02:00
Juergen Hoeller 9376e6322d Revise IoC container introduction for modern configuration styles
Includes @Configuration(proxyBeanMethods=false) documentation.

Closes gh-32429
2024-05-08 17:51:25 +02:00
Juergen Hoeller 0eb937a866 Document limitations of CGLIB proxy class generation in JPMS module setups
Includes extended exception messages with common hints and explanations.

Closes gh-32671
2024-05-08 17:51:17 +02:00
Stéphane Nicoll 6250b64766 Add support for form data in MockHttpServletRequestBuilder
Closes gh-32757
2024-05-08 11:56:16 +02:00
Stéphane Nicoll 5b1278d03c Refine exception message to include bean name
Closes gh-32775
2024-05-08 10:27:34 +02:00
Juergen Hoeller 4f02be263f Polishing 2024-05-07 15:52:13 +02:00
Juergen Hoeller 05d9b52b19 Polishing 2024-05-06 20:10:40 +02:00
Juergen Hoeller 59a125d06f Unwrap raw target Query instance in case of proxy mismatch
Closes gh-32766
2024-05-06 20:09:43 +02:00
Sam Brannen aebc48ee8d Revise contribution
See gh-32704
2024-05-03 17:04:11 +03:00
Mikaël Francoeur f51be0a17e Support varargs invocations in SpEL for varargs array subtype
Closes gh-32704
2024-05-03 17:04:11 +03:00
Sam Brannen 1d2b5a15c3 Polishing 2024-05-03 17:04:11 +03:00
Sam Brannen 4baad16437 Include repeatable annotation container in MergedAnnotations results
A bug has existed in Spring's MergedAnnotations support since it was
introduced in Spring Framework 5.2. Specifically, if the
MergedAnnotations API is used to search for annotations with "standard
repeatable annotation" support enabled (which is the default), it's
possible to search for a repeatable annotation but not for the
repeatable annotation's container annotation.

The reason is that MergedAnnotationFinder.process(Object, int, Object,
Annotation) does not process the container annotation and instead only
processes the "contained" annotations, which prevents a container
annotation from being included in search results.

In #29685, we fixed a bug that prevented the MergedAnnotations support
from recognizing an annotation as a container if the container
annotation declares attributes other than the required `value`
attribute. As a consequence of that bug fix, since Spring Framework
5.3.25, the MergedAnnotations infrastructure considers such an
annotation a container, and due to the aforementioned bug the container
is no longer processed, which results in a regression in behavior for
annotation searches for such a container annotation.

This commit addresses the original bug as well as the regression by
processing container annotations in addition to the contained
repeatable annotations.

See gh-29685
Closes gh-32731
2024-05-03 12:18:04 +03:00
Stéphane Nicoll abcc1dfc6c Review usage of BindingReflectionHintsRegistrar#registerReflectionHints
Closes gh-32753
2024-05-02 16:53:59 +02:00
Brian Clozel 47c5cd208c Add missing "Content-Length: 0" header with HttpComponents
Prior to this commit, HTTP requests sent with the
`HttpComponentsClientHttpRequestFactory` would not set a
"Content-Length" header for empty request bodies. Setting a request
entity is the expected behavior for unsafe HTTP methods, and this would
align the behavior with other HTTP clients.
Developers would often rely on `BufferingClientHttpRequestFactory` to
set this information on the request.

This commit ensures that a `NullEntity` is used for unsafe HTTP methods,
when no body has been set for the request. This result in a
"Content-Length:0" request header.

Fixes gh-32678
2024-05-02 15:42:35 +02:00
Sam Brannen 5a24e94d2e Polish tests 2024-05-02 13:28:48 +03:00
Stéphane Nicoll f90bdbef42 Add noop implementation for ResponseErrorHandler
Closes gh-32750
2024-05-02 11:44:42 +02:00
Sébastien Deleuze f17527a48b Use expectBody<Person>() in WebTestClient documentation
Closes gh-32733
2024-05-02 11:07:36 +02:00
Brian Clozel 64b0283042 Revert "Do not set 0 Content-Length header in BufferingClientHttpRequestFactory"
This reverts commit b3a45670f9.

See gh-32650
2024-05-02 09:11:54 +02:00
Juergen Hoeller 25cedcfb99 Consistently propagate ApplicationStartup to BeanFactory
Closes gh-32747
2024-05-01 18:06:27 +02:00
Juergen Hoeller 610626aec6 Ignore non-String keys in PropertiesPropertySource.getPropertyNames()
Closes gh-32742
2024-05-01 15:41:26 +02:00
Brian Clozel d8afe7a8ad Fix build warnings
See gh-32724
2024-04-30 19:10:31 +02:00
Seungrae Kim 32c80d5ae6 Fix incorrect class reference syntax in Kotlin code sample
Closes gh-32733
2024-04-30 18:09:02 +03:00
Arjen Poutsma 0241a02e66 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:07:03 +02:00
Juergen Hoeller cbda46984c Polishing 2024-04-30 15:46:28 +02:00
Juergen Hoeller 7263771552 Add documentation for CompletableFuture-driven rollback
Closes gh-32709
2024-04-30 15:45:56 +02:00
Juergen Hoeller fab3633c75 Add notes on constructor and factory method overloading
Closes gh-32091
2024-04-30 15:45:46 +02:00
Juergen Hoeller 26706f0039 Upgrade to Groovy 4.0.21, Tomcat 10.1.23, Jetty 12.0.8, Netty 4.1.109, Undertow 2.3.13, Checkstyle 10.16 2024-04-29 18:04:25 +02:00
Juergen Hoeller 3cf2cd70ab Polishing 2024-04-29 18:02:44 +02:00
Juergen Hoeller 0ac04a7f86 Include original exception message in dependency initialization exception
Closes gh-32470
2024-04-29 18:02:39 +02:00
Brian Clozel 370a4ee8b3 Upgrade to gradle-enterprise-conventions 0.0.17
Closes gh-32724
2024-04-29 13:15:05 +02:00
Simon Baslé 55361fa4f6 Release RSocket setup payload when it is not handled
This commit counterbalances the retain in the MessagingRSocket
handleConnectionSetupPayload method with a conditional release on SETUP
frame type in handleNoMatch, preventing Netty buffer leaks.

Closes gh-32424
2024-04-25 10:09:05 +02:00
Sam Brannen 546ca9b834 Polishing 2024-04-24 15:32:57 +03:00
Juergen Hoeller 09b476ac18 Polishing 2024-04-24 13:42:02 +02:00
Juergen Hoeller 387e34d881 Wrap depends-on exception for specifically requested top-level bean
Closes gh-32470
2024-04-24 13:41:48 +02:00
Stéphane Nicoll 4a10bc3288 Refine preDetermineBeanTypes algorithm
This commit refines the preDetermineBeanTypes algorithm that AOT uses
to approximate the order of preInstantiateSingletons more closely.

Previously, the algorithm assumed that all beans where non-lazy
singletons in terms of initialization order, which led to inconsistent
order in CGLIB proxy generation.

We now explicitly park lazy beans so that their types are determined
during a second phase, matching the order of regular initialization
order.

Closes gh-32669

Co-authored-by: Juergen Hoeller <juergen.hoeller@broadcom.com>
2024-04-24 09:23:51 +02:00
Juergen Hoeller 580adfcbed Polishing 2024-04-23 16:07:09 +02:00
Juergen Hoeller d151931f86 Skip close lock if acquired by other thread already
Closes gh-32445
2024-04-23 16:06:48 +02:00
Stéphane Nicoll 16d8d69cf9 Merge pull request #32696 from izeye
* pr/32696:
  Update copyright year of changed files
  Polish

Closes gh-32696
2024-04-23 15:34:44 +02:00
Stéphane Nicoll 95ac0eae4a Update copyright year of changed files
See gh-32696
2024-04-23 15:32:59 +02:00
Johnny Lim cc73ccefef Polish
See gh-32696
2024-04-23 15:31:48 +02:00
Stéphane Nicoll 4d34444a69 Consistent annotation lookup in MvcUriComponentsBuilder
Previously, a UriComponents build based on a method would require the
given method to be the annotated one as method parameter resolution only
applied locally. This was a problem when a controller was specified on
a method whose mapping is defined in a parent.

This commit harmonies the lookup using AnnotatedMethod who provides
support for a synthesized method parameter that takes annotations from
parent parameter into account.

Closes gh-32553
2024-04-23 15:21:27 +02:00
Juergen Hoeller d4ddbd537b Polishing 2024-04-23 13:16:33 +02:00
Juergen Hoeller 0b9b9b4602 Avoid overreading of InputStream in copyRange
Closes gh-32695
2024-04-23 13:16:28 +02:00
Stéphane Nicoll 40596d444c Provide a more explicit link to URI composition examples
Closes gh-32685
2024-04-23 12:43:15 +02:00
Stéphane Nicoll cb5b9dcaed Document AOT limitation of creating beans with custom arguments
Closes gh-32690
2024-04-23 11:03:28 +02:00
Stéphane Nicoll c99e7f8616 Ignore InstanceSupplier for getBean with arguments
Previously, a BeanDefinition that has an instance supplier would be
used irrespective of custom arguments being provided. This commit only
applies the instance supplier if no arguments are provided. With
custom arguments, the regular lookup takes place based on the
information provided in the bean factory.

Closes gh-32657
2024-04-22 16:59:31 +02:00
Stéphane Nicoll 8a8c8fe00e Detect target of factory method with AOT
Previously, if a factory method is defined on a parent, the generated
code would blindly use the method's declaring class for both the target
of the generated code, and the signature of the method.

This commit improves the resolution by considering the factory metadata
in the BeanDefinition.

Closes gh-32609
2024-04-22 15:13:56 +02:00
Stéphane Nicoll f45e7b9b9b Relax scope of DataIntegrityViolationException
This commit updates the Javadoc of DataIntegrityViolationException to
broaden its scope as it was too specific before.

Closes gh-32631
2024-04-22 14:49:17 +02:00
Juergen Hoeller ec1f5ca600 Polishing 2024-04-22 13:43:07 +02:00
Juergen Hoeller 62efdfb89c Try early initialization for all user-declared methods (including interfaces)
Closes gh-32682
2024-04-22 13:43:02 +02:00
Stéphane Nicoll c3da43291b Upgrade to Java 17.0.11 2024-04-22 12:13:01 +02:00
Brian Clozel 5aa576f5c6 Register status handler exceptions in observations
Prior to this commit, `RestClientException` thrown by status handlers
would not be registered as observation errors. This commit ensures that
such exceptions are first caught, registered in the observation and
rethrown as expected.

Closes gh-32575
2024-04-20 19:44:11 +02:00
Brian Clozel 0268180799 Rethrow unhandled JMS listener exceptions
Fixes gh-32666
2024-04-18 21:44:44 +02:00
Brian Clozel da4547a27e Extend observations to RestClient ResponseSpec
Prior to this commit, the `RestClient` observations would be stopped as
soon as the exchange function was called. This means that all errors
related to response decoding or mapping would not be recorded by the
obsevations.

This commit extends the observation recording to the `ResponseSpec` DSL
calls as well as custom exchange functions.

Fixes gh-32575
2024-04-18 21:26:18 +02:00
rstoyanchev 97eddb769a Avoid duplicate subscriptionId's in destinationCache
Closes gh-32625
2024-04-18 14:18:30 +01:00
Juergen Hoeller 0e0397a385 Polishing 2024-04-18 12:18:18 +02:00
Juergen Hoeller fec4f9b8cb Add test for pre-resolved target type on RootBeanDefinition
See gh-32649
2024-04-18 12:17:17 +02:00
Juergen Hoeller 4e20cdeb43 Expand comment on participation in existing transaction
Closes gh-32659
2024-04-18 12:16:33 +02:00
yhao3 7f27ba3902 Update links to HttpOnly documentation at OWASP in ResponseCookie
Closes gh-32663
2024-04-18 11:52:50 +02:00
Brian Clozel b3a45670f9 Do not set 0 Content-Length header in BufferingClientHttpRequestFactory
Prior to this commit, the `BufferingClientHttpRequestFactory`, through
the `AbstractBufferingClientHttpRequest`, would set a "Content-Length"
header value, even if the buffered body was empty.

This behavior is invalid since no request body would be set by the
client code in the first place.

This commit ensures that this header is only set if a request body has
been buffered and is about to be written to the request.

Fixes gh-32650
2024-04-17 22:44:36 +02:00
xumengqi 8ec27438e7 Fix transaction definition setTimeout error message since zero is valid
This commit rephrases the `DefaultTransactionDefinition#setTimeout`
exception message to better reflect the fact that 0 is a valid input
value.

Even though this often leads to a transaction immediately timing out
after opening, there is one notable case where this has another
meaningful effect: in Jakarta transactions (`UserTransaction`), when
passing 0 "the transaction service restores the default value".

Closes gh-32635
2024-04-16 16:39:23 +02:00
xumengqi bf3278596c Include actual cause's message in various parsing exception messages
This change improves the message of several parsing-related exceptions
that would previously entirely swallow the original exception's message
and sometimes have a slightly misleading message as a result.

This is done by appending the cause's `toString` representation to the
IllegalArgumentException messages instead of an hardcoded "cause".

Closes gh-32636
2024-04-16 16:25:42 +02:00
Arjen Poutsma 3971632415 Reintroduce SimpleClientHttpRequestFactory limitations
Closes gh-32641
2024-04-16 11:43:09 +02:00
Simon Baslé 1e54916119 Ensure multipart data is deleted in WebFlux when connection terminates
Before this change temporary files would not consistently be deleted
when the connection which uploads the multipart files closes naturally.

This change uses the usingWhen Reactor operator to ensure that the
termination of the connection doesn't prevent individual file parts
from being deleted due to a cancellation signal.

Closes gh-31217
2024-04-15 14:20:48 +02:00
Brian Clozel 6e20af41bf Upgrade CI image to Java 23ea17 2024-04-11 11:32:48 +02:00
Spring Builds c68c62b6c6 Next development version (v6.1.7-SNAPSHOT) 2024-04-11 08:26:17 +00:00
Brian Clozel 494ed4e852 Refine UriComponentsBuilder parsing
This commit refines the expressions for the scheme, user info, host and
port parts of the URL in UriComponentsBuilder to better conform to
RFC 3986.

Fixes gh-32616
2024-04-11 08:49:11 +02:00
Juergen Hoeller 39cd31613b Polishing 2024-04-10 18:06:32 +02:00
Sébastien Deleuze ca2b3c170c Add Kotlin hints for enclosing class
This is needed by Kotlin reflection in order to be able to list
class members on native.

Closes gh-32472
2024-04-10 17:53:12 +02:00
Brian Clozel 019ce4418c BufferingClientHttpRequestWrapper should not write empty body
Prior to this commit, `BufferingClientHttpRequestWrapper` would always
write to the actual client request body, even if the buffered content
was empty (empty byte array).
This would cause issues with specific client request factories,
especially the OkHttp variant, that would consider empty byte arrays as
non-empty body and would reject such cases for GET requests with an
"IllegalArgumentException: method GET must not have a request body".

This commit only writes to the request if the buffered content is not
empty.

Fixes gh-32612
2024-04-10 16:41:16 +02:00
Stéphane Nicoll a0136a276a Upgrade to Reactor 2023.0.5
Closes gh-32592
2024-04-09 19:51:08 +02:00
rstoyanchev 8d05028c2e RequestParam resolver supports empty array suffix
Closes gh-32577
2024-04-09 18:24:57 +01:00
rstoyanchev 4a68c44a27 Update content-length when reconstructing body
Closes gh-32471
2024-04-09 18:24:57 +01:00
Sam Brannen e702733c7b Detect bridge methods across ApplicationContexts in MethodIntrospector
Prior to this commit, MethodIntrospector failed to properly detect
bridge methods for subsequent invocations of selectMethods() with the
same targetType and MetadataLookup, if such subsequent invocations
occurred after the ApplicationContext had been refreshed.

The reason this occurs is due to the following.

- Class#getDeclaredMethods() always returns "child copies" of the
  underlying Method instances -- which means that `equals()` should be
  used instead of `==` whenever the compared Method instances can come
  from different sources (such as the static caches mentioned below).

- BridgeMethodResolver caches resolved bridge methods in a static cache
  -- which is never cleared.

- ReflectionUtils caches declared methods in a static cache
  -- which gets cleared when an ApplicationContext is refreshed.

Consequently, if you attempt to load an ApplicationContext twice in the
same ClassLoader, the second attempt uses the existing, populated cache
for bridged methods but a cleared, empty cache for declared methods.
This results in new invocations of Class#getDeclaredMethods(), and
identity checks with `==` then fail to detect equivalent bridge methods.

This commit addresses this by additionally comparing bridge methods
using `equals()` in MethodIntrospector.selectMethods().

Note that the `==` checks remain in place as an optimization for when
`equals()` is unnecessary.

Closes gh-32586
2024-04-09 18:56:41 +02:00
Sam Brannen 187f641409 Polishing 2024-04-09 18:55:39 +02:00
Brian Clozel ac74116d76 Instrument JmsTemplate#sendAndReceive
Prior to this commit, the `JmsTemplate#sendAndReceive` method would not
instrument the JMS session. This means that no metric would be recorded
when sending the message and no trace would be propagated downstream.

This commit ensures that the JMS session is instrumented in this case as
well. Note, the reception of the response message does not create a
`"jms.message.process"` observation as the session is only receiving the
message, no listener has been configured on the message consumer.

Fixes gh-32606
2024-04-09 18:34:09 +02:00
Juergen Hoeller c5590ae9e6 Log column type for limited support message in getResultSetValue
Closes gh-32601
2024-04-09 16:14:45 +02:00
Juergen Hoeller 39b551c334 Document hand-off to execution thread (including ScheduledFuture impact)
Closes gh-32589
2024-04-09 16:14:38 +02:00
Sébastien Deleuze 23696b7db8 Add a classpath check for AOP Coroutines/Reactive conversion
Closes gh-32599
2024-04-09 15:21:21 +02:00
Stéphane Nicoll 7b7cfb27a3 Upgrade to Micrometer 1.12.5
Closes gh-32596
2024-04-09 12:59:46 +02:00
Juergen Hoeller f2889b1b43 Consistent support for generic FactoryBean type matching
Closes gh-32590
See gh-32489
2024-04-08 22:39:29 +02:00
Stéphane Nicoll 802967fc98 Add reproducer
See gh-32489
2024-04-08 11:09:56 +02:00
Juergen Hoeller 22328905da Do not extract FactoryBean generic in case of targetType mismatch
Closes gh-32489
2024-04-08 09:51:59 +02:00
Juergen Hoeller 67a81004a2 Upgrade to AspectJ 1.9.22, Groovy 4.0.20, Tomcat 10.1.20, Netty 4.1.108, OpenPDF 1.3.43, Woodstox 6.6.2, Checkstyle 10.15 2024-04-05 18:04:58 +02:00
Juergen Hoeller 84963ba4d8 Polishing 2024-04-05 18:04:08 +02:00
Juergen Hoeller 07472758ee Detect Undertow RequestTooBigException message in handleParseFailure
Closes gh-32549
2024-04-05 18:03:44 +02:00
Arjen Poutsma 47c9c7eb07 Update copyright
See gh-32528
2024-04-05 16:13:39 +02:00
Stéphane Nicoll 8568aa691c Stop linking to Websphere's Javadoc
Closes gh-32581
2024-04-05 15:57:58 +02:00
Arjen Poutsma b24221754a ReactorNettyClientResponse should close response body
This commit ensures that the response body is drained and closed when
the response itself is closed, instead of disposing the connection, as
this will disable the connection pool.

Closes gh-32528
2024-04-05 15:38:18 +02:00
Sébastien Deleuze 7a666cfd86 Revert some null-safety changes
This commit reverts some null-safety changes which make sense
on main but are too impactful for 6.1.x for Kotlin developers
using -Xjsr305=strict.

See gh-32475
2024-04-05 14:59:39 +02:00
Sébastien Deleuze 4a7c24d90f Refine null-safety
See gh-32475
2024-04-05 14:30:50 +02:00
Stéphane Nicoll d955549037 Clarify scope of exception
See gh-29491
2024-04-04 14:42:41 +02:00
Stéphane Nicoll b68f76c86e Polish
See gh-32502
2024-04-04 14:42:41 +02:00
Simon Baslé 521cda009b Use non-blocking thread in WebFlux controller with RequestBody parameter
This commit ensures that `InvocableHandlerMethod` executes the method
on the desired thread if a non-blocking thread is specified, even in the
case where arguments resolution happens on a different thread. This is
notably the case if the method body is resolved as an input argument to
the controller method (`@RequestBody`).

Closes gh-32502
2024-04-04 14:20:16 +02:00
Stéphane Nicoll 08c9b5c96c Upgrade to Gradle 8.7
Closes gh-32566
2024-04-02 18:01:37 +02:00
Stéphane Nicoll a942a6e172 Document behavior of profiles enabled for AOT optimizations
Closes gh-32543
2024-04-02 15:47:43 +02:00
Stéphane Nicoll 9b1d5ea6e0 Merge pull request #32557 from Banuelorigni
* pr/32557:
  Polish reference guide

Closes gh-32557
2024-04-02 09:33:00 +02:00
kexin.an 640b97f33c Polish reference guide
See gh-32557
2024-04-02 09:29:55 +02:00
Stéphane Nicoll 1fb99e4192 Merge pull request #32560 from quaff
* pr/32560:
  Polish javadoc of AnnotatedBeanDefinitionReader

Closes gh-32560
2024-04-01 12:14:51 +02:00
Yanming Zhou 23d89362b0 Polish javadoc of AnnotatedBeanDefinitionReader
See gh-32560
2024-04-01 12:12:02 +02:00
Sébastien Deleuze 048e4f0aa2 Invoke KCallablesJvm.setAccessible only when required
Closes-32536
2024-03-28 11:12:50 +01:00
T45K b28153e1d7 Fix handling of value class with private constructor
See gh-32536
2024-03-28 11:11:58 +01:00
Sébastien Deleuze 88b9c0567d Refine null-safety in spring-test
See gh-32475
2024-03-26 18:09:55 +01:00
Stéphane Nicoll c7c9da56da Consistent atMost period for Awaitility-based tests
Closes gh-32537
2024-03-26 17:45:14 +01:00
Sébastien Deleuze 290a41d398 Refine null-safety in more modules
This commit refines the null-safety in all remaining modules
except spring-test.

See gh-32475
2024-03-26 15:39:18 +01:00
Sébastien Deleuze 1b563f8ba4 Refine null-safety in more modules
This commit refines the null-safety in:
 - spring-jdbc
 - spring-r2dbc
 - spring-orm
 - spring-beans
 - spring-aop

See gh-32475
2024-03-26 09:46:34 +01:00
Sébastien Deleuze dea31dd55e Refine null-safety in spring-messaging
See gh-32475
2024-03-25 12:24:53 +01:00
Sébastien Deleuze 06b91c4ea5 Refine null-safety in spring-jms
See gh-32475
2024-03-25 11:28:00 +01:00
Sébastien Deleuze a63ebe7e9d Refine null-safety in spring-web and spring-websocket
See gh-32475
2024-03-25 11:02:44 +01:00
Stéphane Nicoll c4b615052e Merge pull request #32517 from izeye
* pr/32517:
  Add Javadoc since to KotlinSerializationStringEncoder.setStreamingMediaTypes()

Closes gh-32517
2024-03-24 09:23:05 +01:00
Johnny Lim dca5f1dcd8 Add Javadoc since to KotlinSerializationStringEncoder.setStreamingMediaTypes()
See gh-32517
2024-03-24 09:21:36 +01:00
Sébastien Deleuze a16e8c34b2 Refine null-safety in spring-webmvc
See gh-32475
2024-03-22 17:44:35 +01:00
Sam Brannen 52b8c71dcd Retain null-safe syntax in AST representation of selection & projection
Prior to this commit, SpEL's CompoundExpression omitted the null-safe
syntax in AST string representations of the selection and projection
operators.

To address this, this commit implements isNullSafe() in Projection and
Selection.

Closes gh-32515
2024-03-22 17:05:48 +01:00
Sam Brannen f941754db6 Introduce isNullSafe() in SpelNodeImpl
Prior to this commit, MethodReference and PropertyOrFieldReference
already defined local isNullSafe() methods, but we need identical
methods in Selection, Projection, and Indexer, and we may potentially
need null-safe support for additional operators in the future.

To address the common need for an is-null-safe check, this commit
introduces an isNullSafe() method in SpelNodeImpl with a default
implementation that returns false.

Closes gh-32516
2024-03-22 16:37:08 +01:00
Sam Brannen d4495a5654 Revise PropertyOrFieldReference since isNullSafe() is not final 2024-03-22 16:37:08 +01:00
Stéphane Nicoll c7c61e13e1 Merge pull request #32514 from izeye
* pr/32514:
  Apply UnnecessarySemicolonInEnumeration Checkstyle module

Closes gh-32514
2024-03-22 16:31:54 +01:00
Johnny Lim 4d722414da Apply UnnecessarySemicolonInEnumeration Checkstyle module
This commit also fixes its violation.

See gh-32514
2024-03-22 16:30:06 +01:00
Sébastien Deleuze 87dfa492af Refine null-safety in spring-webflux
See gh-32475
2024-03-22 16:05:17 +01:00
Sébastien Deleuze cf9033a60d Polishing 2024-03-22 16:04:03 +01:00
Sébastien Deleuze 1e80694daf Fix a regression with Kotlin generic controllers
This commit reintroduces a more defensive parameter type check that
skips KClass casting for generic parameters.

Closes gh-32510
2024-03-21 17:55:57 +01:00
Stéphane Nicoll e17c3d3be4 Upgrade actions that use deprecated features 2024-03-20 10:16:09 +01:00
Sébastien Deleuze 2e98a8a2a4 Refine null-safety in spring-expression
See gh-32475
2024-03-20 10:07:56 +01:00
Stéphane Nicoll 592f23674d Merge pull request #32494 from qww1552
* pr/32494:
  Fix link to vavr in the reference guide

Closes gh-32494
2024-03-20 10:01:47 +01:00
Minsung Oh 0b3a05b463 Fix link to vavr in the reference guide
See gh-32494
2024-03-20 09:48:00 +01:00
Sam Brannen ef02f0bad8 Wrap InvalidMimeTypeException in HttpMediaTypeNotAcceptableException
The fix for #31254 resulted in an InvalidMimeTypeException being thrown
by MimeTypeUtils.sortBySpecificity() instead of an
IllegalArgumentException. However, InvalidMimeTypeException extends
IllegalArgumentException. Consequently, the change from
IllegalArgumentException to InvalidMimeTypeException did not result in
the desired effect in HeaderContentNegotiationStrategy.

HeaderContentNegotiationStrategy.resolveMediaTypes() still allows the
InvalidMimeTypeException to propagate as-is without wrapping it in an
HttpMediaTypeNotAcceptableException.

To address this issue, this commit catches InvalidMediaTypeException
and InvalidMimeTypeException in HeaderContentNegotiationStrategy and
wraps the exception in an HttpMediaTypeNotAcceptableException.

See gh-31254
See gh-31769
Closes gh-32483
2024-03-19 15:51:27 +01:00
Sam Brannen 836a0b3a40 Polishing 2024-03-19 14:19:01 +01:00
Sam Brannen 09f210f5f7 Polish wording in reference manual 2024-03-19 14:15:19 +01:00
Sébastien Deleuze aa0fb97ba5 Nullability refinements
See gh-32475
2024-03-19 13:32:13 +01:00
Sébastien Deleuze 71a117c0fd Document AOT limitations related to Kotlin backticks
Closes gh-32487
2024-03-19 11:03:56 +01:00
Juergen Hoeller bd27ddf83a Polishing (aligned with main) 2024-03-19 10:05:32 +01:00
Juergen Hoeller c531a8a705 Nullability refinements and related polishing
See gh-32475
2024-03-19 09:58:44 +01:00
Juergen Hoeller cd7ba1835c Propagate JMS IllegalStateException from commit/rollbackIfNecessary
Closes gh-32473
2024-03-18 16:03:13 +01:00
Juergen Hoeller 5dc6a16c0b Nullability refinements
See gh-32475
2024-03-18 16:03:00 +01:00
Sam Brannen 42a4f28962 Avoid unnecessary Annotation array cloning in TypeDescriptor
Closes gh-32476
2024-03-18 15:17:04 +01:00
Brian Clozel 521d4f24d0 Remove flaky test in JMS observation
There is no way to consistently test this use case because listener
container implementations have different behavior for unhandled errors
and might retry or close the container altogether.

See gh-32458
2024-03-18 14:35:42 +01:00
Stéphane Nicoll 039cbb3466 Merge pull request #32474 from izeye
* pr/32474:
  Add Javadoc since to AbstractClientHttpRequestFactoryWrapper.getDelegate()

Closes gh-32474
2024-03-18 14:10:58 +01:00
Johnny Lim d50c94fca9 Add Javadoc since to AbstractClientHttpRequestFactoryWrapper.getDelegate()
See gh-32474
2024-03-18 14:08:59 +01:00
Brian Clozel c1424acb94 Fix flaky test in JMS observability
See gh-32458
2024-03-18 12:17:57 +01:00
Juergen Hoeller 36d1bc57d7 Upgrade to Checkstyle 10.14.2 2024-03-17 20:54:54 +01:00
Juergen Hoeller b1c3b6e34b Restore original toString representation (revert accidental backport)
See gh-32405
2024-03-17 20:42:29 +01:00
Juergen Hoeller eb8b7c4331 Remove superfluous @NonNull declarations 2024-03-16 14:22:17 +01:00
Juergen Hoeller 58bd057a24 Avoid cloning empty Annotation array in TypeDescriptor (backport)
Closes gh-32405
2024-03-16 14:21:34 +01:00
Brian Clozel a78704af24 Record unhanlded JMS exceptions as observation errors
Prior to this commit, when using the `DefaultMessageListenerContainer`
as a backing listener container for JMS messages, the instrumentation
would not record JMS exceptions as observation errors when they were not
handled by configured `ErrorHandler`.

This commit ensures that this is the case.

Fixes gh-32458
2024-03-15 22:45:36 +01:00
Juergen Hoeller d2000efbd8 Polishing 2024-03-15 21:17:01 +01:00
Juergen Hoeller c23fd784a0 Consistently apply TaskDecorator to ManagedExecutorService as well
Closes gh-32455
2024-03-15 21:16:37 +01:00
Stéphane Nicoll 68a3993897 Merge pull request #32446 from LinorDolev
* pr/32446:
  Polish "Fix default strategy description of ProblemDetail error codes"
  Fix default strategy description of ProblemDetail error codes

Closes gh-32446
2024-03-15 08:28:19 +01:00
Stéphane Nicoll dfc1b839f3 Polish "Fix default strategy description of ProblemDetail error codes"
See gh-32446
2024-03-15 08:27:59 +01:00
Linor Dolev 302c24aaa8 Fix default strategy description of ProblemDetail error codes
See gh-32446
2024-03-15 08:02:20 +01:00
Stéphane Nicoll 7357812b4e Polish "Only include production branches for docs deployment"
See gh-32434
2024-03-14 17:47:12 +01:00
Stéphane Nicoll 30087e1aea Only include production branches for docs deployment
Closes gh-32434
2024-03-14 17:42:02 +01:00
Stéphane Nicoll cd5758e610 Restore CI execution per commit
As scheduled only works on the base branch anyway

See gh-32436
2024-03-14 15:28:23 +01:00
Stéphane Nicoll b82a0dd31a Polish "Move CI and snapshot deployment to GitHub actions"
See gh-32436
2024-03-14 15:16:02 +01:00
Stéphane Nicoll b7280400ee Move CI and snapshot deployment to GitHub actions
Closes gh-32436
2024-03-14 15:01:26 +01:00
Spring Builds a3345920ec Next development version (v6.1.6-SNAPSHOT) 2024-03-14 09:58:35 +00:00
rstoyanchev 381f790329 Extract reusable checkSchemeAndPort method
Closes gh-32440
2024-03-14 08:45:38 +00:00
Juergen Hoeller f5a3658535 Upgrade to Protobuf 3.25.3, Woodstox 6.6.1, JsonPath 2.9, QDox 2.1 2024-03-13 18:06:44 +01:00
Juergen Hoeller 54a6d89da7 Additional unit tests for operations on empty UriTemplate
See gh-32432
2024-03-13 18:06:17 +01:00
Stéphane Nicoll 2922a82275 Merge pull request #32432 from bsgrd
* pr/32432:
  Polish "Allow UriTemplate to be built with an empty template"
  Allow UriTemplate to be built with an empty template

Closes gh-32432
2024-03-13 17:27:52 +01:00
Stéphane Nicoll a34ceb405c Polish "Allow UriTemplate to be built with an empty template"
See gh-32432
2024-03-13 17:21:46 +01:00
Kasper Bisgaard 1b25a1506a Allow UriTemplate to be built with an empty template
See gh-32432
2024-03-13 17:20:08 +01:00
Juergen Hoeller 723c94e5ac Polishing 2024-03-12 20:10:01 +01:00
Juergen Hoeller e5a69dcfdf Upgrade to Reactor 2023.0.4 and Micrometer 1.12.4
Includes AspectJ 1.9.21.1, Groovy 4.0.19, Tomcat 10.1.19, Jetty 12.0.7, Jackson 2.15.4, OpenPDF 1.3.42, Mockito 5.11, Checkstyle 10.14.1

Closes gh-32420
Closes gh-32431
2024-03-12 20:07:58 +01:00
Xednar c2248c968c Update Javadoc in DefaultUserDestinationResolver
Closes gh-32272
2024-03-12 11:43:24 +00:00
Sébastien Deleuze 9cc74e78f8 Refine "Redirecting to a resource" section code sample
The commit updates the code sample to use a null element friendly list.

Closes gh-32423
2024-03-12 12:22:37 +01:00
Brian Clozel 9910df85cd Remove observation context from ClientRequest
Prior to this commit, gh-31609 added the current observation context as
a request attribute for `WebClient` calls. While it was not confirmed as
the main cause, this feature was linked to several reports of memory
leaks. This would indeed attach more memory to the request object graph
at runtime - although it shouldn't prevent its collection by the GC.

This commit removes this feature and instead developers should get the
current observation from the reactor context if they wish to interact
with it.

Closes gh-32198
2024-03-12 09:49:00 +01:00
Stéphane Nicoll 88b3844d9b Fix default value in ReactorNettyClientRequestFactory#setExchangeTimeout
Closes gh-32419
2024-03-12 08:13:42 +01:00
Sébastien Deleuze 80f3be6577 Replace getJvmErasure by getClassifier
Should be slightly faster.

See gh-32334
2024-03-11 13:37:41 +01:00
Sébastien Deleuze 946082f806 Refine publisher type check in CoroutinesUtils
See gh-32390
2024-03-11 13:15:54 +01:00
ZeroCyan 78fb378aef Fix order of sections in Validation chapter of reference manual
Closes gh-32408
2024-03-10 17:41:09 +01:00
Sam Brannen b4e743614e Restore link to Jakarta Servlet issue tracker 2024-03-09 16:30:14 +01:00
Stéphane Nicoll accf7ff645 Merge pull request #32403 from qeeqez
* pr/32403:
  Polish "Fix Javadoc"
  Fix Javadoc

Closes gh-32403
2024-03-09 16:02:51 +01:00
Stéphane Nicoll 4983a802a7 Polish "Fix Javadoc"
See gh-32403
2024-03-09 16:02:01 +01:00
Maksim Sasnouski abdccffa39 Fix Javadoc
This commit fixes various Javadoc issues across the code base.

See gh-32403
2024-03-09 16:02:00 +01:00
Juergen Hoeller c1287d48e2 Polishing 2024-03-08 19:31:01 +01:00
Sam Brannen 528029a0ba Document that SpEL expressions using array construction cannot be compiled
Closes gh-32401
2024-03-08 15:49:08 +01:00
Sam Brannen fea1464562 Ensure SpEL can compile an expression indexing into a boolean array
Closes gh-32400
2024-03-08 15:32:57 +01:00
Brian Clozel f6bc828569 Set error on observation in WebClient instrumentation
Prior to this commit, error signals flowing from the client response
publisher in `WebClient` would be set on the `Observation.Context`. This
is enough for the observation convention to collect data about the error
but observation handlers are not notified of this error.

This commit sets the error instead on the observation directly to fix
this issue.

Fixes gh-32389
2024-03-08 11:33:45 +01:00
Yanming Zhou 0e279fe666 Polishing
Closes gh-32397
2024-03-08 09:25:03 +01:00
rstoyanchev 56a1c810b5 Remove IOException that's not thrown from Javadoc 2024-03-07 16:05:15 +00:00
rstoyanchev dec5265354 Use wrapped response in HandlerFunctionAdapter
webmvc.fn now also uses the StandardServletAsyncWebRequest wrapped response
to enforce lifecycle rules from Servlet spec (section 2.3.3.4).

See gh-32340
2024-03-07 14:47:50 +00:00
Sébastien Deleuze 579dbc48d7 Optimize Coroutine invocations
KClass instantiation in CoroutinesUtils is suboptimal, and should be
replaced by KTypes#isSubtypeOf checks using pre-instantiated types for
Flow, Mono and Publisher.

This commit impact on performances is significant since a throughput
increase between 2x and 3x has been measured on basic endpoints.

Closes gh-32390
2024-03-07 14:27:47 +01:00
Simon Baslé 6d9a2eb9b8 Improve fix of duplicate upstream subscription during reactive cache put
This commit fixes an issue where a Cacheable method which returns a
Flux (or multi-value publisher) will be invoked once, but the returned
publisher is actually subscribed twice.

The previous fix 988f3630c would cause the cached elements to depend on
the first usage pattern / request pattern, which is likely to be too
confusing to users. This fix reintroduces the notion of exhausting the
original Flux by having a second subscriber dedicated to that, but uses
`refCount(2)` to ensure that the original `Flux` returned by the cached
method is still only subscribed once.

Closes gh-32370
2024-03-07 12:08:28 +01:00
Sébastien Deleuze c1d4b610ca Refine Kotlin inline class optimizations
Closes gh-32334
2024-03-07 11:11:20 +01:00
rstoyanchev 5f601ceb45 Mark response errors from @ExceptionHandler as handled
Also fix a couple of related issues:
- add AsyncRequestNotUsableException to the list of exceptions
that imply response issues.
- handle exceptions from @ExceptionHandler regardless of whether
thrown immediately or via Publisher.

Closes gh-32359
2024-03-06 18:17:13 +00:00
Juergen Hoeller 0955f541cb Polishing 2024-03-06 18:03:36 +01:00
Juergen Hoeller e5e61dfa3f Ignore scheduled task exceptions after shutdown
Includes suppression after logging, not propagating exceptions to the thread itself.

Closes gh-32381
See gh-32298
2024-03-06 18:03:31 +01:00
Simon Baslé 988f3630c4 Avoid duplicate upstream subscription during reactive cache put
This commit fixes an issue where a Cacheable method which returns a
Flux (or multi-value publisher) will be invoked once, but the returned
publisher is actually subscribed twice.

By using the Reactor `tap` operator, we ensure that we can emit values
downstream AND accumulate emitted values into the List with a single
subscription.

The SignalListener additionally handles scenarios involving cancel,
for instance in case of a `take(1)` in the chain. In that case values
emitted up until that point will have been stored into the List buffer,
so we can still put it in the cache. In case of error, no caching occurs
and the internal buffer is cleared. This implementation also protects
against competing onComplete/onError signals and cancel signals.

Closes gh-32370
2024-03-05 18:32:32 +01:00
Juergen Hoeller a0ae849856 Polishing 2024-03-05 18:23:13 +01:00
rstoyanchev ef0717935b Test wrapping of response for async request
The following adjustments are also made as a result:
- Use int to check if lock is held and unlock is needed, given that
for non-async requests we don't need to obtain a lock.
- Protect access methods getOutputStream and getWriter with the
same locking and state checks.

Closes gh-32340
2024-03-05 11:42:03 +00:00
rstoyanchev 822e2447a0 Polishing StandardServletAsyncWebRequestTests
See gh-32340
2024-03-05 11:42:03 +00:00
Sébastien Deleuze cfd0aee4db Polish and add MockMvcExtensionsTests.queryParameter
Closes gh-32371
2024-03-05 10:59:12 +01:00
corby kim 132fbe228f Add query parameters to MockMvc Kotlin DSL
See gh-32371
2024-03-05 10:56:41 +01:00
Juergen Hoeller 4300fec023 Restore ability to return original method at ClassUtils level as well
Closes gh-32365
2024-03-04 23:48:26 +01:00
Juergen Hoeller e9110c0729 Polishing 2024-03-04 22:48:52 +01:00
Juergen Hoeller 24759a75f4 Restore ability to return original method for proxy-derived method
Closes gh-32365
2024-03-04 22:48:46 +01:00
Sébastien Deleuze 7493ce86b6 Fix ServletResponseHttpHeaders#get null handling
ServletResponseHttpHeaders#get should be annotated with `@Nullable` and
return null instead of a singleton list containing null when there is no
content type header.

Closes gh-32362
2024-03-04 14:43:09 +01:00
Sébastien Deleuze ce9dc19a3c Optimize content type parsing
This commit avoids calling HttpHeaders#getContentType multiple times in
ServletServerHttpResponse#writeHeaders.

Closes gh-32361
2024-03-04 14:43:09 +01:00
rstoyanchev 4b96cd28c0 Add locking in ServletResponse#flushBuffer
In addition to using the ServletOutputStream, it's also possible to call
ServletResponse#flushBuffer, so the ServletOutputStream wrapper logic needs
to apply there as well.

See gh-32340
2024-03-04 13:35:46 +00:00
Sébastien Deleuze 516a203703 Support nullable Kotlin value class arguments
This commit skips the value class parameter instantiation for nullable
types when a null argument is passed.

Closes gh-32353
2024-03-03 22:26:21 +01:00
rstoyanchev 877e0b1483 Improve concurrent handling of result in WebAsyncManager
1. Use state transitions
2. Increase synchronized scope in setConcurrentResultAndDispatch

See gh-32340
2024-03-03 20:44:52 +00:00
rstoyanchev 379ffac508 Add state and response wrapping to StandardServletAsyncWebRequest
The wrapped response prevents use after AsyncListener onError or completion
to ensure compliance with Servlet Spec 2.3.3.4.

The wrapped response is applied in RequestMappingHandlerAdapter.

The wrapped response raises AsyncRequestNotUsableException that is now
handled in DefaultHandlerExceptionResolver.

See gh-32340
2024-03-03 20:44:36 +00:00
Sam Brannen 380184e85a Support SpEL compilation of #root or #this with non-public type
Prior to this commit, if a Spring Expression Language (SpEL) expression
referenced the root context object via the #root or #this variable, we
inserted a checkcast in the generated byte code that cast the object to
its concrete type. However if the root context object's type was
non-public, that resulted in an IllegalAccessError when the compiled
byte code was executed.

VariableReference.getValueInternal() already contains a solution for
global variables which inserts a checkcast to Object in the generated
byte code instead of to the object's concrete non-public type.

This commit therefore applies the same logic to #root (or #this when
used to reference the root context object) that is already applied to
global variables.

Closes gh-32356
2024-03-03 14:49:42 +01:00
Sam Brannen 5cba32df32 Polish SpEL's VariableReference 2024-03-02 18:03:44 +01:00
Sam Brannen 11c40b5c1c Restructure SpEL indexer compilation tests 2024-03-02 18:03:44 +01:00
Sébastien Deleuze 227e75dae4 Support nullable Kotlin value class arguments
This commit refines WebMVC and WebFlux argument resolution in order to
convert properly Kotlin value class arguments by using the type of the
value instead of the type of the value class.

Closes gh-32353
2024-03-01 16:38:26 +01:00
Sam Brannen de828e9764 Improve documentation for @⁠Sql execution phases regarding lifecycle
Closes gh-32343
2024-03-01 14:37:31 +01:00
Sébastien Deleuze 85a781d517 Instantiate value class parameters with Kotlin reflection
In order to invoke the init block and to improve the maintainability.

Closes gh-32324
2024-03-01 11:50:19 +01:00
Stéphane Nicoll 7f916e0ee3 Merge pull request #32349 from qeeqez
* pr/32349:
  Upgrade to com.gradle.enterprise 3.16.2

Closes gh-32349
2024-02-29 17:16:03 +01:00
Maksim Sasnouski 960e885f88 Upgrade to com.gradle.enterprise 3.16.2
See gh-32349
2024-02-29 17:15:26 +01:00
Arjen Poutsma bf8f398c19 Merge pull request #32318 from kilink:http-headers-getAcceptLanguageAsLocales-optimization
* gh-32318:
  Polishing external contribution
  Optimize HttpHeaders.getAcceptLanguageAsLocales
2024-02-29 15:54:52 +01:00
Arjen Poutsma 33705516ff Polishing external contribution
See gh-32318
2024-02-29 15:51:29 +01:00
Patrick Strawderman beb415dfa3 Optimize HttpHeaders.getAcceptLanguageAsLocales
The HttpHeaders.getAcceptLanguageAsLocales was incurring overhead from
using a Stream, as well as calling the fairly expensive
Locale.getDisplayName method.

Switch to using an ArrayList, and skipping over wildcard ranges to avoid
needing to check the display name.

Closes gh-32318
2024-02-29 15:36:55 +01:00
Juergen Hoeller d45c0e6b8a Upgrade to Undertow 2.3.12, OpenPDF 1.3.41, JRuby 9.4.6 2024-02-28 21:42:16 +01:00
Juergen Hoeller 154ca54c9f Polishing 2024-02-28 21:40:08 +01:00
Juergen Hoeller f22a1eece4 Polishing 2024-02-28 19:14:37 +01:00
Juergen Hoeller 6d9736acd0 Direct reference to PushBuilder API on Servlet 5.0 baseline
See gh-29435
2024-02-28 19:14:30 +01:00
Sébastien Deleuze 0de3b30029 Provide guidelines for using Kotlin properties with proxies
A typical use case is `@Scope` and its popular `@RequestScope`
specialization.

Closes gh-32287
2024-02-28 18:33:39 +01:00
Sébastien Deleuze 45c21042f6 Optimize Kotlin inline class checks
This commit fixes a performance regression caused by gh-31698,
and more specifically by KClass#isValue invocations which are slow since
they load the whole module to find the class to get the descriptor.

After discussing with the Kotlin team, it has been decided that only
checking for the presence of `@JvmInline` annotation is enough for
Spring use case.

As a consequence, this commit introduces a new
KotlinDetector#isInlineClass method that performs such check, and
BeanUtils, CoroutinesUtils and WebMVC/WebFlux InvocableHandlerMethod
have been refined to leverage it.

Closes gh-32334
2024-02-28 17:18:57 +01:00
Sam Brannen 5830aac1d4 Omit parameter names in REST Clients section of reference docs
For consistency with other examples, this commit omits `method` parameter
names in the "Migrating from RestTemplate to RestClient" section of the
reference docs.

Closes gh-32335
2024-02-28 10:41:50 +01:00
Sam Brannen 0eb61c0f72 Polish REST Clients section 2024-02-28 10:34:57 +01:00
Sébastien Deleuze dc1ef23780 Refine *HttpMessageConverter#getContentLength null safety
Closes gh-32325
2024-02-27 15:51:52 +01:00
Sam Brannen cca440eb8e Do not cache Content-Type in ContentCachingResponseWrapper
Based on feedback from several members of the community, we have
decided to revert the caching of the Content-Type header that was
introduced in ContentCachingResponseWrapper in 375e0e6827.

This commit therefore completely removes Content-Type caching in
ContentCachingResponseWrapper and updates the existing tests
accordingly.

To provide guards against future regressions in this area, this commit
also introduces explicit tests for the 6 ways to set the content length
in ContentCachingResponseWrapper and modifies a test in
ShallowEtagHeaderFilterTests to ensure that a Content-Type header set
directly on ContentCachingResponseWrapper is propagated to the
underlying response even if content caching is disabled for the
ShallowEtagHeaderFilter.

See gh-32039
Closes gh-32317
2024-02-26 17:52:56 +01:00
Sam Brannen 497aa3c069 Polish ShallowEtagHeaderFilterTests 2024-02-26 17:44:48 +01:00
Juergen Hoeller 479879c53a Polishing 2024-02-26 13:40:21 +01:00
Juergen Hoeller 2e57603310 Try type conversion for unique fallback write method as well
Closes gh-32329
See gh-32159
2024-02-26 13:40:05 +01:00
Sam Brannen be45481d70 Return unique set from ContentCachingResponseWrapper.getHeaderNames()
Prior to this commit, getHeaderNames() returned duplicates for the
Content-Type and Content-Length headers if they were set in the wrapped
response as well as in ContentCachingResponseWrapper.

This commit fixes that by returning a unique set from getHeaderNames().

In addition, this commit introduces a new test in
ContentCachingResponseWrapperTests to verify the expected behavior for
Content-Type and Content-Length headers that are set in the wrapped
response as well as in ContentCachingResponseWrapper.

See gh-32039
See gh-32317
2024-02-25 16:17:22 +01:00
Sam Brannen 5680d20637 Honor Content-[Type|Length] headers from wrapped response again
Commit 375e0e6827 introduced a regression in
ContentCachingResponseWrapper (CCRW). Specifically, CCRW no longer
honors Content-Type and Content-Length headers that have been set on
the wrapped response and returns null for those header values if they
have not been set directly on the CCRW.

This commit fixes this regression as follows.

- The Content-Type and Content-Length headers set in the wrapped
  response are honored in getContentType(), containsHeader(),
  getHeader(), and getHeaders() unless those headers have been set
  directly on the CCRW.

- In copyBodyToResponse(), the Content-Type in the wrapped response is
  only overridden if the Content-Type has been set directly on the CCRW.

See gh-32039
Closes gh-32317
2024-02-24 16:37:22 +01:00
Sam Brannen 8787381892 Polish ContentCachingResponseWrapper[Tests] 2024-02-24 16:37:14 +01:00
Juergen Hoeller 3cc64968b9 Consistent nullability for internal field access 2024-02-24 08:21:37 +01:00
Juergen Hoeller 4dc3eac864 Polishing 2024-02-22 16:56:22 +01:00
Juergen Hoeller 0188270138 Clarify transaction metadata exposed from currentTransactionStatus()
Closes gh-32310
2024-02-22 16:56:17 +01:00
Sébastien Deleuze 9430b24eaf Adapt Hibernate native support for HHH-17643
This commit adapts Hibernate native support to handle
the changes performed as part of HHH-17643 which impacts
Hibernate versions 6.4.3+ and 6.2.21+.

It ignores the BytecodeProvider services loaded by the
service loader feature in order to default to the
"no-op" provider with native, and makes the substitutions
more lenient when a substituted field or method does not
exist.

gh-32314 is expected to remove the need for such
substitutions which are not great for maintainability
by design.

Closes gh-32311
2024-02-22 16:30:32 +01:00
Juergen Hoeller 41433d445e Polishing 2024-02-21 22:58:42 +01:00
Juergen Hoeller 7ffeb59b40 Polishing 2024-02-21 22:45:39 +01:00
Juergen Hoeller 8d4953d8d6 Add test for cleanup after configuration class creation failure
See gh-23343
2024-02-21 22:45:32 +01:00
Brian Clozel f440d8719c Prepare JDK 23 early access build in CI
See gh-32090
2024-02-21 18:23:38 +01:00
Stéphane Nicoll 5d6501c75e Revisit stored procedure detection
This commit revisits the improved detection algorithm for stored
procedure as, unfortunately, certain JDBC drivers do not support
the documented pattern for schema and procedure name.

To work around this limitation, this commit applies the escaping of
wildcard characters to the case where multiple procedures have been
found for a given search.

Closes gh-32295
2024-02-21 15:54:34 +01:00
Juergen Hoeller 93f0ec2fa1 Polishing 2024-02-20 15:42:15 +01:00
Juergen Hoeller 85c9279431 Consistent default error handling/logging for all scheduled tasks
Closes gh-32298
2024-02-20 15:42:07 +01:00
Stéphane Nicoll 06a39f166e Consistent handling of AssertProvider implementations 2024-02-20 10:19:19 +01:00
Stéphane Nicoll 46bd133892 Upgrade CI image to Java 22+36 RC 2024-02-19 10:52:10 +01:00
Juergen Hoeller 7bb9e85723 Avoid trivial static import 2024-02-16 22:43:56 +01:00
Juergen Hoeller 3aae7a66e6 Polishing 2024-02-16 22:27:09 +01:00
Stéphane Nicoll 26ca7c49fb Merge pull request #32281 from kilink
* pr/32281:
  Update copyright year of changed files
  Use Spliterator of underlying collection

Closes gh-32281
2024-02-16 08:36:20 +01:00
Stéphane Nicoll 6b8105aef2 Update copyright year of changed files
See gh-32281
2024-02-16 08:33:17 +01:00
Patrick Strawderman 481283d2f1 Use Spliterator of underlying collection
Delegate to the spliterator method of the underlying collection in
MutablePropertyValues and MutablePropertySources. In both cases, those
collection types have specialized Spliterator implementations.
Delegating to these Spliterators also means the characteristics of the
Spliterator are properly set.

See gh-32281
2024-02-16 08:32:41 +01:00
Stéphane Nicoll 4230c41d97 Initiate 6.1.x branch 2024-02-15 12:59:07 +01:00
Spring Builds b082348e61 Next development version (v6.1.5-SNAPSHOT) 2024-02-15 10:22:18 +00:00
894 changed files with 13305 additions and 5681 deletions
+56
View File
@@ -0,0 +1,56 @@
name: 'Build'
description: 'Builds the project, optionally publishing it to a local deployment repository'
inputs:
java-version:
required: false
default: '17'
description: 'The Java version to compile and test with'
java-distribution:
required: false
default: 'liberica'
description: 'The Java distribution to use for the build'
java-toolchain:
required: false
default: 'false'
description: 'Whether a Java toolchain should be used'
publish:
required: false
default: 'false'
description: 'Whether to publish artifacts ready for deployment to Artifactory'
develocity-access-key:
required: false
description: 'The access key for authentication with ge.spring.io'
outputs:
build-scan-url:
description: 'The URL, if any, of the build scan produced by the build'
value: ${{ (inputs.publish == 'true' && steps.publish.outputs.build-scan-url) || steps.build.outputs.build-scan-url }}
version:
description: 'The version that was built'
value: ${{ steps.read-version.outputs.version }}
runs:
using: composite
steps:
- name: Prepare Gradle Build
uses: ./.github/actions/prepare-gradle-build
with:
develocity-access-key: ${{ inputs.develocity-access-key }}
java-version: ${{ inputs.java-version }}
java-distribution: ${{ inputs.java-distribution }}
java-toolchain: ${{ inputs.java-toolchain }}
- name: Build
id: build
if: ${{ inputs.publish == 'false' }}
shell: bash
run: ./gradlew check antora
- name: Publish
id: publish
if: ${{ inputs.publish == 'true' }}
shell: bash
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository build publishAllPublicationsToDeploymentRepository
- name: Read Version From gradle.properties
id: read-version
shell: bash
run: |
version=$(sed -n 's/version=\(.*\)/\1/p' gradle.properties)
echo "Version is $version"
echo "version=$version" >> $GITHUB_OUTPUT
@@ -0,0 +1,23 @@
name: Create GitHub Release
description: Create the release on GitHub with a changelog
inputs:
milestone:
description: 'Name of the GitHub milestone for which a release will be created'
required: true
token:
description: 'Token to use for authentication with GitHub'
required: true
runs:
using: composite
steps:
- name: Generate Changelog
uses: spring-io/github-changelog-generator@185319ad7eaa75b0e8e72e4b6db19c8b2cb8c4c1 #v0.0.11
with:
milestone: ${{ inputs.milestone }}
token: ${{ inputs.token }}
config-file: .github/actions/create-github-release/changelog-generator.yml
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ inputs.token }}
shell: bash
run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md
@@ -0,0 +1,28 @@
changelog:
repository: spring-projects/spring-framework
sections:
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
contributors:
exclude:
names:
- "bclozel"
- "jhoeller"
- "poutsma"
- "rstoyanchev"
- "sbrannen"
- "sdeleuze"
- "simonbasle"
- "snicoll"
@@ -0,0 +1,49 @@
name: 'Prepare Gradle Build'
description: 'Prepares a Gradle build. Sets up Java and Gradle and configures Gradle properties'
inputs:
java-version:
required: false
default: '17'
description: 'The Java version to use for the build'
java-distribution:
required: false
default: 'liberica'
description: 'The Java distribution to use for the build'
java-toolchain:
required: false
default: 'false'
description: 'Whether a Java toolchain should be used'
develocity-access-key:
required: false
description: 'The access key for authentication with ge.spring.io'
runs:
using: composite
steps:
- name: Set Up Java
uses: actions/setup-java@v4
with:
distribution: ${{ inputs.java-distribution }}
java-version: |
${{ inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '17' || '' }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2
with:
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
- name: Configure Gradle Properties
shell: bash
run: |
mkdir -p $HOME/.gradle
echo 'systemProp.user.name=spring-builds+github' >> $HOME/.gradle/gradle.properties
echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $HOME/.gradle/gradle.properties
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
echo 'org.gradle.daemon=4' >> $HOME/.gradle/gradle.properties
- name: Configure Toolchain Properties
if: ${{ inputs.java-toolchain == 'true' }}
shell: bash
run: |
echo toolchainVersion=${{ inputs.java-version }} >> $HOME/.gradle/gradle.properties
echo systemProp.org.gradle.java.installations.auto-detect=false >> $HOME/.gradle/gradle.properties
echo systemProp.org.gradle.java.installations.auto-download=false >> $HOME/.gradle/gradle.properties
echo systemProp.org.gradle.java.installations.paths=${{ format('$JAVA_HOME_{0}_X64', inputs.java-version) }} >> $HOME/.gradle/gradle.properties
@@ -0,0 +1,33 @@
name: Send Notification
description: Sends a Google Chat message as a notification of the job's outcome
inputs:
webhook-url:
description: 'Google Chat Webhook URL'
required: true
status:
description: 'Status of the job'
required: true
build-scan-url:
description: 'URL of the build scan to include in the notification'
run-name:
description: 'Name of the run to include in the notification'
default: ${{ format('{0} {1}', github.ref_name, github.job) }}
runs:
using: composite
steps:
- shell: bash
run: |
echo "BUILD_SCAN=${{ inputs.build-scan-url == '' && ' [build scan unavailable]' || format(' [<{0}|Build Scan>]', inputs.build-scan-url) }}" >> "$GITHUB_ENV"
echo "RUN_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> "$GITHUB_ENV"
- shell: bash
if: ${{ inputs.status == 'success' }}
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was successful ${{ env.BUILD_SCAN }}"}' || true
- shell: bash
if: ${{ inputs.status == 'failure' }}
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<users/all> *<${{ env.RUN_URL }}|${{ inputs.run-name }}> failed* ${{ env.BUILD_SCAN }}"}' || true
- shell: bash
if: ${{ inputs.status == 'cancelled' }}
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was cancelled"}' || true
@@ -0,0 +1,50 @@
name: Sync to Maven Central
description: Syncs a release to Maven Central and waits for it to be available for use
inputs:
jfrog-cli-config-token:
description: 'Config token for the JFrog CLI'
required: true
spring-framework-version:
description: 'The version of Spring Framework that is being synced to Central'
required: true
ossrh-s01-token-username:
description: 'Username for authentication with s01.oss.sonatype.org'
required: true
ossrh-s01-token-password:
description: 'Password for authentication with s01.oss.sonatype.org'
required: true
ossrh-s01-staging-profile:
description: 'Staging profile to use when syncing to Central'
required: true
runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.1.2
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Release Artifacts
shell: bash
run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-framework-{0}', inputs.spring-framework-version) }};buildNumber=${{ github.run_number }}'
- name: Sync
uses: spring-io/nexus-sync-action@42477a2230a2f694f9eaa4643fa9e76b99b7ab84 # v0.0.1
with:
username: ${{ inputs.ossrh-s01-token-username }}
password: ${{ inputs.ossrh-s01-token-password }}
staging-profile-name: ${{ inputs.ossrh-s01-staging-profile }}
create: true
upload: true
close: true
release: true
generate-checksums: true
- name: Await
shell: bash
run: |
url=${{ format('https://repo.maven.apache.org/maven2/org/springframework/spring-context/{0}/spring-context-{0}.jar', inputs.spring-framework-version) }}
echo "Waiting for $url"
until curl --fail --head --silent $url > /dev/null
do
echo "."
sleep 60
done
echo "$url is available"
@@ -0,0 +1,20 @@
{
"files": [
{
"aql": {
"items.find": {
"$and": [
{
"@build.name": "${buildName}",
"@build.number": "${buildNumber}",
"path": {
"$nmatch": "org/springframework/framework-api/*"
}
}
]
}
},
"target": "nexus/"
}
]
}
+6 -4
View File
@@ -18,11 +18,13 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- name: Check out code
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
distribution: 'liberica'
java-version: 17
- name: Download BackportBot
run: wget https://github.com/spring-io/backport-bot/releases/download/latest/backport-bot-0.0.1-SNAPSHOT.jar
- name: Backport
@@ -0,0 +1,59 @@
name: Build and Deploy Snapshot
on:
push:
branches:
- 6.1.x
permissions:
actions: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-deploy-snapshot:
name: Build and Deploy Snapshot
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-framework' }}
steps:
- name: Check Out Code
uses: actions/checkout@v4
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
with:
develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
publish: true
- name: Deploy
uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1
with:
uri: 'https://repo.spring.io'
username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
build-name: 'spring-framework-6.1.x'
repository: 'libs-snapshot-local'
folder: 'deployment-repository'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
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
- name: Send Notification
uses: ./.github/actions/send-notification
if: always()
with:
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
status: ${{ job.status }}
build-scan-url: ${{ steps.build-and-publish.outputs.build-scan-url }}
run-name: ${{ format('{0} | Linux | Java 17', github.ref_name) }}
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
verify:
name: Verify
needs: build-and-deploy-snapshot
uses: ./.github/workflows/verify.yml
secrets:
google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
with:
version: ${{ needs.build-and-deploy-snapshot.outputs.version }}
+57
View File
@@ -0,0 +1,57 @@
name: CI
on:
push:
branches:
- 6.1.x
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
ci:
name: '${{ matrix.os.name}} | Java ${{ matrix.java.version}}'
runs-on: ${{ matrix.os.id }}
if: ${{ github.repository == 'spring-projects/spring-framework' }}
strategy:
matrix:
os:
- id: ubuntu-latest
name: Linux
java:
- version: 17
toolchain: false
- version: 21
toolchain: true
- version: 22
toolchain: true
- version: 23-ea
distribution: temurin
toolchain: true
exclude:
- os:
name: Linux
java:
version: 17
steps:
- name: Prepare Windows runner
if: ${{ runner.os == 'Windows' }}
run: |
git config --global core.autocrlf true
git config --global core.longPaths true
Stop-Service -name Docker
- name: Check Out Code
uses: actions/checkout@v4
- name: Build
id: build
uses: ./.github/actions/build
with:
java-version: ${{ matrix.java.version }}
java-distribution: ${{ matrix.java.distribution || 'liberica' }}
java-toolchain: ${{ matrix.java.toolchain }}
develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
- name: Send Notification
uses: ./.github/actions/send-notification
if: always()
with:
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
status: ${{ job.status }}
build-scan-url: ${{ steps.build.outputs.build-scan-url }}
run-name: ${{ format('{0} | {1} | Java {2}', github.ref_name, matrix.os.name, matrix.java.version) }}
+8 -6
View File
@@ -1,12 +1,14 @@
name: Deploy Docs
on:
push:
branches-ignore: [ gh-pages ]
tags: '**'
branches:
- 'main'
- '*.x'
- '!gh-pages'
tags:
- 'v*'
repository_dispatch:
types: request-build-reference # legacy
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions:
actions: write
@@ -15,8 +17,8 @@ jobs:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Check out code
uses: actions/checkout@v4
with:
ref: docs-build
fetch-depth: 1
@@ -1,13 +0,0 @@
name: "Validate Gradle Wrapper"
on: [push, pull_request]
permissions:
contents: read
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
+90
View File
@@ -0,0 +1,90 @@
name: Release
on:
push:
tags:
- v6.1.[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-stage-release:
if: ${{ github.repository == 'spring-projects/spring-framework' }}
name: Build and Stage Release
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v4
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
with:
develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
publish: true
- name: Stage Release
uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1
with:
build-name: ${{ format('spring-framework-{0}', steps.build-and-publish.outputs.version)}}
folder: 'deployment-repository'
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository: 'libs-staging-local'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
uri: 'https://repo.spring.io'
username: ${{ secrets.ARTIFACTORY_USERNAME }}
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
verify:
name: Verify
needs: build-and-stage-release
uses: ./.github/workflows/verify.yml
with:
staging: true
version: ${{ needs.build-and-stage-release.outputs.version }}
secrets:
google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
sync-to-maven-central:
name: Sync to Maven Central
needs:
- build-and-stage-release
- verify
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Sync to Maven Central
uses: ./.github/actions/sync-to-maven-central
with:
jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}
ossrh-s01-staging-profile: ${{ secrets.OSSRH_S01_STAGING_PROFILE }}
ossrh-s01-token-password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }}
ossrh-s01-token-username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }}
spring-framework-version: ${{ needs.build-and-stage-release.outputs.version }}
promote-release:
name: Promote Release
needs:
- build-and-stage-release
- sync-to-maven-central
runs-on: ubuntu-latest
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.1.2
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build
run: jfrog rt build-promote ${{ format('spring-framework-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-release-local
create-github-release:
name: Create GitHub Release
needs:
- build-and-stage-release
- promote-release
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
milestone: ${{ needs.build-and-stage-release.outputs.version }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
@@ -0,0 +1,11 @@
name: "Validate Gradle Wrapper"
on: [push, pull_request]
permissions:
contents: read
jobs:
validation:
name: "Validate Gradle Wrapper"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2
+71
View File
@@ -0,0 +1,71 @@
name: Verify
on:
workflow_call:
inputs:
version:
required: true
type: string
staging:
required: false
default: false
type: boolean
secrets:
repository-username:
required: false
repository-password:
required: false
google-chat-webhook-url:
required: true
token:
required: true
jobs:
verify:
name: Verify
runs-on: ubuntu-latest
steps:
- name: Check Out Release Verification Tests
uses: actions/checkout@v4
with:
repository: spring-projects/spring-framework-release-verification
ref: 'v0.0.2'
token: ${{ secrets.token }}
- name: Check Out Send Notification Action
uses: actions/checkout@v4
with:
path: spring-framework
sparse-checkout: .github/actions/send-notification
- name: Set Up Java
uses: actions/setup-java@v4
with:
distribution: 'liberica'
java-version: 17
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2
with:
cache-read-only: false
- name: Configure Gradle Properties
shell: bash
run: |
mkdir -p $HOME/.gradle
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
- name: Run Release Verification Tests
env:
RVT_VERSION: ${{ inputs.version }}
RVT_RELEASE_TYPE: oss
RVT_STAGING: ${{ inputs.staging }}
RVT_OSS_REPOSITORY_USERNAME: ${{ secrets.repository-username }}
RVT_OSS_REPOSITORY_PASSWORD: ${{ secrets.repository-password }}
run: ./gradlew spring-framework-release-verification-tests:test
- name: Upload Build Reports on Failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: build-reports
path: '**/build/reports/'
- name: Send Notification
uses: ./spring-framework/.github/actions/send-notification
if: failure()
with:
webhook-url: ${{ secrets.google-chat-webhook-url }}
status: ${{ job.status }}
run-name: ${{ format('{0} | Verification | {1}', github.ref_name, inputs.version) }}
+2
View File
@@ -51,3 +51,5 @@ atlassian-ide-plugin.xml
.vscode/
cached-antora-playbook.yml
node_modules
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.10-librca
java=17.0.11-librca
-44
View File
@@ -1,44 +0,0 @@
= Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open
and welcoming community, we pledge to respect all people who contribute through reporting
issues, posting feature requests, updating documentation, submitting pull requests or
patches, and other activities.
We are committed to making participation in this project a harassment-free experience for
everyone, regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses,
without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
consistently applying these principles to every aspect of managing this project. Project
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
be reviewed and investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
+1 -1
View File
@@ -18,7 +18,7 @@ First off, thank you for taking the time to contribute! :+1: :tada:
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc).
By participating you are expected to uphold this code.
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
Please report unacceptable behavior to spring-code-of-conduct@spring.io.
### How to Contribute
+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://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-6.1.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.1.x?groups=Build") [![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=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)
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
@@ -6,7 +6,7 @@ Spring provides everything required beyond the Java programming language for cre
## Code of Conduct
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@spring.io.
## Access to Binaries
-3
View File
@@ -89,9 +89,6 @@ configure([rootProject] + javaProjects) { project ->
ext.javadocLinks = [
"https://docs.oracle.com/en/java/javase/17/docs/api/",
"https://jakarta.ee/specifications/platform/9/apidocs/",
"https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ and weblogic.* packages
"https://www.ibm.com/docs/api/v1/content/SSEQTP_8.5.5/com.ibm.websphere.javadoc.doc/web/apidocs/", // com.ibm.*
"https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/", // org.jboss.resource.*
"https://docs.jboss.org/hibernate/orm/5.6/javadocs/",
"https://eclipse.dev/aspectj/doc/released/aspectj5rt-api",
"https://www.quartz-scheduler.org/api/2.3.0/",
+1 -1
View File
@@ -1,2 +1,2 @@
org.gradle.caching=true
javaFormatVersion=0.0.41
javaFormatVersion=0.0.42
@@ -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.13.0");
checkstyle.setToolVersion("10.17.0");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
@@ -64,7 +64,7 @@ public class CheckstyleConventions {
NoHttpExtension noHttp = project.getExtensions().getByType(NoHttpExtension.class);
noHttp.setAllowlistFile(project.file("src/nohttp/allowlist.lines"));
noHttp.getSource().exclude("**/test-output/**", "**/.settings/**",
"**/.classpath", "**/.project", "**/.gradle/**");
"**/.classpath", "**/.project", "**/.gradle/**", "**/node_modules/**");
List<String> buildFolders = List.of("bin", "build", "out");
project.allprojects(subproject -> {
Path rootPath = project.getRootDir().toPath();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,8 +63,7 @@ class TestConventions {
test.systemProperty("testGroups", project.getProperties().get("testGroups"));
}
test.jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"-Djava.locale.providers=COMPAT");
"--add-opens=java.base/java.util=ALL-UNNAMED");
}
private void configureTestRetryPlugin(Project project, Test test) {
+2
View File
@@ -1,5 +1,7 @@
== Spring Framework Concourse pipeline
NOTE: CI is being migrated to GitHub Actions.
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.1.x[Spring Framework 6.1.x].
+10 -1
View File
@@ -17,4 +17,13 @@ changelog:
- "type: dependency-upgrade"
contributors:
exclude:
names: ["bclozel", "jhoeller", "poutsma", "rstoyanchev", "sbrannen", "sdeleuze", "snicoll", "simonbasle"]
names:
- "bclozel"
- "github-actions[bot]"
- "jhoeller"
- "poutsma"
- "rstoyanchev"
- "sbrannen"
- "sdeleuze"
- "simonbasle"
- "snicoll"
+1 -1
View File
@@ -7,6 +7,6 @@ RUN ./setup.sh
ENV JAVA_HOME /opt/openjdk/java17
ENV JDK17 /opt/openjdk/java17
ENV JDK21 /opt/openjdk/java21
ENV JDK22 /opt/openjdk/java22
ENV JDK23 /opt/openjdk/java23
ENV PATH $JAVA_HOME/bin:$PATH
+2 -2
View File
@@ -8,8 +8,8 @@ case "$1" in
java21)
echo "https://github.com/bell-sw/Liberica/releases/download/21.0.2%2B14/bellsoft-jdk21.0.2+14-linux-amd64.tar.gz"
;;
java22)
echo "https://download.java.net/java/early_access/jdk22/33/GPL/openjdk-22-ea+33_linux-x64_bin.tar.gz"
java23)
echo "https://download.java.net/java/early_access/jdk23/17/GPL/openjdk-23-ea+17_linux-x64_bin.tar.gz"
;;
*)
echo $"Unknown java version"
+1 -1
View File
@@ -20,7 +20,7 @@ curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/c
mkdir -p /opt/openjdk
pushd /opt/openjdk > /dev/null
for jdk in java17 java21 java22
for jdk in java17 java21 java23
do
JDK_URL=$( /get-jdk-url.sh $jdk )
mkdir $jdk
+1 -2
View File
@@ -3,9 +3,8 @@ github-repo-name: "spring-projects/spring-framework"
sonatype-staging-profile: "org.springframework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "main"
branch: "6.1.x"
milestone: "6.1.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
task-timeout: 1h00m
+28 -170
View File
@@ -5,12 +5,10 @@ anchors:
password: ((github-ci-release-token))
branch: ((branch))
gradle-enterprise-task-params: &gradle-enterprise-task-params
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
DEVELOCITY_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
sonatype-task-params: &sonatype-task-params
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_USERNAME: ((s01-user-token))
SONATYPE_PASSWORD: ((s01-user-token-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE: ((sonatype-staging-profile))
artifactory-task-params: &artifactory-task-params
@@ -23,14 +21,6 @@ anchors:
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
[$TEXT_FILE_CONTENT]
text_file: git-repo/build/build-scan-uri.txt
silent: true
icon_emoji: ":concourse:"
username: concourse-ci
changelog-task-params: &changelog-task-params
name: generated-changelog/tag
tag: generated-changelog/tag
@@ -64,12 +54,6 @@ resource_types:
<<: *docker-resource-source
repository: dpb587/github-status-resource
tag: master
- name: slack-notification
type: registry-image
source:
<<: *docker-resource-source
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
- name: git-repo
type: git
@@ -90,13 +74,6 @@ resources:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
tag: ((milestone))
- name: every-morning
type: time
icon: alarm
source:
start: 8:00 AM
stop: 9:00 AM
location: Europe/Vienna
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
@@ -105,35 +82,6 @@ resources:
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: build
- name: repo-status-jdk21-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk21-build
- name: repo-status-jdk22-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk22-build
- name: slack-alert
type: slack-notification
icon: slack
source:
url: ((slack-webhook-url))
- name: github-pre-release
type: github-release
icon: briefcase-download-outline
@@ -168,115 +116,6 @@ jobs:
- put: ci-image
params:
image: ci-image/image.tar
- name: build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
trigger: true
- put: repo-status-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
image: ci-image
file: git-repo/ci/tasks/build-project.yml
privileged: true
timeout: ((task-timeout))
params:
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-build
params: { state: "success", commit: "git-repo" }
- put: artifactory-repo
params: &artifactory-params
signing_key: ((signing-key))
signing_passphrase: ((signing-passphrase))
repo: libs-snapshot-local
folder: distribution-repository
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}"
disable_checksum_uploads: true
threads: 8
artifact_set:
- include:
- "/**/framework-api-*.zip"
properties:
"zip.name": "spring-framework"
"zip.displayname": "Spring Framework"
"zip.deployed": "false"
- include:
- "/**/framework-api-*-docs.zip"
properties:
"zip.type": "docs"
- include:
- "/**/framework-api-*-schema.zip"
properties:
"zip.type": "schema"
get_params:
threads: 8
- name: jdk21-build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk21-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
image: ci-image
file: git-repo/ci/tasks/check-project.yml
privileged: true
timeout: ((task-timeout))
params:
TEST_TOOLCHAIN: 21
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk21-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk21-build
params: { state: "success", commit: "git-repo" }
- name: jdk22-build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk22-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
image: ci-image
file: git-repo/ci/tasks/check-project.yml
privileged: true
timeout: ((task-timeout))
params:
TEST_TOOLCHAIN: 22
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk22-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk22-build
params: { state: "success", commit: "git-repo" }
- name: stage-milestone
serial: true
plan:
@@ -290,9 +129,32 @@ jobs:
RELEASE_TYPE: M
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
params: &artifactory-params
signing_key: ((signing-key))
signing_passphrase: ((signing-passphrase))
repo: libs-staging-local
folder: distribution-repository
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}"
disable_checksum_uploads: true
threads: 8
artifact_set:
- include:
- "/**/framework-api-*.zip"
properties:
"zip.name": "spring-framework"
"zip.displayname": "Spring Framework"
"zip.deployed": "false"
- include:
- "/**/framework-api-*-docs.zip"
properties:
"zip.type": "docs"
- include:
- "/**/framework-api-*-schema.zip"
properties:
"zip.type": "schema"
get_params:
threads: 8
- put: git-repo
params:
repository: stage-git-repo
@@ -337,7 +199,6 @@ jobs:
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
@@ -382,7 +243,6 @@ jobs:
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
@@ -427,8 +287,6 @@ jobs:
<<: *changelog-task-params
groups:
- name: "builds"
jobs: ["build", "jdk21-build", "jdk22-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21 \
--no-daemon --max-workers=4 check
popd > /dev/null
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21,JDK22 \
--no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
popd > /dev/null
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21,JDK22 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check antora
popd > /dev/null
-19
View File
@@ -1,19 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/build-pr.sh
-22
View File
@@ -1,22 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/build-project.sh
-24
View File
@@ -1,24 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
MAIN_TOOLCHAIN:
TEST_TOOLCHAIN:
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/check-project.sh
+39
View File
@@ -0,0 +1,39 @@
antora:
extensions:
- require: '@springio/antora-extensions'
root_component_name: 'framework'
site:
title: Spring Framework
url: https://docs.spring.io/spring-framework/reference
robots: allow
git:
ensure_git_suffix: false
content:
sources:
- url: https://github.com/spring-projects/spring-framework
# Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
branches: ['main', '{6..9}.+({0..9}).x']
tags: ['v{6..9}.+({0..9}).+({0..9})?(-{RC,M}*)', '!(v6.0.{0..8})', '!(v6.0.0-{RC,M}{0..9})']
start_path: framework-docs
asciidoc:
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@springio/asciidoctor-extensions/include-code-extension'
attributes:
page-stackoverflow-url: https://stackoverflow.com/questions/tagged/spring
page-pagination: ''
hide-uri-scheme: '@'
tabs-sync-option: '@'
include-java: 'example$docs-src/main/java/org/springframework/docs'
urls:
latest_version_segment_strategy: redirect:to
latest_version_segment: ''
redirect_facility: httpd
runtime:
log:
failure_level: warn
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.16/ui-bundle.zip
+3 -20
View File
@@ -10,27 +10,10 @@ apply from: "${rootDir}/gradle/ide.gradle"
apply from: "${rootDir}/gradle/publications.gradle"
antora {
version = '3.2.0-alpha.2'
playbook = 'cached-antora-playbook.yml'
playbookProvider {
repository = 'spring-projects/spring-framework'
branch = 'docs-build'
path = 'lib/antora/templates/per-branch-antora-playbook.yml'
checkLocalBranch = true
}
options = ['--clean', '--stacktrace']
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
environment = [
'ALGOLIA_API_KEY': '82c7ead946afbac3cf98c32446154691',
'ALGOLIA_APP_ID': '244V8V9FGG',
'ALGOLIA_INDEX_NAME': 'framework-docs'
]
dependencies = [
'@antora/atlas-extension': '1.0.0-alpha.1',
'@antora/collector-extension': '1.0.0-alpha.3',
'@asciidoctor/tabs': '1.0.0-beta.3',
'@opendevise/antora-release-line-extension': '1.0.0',
'@springio/antora-extensions': '1.8.2',
'@springio/asciidoctor-extensions': '1.0.0-alpha.9'
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
]
}
+3 -2
View File
@@ -39,8 +39,8 @@
** xref:core/resources.adoc[]
** xref:core/validation.adoc[]
*** xref:core/validation/validator.adoc[]
*** xref:core/validation/conversion.adoc[]
*** xref:core/validation/beans-beans.adoc[]
*** xref:core/validation/conversion.adoc[]
*** xref:core/validation/convert.adoc[]
*** xref:core/validation/format.adoc[]
*** xref:core/validation/format-configuring-formatting-globaldatetimeformat.adoc[]
@@ -439,4 +439,5 @@
** xref:languages/groovy.adoc[]
** xref:languages/dynamic.adoc[]
* xref:appendix.adoc[]
* {spring-framework-wiki}[Wiki]
* {spring-framework-wiki}[Wiki]
@@ -221,8 +221,8 @@ NOTE: `ThreadLocal` instances come with serious issues (potentially resulting in
incorrectly using them in multi-threaded and multi-classloader environments. You
should always consider wrapping a `ThreadLocal` in some other class and never directly use
the `ThreadLocal` itself (except in the wrapper class). Also, you should
always remember to correctly set and unset (where the latter simply involves a call to
`ThreadLocal.set(null)`) the resource local to the thread. Unsetting should be done in
always remember to correctly set and unset (where the latter involves a call to
`ThreadLocal.remove()`) the resource local to the thread. Unsetting should be done in
any case, since not unsetting it might result in problematic behavior. Spring's
`ThreadLocal` support does this for you and should always be considered in favor of using
`ThreadLocal` instances without other proper handling code.
@@ -19,6 +19,10 @@ you can do so. However, you should consider the following issues:
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
`--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
of the `<aop:config>` element to true, as follows:
@@ -15,7 +15,7 @@ Applying such optimizations early implies the following restrictions:
* The classpath is fixed and fully defined at build time.
* The beans defined in your application cannot change at runtime, meaning:
** `@Profile`, in particular profile-specific configuration needs to be chosen at build time.
** `@Profile`, in particular profile-specific configuration, needs to be chosen at build time and is automatically enabled at runtime when AOT is enabled.
** `Environment` properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
* Bean definitions with instance suppliers (lambdas or method references) cannot be transformed ahead-of-time.
* Beans registered as singletons (using `registerSingleton`, typically from
@@ -152,8 +152,23 @@ Java::
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@Configuration(proxyBeanMethods = false)
class DataSourceConfiguration {
@Bean
fun dataSource() = SimpleDataSource()
}
----
======
WARNING: Kotlin class names with backticks that use invalid Java identifiers (not starting with a letter, containing spaces, etc.) are not supported.
Since there isn't any particular condition on this class, `dataSourceConfiguration` and `dataSource` are identified as candidates.
The AOT engine will convert the configuration class above to code similar to the following:
@@ -209,6 +224,17 @@ There is a bean definition for `dataSourceConfiguration` and one for `dataSource
When a `datasource` instance is required, a `BeanInstanceSupplier` is called.
This supplier invokes the `dataSource()` method on the `dataSourceConfiguration` bean.
[[aot.running]]
== Running with AOT optimizations
AOT is a mandatory step to transform a Spring application to a native executable, so it
is automatically enabled when running in this mode. It is possible to use those optimizations
on the JVM by setting the `spring.aot.enabled` System property to `true`.
NOTE: When AOT optimizations are included, some decisions that have been taken at build-time
are hard-coded in the application setup. For instance, profiles that have been enabled at
build-time are automatically enabled at runtime as well.
[[aot.bestpractices]]
== Best Practices
@@ -300,6 +326,32 @@ However, this is not a best practice and flagging the preferred constructor with
In case you are working on a code base that you cannot modify, you can set the {spring-framework-api}/beans/factory/support/AbstractBeanDefinition.html#PREFERRED_CONSTRUCTORS_ATTRIBUTE[`preferredConstructors` attribute] on the related bean definition to indicate which constructor should be used.
[[aot.bestpractices.comlext-data-structure]]
=== Avoid Complex Data Structure for Constructor Parameters and Properties
When crafting a `RootBeanDefinition` programmatically, you are not constrained in terms of types that you can use.
For instance, you may have a custom `record` with several properties that your bean takes as a constructor argument.
While this works fine with the regular runtime, AOT does not know how to generate the code of your custom data structure.
A good rule of thumb is to keep in mind that bean definitions are an abstraction on top of several models.
Rather than using such structure, decomposing to simple types or referring to a bean that is built as such is recommended.
As a last resort, you can implement your own `org.springframework.aot.generate.ValueCodeGenerator$Delegate`.
To use it, register its fully qualified name in `META-INF/spring/aot.factories` using the `Delegate` as the key.
[[aot.bestpractices.custom-arguments]]
=== Avoid Creating Bean with Custom Arguments
Spring AOT detects what needs to be done to create a bean and translates that in generated code using an instance supplier.
The container also supports creating a bean with {spring-framework-api}++/beans/factory/BeanFactory.html#getBean(java.lang.String,java.lang.Object...)++[custom arguments] that leads to several issues with AOT:
. The custom arguments require dynamic introspection of a matching constructor or factory method.
Those arguments cannot be detected by AOT, so the necessary reflection hints will have to be provided manually.
. By-passing the instance supplier means that all other optimizations after creation are skipped as well.
For instance, autowiring on fields and methods will be skipped as they are handled in the instance supplier.
Rather than having prototype-scoped beans created with custom arguments, we recommend a manual factory pattern where a bean is responsible for the creation of the instance.
[[aot.bestpractices.factory-bean]]
=== FactoryBean
@@ -1,33 +1,16 @@
[[beans-annotation-config]]
= Annotation-based Container Configuration
.Are annotations better than XML for configuring Spring?
****
The introduction of annotation-based configuration raised the question of whether this
approach is "`better`" than XML. The short answer is "`it depends.`" The long answer is
that each approach has its pros and cons, and, usually, it is up to the developer to
decide which strategy suits them better. Due to the way they are defined, annotations
provide a lot of context in their declaration, leading to shorter and more concise
configuration. However, XML excels at wiring up components without touching their source
code or recompiling them. Some developers prefer having the wiring close to the source
while others argue that annotated classes are no longer POJOs and, furthermore, that the
configuration becomes decentralized and harder to control.
Spring provides comprehensive support for annotation-based configuration, operating on
metadata in the component class itself by using annotations on the relevant class,
method, or field declaration. As mentioned in
xref:core/beans/factory-extension.adoc#beans-factory-extension-bpp-examples-aabpp[Example: The `AutowiredAnnotationBeanPostProcessor`],
Spring uses `BeanPostProcessors` in conjunction with annotations to make the core IOC
container aware of specific annotations.
No matter the choice, Spring can accommodate both styles and even mix them together.
It is worth pointing out that through its xref:core/beans/java.adoc[JavaConfig] option, Spring lets
annotations be used in a non-invasive way, without touching the target components'
source code and that, in terms of tooling, all configuration styles are supported by
{spring-site-tools}[Spring Tools] for Eclipse, Visual Studio Code, and Theia.
****
An alternative to XML setup is provided by annotation-based configuration, which relies
on bytecode metadata for wiring up components instead of XML declarations. Instead of
using XML to describe a bean wiring, the developer moves the configuration into the
component class itself by using annotations on the relevant class, method, or field
declaration. As mentioned in xref:core/beans/factory-extension.adoc#beans-factory-extension-bpp-examples-aabpp[Example: The `AutowiredAnnotationBeanPostProcessor`], using a
`BeanPostProcessor` in conjunction with annotations is a common means of extending the
Spring IoC container. For example, the xref:core/beans/annotation-config/autowired.adoc[`@Autowired`]
annotation provides the same capabilities as described in xref:core/beans/dependencies/factory-autowire.adoc[Autowiring Collaborators] but
For example, the xref:core/beans/annotation-config/autowired.adoc[`@Autowired`]
annotation provides the same capabilities as described in
xref:core/beans/dependencies/factory-autowire.adoc[Autowiring Collaborators] but
with more fine-grained control and wider applicability. In addition, Spring provides
support for JSR-250 annotations, such as `@PostConstruct` and `@PreDestroy`, as well as
support for JSR-330 (Dependency Injection for Java) annotations contained in the
@@ -36,13 +19,16 @@ can be found in the xref:core/beans/standard-annotations.adoc[relevant section].
[NOTE]
====
Annotation injection is performed before XML injection. Thus, the XML configuration
overrides the annotations for properties wired through both approaches.
Annotation injection is performed before external property injection. Thus, external
configuration (e.g. XML-specified bean properties) effectively overrides the annotations
for properties when wired through mixed approaches.
====
As always, you can register the post-processors as individual bean definitions, but they
can also be implicitly registered by including the following tag in an XML-based Spring
configuration (notice the inclusion of the `context` namespace):
Technically, you can register the post-processors as individual bean definitions, but they
are implicitly registered in an `AnnotationConfigApplicationContext` already.
In an XML-based Spring setup, you may include the following configuration tag to enable
mixing and matching with annotation-based configuration:
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -153,17 +153,15 @@ Letting qualifier values select against target bean names, within the type-match
candidates, does not require a `@Qualifier` annotation at the injection point.
If there is no other resolution indicator (such as a qualifier or a primary marker),
for a non-unique dependency situation, Spring matches the injection point name
(that is, the field name or parameter name) against the target bean names and chooses the
same-named candidate, if any.
(that is, the field name or parameter name) against the target bean names and chooses
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.
====
That said, if you intend to express annotation-driven injection by name, do not
primarily use `@Autowired`, even if it is capable of selecting by bean name among
type-matching candidates. Instead, use 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
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`
qualifier value is considered within those type-selected candidates only (for example,
matching an `account` qualifier against beans marked with the same qualifier label).
@@ -186,6 +186,15 @@ 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).
====
[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.
====
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
expects an array of that type, as the following example shows:
@@ -268,6 +277,12 @@ use the same bean class). `@Order` values may influence priorities at injection
but be aware that they do not influence singleton startup order, which is an
orthogonal concern determined by dependency relationships and `@DependsOn` declarations.
Note that `@Order` annotations on configuration classes just influence the evaluation
order within the overall set of configuration classes on startup. Such configuration-level
order values do not affect the contained `@Bean` methods at all. For bean-level ordering,
each `@Bean` method needs to have its own `@Order` annotation which applies within a
set of multiple matches for the specific bean type (as returned by the factory method).
Note that the standard `jakarta.annotation.Priority` annotation is not available at the
`@Bean` level, since it cannot be declared on methods. Its semantics can be modeled
through `@Order` values in combination with `@Primary` on a single bean for each type.
@@ -2,36 +2,28 @@
= Container Overview
The `org.springframework.context.ApplicationContext` interface represents the Spring IoC
container and is responsible for instantiating, configuring, and assembling the
beans. The container gets its instructions on what objects to
instantiate, configure, and assemble by reading configuration metadata. The
configuration metadata is represented in XML, Java annotations, or Java code. It lets
you express the objects that compose your application and the rich interdependencies
between those objects.
container and is responsible for instantiating, configuring, and assembling the beans.
The container gets its instructions on the components to instantiate, configure, and
assemble by reading configuration metadata. The configuration metadata can be represented
as annotated component classes, configuration classes with factory methods, or external
XML files or Groovy scripts. With either format, you may compose your application and the
rich interdependencies between those components.
Several implementations of the `ApplicationContext` interface are supplied
with Spring. In stand-alone applications, it is common to create an
instance of
{spring-framework-api}/context/support/ClassPathXmlApplicationContext.html[`ClassPathXmlApplicationContext`]
or {spring-framework-api}/context/support/FileSystemXmlApplicationContext.html[`FileSystemXmlApplicationContext`].
While XML has been the traditional format for defining configuration metadata, you can
instruct the container to use Java annotations or code as the metadata format by
providing a small amount of XML configuration to declaratively enable support for these
additional metadata formats.
Several implementations of the `ApplicationContext` interface are part of core Spring.
In stand-alone applications, it is common to create an instance of
{spring-framework-api}/context/annotation/AnnotationConfigApplicationContext.html[`AnnotationConfigApplicationContext`]
or {spring-framework-api}/context/support/ClassPathXmlApplicationContext.html[`ClassPathXmlApplicationContext`].
In most application scenarios, explicit user code is not required to instantiate one or
more instances of a Spring IoC container. For example, in a web application scenario, a
simple eight (or so) lines of boilerplate web descriptor XML in the `web.xml` file
of the application typically suffices (see
more instances of a Spring IoC container. For example, in a plain web application scenario,
a simple boilerplate web descriptor XML in the `web.xml` file of the application suffices (see
xref:core/beans/context-introduction.adoc#context-create[Convenient ApplicationContext Instantiation for Web Applications]).
If you use the {spring-site-tools}[Spring Tools for Eclipse] (an Eclipse-powered
development environment), you can easily create this boilerplate configuration with a
few mouse clicks or keystrokes.
In a Spring Boot scenario, the application context is implicitly bootstrapped for you
based on common setup conventions.
The following diagram shows a high-level view of how Spring works. Your application classes
are combined with configuration metadata so that, after the `ApplicationContext` is
created and initialized, you have a fully configured and executable system or
application.
created and initialized, you have a fully configured and executable system or application.
.The Spring IoC container
image::container-magic.png[]
@@ -43,33 +35,25 @@ image::container-magic.png[]
As the preceding diagram shows, the Spring IoC container consumes a form of
configuration metadata. This configuration metadata represents how you, as an
application developer, tell the Spring container to instantiate, configure, and assemble
the objects in your application.
application developer, tell the Spring container to instantiate, configure,
and assemble the components in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format,
which is what most of this chapter uses to convey key concepts and features of the
Spring IoC container.
NOTE: XML-based metadata is not the only allowed form of configuration metadata.
The Spring IoC container itself is totally decoupled from the format in which this
configuration metadata is actually written. These days, many developers choose
xref:core/beans/java.adoc[Java-based configuration] for their Spring applications.
For information about using other forms of metadata with the Spring container, see:
xref:core/beans/java.adoc[Java-based configuration] for their Spring applications:
* xref:core/beans/annotation-config.adoc[Annotation-based configuration]: define beans using
annotation-based configuration metadata.
annotation-based configuration metadata on your application's component classes.
* xref:core/beans/java.adoc[Java-based configuration]: define beans external to your application
classes by using Java rather than XML files. To use these features, see the
classes by using Java-based configuration classes. To use these features, see the
{spring-framework-api}/context/annotation/Configuration.html[`@Configuration`],
{spring-framework-api}/context/annotation/Bean.html[`@Bean`],
{spring-framework-api}/context/annotation/Import.html[`@Import`],
and {spring-framework-api}/context/annotation/DependsOn.html[`@DependsOn`] annotations.
Spring configuration consists of at least one and typically more than one bean
definition that the container must manage. XML-based configuration metadata configures these
beans as `<bean/>` elements inside a top-level `<beans/>` element. Java
configuration typically uses `@Bean`-annotated methods within a `@Configuration` class.
Spring configuration consists of at least one and typically more than one bean definition
that the container must manage. Java configuration typically uses `@Bean`-annotated
methods within a `@Configuration` class, each corresponding to one bean definition.
These bean definitions correspond to the actual objects that make up your application.
Typically, you define service layer objects, persistence layer objects such as
@@ -79,7 +63,14 @@ Typically, one does not configure fine-grained domain objects in the container,
it is usually the responsibility of repositories and business logic to create and load
domain objects.
The following example shows the basic structure of XML-based configuration metadata:
[[beans-factory-xml]]
=== XML as an External Configuration DSL
XML-based configuration metadata configures these beans as `<bean/>` elements inside
a top-level `<beans/>` element. The following example shows the basic structure of
XML-based configuration metadata:
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -110,14 +101,9 @@ The value of the `id` attribute can be used to refer to collaborating objects. T
for referring to collaborating objects is not shown in this example. See
xref:core/beans/dependencies.adoc[Dependencies] for more information.
[[beans-factory-instantiation]]
== Instantiating a Container
The location path or paths
supplied to an `ApplicationContext` constructor are resource strings that let
the container load configuration metadata from a variety of external resources, such
For instantiating a container, the location path or paths to the XML resource files
need to be supplied to a `ClassPathXmlApplicationContext` constructor that let the
container load configuration metadata from a variety of external resources, such
as the local file system, the Java `CLASSPATH`, and so on.
[tabs]
@@ -209,9 +195,9 @@ xref:core/beans/dependencies.adoc[Dependencies].
It can be useful to have bean definitions span multiple XML files. Often, each individual
XML configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these
You can use the `ClassPathXmlApplicationContext` constructor to load bean definitions from
XML fragments. This constructor takes multiple `Resource` locations, as was shown in the
xref:core/beans/basics.adoc#beans-factory-instantiation[previous section]. Alternatively,
xref:core/beans/basics.adoc#beans-factory-xml[previous section]. Alternatively,
use one or more occurrences of the `<import/>` element to load bean definitions from
another file or files. The following example shows how to do so:
@@ -259,7 +245,7 @@ configuration features beyond plain bean definitions are available in a selectio
of XML namespaces provided by Spring -- for example, the `context` and `util` namespaces.
[[groovy-bean-definition-dsl]]
[[beans-factory-groovy]]
=== The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also
@@ -420,4 +406,3 @@ a dependency on a specific bean through metadata (such as an autowiring annotati
@@ -75,6 +75,31 @@ 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.
To disable bean overriding altogether, you can set the `allowBeanDefinitionOverriding`
flag to `false` on the `ApplicationContext` before it is refreshed. In such 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`.
.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
`@Bean` method matches that bean class. This simply means that the container will call
the `@Bean` factory method in favor of any pre-declared constructor on the bean class.
****
[[beans-beanname]]
== Naming Beans
@@ -234,6 +259,10 @@ For details about the mechanism for supplying arguments to the constructor (if r
and setting object instance properties after the object is constructed, see
xref:core/beans/dependencies/factory-collaborators.adoc[Injecting Dependencies].
NOTE: In the case of constructor arguments, the container can select a corresponding
constructor among several overloaded constructors. That said, to avoid ambiguities,
it is recommended to keep your constructor signatures as straightforward as possible.
[[beans-factory-class-static-factory-method]]
=== Instantiation with a Static Factory Method
@@ -294,6 +323,24 @@ For details about the mechanism for supplying (optional) arguments to the factor
and setting object instance properties after the object is returned from the factory,
see xref:core/beans/dependencies/factory-properties-detailed.adoc[Dependencies and Configuration in Detail].
NOTE: In the case of factory method arguments, the container can select a corresponding
method among several overloaded methods of the same name. That said, to avoid ambiguities,
it is recommended to keep your factory method signatures as straightforward as possible.
[TIP]
====
A typical problematic case with factory method overloading is Mockito with its many
overloads of the `mock` method. Choose the most specific variant of `mock` possible:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="clientService" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg type="java.lang.Class" value="examples.ClientService"/>
<constructor-arg type="java.lang.String" value="clientService"/>
</bean>
----
====
[[beans-factory-class-instance-factory-method]]
=== Instantiation by Using an Instance Factory Method
@@ -416,8 +463,8 @@ Kotlin::
======
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See xref:core/beans/dependencies/factory-properties-detailed.adoc[Dependencies and Configuration in Detail]
.
dependency injection (DI).
See xref:core/beans/dependencies/factory-properties-detailed.adoc[Dependencies and Configuration in Detail].
NOTE: In Spring documentation, "factory bean" refers to a bean that is configured in the
Spring container and that creates objects through an
@@ -444,5 +491,3 @@ cases into account and returns the type of object that a `BeanFactory.getBean` c
going to return for the same bean name.
@@ -201,7 +201,7 @@ the original class. Consider the following example:
<!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<!-- commandManager uses myCommand prototype bean -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="myCommand"/>
</bean>
@@ -439,7 +439,7 @@ dataSource.url=jdbc:mysql:mydb
----
This example file can be used with a container definition that contains a bean called
`dataSource` that has `driver` and `url` properties.
`dataSource` that has `driverClassName` and `url` properties.
Compound property names are also supported, as long as every component of the path
except the final property being overridden is already non-null (presumably initialized
@@ -55,33 +55,34 @@ The preceding `AppConfig` class is equivalent to the following Spring `<beans/>`
</beans>
----
.Full @Configuration vs "`lite`" @Bean mode?
.@Configuration classes with or without local calls between @Bean methods?
****
When `@Bean` methods are declared within classes that are not annotated with
`@Configuration`, they are referred to as being processed in a "`lite`" mode. Bean methods
declared on a bean that is not annotated with `@Configuration` are considered to be "`lite`",
with a different primary purpose of the containing class and a `@Bean` method
being a sort of bonus there. For example, service components may expose management views
to the container through an additional `@Bean` method on each applicable component class.
In such scenarios, `@Bean` methods are a general-purpose factory method mechanism.
Unlike full `@Configuration`, lite `@Bean` methods cannot declare inter-bean dependencies.
Instead, they operate on their containing component's internal state and, optionally, on
arguments that they may declare. Such a `@Bean` method should therefore not invoke other
`@Bean` methods. Each such method is literally only a factory method for a particular
bean reference, without any special runtime semantics. The positive side-effect here is
that no CGLIB subclassing has to be applied at runtime, so there are no limitations in
terms of class design (that is, the containing class may be `final` and so forth).
In common scenarios, `@Bean` methods are to be declared within `@Configuration` classes,
ensuring that "`full`" mode is always used and that cross-method references therefore
get redirected to the container's lifecycle management. This prevents the same
`@Bean` method from accidentally being invoked through a regular Java call, which helps
to reduce subtle bugs that can be hard to track down when operating in "`lite`" mode.
ensuring that full configuration class processing applies and that cross-method
references therefore get redirected to the container's lifecycle management.
This prevents the same `@Bean` method from accidentally being invoked through a regular
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 -,
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).
A custom Java call to such a method will not get intercepted by the container and
therefore behaves just like a regular method call, creating a new instance every time
rather than reusing an existing singleton (or scoped) instance for the given bean.
As a consequence, `@Bean` methods on classes without runtime proxying are not meant to
declare inter-bean dependencies at all. Instead, they are expected to operate on their
containing component's fields and, optionally, on arguments that a factory method may
declare in order to receive autowired collaborators. Such a `@Bean` method therefore
never needs to invoke other `@Bean` methods; every such call can be expressed through
a factory method argument instead. The positive side-effect here is that no CGLIB
subclassing has to be applied at runtime, reducing the overhead and the footprint.
****
The `@Bean` and `@Configuration` annotations are discussed in depth in the following sections.
First, however, we cover the various ways of creating a spring container by using
First, however, we cover the various ways of creating a Spring container by using
Java-based configuration.
@@ -518,6 +518,7 @@ following kinds of expressions cannot be compiled.
* Expressions relying on the conversion service
* Expressions using custom resolvers or accessors
* Expressions using overloaded operators
* Expressions using array construction syntax
* Expressions using selection or projection
Compilation of additional kinds of expressions may be supported in the future.
@@ -13,7 +13,7 @@ Java::
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
int[] numbers2 = (int[]) parser.parseExpression("new int[] {1, 2, 3}").getValue(context);
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
@@ -26,14 +26,22 @@ Kotlin::
val numbers1 = parser.parseExpression("new int[4]").getValue(context) as IntArray
// Array with initializer
val numbers2 = parser.parseExpression("new int[]{1,2,3}").getValue(context) as IntArray
val numbers2 = parser.parseExpression("new int[] {1, 2, 3}").getValue(context) as IntArray
// Multi dimensional array
val numbers3 = parser.parseExpression("new int[4][5]").getValue(context) as Array<IntArray>
----
======
[NOTE]
====
You cannot currently supply an initializer when you construct a multi-dimensional array.
====
[CAUTION]
====
Any expression that constructs an array for example, via `new int[4]` or
`new int[] {1, 2, 3}` cannot be compiled. See
xref:core/expressions/evaluation.adoc#expressions-compiler-limitations[Compiler Limitations]
for details.
====
@@ -20,6 +20,15 @@ characters.
* dollar sign: `$`
====
[TIP]
====
When setting a variable or root context object in the `EvaluationContext`, it is advised
that the type of the variable or root context object be `public`.
Otherwise, certain types of SpEL expressions involving a variable or root context object
with a non-public type may fail to evaluate or compile.
====
[WARNING]
====
Since variables share a common namespace with
@@ -299,7 +299,7 @@ Java::
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
public static MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
@@ -341,7 +341,7 @@ xref:web/webflux/ann-rest-exceptions.adoc[Error Responses] sections.
=== Method Validation Exceptions
By default, `jakarta.validation.ConstraintViolationException` is raised with the set of
``ConstraintViolation``s returned by `jakarata.validation.Validator`. As an alternative,
``ConstraintViolation``s returned by `jakarta.validation.Validator`. As an alternative,
you can have `MethodValidationException` raised instead with ``ConstraintViolation``s
adapted to `MessageSourceResolvable` errors. To enable set the following flag:
@@ -357,7 +357,7 @@ Java::
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
public static MethodValidationPostProcessor validationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setAdaptConstraintViolations(true);
return processor;
@@ -211,19 +211,28 @@ the JDBC driver. If the count is not available, the JDBC driver returns a value
====
In such a scenario, with automatic setting of values on an underlying `PreparedStatement`,
the corresponding JDBC type for each value needs to be derived from the given Java type.
While this usually works well, there is a potential for issues (for example, with Map-contained
`null` values). Spring, by default, calls `ParameterMetaData.getParameterType` in such a
case, which can be expensive with your JDBC driver. You should use a recent driver
While this usually works well, there is a potential for issues (for example, with
Map-contained `null` values). Spring, by default, calls `ParameterMetaData.getParameterType`
in such a case, which can be expensive with your JDBC driver. You should use a recent driver
version and consider setting the `spring.jdbc.getParameterType.ignore` property to `true`
(as a JVM system property or via the
xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism) if you encounter
a performance issue (as reported on Oracle 12c, JBoss, and PostgreSQL).
xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism)
if you encounter a specific performance issue for your application.
Alternatively, you might consider specifying the corresponding JDBC types explicitly,
either through a `BatchPreparedStatementSetter` (as shown earlier), through an explicit type
array given to a `List<Object[]>` based call, through `registerSqlType` calls on a
custom `MapSqlParameterSource` instance, or through a `BeanPropertySqlParameterSource`
that derives the SQL type from the Java-declared property type even for a null value.
As of 6.1.2, Spring bypasses the default `getParameterType` resolution on PostgreSQL and
MS SQL Server. This is a common optimization to avoid further roundtrips to the DBMS just
for parameter type resolution which is known to make a very significant difference on
PostgreSQL and MS SQL Server specifically, in particular for batch operations. If you
happen to see a side effect e.g. when setting a byte array to null without specific type
indication, you may explicitly set the `spring.jdbc.getParameterType.ignore=false` flag
as a system property (see above) to restore full `getParameterType` resolution.
Alternatively, you could consider specifying the corresponding JDBC types explicitly,
either through a `BatchPreparedStatementSetter` (as shown earlier), through an explicit
type array given to a `List<Object[]>` based call, through `registerSqlType` calls on a
custom `MapSqlParameterSource` instance, through a `BeanPropertySqlParameterSource`
that derives the SQL type from the Java-declared property type even for a null value, or
through providing individual `SqlParameterValue` instances instead of plain null values.
====
@@ -112,7 +112,7 @@ Java::
this.actorMappingQuery = new ActorMappingQuery(dataSource);
}
public Customer getCustomer(Long id) {
public Actor getActor(Long id) {
return actorMappingQuery.findObject(id);
}
----
@@ -123,11 +123,11 @@ Kotlin::
----
private val actorMappingQuery = ActorMappingQuery(dataSource)
fun getCustomer(id: Long) = actorMappingQuery.findObject(id)
fun getActor(id: Long) = actorMappingQuery.findObject(id)
----
======
The method in the preceding example retrieves the customer with the `id` that is passed in as the
The method in the preceding example retrieves the actor with the `id` that is passed in as the
only parameter. Since we want only one object to be returned, we call the `findObject` convenience
method with the `id` as the parameter. If we had instead a query that returned a
list of objects and took additional parameters, we would use one of the `execute`
@@ -268,8 +268,8 @@ The actual JPA provider bootstrapping is handed off to the specified executor an
running in parallel, to the application bootstrap thread. The exposed `EntityManagerFactory`
proxy can be injected into other application components and is even able to respond to
`EntityManagerFactoryInfo` configuration inspection. However, once the actual JPA provider
is being accessed by other components (for example, calling `createEntityManager`), those calls
block until the background bootstrapping has completed. In particular, when you use
is being accessed by other components (for example, calling `createEntityManager`), those
calls block until the background bootstrapping has completed. In particular, when you use
Spring Data JPA, make sure to set up deferred bootstrapping for its repositories as well.
@@ -284,9 +284,9 @@ to a newly created `EntityManager` per operation, in effect making its usage thr
It is possible to write code against the plain JPA without any Spring dependencies, by
using an injected `EntityManagerFactory` or `EntityManager`. Spring can understand the
`@PersistenceUnit` and `@PersistenceContext` annotations both at the field and the method level
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain
JPA DAO implementation that uses the `@PersistenceUnit` annotation:
`@PersistenceUnit` and `@PersistenceContext` annotations both at the field and the method
level if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example
shows a plain JPA DAO implementation that uses the `@PersistenceUnit` annotation:
[tabs]
======
@@ -74,10 +74,11 @@ Kotlin::
----
======
Used at the class level as above, the annotation indicates a default for all methods of
the declaring class (as well as its subclasses). Alternatively, each method can be
annotated individually. See xref:data-access/transaction/declarative/annotations.adoc#transaction-declarative-annotations-method-visibility[method visibility] for
further details on which methods Spring considers transactional. Note that a class-level
Used at the class level as above, the annotation indicates a default for all methods
of the declaring class (as well as its subclasses). Alternatively, each method can be
annotated individually. See
xref:data-access/transaction/declarative/annotations.adoc#transaction-declarative-annotations-method-visibility[method visibility]
for further details on which methods Spring considers transactional. Note that a class-level
annotation does not apply to ancestor classes up the class hierarchy; in such a scenario,
inherited methods need to be locally redeclared in order to participate in a
subclass-level annotation.
@@ -436,9 +437,10 @@ properties of the `@Transactional` annotation:
| Optional array of exception name patterns that must not cause rollback.
|===
TIP: See xref:data-access/transaction/declarative/rolling-back.adoc#transaction-declarative-rollback-rules[Rollback rules] for further details
on rollback rule semantics, patterns, and warnings regarding possible unintentional
matches for pattern-based rollback rules.
TIP: See
xref:data-access/transaction/declarative/rolling-back.adoc#transaction-declarative-rollback-rules[Rollback rules]
for further details on rollback rule semantics, patterns, and warnings
regarding possible unintentional matches for pattern-based rollback rules.
Currently, you cannot have explicit control over the name of a transaction, where 'name'
means the transaction name that appears in a transaction monitor and in logging output.
@@ -23,9 +23,9 @@ As of Spring Framework 5.2, the default configuration also provides support for
Vavr's `Try` method to trigger transaction rollbacks when it returns a 'Failure'.
This allows you to handle functional-style errors using Try and have the transaction
automatically rolled back in case of a failure. For more information on Vavr's Try,
refer to the [official Vavr documentation](https://www.vavr.io/vavr-docs/#_try).
refer to the https://docs.vavr.io/#_try[official Vavr documentation].
Here's an example of how to use Vavr's Try with a transactional method:
[tabs]
======
Java::
@@ -42,6 +42,32 @@ Java::
----
======
As of Spring Framework 6.1, there is also special treatment of `CompletableFuture`
(and general `Future`) return values, triggering a rollback for such a handle if it
was exceptionally completed at the time of being returned from the original method.
This is intended for `@Async` methods where the actual method implementation may
need to comply with a `CompletableFuture` signature (auto-adapted to an actual
asynchronous handle for a call to the proxy by `@Async` processing at runtime),
preferring exposure in the returned handle rather than rethrowing an exception:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@Transactional @Async
public CompletableFuture<String> myTransactionalMethod() {
try {
return CompletableFuture.completedFuture(delegate.myDataAccessOperation());
}
catch (DataAccessException ex) {
return CompletableFuture.failedFuture(ex);
}
}
----
======
Checked exceptions that are thrown from a transactional method do not result in a rollback
in the default configuration. You can configure exactly which `Exception` types mark a
transaction for rollback, including checked exceptions by specifying _rollback rules_.
+1 -3
View File
@@ -29,8 +29,6 @@ Brannen, Ramnivas Laddad, Arjen Poutsma, Chris Beams, Tareq Abedrabbo, Andy Clem
Syer, Oliver Gierke, Rossen Stoyanchev, Phillip Webb, Rob Winch, Brian Clozel, Stephane
Nicoll, Sebastien Deleuze, Jay Bryant, Mark Paluch
Copyright © 2002 - 2024 VMware, Inc. All Rights Reserved.
Copies of this document may be made for your own use and for distribution to others,
provided that you do not charge any fee for such copies and further provided that each
copy contains this Copyright Notice, whether distributed in print or electronically.
copy contains the Copyright Notice, whether distributed in print or electronically.
@@ -24,7 +24,7 @@ To create the archive, two additional JVM flags must be specified:
* `-Dspring.context.exit=onRefresh`: starts and then immediately exits your Spring
application as described above
To create a CDS archive, your JDK must have a base image. If you add the flags above to
To create a CDS archive, your JDK/JRE must have a base image. If you add the flags above to
your startup script, you may get a warning that looks like this:
[source,shell,indent=0,subs="verbatim"]
@@ -32,7 +32,8 @@ your startup script, you may get a warning that looks like this:
-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info.
----
The base CDS archive can be created by issuing the following command:
The base CDS archive is usually provided out-of-the-box, but can also be created if needed by issuing the following
command:
[source,shell,indent=0,subs="verbatim"]
----
@@ -44,6 +45,9 @@ The base CDS archive can be created by issuing the following command:
Once the archive is available, add `-XX:SharedArchiveFile=application.jsa` to your startup
script to use it, assuming an `application.jsa` file in the working directory.
To check if the CDS cache is effective, you can use (for testing purposes only, not in production) `-Xshare:on` which
prints an error message and exits if CDS can't be enabled.
To figure out how effective the cache is, you can enable class loading logs by adding
an extra attribute: `-Xlog:class+load:file=cds.log`. This creates a `cds.log` with every
attempt to load a class and its source. Classes that are loaded from the cache should have
@@ -58,8 +62,11 @@ a "shared objects file" source, as shown in the following example:
[0.065s][info][class,load] org.springframework.context.MessageSource source: shared objects file (top)
----
TIP: If you have a large number of classes that are not loaded from the cache, make sure that
the JDK and classpath used by the commands that create the archive and start the application
are identical. Note also that to effectively cache classes, the classpath should be specified
as a list of JARs containing those classes, and avoid the usage of directories and `*`
wildcard characters.
If CDS can't be enabled or if you have a large number of classes that are not loaded from the cache, make sure that
the following conditions are fulfilled when creating and using the archive:
- The very same JVM must used.
- The classpath must be specified as a list of JARs, and avoid the usage of directories and `*` wildcard characters.
- The timestamps of the JARs must be preserved.
- When using the archive, the classpath must be the same than the one used to create the archive, in the same order.
Additional JARs or directories can be specified *at the end* (but won't be cached).
@@ -58,7 +58,7 @@ your `@Configuration` classes, as the following example shows:
By default, the infrastructure looks for a bean named `jmsListenerContainerFactory`
as the source for the factory to use to create message listener containers. In this
case (and ignoring the JMS infrastructure setup), you can invoke the `processOrder`
method with a core poll size of three threads and a maximum pool size of ten threads.
method with a core pool size of three threads and a maximum pool size of ten threads.
You can customize the listener container factory to use for each annotation or you can
configure an explicit default by implementing the `JmsListenerConfigurer` interface.
@@ -13,12 +13,12 @@ The Spring Framework provides the following choices for making calls to REST end
== `RestClient`
The `RestClient` is a synchronous HTTP client that offers a modern, fluent API.
It offers an abstraction over HTTP libraries that allows for convenient conversion from Java object to HTTP request, and creation of objects from the HTTP response.
It offers an abstraction over HTTP libraries that allows for convenient conversion from a Java object to an HTTP request, and the creation of objects from an HTTP response.
=== Creating a `RestClient`
The `RestClient` is created using one of the static `create` methods.
You can also use `builder` to get a builder with further options, such as specifying which HTTP library to use (see <<rest-request-factories>>) and which message converters to use (see <<rest-message-conversion>>), setting a default URI, default path variables, a default request headers, or `uriBuilderFactory`, or registering interceptors and initializers.
You can also use `builder()` to get a builder with further options, such as specifying which HTTP library to use (see <<rest-request-factories>>) and which message converters to use (see <<rest-message-conversion>>), setting a default URI, default path variables, default request headers, or `uriBuilderFactory`, or registering interceptors and initializers.
Once created (or built), the `RestClient` can be used safely by multiple threads.
@@ -64,35 +64,62 @@ val customClient = RestClient.builder()
=== Using the `RestClient`
When making an HTTP request with the `RestClient`, the first thing to specify is which HTTP method to use.
This can be done with `method(HttpMethod)`, or with the convenience methods `get()`, `head()`, `post()`, and so on.
This can be done with `method(HttpMethod)` or with the convenience methods `get()`, `head()`, `post()`, and so on.
==== Request URL
Next, the request URI can be specified with the `uri` methods.
This step is optional, and can be skipped if the `RestClient` is configured with a default URI.
The URL is typically specified as `String`, with optional URI template variables.
String URLs are encoded by default, but this can be changed by building a client with a custom `uriBuilderFactory`.
This step is optional and can be skipped if the `RestClient` is configured with a default URI.
The URL is typically specified as a `String`, with optional URI template variables.
The following example configures a GET request to `https://example.com/orders/42`:
The URL can also be provided with a function, or as `java.net.URI`, both of which are not encoded.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
int id = 42;
restClient.get()
.uri("https://example.com/orders/{id}", id)
....
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val id = 42
restClient.get()
.uri("https://example.com/orders/{id}", id)
...
----
======
A function can also be used for more controls, such as specifying xref:web/webmvc/mvc-uri-building.adoc[request parameters].
String URLs are encoded by default, but this can be changed by building a client with a custom `uriBuilderFactory`.
The URL can also be provided with a function or as a `java.net.URI`, both of which are not encoded.
For more details on working with and encoding URIs, see xref:web/webmvc/mvc-uri-building.adoc[URI Links].
==== Request headers and body
If necessary, the HTTP request can be manipulated, by adding request headers with `header(String, String)`, `headers(Consumer<HttpHeaders>`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on.
For HTTP request that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`.
If necessary, the HTTP request can be manipulated by adding request headers with `header(String, String)`, `headers(Consumer<HttpHeaders>`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on.
For HTTP requests that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`.
The request body itself can be set by `body(Object)`, which internally uses <<rest-message-conversion>>.
Alternatively, the request body can be set using a `ParameterizedTypeReference`, allowing you to use generics.
Finally, the body can be set to a callback function that writes to an `OutputStream`.
==== Retrieving the response
Once the request has been set up, the HTTP response is accessed by invoking `retrieve()`.
The response body can be accessed by using `body(Class)`, or `body(ParameterizedTypeReference)` for parameterized types like lists.
The `body` method converts the response contents into various types, for instance bytes can be converted into a `String`, JSON into objects using Jackson, and so on (see <<rest-message-conversion>>).
The response body can be accessed by using `body(Class)` or `body(ParameterizedTypeReference)` for parameterized types like lists.
The `body` method converts the response contents into various types for instance, bytes can be converted into a `String`, JSON can be converted into objects using Jackson, and so on (see <<rest-message-conversion>>).
The response can also be converted into a `ResponseEntity`, giving access to the response headers as well as the body.
This sample shows how `RestClient` can be used to perform a simple GET request.
This sample shows how `RestClient` can be used to perform a simple `GET` request.
[tabs]
======
@@ -171,7 +198,7 @@ println("Contents: " + result.body) <3>
======
`RestClient` can convert JSON to objects, using the Jackson library.
Note the usage of uri variables in this sample, and that the `Accept` header is set to JSON.
Note the usage of URI variables in this sample and that the `Accept` header is set to JSON.
[tabs]
======
@@ -248,8 +275,9 @@ val response = restClient.post() <2>
======
==== Error handling
By default, `RestClient` throws a subclass of `RestClientException` when retrieving a response with a 4xx or 5xx status code.
This behavior can be overriden using `onStatus`.
This behavior can be overridden using `onStatus`.
[tabs]
======
@@ -286,8 +314,9 @@ val result = restClient.get() <1>
======
==== Exchange
For more advanced scenarios, the `RestClient` gives access to the underlying HTTP request and response through the `exchange` method, which can be used instead of `retrieve()`.
Status handlers are not applied when you exchange, because the exchange function already provides access to the full response, allowing you to perform any error handling necessary.
For more advanced scenarios, the `RestClient` gives access to the underlying HTTP request and response through the `exchange()` method, which can be used instead of `retrieve()`.
Status handlers are not applied when use `exchange()`, because the exchange function already provides access to the full response, allowing you to perform any error handling necessary.
[tabs]
======
@@ -336,6 +365,7 @@ val result = restClient.get()
[[rest-message-conversion]]
=== HTTP Message Conversion
[.small]#xref:web/webflux/reactive-spring.adoc#webflux-codecs[See equivalent in the Reactive stack]#
The `spring-web` module contains the `HttpMessageConverter` interface for reading and writing the body of HTTP requests and responses through `InputStream` and `OutputStream`.
@@ -397,7 +427,7 @@ By default, this converter supports `text/xml` and `application/xml`.
|===
By default, `RestClient` and `RestTemplate` register all built-in message converters, depending on the availability of underlying libraries on the classpath.
You can also set the message converters to use explicitly, by using `messageConverters` on the `RestClient` builder, or via the `messageConverters` property of `RestTemplate`.
You can also set the message converters to use explicitly, by using the `messageConverters()` method on the `RestClient` builder, or via the `messageConverters` property of `RestTemplate`.
==== Jackson JSON Views
@@ -437,13 +467,13 @@ parts.add("xmlPart", new HttpEntity<>(myBean, headers));
----
In most cases, you do not have to specify the `Content-Type` for each part.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource` based on the file extension.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource`, based on the file extension.
If necessary, you can explicitly provide the `MediaType` with an `HttpEntity` wrapper.
Once the `MultiValueMap` is ready, you can use it as the body of a POST request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
Once the `MultiValueMap` is ready, you can use it as the body of a `POST` request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set to `multipart/form-data` by the `FormHttpMessageConverter`.
If the `MultiValueMap` has `String` values the `Content-Type` defaults to `application/x-www-form-urlencoded`.
If the `MultiValueMap` has `String` values, the `Content-Type` defaults to `application/x-www-form-urlencoded`.
If necessary the `Content-Type` may also be set explicitly.
[[rest-request-factories]]
@@ -453,17 +483,20 @@ To execute the HTTP request, `RestClient` uses a client HTTP library.
These libraries are adapted via the `ClientRequestFactory` interface.
Various implementations are available:
* `JdkClientHttpRequestFactory` for Java's `HttpClient`,
* `HttpComponentsClientHttpRequestFactory` for use with Apache HTTP Components `HttpClient`,
* `JettyClientHttpRequestFactory` for Jetty's `HttpClient`,
* `ReactorNettyClientRequestFactory` for Reactor Netty's `HttpClient`,
* `SimpleClientHttpRequestFactory` as a simple default.
* `JdkClientHttpRequestFactory` for Java's `HttpClient`
* `HttpComponentsClientHttpRequestFactory` for use with Apache HTTP Components `HttpClient`
* `JettyClientHttpRequestFactory` for Jetty's `HttpClient`
* `ReactorNettyClientRequestFactory` for Reactor Netty's `HttpClient`
* `SimpleClientHttpRequestFactory` as a simple default
If no request factory is specified when the `RestClient` was built, it will use the Apache or Jetty `HttpClient` if they are available on the classpath.
Otherwise, if the `java.net.http` module is loaded, it will use Java's `HttpClient`.
Finally, it will resort to the simple default.
TIP: Note that the `SimpleClientHttpRequestFactory` may raise an exception when accessing the status of a response that represents an error (e.g. 401).
If this is an issue, use any of the alternative request factories.
[[rest-webclient]]
== `WebClient`
@@ -473,12 +506,12 @@ synchronous, asynchronous, and streaming scenarios.
`WebClient` supports the following:
* Non-blocking I/O.
* Reactive Streams back pressure.
* High concurrency with fewer hardware resources.
* Functional-style, fluent API that takes advantage of Java 8 lambdas.
* Synchronous and asynchronous interactions.
* Streaming up to or streaming down from a server.
* Non-blocking I/O
* Reactive Streams back pressure
* High concurrency with fewer hardware resources
* Functional-style, fluent API that takes advantage of Java 8 lambdas
* Synchronous and asynchronous interactions
* Streaming up to or streaming down from a server
See xref:web/webflux-webclient.adoc[WebClient] for more details.
@@ -848,17 +881,17 @@ It can be used to migrate from the latter to the former.
.toEntity(ParameterizedTypeReference)` footnote:request-entity[]
| `execute(String, HttpMethod method, RequestCallback, ResponseExtractor, Object...)`
| `execute(String, HttpMethod, RequestCallback, ResponseExtractor, Object...)`
| `method(HttpMethod)
.uri(String, Object...)
.exchange(ExchangeFunction)`
| `execute(String, HttpMethod method, RequestCallback, ResponseExtractor, Map)`
| `execute(String, HttpMethod, RequestCallback, ResponseExtractor, Map)`
| `method(HttpMethod)
.uri(String, Map)
.exchange(ExchangeFunction)`
| `execute(URI, HttpMethod method, RequestCallback, ResponseExtractor)`
| `execute(URI, HttpMethod, RequestCallback, ResponseExtractor)`
| `method(HttpMethod)
.uri(URI)
.exchange(ExchangeFunction)`
@@ -8,7 +8,7 @@ existing Java application.
The Spring Framework provides a dedicated `ApplicationContext` that supports a Groovy-based
Bean Definition DSL. For more details, see
xref:core/beans/basics.adoc#groovy-bean-definition-dsl[The Groovy Bean Definition DSL].
xref:core/beans/basics.adoc#beans-factory-groovy[The Groovy Bean Definition DSL].
Further support for Groovy, including beans written in Groovy, refreshable script beans,
and more is available in xref:languages/dynamic.adoc[Dynamic Language Support].
@@ -9,7 +9,7 @@ in Kotlin.
[[final-by-default]]
== Final by Default
By default, https://discuss.kotlinlang.org/t/classes-final-by-default/166[all classes in Kotlin are `final`].
By default, https://discuss.kotlinlang.org/t/classes-final-by-default/166[all classes and member functions in Kotlin are `final`].
The `open` modifier on a class is the opposite of Java's `final`: It allows others to inherit from this
class. This also applies to member functions, in that they need to be marked as `open` to be overridden.
@@ -38,6 +38,12 @@ Meta-annotation support means that types annotated with `@Configuration`, `@Cont
`@RestController`, `@Service`, or `@Repository` are automatically opened since these
annotations are meta-annotated with `@Component`.
WARNING: Some use cases involving proxies and automatic generation of final methods by the Kotlin compiler require extra
care. For example, a Kotlin class with properties will generate related `final` getters and setters. In order
to be able to proxy related methods, a type level `@Component` annotation should be preferred to method level `@Bean` in
order to have those methods opened by the `kotlin-spring` plugin. A typical use case is `@Scope` and its popular
`@RequestScope` specialization.
https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io] enables
the `kotlin-spring` plugin by default. So, in practice, you can write your Kotlin beans
without any additional `open` keyword, as in Java.
@@ -160,7 +166,7 @@ public class SampleConfiguration {
@Bean
@NotNull
public SampleBean sampleBean$demo_kotlin_internal_test() {
return new SampleBean();
return new SampleBean();
}
}
----
@@ -111,7 +111,8 @@ a mock service with Mockito:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="accountService" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.example.AccountService"/>
<constructor-arg type="java.lang.Class" value="org.example.AccountService"/>
<constructor-arg type="java.lang.String" value="accountService"/>
</bean>
----
@@ -1,7 +1,7 @@
[[spring-mvc-test-vs-end-to-end-integration-tests]]
= MockMvc vs End-to-End Tests
MockMVc is built on Servlet API mock implementations from the
MockMvc is built on Servlet API mock implementations from the
`spring-test` module and does not rely on a running container. Therefore, there are
some differences when compared to full end-to-end integration tests with an actual
client and a live server running.
@@ -1,38 +1,16 @@
[[spring-mvc-test-vs-streaming-response]]
= Streaming Responses
The best way to test streaming responses such as Server-Sent Events is through the
<<WebTestClient>> which can be used as a test client to connect to a `MockMvc` instance
to perform tests on Spring MVC controllers without a running server. For example:
You can use `WebTestClient` to test xref:testing/webtestclient.adoc#webtestclient-stream[streaming responses]
such as Server-Sent Events. However, `MockMvcWebTestClient` doesn't support infinite
streams because there is no way to cancel the server stream from the client side.
To test infinite streams, you'll need to
xref:testing/webtestclient.adoc#webtestclient-server-config[bind to] a running server,
or when using Spring Boot,
{spring-boot-docs}/spring-boot-features.html#boot-features-testing-spring-boot-applications-testing-with-running-server[test with a running server].
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
WebTestClient client = MockMvcWebTestClient.bindToController(new SseController()).build();
FluxExchangeResult<Person> exchangeResult = client.get()
.uri("/persons")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType("text/event-stream")
.returnResult(Person.class);
// Use StepVerifier from Project Reactor to test the streaming response
StepVerifier.create(exchangeResult.getResponseBody())
.expectNext(new Person("N0"), new Person("N1"), new Person("N2"))
.expectNextCount(4)
.consumeNextWith(person -> assertThat(person.getName()).endsWith("7"))
.thenCancel()
.verify();
----
======
`WebTestClient` can also connect to a live server and perform full end-to-end integration
tests. This is also supported in Spring Boot where you can
{spring-boot-docs}/spring-boot-features.html#boot-features-testing-spring-boot-applications-testing-with-running-server[test a running server].
`MockMvcWebTestClient` does support asynchronous responses, and even streaming responses.
The limitation is that it can't influence the server to stop, and therefore the server
must finish writing the response on its own.
@@ -2,7 +2,7 @@
= Context Configuration with Groovy Scripts
To load an `ApplicationContext` for your tests by using Groovy scripts that use the
xref:core/beans/basics.adoc#groovy-bean-definition-dsl[Groovy Bean Definition DSL], you can annotate
xref:core/beans/basics.adoc#beans-factory-groovy[Groovy Bean Definition DSL], you can annotate
your test class with `@ContextConfiguration` and configure the `locations` or `value`
attribute with an array that contains the resource locations of Groovy scripts. Resource
lookup semantics for Groovy scripts are the same as those described for
@@ -672,13 +672,13 @@ Kotlin::
val result = client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody(Person.class)
.returnResult();
.expectBody<Person>()
.returnResult()
// For a response without a body
val result = client.get().uri("/path")
.exchange()
.expectBody().isEmpty();
.expectBody().isEmpty()
----
======
@@ -803,7 +803,7 @@ Java::
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ClassPathResource index = new ClassPathResource("static/index.html");
List<String> extensions = List.of("js", "css", "ico", "png", "jpg", "gif");
List<String> extensions = Arrays.asList("js", "css", "ico", "png", "jpg", "gif");
RequestPredicate spaPredicate = path("/api/**").or(path("/error")).or(pathExtension(extensions::contains)).negate();
RouterFunction<ServerResponse> redirectToIndex = route()
.resource(spaPredicate, index)
@@ -4,10 +4,13 @@
`spring-webflux` depends on `reactor-core` and uses it internally to compose asynchronous
logic and to provide Reactive Streams support. Generally, WebFlux APIs return `Flux` or
`Mono` (since those are used internally) and leniently accept any Reactive Streams
`Publisher` implementation as input. The use of `Flux` versus `Mono` is important, because
it helps to express cardinality -- for example, whether a single or multiple asynchronous
values are expected, and that can be essential for making decisions (for example, when
encoding or decoding HTTP messages).
`Publisher` implementation as input.
When a `Publisher` is provided, it can be treated only as a stream with unknown semantics (0..N).
If, however, the semantics are known, you should wrap it with `Flux` or `Mono.from(Publisher)` instead
of passing the raw `Publisher`.
The use of `Flux` versus `Mono` is important, because it helps to express cardinality --
for example, whether a single or multiple asynchronous values are expected,
and that can be essential for making decisions (for example, when encoding or decoding HTTP messages).
For annotated controllers, WebFlux transparently adapts to the reactive library chosen by
the application. This is done with the help of the
@@ -15,15 +18,3 @@ the application. This is done with the help of the
provides pluggable support for reactive library and other asynchronous types. The registry
has built-in support for RxJava 3, Kotlin coroutines and SmallRye Mutiny, but you can
register others, too.
For functional APIs (such as <<webflux-fn>>, the `WebClient`, and others), the general rules
for WebFlux APIs apply -- `Flux` and `Mono` as return values and a Reactive Streams
`Publisher` as input. When a `Publisher`, whether custom or from another reactive library,
is provided, it can be treated only as a stream with unknown semantics (0..N). If, however,
the semantics are known, you can wrap it with `Flux` or `Mono.from(Publisher)` instead
of passing the raw `Publisher`.
For example, given a `Publisher` that is not a `Mono`, the Jackson JSON message writer
expects multiple values. If the media type implies an infinite stream (for example,
`application/json+stream`), values are written and flushed individually. Otherwise,
values are buffered into a list and rendered as a JSON array.
@@ -97,8 +97,8 @@ Java::
Mono<Person> result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> ...)
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.onStatus(HttpStatusCode::is4xxClientError, response -> ...)
.onStatus(HttpStatusCode::is5xxServerError, response -> ...)
.bodyToMono(Person.class);
----
@@ -109,8 +109,8 @@ Kotlin::
val result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatus::is4xxClientError) { ... }
.onStatus(HttpStatus::is5xxServerError) { ... }
.onStatus(HttpStatusCode::is4xxClientError) { ... }
.onStatus(HttpStatusCode::is5xxServerError) { ... }
.awaitBody<Person>()
----
======
@@ -5,14 +5,14 @@
A common requirement for REST services is to include details in the body of error
responses. The Spring Framework supports the "Problem Details for HTTP APIs"
specification, {rfc-site}/rfc7807.html[RFC 7807].
specification, {rfc-site}/rfc9457.html[RFC 9457].
The following are the main abstractions for this support:
- `ProblemDetail` -- representation for an RFC 7807 problem detail; a simple container
- `ProblemDetail` -- representation for an RFC 9457 problem detail; a simple container
for both standard fields defined in the spec, and for non-standard ones.
- `ErrorResponse` -- contract to expose HTTP error response details including HTTP
status, response headers, and a body in the format of RFC 7807; this allows exceptions to
status, response headers, and a body in the format of RFC 9457; this allows exceptions to
encapsulate and expose the details of how they map to an HTTP response. All Spring WebFlux
exceptions implement this.
- `ErrorResponseException` -- basic `ErrorResponse` implementation that others
@@ -28,7 +28,7 @@ and any `ErrorResponseException`, and renders an error response with a body.
[.small]#xref:web/webmvc/mvc-ann-rest-exceptions.adoc#mvc-ann-rest-exceptions-render[See equivalent in the Servlet stack]#
You can return `ProblemDetail` or `ErrorResponse` from any `@ExceptionHandler` or from
any `@RequestMapping` method to render an RFC 7807 response. This is processed as follows:
any `@RequestMapping` method to render an RFC 9457 response. This is processed as follows:
- The `status` property of `ProblemDetail` determines the HTTP status.
- The `instance` property of `ProblemDetail` is set from the current URL path, if not
@@ -37,7 +37,7 @@ already set.
"application/problem+json" over "application/json" when rendering a `ProblemDetail`,
and also falls back on it if no compatible media type is found.
To enable RFC 7807 responses for Spring WebFlux exceptions and for any
To enable RFC 9457 responses for Spring WebFlux exceptions and for any
`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an
xref:web/webflux/controller/ann-advice.adoc[@ControllerAdvice] in Spring configuration. The handler
has an `@ExceptionHandler` method that handles any `ErrorResponse` exception, which
@@ -50,7 +50,7 @@ use a protected method to map any exception to a `ProblemDetail`.
== Non-Standard Fields
[.small]#xref:web/webmvc/mvc-ann-rest-exceptions.adoc#mvc-ann-rest-exceptions-non-standard[See equivalent in the Servlet stack]#
You can extend an RFC 7807 response with non-standard fields in one of two ways.
You can extend an RFC 9457 response with non-standard fields in one of two ways.
One, insert into the "properties" `Map` of `ProblemDetail`. When using the Jackson
library, the Spring Framework registers `ProblemDetailJacksonMixin` that ensures this
@@ -338,7 +338,7 @@ Kotlin::
class WebConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
// ...
configurer.defaultCodecs().maxInMemorySize(512 * 1024)
}
}
----
@@ -77,7 +77,7 @@ and others) and is equivalent to `required=false`.
| For access to a part in a `multipart/form-data` request. Supports reactive types.
See xref:web/webflux/controller/ann-methods/multipart-forms.adoc[Multipart Content] and xref:web/webflux/reactive-spring.adoc#webflux-multipart[Multipart Data].
| `java.util.Map`, `org.springframework.ui.Model`, and `org.springframework.ui.ModelMap`.
| `java.util.Map` or `org.springframework.ui.Model`
| For access to the model that is used in HTML controllers and is exposed to templates as
part of view rendering.
@@ -89,9 +89,9 @@ and others) and is equivalent to `required=false`.
Note that use of `@ModelAttribute` is optional -- for example, to set its attributes.
See "`Any other argument`" later in this table.
| `Errors`, `BindingResult`
| `Errors` or `BindingResult`
| For access to errors from validation and data binding for a command object, i.e. a
`@ModelAttribute` argument. An `Errors`, or `BindingResult` argument must be declared
`@ModelAttribute` argument. An `Errors` or `BindingResult` argument must be declared
immediately after the validated method argument.
| `SessionStatus` + class-level `@SessionAttributes`
@@ -81,7 +81,7 @@ Kotlin::
----
======
NOTE: `@JsonView` allows an array of view classes but you can only specify only one per
NOTE: `@JsonView` allows an array of view classes but you can specify only one per
controller method. Use a composite interface if you need to activate multiple views.
@@ -4,9 +4,20 @@
[.small]#xref:web/webmvc/mvc-controller/ann-methods/return-types.adoc[See equivalent in the Servlet stack]#
The following table shows the supported controller method return values. Note that reactive
types from libraries such as Reactor, RxJava, xref:web-reactive.adoc#webflux-reactive-libraries[or other] are
types from libraries such as Reactor, RxJava, xref:web/webflux-reactive-libraries.adoc[or other] are
generally supported for all return values.
For return types like `Flux`, when multiple values are expected, elements are streamed as they come
and are not buffered. This is the default behavior, as keeping a potentially large amount of elements in memory
is not efficient. If the media type implies an infinite stream (for example,
`application/json+stream`), values are written and flushed individually. Otherwise,
values are written individually and the flushing happens separately.
NOTE: If an error happens while an element is encoded to JSON, the response might have been written to and committed already
and it is impossible at that point to render a proper error response.
In some cases, applications can choose to trade memory efficiency for better handling such errors by buffering elements and encoding them all at once.
Controllers can then return a `Flux<List<B>>`; Reactor provides a dedicated operator for that, `Flux#collectList()`.
[cols="1,2", options="header"]
|===
| Controller method return value | Description
@@ -24,11 +35,11 @@ generally supported for all return values.
| For returning a response with headers and no body.
| `ErrorResponse`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webflux/ann-rest-exceptions.adoc[Error Responses]
| `ProblemDetail`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webflux/ann-rest-exceptions.adoc[Error Responses]
| `String`
@@ -3,31 +3,43 @@
[.small]#xref:web/webmvc/mvc-controller/ann-validation.adoc[See equivalent in the Servlet stack]#
Spring WebFlux has built-in xref:core/validation/validator.adoc[Validation] support for
`@RequestMapping` methods, including the option to use
xref:core/validation/beanvalidation.adoc[Java Bean Validation].
The validation support works on two levels.
Spring WebFlux has built-in xref:core/validation/validator.adoc[Validation] for
`@RequestMapping` methods, including xref:core/validation/beanvalidation.adoc[Java Bean Validation].
Validation may be applied at one of two levels:
First, resolvers for
xref:web/webflux/controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
1. xref:web/webflux/controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
xref:web/webflux/controller/ann-methods/requestbody.adoc[@RequestBody], and
xref:web/webflux/controller/ann-methods/multipart-forms.adoc[@RequestPart] method
parameters perform validation if the parameter has Jakarta's `@Valid` or Spring's
`@Validated` annotation, and raise `MethodArgumentNotValidException` if necessary.
Alternatively, you can handle the errors in the controller method by adding an
`Errors` or `BindingResult` method parameter immediately after the validated one.
xref:web/webflux/controller/ann-methods/multipart-forms.adoc[@RequestPart] argument
resolvers validate a method argument individually if the method parameter is annotated
with Jakarta `@Valid` or Spring's `@Validated`, _AND_ there is no `Errors` or
`BindingResult` parameter immediately after, _AND_ method validation is not needed (to be
discussed next). The exception raised in this case is `WebExchangeBindException`.
Second, if {bean-validation-site}[Java Bean Validation] is present _AND_ any method
parameter has `@Constraint` annotations, then method validation is applied instead,
raising `HandlerMethodValidationException` if necessary. For this case you can still add
an `Errors` or `BindingResult` method parameter to handle validation errors within the
controller method, but if other method arguments have validation errors then
`HandlerMethodValidationException` is raised instead. Method validation can apply
to the return value if the method is annotated with `@Valid` or with `@Constraint`
annotations.
2. When `@Constraint` annotations such as `@Min`, `@NotBlank` and others are declared
directly on method parameters, or on the method (for the return value), then method
validation must be applied, and that supersedes validation at the method argument level
because method validation covers both method parameter constraints and nested constraints
via `@Valid`. The exception raised in this case is `HandlerMethodValidationException`.
Applications must handle both `WebExchangeBindException` and
`HandlerMethodValidationException` as either may be raised depending on the controller
method signature. The two exceptions, however are designed to be very similar, and can be
handled with almost identical code. The main difference is that the former is for a single
object while the latter is for a list of method parameters.
NOTE: `@Valid` is not a constraint annotation, but rather for nested constraints within
an Object. Therefore, by itself `@Valid` does not lead to method validation. `@NotNull`
on the other hand is a constraint, and adding it to an `@Valid` parameter leads to method
validation. For nullability specifically, you may also use the `required` flag of
`@RequestBody` or `@ModelAttribute`.
Method validation may be used in combination with `Errors` or `BindingResult` method
parameters. However, the controller method is called only if all validation errors are on
method parameters with an `Errors` immediately after. If there are validation errors on
any other method parameter then `HandlerMethodValidationException` is raised.
You can configure a `Validator` globally through the
xref:web/webflux/config.adoc#webflux-config-validation[WebMvc config], or locally
xref:web/webflux/config.adoc#webflux-config-validation[WebFlux config], or locally
through an xref:web/webflux/controller/ann-initbinder.adoc[@InitBinder] method in an
`@Controller` or `@ControllerAdvice`. You can also use multiple validators.
@@ -37,8 +49,8 @@ through an AOP proxy. In order to take advantage of the Spring MVC built-in supp
method validation added in Spring Framework 6.1, you need to remove the class level
`@Validated` annotation from the controller.
The xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses] section provides further
details on how `MethodArgumentNotValidException` and `HandlerMethodValidationException`
The xref:web/webflux/ann-rest-exceptions.adoc[Error Responses] section provides further
details on how `WebExchangeBindException` and `HandlerMethodValidationException`
are handled, and also how their rendering can be customized through a `MessageSource` and
locale and language specific resource bundles.
@@ -781,7 +781,7 @@ Java::
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ClassPathResource index = new ClassPathResource("static/index.html");
List<String> extensions = List.of("js", "css", "ico", "png", "jpg", "gif");
List<String> extensions = Arrays.asList("js", "css", "ico", "png", "jpg", "gif");
RequestPredicate spaPredicate = path("/api/**").or(path("/error")).or(pathExtension(extensions::contains)).negate();
RouterFunction<ServerResponse> redirectToIndex = route()
.resource(spaPredicate, index)
@@ -36,7 +36,7 @@ to render the response content as XML. If the model contains multiple entries, y
explicitly set the object to be serialized by using the `modelKey` bean property. If the
model contains a single entry, it is serialized automatically.
You can customized XML mapping as needed by using JAXB or Jackson's provided
You can customize XML mapping as needed by using JAXB or Jackson's provided
annotations. When you need further control, you can inject a custom `XmlMapper`
through the `ObjectMapper` property, for cases where custom XML
you need to provide serializers and deserializers for specific types.
@@ -683,7 +683,7 @@ the HTML would be as follows:
----
What if we want to display the entire list of errors for a given page? The next example
shows that the `errors` tag also supports some basic wildcarding functionality.
shows that the `errors` tag also supports some basic wildcard functionality.
* `path="{asterisk}"`: Displays all errors.
* `path="lastName"`: Displays all errors associated with the `lastName` field.
@@ -500,8 +500,8 @@ The MVC configuration exposes the following options for asynchronous request pro
You can configure the following:
* Default timeout value for async requests, which if not set, depends
on the underlying Servlet container.
* The default timeout value for async requests depends
on the underlying Servlet container, unless it is set explicitly.
* `AsyncTaskExecutor` to use for blocking writes when streaming with
xref:web/webmvc/mvc-ann-async.adoc#mvc-ann-async-reactive-types[Reactive Types] and for
executing `Callable` instances returned from controller methods.
@@ -5,14 +5,14 @@
A common requirement for REST services is to include details in the body of error
responses. The Spring Framework supports the "Problem Details for HTTP APIs"
specification, {rfc-site}/rfc7807[RFC 7807].
specification, {rfc-site}/rfc9457[RFC 9457].
The following are the main abstractions for this support:
- `ProblemDetail` -- representation for an RFC 7807 problem detail; a simple container
- `ProblemDetail` -- representation for an RFC 9457 problem detail; a simple container
for both standard fields defined in the spec, and for non-standard ones.
- `ErrorResponse` -- contract to expose HTTP error response details including HTTP
status, response headers, and a body in the format of RFC 7807; this allows exceptions to
status, response headers, and a body in the format of RFC 9457; this allows exceptions to
encapsulate and expose the details of how they map to an HTTP response. All Spring MVC
exceptions implement this.
- `ErrorResponseException` -- basic `ErrorResponse` implementation that others
@@ -28,7 +28,7 @@ and any `ErrorResponseException`, and renders an error response with a body.
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-render[See equivalent in the Reactive stack]#
You can return `ProblemDetail` or `ErrorResponse` from any `@ExceptionHandler` or from
any `@RequestMapping` method to render an RFC 7807 response. This is processed as follows:
any `@RequestMapping` method to render an RFC 9457 response. This is processed as follows:
- The `status` property of `ProblemDetail` determines the HTTP status.
- The `instance` property of `ProblemDetail` is set from the current URL path, if not
@@ -37,7 +37,7 @@ already set.
"application/problem+json" over "application/json" when rendering a `ProblemDetail`,
and also falls back on it if no compatible media type is found.
To enable RFC 7807 responses for Spring WebFlux exceptions and for any
To enable RFC 9457 responses for Spring WebFlux exceptions and for any
`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an
xref:web/webmvc/mvc-controller/ann-advice.adoc[@ControllerAdvice] in Spring configuration. The handler
has an `@ExceptionHandler` method that handles any `ErrorResponse` exception, which
@@ -50,7 +50,7 @@ use a protected method to map any exception to a `ProblemDetail`.
== Non-Standard Fields
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-non-standard[See equivalent in the Reactive stack]#
You can extend an RFC 7807 response with non-standard fields in one of two ways.
You can extend an RFC 9457 response with non-standard fields in one of two ways.
One, insert into the "properties" `Map` of `ProblemDetail`. When using the Jackson
library, the Spring Framework registers `ProblemDetailJacksonMixin` that ensures this
@@ -79,9 +79,11 @@ message code arguments for the "detail" field. `ResponseEntityExceptionHandler`
these through a xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource]
and updates the corresponding `ProblemDetail` fields accordingly.
The default strategy for message codes follows the pattern:
The default strategy for message codes is as follows:
`problemDetail.[type|title|detail].[fully qualified exception class name]`
* "type": `problemDetail.type.[fully qualified exception class name]`
* "title": `problemDetail.title.[fully qualified exception class name]`
* "detail": `problemDetail.[fully qualified exception class name][suffix]`
An `ErrorResponse` may expose more than one message code, typically adding a suffix
to the default message code. The table below lists message codes, and arguments for
@@ -136,7 +138,7 @@ Message codes and arguments for each error are also resolved via `MessageSource`
| `MethodArgumentNotValidException`
| (default)
| `+{0}+` the list of global errors, `+{1}+` the list of field errors.
Message codes and arguments for each error are also resolvedvia `MessageSource`.
Message codes and arguments for each error are also resolved via `MessageSource`.
| `MissingRequestHeaderException`
| (default)
@@ -52,14 +52,10 @@ The following example shows how to achieve the same configuration in XML:
</mvc:interceptors>
----
NOTE: Interceptors are not ideally suited as a security layer due to the potential
for a mismatch with annotated controller path matching, which can also match trailing
slashes and path extensions transparently, along with other path matching options. Many
of these options have been deprecated but the potential for a mismatch remains.
Generally, we recommend using Spring Security which includes a dedicated
https://docs.spring.io/spring-security/reference/servlet/integrations/mvc.html#mvc-requestmatcher[MvcRequestMatcher]
to align with Spring MVC path matching and also has a security firewall that blocks many
unwanted characters in URL paths.
WARNING: Interceptors are not ideally suited as a security layer due to the potential for
a mismatch with annotated controller path matching. Generally, we recommend using Spring
Security, or alternatively a similar approach integrated with the Servlet filter chain,
and applied as early as possible.
NOTE: The XML config declares interceptors as `MappedInterceptor` beans, and those are in
turn detected by any `HandlerMapping` bean, including those from other frameworks.
@@ -228,11 +228,11 @@ level, xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[HandlerExceptionResolv
See xref:web/webmvc/mvc-controller/ann-methods/responseentity.adoc[ResponseEntity].
| `ErrorResponse`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `ProblemDetail`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `String`
@@ -37,6 +37,13 @@ Kotlin::
all controller methods. This is the effect of `@RestController`, which is nothing more
than a meta-annotation marked with `@Controller` and `@ResponseBody`.
A `Resource` object can be returned for file content, copying the `InputStream`
content of the provided resource to the response `OutputStream`. Note that the
`InputStream` should be lazily retrieved by the `Resource` handle in order to reliably
close it after it has been copied to the response. If you are using `InputStreamResource`
for such a purpose, make sure to construct it with an on-demand `InputStreamSource`
(e.g. through a lambda expression that retrieves the actual `InputStream`).
You can use `@ResponseBody` with reactive types.
See xref:web/webmvc/mvc-ann-async.adoc[Asynchronous Requests] and xref:web/webmvc/mvc-ann-async.adoc#mvc-ann-async-reactive-types[Reactive Types] for more details.
@@ -32,6 +32,18 @@ Kotlin::
----
======
The body will usually be provided as a value object to be rendered to a corresponding
response representation (e.g. JSON) by one of the registered `HttpMessageConverters`.
A `ResponseEntity<Resource>` can be returned for file content, copying the `InputStream`
content of the provided resource to the response `OutputStream`. Note that the
`InputStream` should be lazily retrieved by the `Resource` handle in order to reliably
close it after it has been copied to the response. If you are using `InputStreamResource`
for such a purpose, make sure to construct it with an on-demand `InputStreamSource`
(e.g. through a lambda expression that retrieves the actual `InputStream`). Also, custom
subclasses of `InputStreamResource` are only supported in combination with a custom
`contentLength()` implementation which avoids consuming the stream for that purpose.
Spring MVC supports using a single value xref:web/webmvc/mvc-ann-async.adoc#mvc-ann-async-reactive-types[reactive type]
to produce the `ResponseEntity` asynchronously, and/or single and multi-value reactive
types for the body. This allows the following types of async responses:
@@ -23,11 +23,11 @@ supported for all return values.
| For returning a response with headers and no body.
| `ErrorResponse`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `ProblemDetail`
| To render an RFC 7807 error response with details in the body,
| To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `String`
@@ -3,28 +3,40 @@
[.small]#xref:web/webflux/controller/ann-validation.adoc[See equivalent in the Reactive stack]#
Spring MVC has built-in xref:core/validation/validator.adoc[Validation] support for
`@RequestMapping` methods, including the option to use
xref:core/validation/beanvalidation.adoc[Java Bean Validation].
The validation support works on two levels.
Spring MVC has built-in xref:core/validation/validator.adoc[validation] for
`@RequestMapping` methods, including xref:core/validation/beanvalidation.adoc[Java Bean Validation].
Validation may be applied at one of two levels:
First, resolvers for
xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
1. xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[@ModelAttribute],
xref:web/webmvc/mvc-controller/ann-methods/requestbody.adoc[@RequestBody], and
xref:web/webmvc/mvc-controller/ann-methods/multipart-forms.adoc[@RequestPart] method
parameters perform validation if the parameter has Jakarta's `@Valid` or Spring's
`@Validated` annotation, and raise `MethodArgumentNotValidException` if necessary.
Alternatively, you can handle the errors in the controller method by adding an
`Errors` or `BindingResult` method parameter immediately after the validated one.
xref:web/webmvc/mvc-controller/ann-methods/multipart-forms.adoc[@RequestPart] argument
resolvers validate a method argument individually if the method parameter is annotated
with Jakarta `@Valid` or Spring's `@Validated`, _AND_ there is no `Errors` or
`BindingResult` parameter immediately after, _AND_ method validation is not needed (to be
discussed next). The exception raised in this case is `MethodArgumentNotValidException`.
Second, if {bean-validation-site}[Java Bean Validation] is present _AND_ any method
parameter has `@Constraint` annotations, then method validation is applied instead,
raising `HandlerMethodValidationException` if necessary. For this case you can still add
an `Errors` or `BindingResult` method parameter to handle validation errors within the
controller method, but if other method arguments have validation errors then
`HandlerMethodValidationException` is raised instead. Method validation can apply
to the return value if the method is annotated with `@Valid` or with `@Constraint`
annotations.
2. When `@Constraint` annotations such as `@Min`, `@NotBlank` and others are declared
directly on method parameters, or on the method (for the return value), then method
validation must be applied, and that supersedes validation at the method argument level
because method validation covers both method parameter constraints and nested constraints
via `@Valid`. The exception raised in this case is `HandlerMethodValidationException`.
Applications must handle both `MethodArgumentNotValidException` and
`HandlerMethodValidationException` as either may be raised depending on the controller
method signature. The two exceptions, however are designed to be very similar, and can be
handled with almost identical code. The main difference is that the former is for a single
object while the latter is for a list of method parameters.
NOTE: `@Valid` is not a constraint annotation, but rather for nested constraints within
an Object. Therefore, by itself `@Valid` does not lead to method validation. `@NotNull`
on the other hand is a constraint, and adding it to an `@Valid` parameter leads to method
validation. For nullability specifically, you may also use the `required` flag of
`@RequestBody` or `@ModelAttribute`.
Method validation may be used in combination with `Errors` or `BindingResult` method
parameters. However, the controller method is called only if all validation errors are on
method parameters with an `Errors` immediately after. If there are validation errors on
any other method parameter then `HandlerMethodValidationException` is raised.
You can configure a `Validator` globally through the
xref:web/webmvc/mvc-config/validation.adoc[WebMvc config], or locally through an
@@ -1,34 +1,29 @@
[[mvc-handlermapping-interceptor]]
= Interception
All `HandlerMapping` implementations support handler interceptors that are useful when
you want to apply specific functionality to certain requests -- for example, checking for
a principal. Interceptors must implement `HandlerInterceptor` from the
`org.springframework.web.servlet` package with three methods that should provide enough
flexibility to do all kinds of pre-processing and post-processing:
All `HandlerMapping` implementations support handler interception which is useful when
you want to apply functionality across requests. A `HandlerInterceptor` can implement the
following:
* `preHandle(..)`: Before the actual handler is run
* `postHandle(..)`: After the handler is run
* `afterCompletion(..)`: After the complete request has finished
* `preHandle(..)` -- callback before the actual handler is run that returns a boolean.
If the method returns `true`, execution continues; if it returns `false`, the rest of the
execution chain is bypassed and the handler is not called.
* `postHandle(..)` -- callback after the handler is run.
* `afterCompletion(..)` -- callback after the complete request has finished.
The `preHandle(..)` method returns a boolean value. You can use this method to break or
continue the processing of the execution chain. When this method returns `true`, the
handler execution chain continues. When it returns false, the `DispatcherServlet`
assumes the interceptor itself has taken care of requests (and, for example, rendered an
appropriate view) and does not continue executing the other interceptors and the actual
handler in the execution chain.
NOTE: For `@ResponseBody` and `ResponseEntity` controller methods, the response is written
and committed within the `HandlerAdapter`, before `postHandle` is called. That means it is
too late to change the response, such as to add an extra header. You can implement
`ResponseBodyAdvice` and declare it as an
xref:web/webmvc/mvc-controller/ann-advice.adoc[Controller Advice] bean or configure it
directly on `RequestMappingHandlerAdapter`.
See xref:web/webmvc/mvc-config/interceptors.adoc[Interceptors] in the section on MVC configuration for examples of how to
configure interceptors. You can also register them directly by using setters on individual
`HandlerMapping` implementations.
`postHandle` method is less useful with `@ResponseBody` and `ResponseEntity` methods for
which the response is written and committed within the `HandlerAdapter` and before
`postHandle`. That means it is too late to make any changes to the response, such as adding
an extra header. For such scenarios, you can implement `ResponseBodyAdvice` and either
declare it as an xref:web/webmvc/mvc-controller/ann-advice.adoc[Controller Advice] bean or configure it directly on
`RequestMappingHandlerAdapter`.
WARNING: Interceptors are not ideally suited as a security layer due to the potential for
a mismatch with annotated controller path matching. Generally, we recommend using Spring
Security, or alternatively a similar approach integrated with the Servlet filter chain,
and applied as early as possible.
@@ -13,7 +13,7 @@ If configured with a task scheduler, the simple broker supports
https://stomp.github.io/stomp-specification-1.2.html#Heart-beating[STOMP heartbeats].
To configure a scheduler, you can declare your own `TaskScheduler` bean and set it through
the `MessageBrokerRegistry`. Alternatively, you can use the one that is automatically
declared in the built-in WebSocket configuration, however, you'll' need `@Lazy` to avoid
declared in the built-in WebSocket configuration, however, you'll need `@Lazy` to avoid
a cycle between the built-in WebSocket configuration and your
`WebSocketMessageBrokerConfigurer`. For example:
@@ -389,7 +389,7 @@ template.
encode URI component value _after_ URI variables are expanded.
* `NONE`: No encoding is applied.
The `RestTemplate` is set to `EncodingMode.URI_COMPONENT` for historic
The `RestTemplate` is set to `EncodingMode.URI_COMPONENT` for historical
reasons and for backwards compatibility. The `WebClient` relies on the default value
in `DefaultUriBuilderFactory`, which was changed from `EncodingMode.URI_COMPONENT` in
5.0.x to `EncodingMode.TEMPLATE_AND_VALUES` in 5.1.
+10
View File
@@ -0,0 +1,10 @@
{
"dependencies": {
"antora": "3.2.0-alpha.4",
"@antora/atlas-extension": "1.0.0-alpha.2",
"@antora/collector-extension": "1.0.0-alpha.3",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/antora-extensions": "1.11.1",
"@springio/asciidoctor-extensions": "1.0.0-alpha.10"
}
}
+34 -34
View File
@@ -7,33 +7,33 @@ javaPlatform {
}
dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.15.3"))
api(platform("io.micrometer:micrometer-bom:1.12.3"))
api(platform("io.netty:netty-bom:4.1.107.Final"))
api(platform("com.fasterxml.jackson:jackson-bom:2.15.4"))
api(platform("io.micrometer:micrometer-bom:1.12.8"))
api(platform("io.netty:netty-bom:4.1.111.Final"))
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
api(platform("io.projectreactor:reactor-bom:2023.0.3"))
api(platform("io.projectreactor:reactor-bom:2023.0.8"))
api(platform("io.rsocket:rsocket-bom:1.1.3"))
api(platform("org.apache.groovy:groovy-bom:4.0.18"))
api(platform("org.apache.groovy:groovy-bom:4.0.22"))
api(platform("org.apache.logging.log4j:log4j-bom:2.21.1"))
api(platform("org.assertj:assertj-bom:3.25.3"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.6"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.6"))
api(platform("org.assertj:assertj-bom:3.26.0"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.11"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.11"))
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3"))
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.0"))
api(platform("org.junit:junit-bom:5.10.2"))
api(platform("org.mockito:mockito-bom:5.10.0"))
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3"))
api(platform("org.junit:junit-bom:5.10.3"))
api(platform("org.mockito:mockito-bom:5.12.0"))
constraints {
api("com.fasterxml:aalto-xml:1.3.2")
api("com.fasterxml.woodstox:woodstox-core:6.5.1")
api("com.fasterxml.woodstox:woodstox-core:6.6.2")
api("com.github.ben-manes.caffeine:caffeine:3.1.8")
api("com.github.librepdf:openpdf:1.3.40")
api("com.github.librepdf:openpdf:1.3.43")
api("com.google.code.findbugs:findbugs:3.0.1")
api("com.google.code.findbugs:jsr305:3.0.2")
api("com.google.code.gson:gson:2.10.1")
api("com.google.protobuf:protobuf-java-util:3.25.2")
api("com.google.protobuf:protobuf-java-util:3.25.3")
api("com.h2database:h2:2.2.224")
api("com.jayway.jsonpath:json-path:2.8.0")
api("com.jayway.jsonpath:json-path:2.9.0")
api("com.rometools:rome:1.19.0")
api("com.squareup.okhttp3:mockwebserver:3.14.9")
api("com.squareup.okhttp3:okhttp:3.14.9")
@@ -42,7 +42,7 @@ dependencies {
api("com.sun.xml.bind:jaxb-core:3.0.2")
api("com.sun.xml.bind:jaxb-impl:3.0.2")
api("com.sun.xml.bind:jaxb-xjc:3.0.2")
api("com.thoughtworks.qdox:qdox:2.0.3")
api("com.thoughtworks.qdox:qdox:2.1.0")
api("com.thoughtworks.xstream:xstream:1.4.20")
api("commons-io:commons-io:2.15.0")
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2")
@@ -55,9 +55,9 @@ dependencies {
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
api("io.reactivex.rxjava3:rxjava:3.1.8")
api("io.smallrye.reactive:mutiny:1.10.0")
api("io.undertow:undertow-core:2.3.11.Final")
api("io.undertow:undertow-servlet:2.3.11.Final")
api("io.undertow:undertow-websockets-jsr:2.3.11.Final")
api("io.undertow:undertow-core:2.3.14.Final")
api("io.undertow:undertow-servlet:2.3.14.Final")
api("io.undertow:undertow-websockets-jsr:2.3.14.Final")
api("io.vavr:vavr:0.10.4")
api("jakarta.activation:jakarta.activation-api:2.0.1")
api("jakarta.annotation:jakarta.annotation-api:2.0.0")
@@ -101,26 +101,26 @@ dependencies {
api("org.apache.derby:derbyclient:10.16.1.1")
api("org.apache.derby:derbytools:10.16.1.1")
api("org.apache.httpcomponents.client5:httpclient5:5.3.1")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.4")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.5")
api("org.apache.poi:poi-ooxml:5.2.5")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.18")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.18")
api("org.apache.tomcat:tomcat-util:10.1.18")
api("org.apache.tomcat:tomcat-websocket:10.1.18")
api("org.aspectj:aspectjrt:1.9.21")
api("org.aspectj:aspectjtools:1.9.21")
api("org.aspectj:aspectjweaver:1.9.21")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.25")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.25")
api("org.apache.tomcat:tomcat-util:10.1.25")
api("org.apache.tomcat:tomcat-websocket:10.1.25")
api("org.aspectj:aspectjrt:1.9.22.1")
api("org.aspectj:aspectjtools:1.9.22.1")
api("org.aspectj:aspectjweaver:1.9.22.1")
api("org.awaitility:awaitility:4.2.0")
api("org.bouncycastle:bcpkix-jdk18on:1.72")
api("org.codehaus.jettison:jettison:1.5.4")
api("org.crac:crac:1.4.0")
api("org.dom4j:dom4j:2.1.4")
api("org.eclipse.jetty:jetty-reactive-httpclient:4.0.2")
api("org.eclipse.jetty:jetty-reactive-httpclient:4.0.5")
api("org.eclipse.persistence:org.eclipse.persistence.jpa:3.0.4")
api("org.eclipse:yasson:2.0.4")
api("org.ehcache:ehcache:3.10.8")
api("org.ehcache:jcache:1.0.1")
api("org.freemarker:freemarker:2.3.32")
api("org.freemarker:freemarker:2.3.33")
api("org.glassfish.external:opendmk_jmxremote_optional_jar:1.0-b01-ea")
api("org.glassfish:jakarta.el:4.0.2")
api("org.glassfish.tyrus:tyrus-container-servlet:2.1.3")
@@ -129,17 +129,17 @@ dependencies {
api("org.hibernate:hibernate-core-jakarta:5.6.15.Final")
api("org.hibernate:hibernate-validator:7.0.5.Final")
api("org.hsqldb:hsqldb:2.7.2")
api("org.javamoney:moneta:1.4.2")
api("org.jruby:jruby:9.4.5.0")
api("org.javamoney:moneta:1.4.4")
api("org.jruby:jruby:9.4.8.0")
api("org.junit.support:testng-engine:1.0.5")
api("org.mozilla:rhino:1.7.14")
api("org.mozilla:rhino:1.7.15")
api("org.ogce:xpp3:1.1.6")
api("org.python:jython-standalone:2.7.3")
api("org.quartz-scheduler:quartz:2.3.2")
api("org.seleniumhq.selenium:htmlunit-driver:2.70.0")
api("org.seleniumhq.selenium:selenium-java:3.141.59")
api("org.skyscreamer:jsonassert:1.5.1")
api("org.slf4j:slf4j-api:2.0.12")
api("org.skyscreamer:jsonassert:1.5.3")
api("org.slf4j:slf4j-api:2.0.13")
api("org.testng:testng:7.9.0")
api("org.webjars:underscorejs:1.8.3")
api("org.webjars:webjars-locator-core:0.55")
+2 -2
View File
@@ -1,10 +1,10 @@
version=6.1.4-SNAPSHOT
version=6.1.11
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m
org.gradle.parallel=true
kotlinVersion=1.9.22
kotlinVersion=1.9.24
kotlin.jvm.target.validation.mode=ignore
kotlin.stdlib.default.dependency=false
+2
View File
@@ -6,6 +6,7 @@ tasks.findByName("dokkaHtmlPartial")?.configure {
classpath.from(sourceSets["main"].runtimeClasspath)
externalDocumentationLink {
url.set(new URL("https://docs.spring.io/spring-framework/docs/current/javadoc-api/"))
packageListUrl.set(new URL("https://docs.spring.io/spring-framework/docs/current/javadoc-api/element-list"))
}
externalDocumentationLink {
url.set(new URL("https://projectreactor.io/docs/core/release/api/"))
@@ -21,6 +22,7 @@ tasks.findByName("dokkaHtmlPartial")?.configure {
}
externalDocumentationLink {
url.set(new URL("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/"))
packageListUrl.set(new URL("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/element-list"))
}
externalDocumentationLink {
url.set(new URL("https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/"))
+1 -1
View File
@@ -29,7 +29,7 @@ publishing {
developer {
id = "jhoeller"
name = "Juergen Hoeller"
email = "jhoeller@pivotal.io"
email = "juergen.hoeller@broadcom.com"
}
}
issueManagement {
+2 -2
View File
@@ -87,12 +87,12 @@ rootProject.ext {
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (!resolvedMainToolchain && task instanceof JavaCompile && task.javaCompiler.isPresent()) {
def metadata = task.javaCompiler.get().metadata
task.project.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
task.project.develocity.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
resolvedMainToolchain = true
}
if (testToolchainConfigured() && !resolvedTestToolchain && task instanceof Test && task.javaLauncher.isPresent()) {
def metadata = task.javaLauncher.get().metadata
task.project.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
task.project.develocity.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
resolvedTestToolchain = true
}
}

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