Compare commits

..

1369 Commits

Author SHA1 Message Date
rstoyanchev 8d16a50907 Efficient ETag parsing
Closes gh-33372
2024-08-14 07:53:23 +03:00
Juergen Hoeller ab161ca796 Upgrade to Netty 4.1.112 and Undertow 2.3.15 2024-08-13 19:34:50 +02:00
Juergen Hoeller b5377ee9cf Polishing 2024-08-13 19:34:30 +02:00
Stéphane Nicoll eff1ca92f0 Upgrade to Reactor 2022.0.22
Closes gh-33324
2024-08-13 17:24:20 +02:00
Sam Brannen 79c7bfdbad Introduce withAssignmentDisabled() option for SimpleEvaluationContext
To support additional use cases, this commit introduces a
withAssignmentDisabled() method in the Builder for
SimpleEvaluationContext.

See gh-33319
Closes gh-33321

(cherry picked from commit e74406afd0)
2024-08-13 17:49:44 +03:00
Riley Park f78b09fddf Fix incorrect weak ETag assertion
Closes gh-33376
2024-08-13 17:02:11 +03:00
Stéphane Nicoll b7ca746493 Sync GHA setup 2024-08-09 16:05:42 +02:00
Stéphane Nicoll 6c062399ea Start building against Reactor 2022.0.22 snapshots
See gh-33324
2024-08-07 09:55:31 +02:00
Sam Brannen e1ab306506 Enforce read-only semantics in SpEL's SimpleEvaluationContext
SimpleEvaluationContext.forReadOnlyDataBinding() documents that it
creates a SimpleEvaluationContext for read-only access to public
properties; however, prior to this commit write access was not disabled
for indexed structures when using the assignment operator, the
increment operator, or the decrement operator.

In order to better align with the documented contract for
forReadOnlyDataBinding(), this commit makes it possible to disable
assignment in general in order to enforce read-only semantics for
SpEL's SimpleEvaluationContext when created via the
forReadOnlyDataBinding() factory method. Specifically:

- This commit introduces a new isAssignmentEnabled() "default" method
  in the EvaluationContext API, which returns true by default.

- SimpleEvaluationContext overrides isAssignmentEnabled(), returning
  false if the context was created via the forReadOnlyDataBinding()
  factory method.

- The Assign, OpDec, and OpInc AST nodes -- representing the assignment
  (=), increment (++), and decrement (--) operators, respectively --
  now throw a SpelEvaluationException if assignment is disabled for the
  current EvaluationContext.

See gh-33319
Closes gh-33321

(cherry picked from commit 0127de5a7a)
2024-08-06 14:12:03 +03:00
Sam Brannen 2165b1651b Throw exception for failure to set property as index in SpEL
Prior to this commit, the Indexer in the Spring Expression Language
(SpEL) silently ignored a failure to set a property via the indexed
property syntax (['<property name>'] = <new value>) – for example, if
property write access was disabled in the EvaluationContext.

This commit addresses this issue by properly throwing a
SpelEvaluationException in PropertyIndexingValueRef.setValue(Object) if
the property could not be set.

See gh-33310
Closes gh-33311

(cherry picked from commit c57c2272a1)
2024-08-05 14:27:03 +03:00
Sam Brannen bf72e92145 Polishing 2024-08-05 14:25:17 +03:00
Sam Brannen 3e7372491c Support conversion from primitive array to Object[] in ConversionService
Prior to this commit, the ConversionService failed to convert a primitive
array (such as int[]) to an Object[] due to an error in the logic in
ArrayToArrayConverter.

This commit addresses this by augmenting the "can bypass conversion"
check in ArrayToArrayConverter to ensure that the supplied source object
is an instance of the target type (i.e., that the source array can be
cast to the target type array without conversion).

Closes gh-33212

(cherry picked from commit cb6a5baac5)
2024-08-05 10:23:29 +03:00
Sam Brannen e11a419cc3 Revert "Support single String argument for varargs invocations in SpEL"
This reverts commit d33f66d9b5.

See gh-33013
See gh-33189
2024-08-04 16:43:07 +03:00
Sam Brannen d33f66d9b5 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.

See gh-33013
Closes gh-33189
2024-07-26 17:46:19 +03:00
Stéphane Nicoll 8da2963644 Remove useless permissions on build-and-deploy-snapshot workflow
Closes gh-33239
2024-07-19 11:47:06 +02:00
Stéphane Nicoll 9a11c12740 Upgrade to Gradle 8.9
Closes gh-33215
2024-07-14 11:13:35 +02:00
Stéphane Nicoll 743c8f755b Add missing artifact properties for staging
This commit makes sure that docs artifacts have their attributes set
for staging as well. Previously they were not and deployment of Javadoc
did not occur.

Closes gh-33207
2024-07-12 08:57:19 +02:00
Stéphane Nicoll 0376ebeaf3 Remove concourse configuration now that CI is using GitHub Actions 2024-07-11 16:58:01 +02:00
Stéphane Nicoll a2a793e324 Release from GitHub Actions
Closes gh-33201
2024-07-11 16:54:40 +02:00
Juergen Hoeller fd7e7633d4 Polishing 2024-07-10 15:45:02 +02:00
Stéphane Nicoll be7029c35d 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-33185
2024-07-10 12:40:24 +02:00
Juergen Hoeller 84efba682d Upgrade to Groovy 4.0.22, Jetty 11.0.22, Undertow 2.3.14
Includes downgrade to Awaitility 4.2.0 (aligned with 6.1.x branch)
2024-07-08 23:25:34 +02:00
Stéphane Nicoll e66be91005 Backport "Harmonize CI configuration"
This commit applies the harmonization changes in eacfd77 whilst keeping
the doc attributes specific changes to 6.0.x
2024-07-05 10:05:04 +02:00
Stéphane Nicoll c7fd5c9c34 Upgrade to Gradle 8.8
Closes gh-33147
2024-07-04 10:31:50 +02:00
Juergen Hoeller 09123def57 Detect ajc markers in superclasses as well (for weaving check)
Closes gh-33113

(cherry picked from commit 100da83913)
2024-07-03 17:12:08 +02:00
Juergen Hoeller 069d0819dd Apply fallback resolution for non-hierarchical URIs such as "file:."
Includes meaningful exception message for file system resolution.

Closes gh-33124

(cherry picked from commit daea3f0eae)
2024-07-03 16:43:14 +02:00
Brian Clozel a352d884c9 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-33128
2024-07-01 11:49:42 +02:00
Stéphane Nicoll 3498a35377 Fix name of GitHub actions bot
See gh-gh-33077
2024-06-21 14:15:58 +02:00
Stéphane Nicoll 06fc5bc3ea Exclude GitHub Actions bot from changelog
Closes gh-33077
2024-06-20 14:17:02 +02:00
Brian Clozel f59b56c4c9 Use Sonatype S01 token in release pipeline 2024-06-18 19:28:28 +02:00
Juergen Hoeller 5a83fc8f86 Polishing 2024-06-17 19:07:04 +02:00
Juergen Hoeller db8d2d1626 Backported test for @Autowired @Bean method on configuration subclass
See gh-33030
2024-06-17 19:06:49 +02:00
Juergen Hoeller 12949becfc Correct and consistent event class names in constructor javadoc
Closes gh-33032

(cherry picked from commit e79a9a5bff)
2024-06-17 18:58:20 +02:00
Stéphane Nicoll debf571722 Fix typo
Closes gh-33054
2024-06-17 13:39:44 +02:00
github-actions[bot] f87b1bd6ce Update Antora Spring UI to v0.4.16 2024-06-17 10:06:47 +00:00
Stéphane Nicoll e17afed0fe Fix property name in Container Extension Points section
Closes gh-33038
2024-06-16 16:49:18 +02:00
Juergen Hoeller 77964374f9 Do not attempt to load pre-enhanced class for reloadable classes
Closes gh-33024

(cherry picked from commit 089e4e69f1)
2024-06-14 22:12:11 +02:00
Stéphane Nicoll 67686d776e Fix invalid character in Javadoc of BeanFactory 2024-06-13 14:10:00 +02:00
Spring Builds 2d83fca571 Next development version (v6.0.23-SNAPSHOT) 2024-06-13 09:24:34 +00:00
Juergen Hoeller f285df692c Upgrade to SLF4J 2.0.13, JRuby 9.4.7, Awaitility 4.2.1 2024-06-12 14:42:49 +02:00
Juergen Hoeller b9eeee8341 Polishing 2024-06-12 13:59:33 +02:00
Juergen Hoeller df1f4812aa Upgrade to Netty 4.1.111 2024-06-12 13:58:57 +02:00
Juergen Hoeller 230848c8e5 Upgrade to spring-javaformat-checkstyle 0.0.42 2024-06-12 13:58:27 +02:00
Stéphane Nicoll eda868792a Upgrade to Reactor 2022.0.20
Closes gh-33008
2024-06-11 14:35:56 +02:00
Brian Clozel 76604db8da 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-32986
2024-06-07 19:00:26 +02:00
Sébastien Deleuze 38b7209dc5 Polishing
See gh-32984
2024-06-07 13:44:30 +02:00
Sébastien Deleuze df0764db5d Remove outdated copyright from index.adoc
Closes gh-32984
2024-06-07 13:38:25 +02:00
Sébastien Deleuze 1e2c4635a3 Exclude node_modules from NoHttp checks
Closes gh-32981
2024-06-07 11:49:43 +02:00
Juergen Hoeller 628b0504ec Skip ajc-compiled aspects for ajc-compiled target classes
Includes defensive ignoring of incompatible aspect types.

Closes gh-32970

(cherry picked from commit 0ea96b4806)
2024-06-06 21:01:42 +02:00
Juergen Hoeller 8b589db028 Avoid NoSuchMethodException for annotation attribute checks
Closes gh-32921

(cherry picked from commit b08883b65c)
2024-06-03 12:51:47 +02:00
Sam Brannen aed1d5f762 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

(cherry picked from commit e9de426eb5)
2024-05-28 10:39:54 +02:00
Sam Brannen 079d53c8d6 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 an 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

(cherry picked from commit cda577d1aa)
2024-05-27 17:28:54 +02:00
Juergen Hoeller 206a89017c Test detection of original generic method for CGLIB bridge method
See gh-32888
2024-05-24 12:29:31 +02:00
Juergen Hoeller 8d1bf9607b Polishing
(cherry picked from commit 6c08d93992)
2024-05-23 17:12:22 +02:00
Juergen Hoeller e12440a7af Defensive handling of incompatible advice methods
This covers AspectJ transaction and caching aspects when encountered by Spring AOP.

Closes gh-32882
See gh-32793

(cherry picked from commit 6d7cd9c7dc)
2024-05-23 17:12:18 +02:00
Spring Builds 093e6a8e8d Next development version (v6.0.22-SNAPSHOT) 2024-05-22 16:07:26 +00:00
Stéphane Nicoll c993615f98 Remove outdated Javadoc links
Closes gh-32873
2024-05-22 14:49:07 +02:00
Rob Winch d068f5a4c6 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:33 +02:00
Juergen Hoeller e73d68b0a8 Select most specific advice method in case of override
Closes gh-32865

(cherry picked from commit ea596aa211)
2024-05-22 10:07:31 +02:00
Juergen Hoeller 0ca47e5e03 Polishing 2024-05-21 18:24:04 +02:00
Juergen Hoeller 33d3496a16 Polishing
(cherry picked from commit 20dea0dae2)
2024-05-21 17:59:39 +02:00
Juergen Hoeller 84a5a8a61e Default fallback parsing for UTC without milliseconds
Closes gh-32856

(cherry picked from commit fee17e11ba)
2024-05-21 17:52:11 +02:00
Juergen Hoeller 2b8a1faeaa Polishing
(cherry picked from commit 65e1337d35)
2024-05-21 11:42:30 +02:00
Juergen Hoeller 4c9de3cbbd 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

(cherry picked from commit a4c2f291d9)
2024-05-21 11:35:08 +02:00
Stéphane Nicoll a0f07af375 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-32848
2024-05-20 13:59:50 +02:00
Juergen Hoeller 97e12bd0e8 Defensively catch and log pointcut parsing exceptions
Closes gh-32838
See gh-32793

(cherry picked from commit 617833bec9)
2024-05-17 12:50:12 +02:00
Spring Builds c374c46cdc Next development version (v6.0.21-SNAPSHOT) 2024-05-16 08:24:45 +00:00
rstoyanchev ea208dc304 Polishing contribution
Closes gh-32799
2024-05-15 20:16:39 +01:00
Juergen Hoeller c8c95e360f Polishing (aligned with 6.1.x) 2024-05-15 14:31:48 +02:00
Juergen Hoeller 9fb36a5dcb Upgrade to Reactor 2022.0.19
Includes AspectJ 1.9.22.1, Mockito 5.12, plugin alignment with 6.1.x

Closes gh-32787
2024-05-14 22:45:33 +02:00
Juergen Hoeller 4caf6bc5b8 Polishing 2024-05-14 13:45:38 +02:00
Juergen Hoeller ee3e1591de Polishing 2024-05-14 13:03:35 +02:00
Juergen Hoeller e81c788274 Accept ajc-compiled @Aspect classes for Spring AOP proxy usage
AspectJExpressionPointcut leniently ignores unsupported expression.

Closes gh-32793
2024-05-14 13:03:29 +02:00
rstoyanchev 09f23a578b Update docs on HandlerInterceptor
Closes gh-32729
2024-05-13 12:10:52 +01:00
rstoyanchev 5288504ceb Use instance field for ProblemDetail in ErrorResponse's
Closes gh-32644
2024-05-13 12:10:52 +01:00
rstoyanchev 8b6a54c45f Update MockMvc section on Streaming in the docs
Closes gh-32687
2024-05-13 12:10:52 +01:00
Sam Brannen f3f3063091 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

(cherry picked from commit 7536980be9)
2024-05-12 12:33:00 +02:00
Stéphane Nicoll c1f3e37acd Polish 2024-05-08 15:35:41 +02:00
Stéphane Nicoll 427a96befc Adapt docs deployment properties
This commit fixes the artifact properties we set for "framework-docs"
artifacts. These have a different name as of 6.1.x and were backported
as is.

Closes gh-32780
2024-05-08 15:21:47 +02:00
Juergen Hoeller 77951dc622 Consistent RuntimeHintsRegistrar signature (plus related polishing) 2024-05-07 15:43:17 +02:00
Juergen Hoeller 43dd22ba31 Polishing
(cherry picked from commit 05d9b52b19)
2024-05-06 20:28:41 +02:00
Juergen Hoeller dfe437ac88 Unwrap raw target Query instance in case of proxy mismatch
Closes gh-32766

(cherry picked from commit 59a125d06f)
2024-05-06 20:25:46 +02:00
Sam Brannen 9c775d2643 Fix compilation error in test 2024-05-03 12:40:14 +03:00
Sam Brannen 3b50b6ef94 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

(cherry picked from commit 4baad16437)
2024-05-03 12:19:27 +03:00
Juergen Hoeller 9a31f3b5a5 Consistently propagate ApplicationStartup to BeanFactory
Closes gh-32747

(cherry picked from commit 25cedcfb99)
2024-05-01 18:11:55 +02:00
Juergen Hoeller b11d118376 Upgrade to Groovy 4.0.21, Netty 4.1.109, Undertow 2.3.13 2024-05-01 15:56:28 +02:00
Juergen Hoeller 0931769822 Polishing 2024-05-01 15:49:14 +02:00
Juergen Hoeller f7b7e29fd7 Ignore non-String keys in PropertiesPropertySource.getPropertyNames()
Closes gh-32742

(cherry picked from commit 610626aec6)
2024-05-01 15:45:21 +02:00
Brian Clozel 08a63a4180 Fix build warnings
See gh-32726
2024-04-30 19:09:44 +02:00
Arjen Poutsma 4e3b834310 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.

See gh-32727
Closes gh-32732
2024-04-30 16:20:20 +02:00
Brian Clozel fb67f97a41 Upgrade to gradle-enterprise-conventions 0.0.17
Closes gh-32726
2024-04-29 13:16:15 +02:00
Stéphane Nicoll cafb5cfbbe 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-32701

Co-authored-by: Juergen Hoeller <juergen.hoeller@broadcom.com>
2024-04-24 11:09:44 +02:00
Juergen Hoeller 9d2c6f80b8 Polishing 2024-04-23 16:25:24 +02:00
Juergen Hoeller d9330bcac7 Skip close lock if acquired by other thread already
Closes gh-32445

(cherry picked from commit d151931f86)
2024-04-23 16:11:16 +02:00
Stéphane Nicoll 1fb179b057 Relax scope of DataIntegrityViolationException
This commit updates the Javadoc of DataIntegrityViolationException to
broaden its scope as it was too specific before.

Closes gh-32686
2024-04-22 14:53:06 +02:00
Juergen Hoeller 5c9f364352 Polishing
(cherry picked from commit ec1f5ca600)
2024-04-22 14:07:51 +02:00
Juergen Hoeller 55f9581743 Try early initialization for all user-declared methods (including interfaces)
Closes gh-32682

(cherry picked from commit 62efdfb89c)
2024-04-22 13:51:15 +02:00
Stéphane Nicoll 190397d5e0 Upgrade to Java 17.0.11 2024-04-22 12:12:11 +02:00
Juergen Hoeller 94097fb112 Polishing (aligned with 6.1.x) 2024-04-18 12:46:55 +02:00
yhao3 e4ab2aa775 Update links to HttpOnly documentation at OWASP in ResponseCookie
See gh-32663
Closes gh-32667

(cherry picked from commit 7f27ba3902)
2024-04-18 12:00:10 +02:00
Simon Baslé 40bf550d56 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.

See gh-31217
Closes gh-32638
2024-04-15 14:22:42 +02:00
Spring Builds f3bdce455e Next development version (v6.0.20-SNAPSHOT) 2024-04-11 07:56:46 +00:00
Brian Clozel 402246df28 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-32617
2024-04-11 08:50:23 +02:00
Stéphane Nicoll 88a68ddbd2 Upgrade to Reactor 2022.0.18
Closes gh-32593
2024-04-09 19:54:22 +02:00
Sam Brannen 7d178c6771 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

(cherry picked from commit e702733c7b)
2024-04-09 19:05:53 +02:00
Juergen Hoeller ba776d7201 Log column type for limited support message in getResultSetValue
Closes gh-32601

(cherry picked from commit c5590ae9e6)
2024-04-09 16:20:51 +02:00
Juergen Hoeller aba5f421fc Remove accidental backport of 6.1 class 2024-04-08 23:51:13 +02:00
Juergen Hoeller 2bac1629e6 Upgrade to Groovy 4.0.20, Netty 4.1.108, OpenPDF 1.3.43 2024-04-08 23:26:19 +02:00
Juergen Hoeller 9412d782ce Revised tests for generic FactoryBean type matching (backported)
See gh-32489
2024-04-08 23:00:33 +02:00
Juergen Hoeller a0bd13ceb1 Do not extract FactoryBean generic in case of targetType mismatch
Closes gh-32489
2024-04-08 10:16:48 +02:00
Stéphane Nicoll 46a0821205 Stop linking to Websphere's Javadoc
Closes gh-32582
2024-04-05 15:58:42 +02:00
Stéphane Nicoll 2c531344c6 Upgrade to Gradle 8.7
Closes gh-32567
2024-04-02 18:02:34 +02:00
Stéphane Nicoll 6610ee360e Upgrade actions that use deprecated features 2024-03-20 10:35:46 +01:00
Minsung Oh afde96c540 Fix link to vavr in the reference guide
Closes gh-32495
2024-03-20 10:03:29 +01:00
Sam Brannen da799bc519 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

(cherry picked from commit ef02f0bad8)
2024-03-19 15:55:15 +01:00
Sam Brannen 755968fd2c Polishing
(cherry picked from commit 836a0b3a40)
2024-03-19 15:55:08 +01:00
Juergen Hoeller eea00628f9 Polishing 2024-03-18 16:22:03 +01:00
Juergen Hoeller 8d745462b4 Propagate JMS IllegalStateException from commit/rollbackIfNecessary
Closes gh-32473

(cherry picked from commit cd7ba1835c)
2024-03-18 16:13:55 +01:00
Sam Brannen ed6c25fb6e Avoid unnecessary Annotation array cloning in TypeDescriptor
Closes gh-32476

(cherry picked from commit 42a4f28962)
2024-03-18 15:18:43 +01:00
Juergen Hoeller 8460a2d285 Restore original toString representation (revert accidental backport)
See gh-32405
2024-03-17 20:43:07 +01:00
Juergen Hoeller c3d186b4d0 Remove superfluous @NonNull declarations 2024-03-16 14:23:12 +01:00
Juergen Hoeller f8926d6a66 Avoid cloning empty Annotation array in TypeDescriptor (backport)
Closes gh-32405
2024-03-16 14:23:06 +01:00
Juergen Hoeller 19b21b15c1 Polishing 2024-03-15 21:22:49 +01:00
Juergen Hoeller 547425275c Consistently apply TaskDecorator to ManagedExecutorService as well
Closes gh-32455
2024-03-15 21:17:46 +01:00
Stéphane Nicoll 658194c155 Harmonize Concourse configuration 2024-03-15 09:15:24 +01:00
Stéphane Nicoll 769f73ebf1 Polish "Move CI to GitHub Actions"
See gh-32447
2024-03-15 09:14:22 +01:00
Stéphane Nicoll 80809bbc14 Move CI to GitHub Actions
Closes gh-32447
2024-03-15 09:00:28 +01:00
Spring Builds 6d323d710a Next development version (v6.0.19-SNAPSHOT) 2024-03-14 09:30:16 +00:00
rstoyanchev f2fd2f1226 Extract reusable checkSchemeAndPort method
Closes gh-32440
2024-03-14 08:48:42 +00:00
Juergen Hoeller 072ebb6ffc Additional unit tests for operations on empty UriTemplate
See gh-32432

(cherry picked from commit 54a6d89da7)
2024-03-13 18:18:52 +01:00
Kasper Bisgaard 08e7f7efa4 Allow UriTemplate to be built with an empty template
Closes gh-32437
2024-03-13 17:32:48 +01:00
Juergen Hoeller b1fafbf7e1 Upgrade to Reactor 2022.0.17
Includes Groovy 4.0.19, OpenPDF 1.3.42, Mockito 5.11

Closes gh-32421
2024-03-12 20:26:44 +01:00
Juergen Hoeller a3647a8c5e Polishing
(cherry picked from commit 723c94e5ac)
2024-03-12 20:26:24 +01:00
ZeroCyan 5c8d9cd0b2 Fix order of sections in Validation chapter of reference manual
Closes gh-32408
2024-03-10 17:31:30 +01:00
Juergen Hoeller 40d5196243 Polishing 2024-03-08 19:40:45 +01:00
Brian Clozel ec2c9b5d0e 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-32399
2024-03-08 11:36:20 +01:00
rstoyanchev 36539bdaa9 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-32341
2024-03-07 14:51:01 +00:00
rstoyanchev 67ba7dd1da DisconnectedClientHelper recognizes AsyncRequestNotUsableException
See gh-32341
2024-03-06 18:20:31 +00:00
rstoyanchev 7b3fcf2647 Fix Javadoc error 2024-03-05 13:06:12 +00:00
rstoyanchev fd76c33589 Fix Javadoc error 2024-03-05 12:40:32 +00:00
rstoyanchev 1a7a6f421f Backport tests for wrapping of response for async requests
This is a backport of commits 4b96cd and ef0717.

Closes gh-32341
2024-03-05 12:03:48 +00:00
Juergen Hoeller 9ac1feceb5 Restore ability to return original method for proxy-derived method
Closes gh-32365
2024-03-04 23:32:27 +01:00
Juergen Hoeller 7029042e44 Polishing
(cherry picked from commit e9110c0729)
2024-03-04 23:31:51 +01:00
rstoyanchev 1a5661d426 Improve concurrent handling of result in WebAsyncManager
1. Use state transitions
2. Increase synchronized scope in setConcurrentResultAndDispatch

See gh-32341
2024-03-03 20:32:00 +00:00
rstoyanchev b208c63414 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-32341
2024-03-03 20:31:45 +00:00
rstoyanchev 814c003b43 Align 5.3.x with 6.1.x
In preparation for a larger update, start by aligning with
6.1.x, which includes changes for gh-32042 and gh-30232.

See gh-32341
2024-02-29 17:46:18 +00:00
Juergen Hoeller 5c34e1d11a Upgrade to Undertow 2.3.12, OpenPDF 1.3.41, JRuby 9.4.6 2024-02-28 21:38:57 +01:00
Juergen Hoeller d57775bbb2 Polishing 2024-02-28 21:38:38 +01:00
Juergen Hoeller b598ad3f33 Polishing 2024-02-28 19:26:11 +01:00
Juergen Hoeller b44ef70bc3 Direct reference to PushBuilder API on Servlet 5.0 baseline
See gh-29435
2024-02-28 19:17:13 +01:00
Sam Brannen d1b3107398 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
See gh-32317
Closes gh-32321
2024-02-28 10:51:48 +01:00
Sam Brannen 629c560316 Polish ShallowEtagHeaderFilterTests 2024-02-28 10:49:13 +01:00
Sébastien Deleuze 7bf07ef393 Refine *HttpMessageConverter#getContentLength null safety
Closes gh-32333
2024-02-27 15:48:36 +01:00
Sam Brannen ca602ef874 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 in
the wrapped response and now incorrectly returns null for those header
values if they have not been set directly in 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 in the CCRW.

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

Furthermore, 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 CCRW.

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

This commit also updates ContentCachingResponseWrapperTests to verify
the expected behavior for Content-Type and Content-Length headers that
are set in the wrapped response as well as in CCRW.

See gh-32039
See gh-32317
Closes gh-32321
2024-02-25 17:35:54 +01:00
Sam Brannen e9bf5f5569 Polish ContentCachingResponseWrapper[Tests] 2024-02-25 17:35:54 +01:00
Juergen Hoeller 9a6f636e17 Consistent nullability for internal field access 2024-02-24 08:31:56 +01:00
Sébastien Deleuze 7686f5467e 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.

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

Closes gh-32312
2024-02-22 17:06:53 +01:00
Juergen Hoeller 429c477f6a Polishing 2024-02-22 16:59:53 +01:00
Juergen Hoeller 5187281b50 Polishing 2024-02-21 22:56:21 +01:00
Juergen Hoeller 24a4487050 Add test for cleanup after configuration class creation failure
See gh-23343
2024-02-21 22:47:23 +01:00
Juergen Hoeller 8fba4a448a Polishing 2024-02-16 22:41:50 +01:00
Spring Builds 8f286de773 Next development version (v6.0.18-SNAPSHOT) 2024-02-15 12:34:07 +00:00
Juergen Hoeller ee100cfba7 Upgrade to Mockito 5.10, Mutiny 1.10, Undertow 2.3.11 2024-02-15 10:49:54 +01:00
Juergen Hoeller aaf90f5a96 Upgrade to Reactor 2022.0.16
Includes SLF4J 2.0.12, Groovy 4.0.18, Jetty 11.0.20, Netty 4.1.107, OpenPDF 1.3.40
2024-02-15 10:28:18 +01:00
Simon Baslé 70be04ba81 Infer reflection hints for Jackson annotations builder attributes
This notably enables Jackson to reflectively call a user-provided
builder class and invoke its declared methods (setters and build) in
a native app.

See gh-32238
Closes gh-32257
2024-02-13 15:16:04 +01:00
Juergen Hoeller b976ee3f67 Consistent Lock field declaration (instead of ReentrantLock field type)
(cherry picked from commit b4153618a4)
2024-02-13 11:14:10 +01:00
rstoyanchev b11ff96652 Update user info pattern
Closes gh-32211
2024-02-13 07:14:12 +00:00
Arjen Poutsma 667e4e7531 Implement MatchableHandlerMapping in RouterFunctionMapping
See gh-32221
Closes gh-32222
2024-02-08 12:25:00 +01:00
Juergen Hoeller 5fd9fab0ce Polishing (backported from main) 2024-02-07 23:40:11 +01:00
Juergen Hoeller 95a8646309 Polishing 2024-02-06 17:06:05 +01:00
Juergen Hoeller 5434edd726 Avoid sendError call when response committed already (Tomcat 10.1.16)
Closes gh-32206

(cherry picked from commit 4ed337247c)
2024-02-06 16:48:15 +01:00
Brian Clozel 5f13ea95fb Polish
See gh-32197
2024-02-05 11:15:49 +01:00
Patrick Strawderman 74bb42b78f Optimize Map methods in ServletAttributesMap
ServletAttributesMap inherited default implementations of the size
and isEmpty methods from AbstractMap which delegates to the Set returned
by entrySet. ServletAttributesMap's entrySet method made this fairly
expensive, since it would copy the attributes to a List, then use a
Stream to build the Set. To avoid the cost, add implementations of
isEmpty / size that don't need to call entrySet at all.

Additionally, change entrySet to return a Set view that simply lazily
delegates to the underlying servlet request for iteration.

Closes gh-32197
2024-02-05 10:42:46 +01:00
Stéphane Nicoll 55717adf88 Upgrade to Gradle 8.6
Closes gh-32193
2024-02-03 11:36:40 +01:00
Juergen Hoeller 72835f10b9 Polishing 2024-02-01 14:58:13 +01:00
Stéphane Nicoll 125ebd029c Prevent AOT from failing with spring-orm without JPA
This commit improves PersistenceManagedTypesBeanRegistrationAotProcessor
so that it does not attempt to load JPA classes when checking for the
presence of a PersistenceManagedTypes bean. To make it more clear a
check on the presence for JPA has been added to prevent the nested
classes to be loaded regardless of the presence of the bean.

Closes gh-32160
2024-01-30 15:42:19 +01:00
Juergen Hoeller d8d4fa0e24 Polishing 2024-01-29 16:42:32 +01:00
Juergen Hoeller bfd3b3ad88 Eagerly initialize ZERO_NANOS constant 2024-01-29 16:21:35 +01:00
Juergen Hoeller 0909161ba1 Polishing 2024-01-29 14:19:48 +01:00
Juergen Hoeller 4910c217dc Explicit documentation note on cron-vs-quartz parsing convention
Closes gh-32128

(cherry picked from commit a738e4d5fd)
2024-01-29 13:58:39 +01:00
Sébastien Deleuze f262046ef9 Update basics.adoc
Closes gh-32151
2024-01-29 09:15:17 +01:00
Juergen Hoeller d50d4a9092 Polishing 2024-01-24 22:44:29 +01:00
Juergen Hoeller b06305e64f Compare qualifier value arrays with equality semantics
Closes gh-32106

(cherry picked from commit c5a75219ce)
2024-01-24 22:39:24 +01:00
Arjen Poutsma c749a14326 Guard against multiple body subscriptions
Before this commit, the JDK and Jetty connectors do not have any
safeguards against multiple body subscriptions. Such as check has now
been added.

See gh-32100
Closes gh-32102
2024-01-24 13:42:25 +01:00
Juergen Hoeller 3817936ca5 Declare current observation context as available since 6.0.15
See gh-31609
See gh-31646
2024-01-24 12:35:30 +01:00
Juergen Hoeller 9bd2be80b9 Declare allowPrivateNetwork as available since 5.3.32
See gh-28546
See gh-31974
2024-01-24 12:34:53 +01:00
Juergen Hoeller c6e9cd0c62 Polishing 2024-01-24 11:59:15 +01:00
Juergen Hoeller e2a5cfb459 Consistent nullability for concurrent result
(cherry picked from commit b92877990d)
2024-01-24 11:59:10 +01:00
Brian Clozel b484ab116f Record errors thrown by custom handler in RestTemplate observations
Prior to this commit, the `RestTemplate` observation instrumentation
would only record `RestClientException` and `IOException` as errors in
the observation. Other types of errors can be thrown by custom
components, such as `ResponseErrorHandler` and in this case they aren't
recorded with the observation.
Also, the current instrumentation does not create any observation scope
around the execution. While this would have a limited benefit as no
application code is executed there, developers could set up custom
components (such as, again, `ResponseErrorHandler`) that could use
contextual logging with trace ids.

This commit ensures that all `Throwable` are recorded as errors with the
observations and that an observation `Scope` is created around the
execution of the client exchange.

Fixes gh-32063
2024-01-22 11:28:07 +01:00
Juergen Hoeller c668473186 Polishing 2024-01-19 17:18:28 +01:00
Arjen Poutsma 38595c6a99 Handle Content-Length in ShallowEtagHeaderFilter more robustly
This commit ensures that setting the Content-Length through
setHeader("Content-Length", x") has the same effect as calling
setContentLength in the ShallowEtagHeaderFilter. It also filters out
Content-Type headers similarly to Content-Length.

See gh-32039
Closes gh-32050
2024-01-18 15:46:14 +01:00
Brian Clozel d756c2b128 Remove JDK 20 variant from CI build. 2024-01-17 21:26:37 +01:00
Brian Clozel 3be4322f71 Upgrade CI image to JDK 17.0.10+13 2024-01-17 21:21:55 +01:00
Brian Clozel 328e444db3 Upgrade CI image to Ubuntu Jammy 20240111 2024-01-17 21:19:27 +01:00
Stéphane Nicoll 94bdd4380f Fix incorrect assertions using json path
Closes gh-32040
2024-01-16 11:02:36 +01:00
rstoyanchev 3f9d479583 Double-checked lock in ChannelSendOperator#request
Closes gh-31865
2024-01-12 17:16:23 +00:00
Sébastien Deleuze 338922f03d Find destroy methods in superclass interfaces
Related tests will be added in
https://github.com/spring-projects/spring-aot-smoke-tests.

Closes gh-32017
2024-01-12 12:28:07 +01:00
Spring Builds fad857e06a Next development version (v6.0.17-SNAPSHOT) 2024-01-11 10:33:22 +00:00
Juergen Hoeller b8395a2321 Upgrade to spring-javaformat-checkstyle 0.0.41 2024-01-10 17:10:23 +01:00
rstoyanchev 6df8be8be3 Exclude query from URI in WebClient checkpoints
Closes gh-31992
2024-01-10 12:33:28 +00:00
Juergen Hoeller 4a599d0b22 Upgrade to Reactor 2022.0.15
Includes SLF4J 2.0.11, Groovy 4.0.17, Jetty 11.0.19, Netty 4.1.104, Apache HttpClient 5.2.3, POI 5.2.5, OpenPDF 1.3.36, Checkstyle 10.12.7

Closes gh-31997
2024-01-10 11:09:11 +01:00
rstoyanchev a1463c2bf2 Do not set exception attribute if response body is set
ResponseEntityExceptionHandler should not set the exception attribute
when there is a response body, and the response is fully handled.

Closes gh-31541
2024-01-09 14:54:48 +00:00
Sébastien Deleuze 23eff5c650 Update ContentRequestMatchers#multipartData Javadoc
This commit updates ContentRequestMatchers#multipartData
Javadoc to mention Tomcat fork of Commons FileUpload library
instead of the original variant.

It also adds a similar note to
ContentRequestMatchers#multipartDataContains.

Closes gh-31989

(Backport of 598c972a78)
2024-01-09 14:14:45 +01:00
Juergen Hoeller c44bb29aa5 Polishing 2024-01-09 12:56:52 +01:00
Arjen Poutsma 0c22866b72 Ensure correct capacity in DefaultDataBuffer
See gh-31873
Closes gh-31979
2024-01-09 10:40:41 +01:00
Sébastien Deleuze 0c6957e395 Polishing
See gh-31975
2024-01-08 12:26:03 +01:00
Sébastien Deleuze 8d51fc0444 Add CORS support for Private Network Access
This commit adds CORS support for Private Network Access
by adding an Access-Control-Allow-Private-Network response
header when the preflight request is sent with an
Access-Control-Request-Private-Network header and that
Private Network Access has been enabled in the CORS
configuration.

See https://developer.chrome.com/blog/private-network-access-preflight/
for more details.

Closes gh-31975

(cherry picked from commit 318d460256)
2024-01-08 11:23:03 +01:00
Juergen Hoeller bad01011da Avoid getMostSpecificMethod resolution for non-annotated methods
This is aligned with AutowiredAnnotationBeanPostProcessor now.

Closes gh-31967

(cherry picked from commit 9912a52bb8)
2024-01-07 16:35:12 +01:00
Juergen Hoeller 867a199507 Propagate arguments for dynamic prototype-scoped advice
Closes gh-28407

(cherry picked from commit 43107e7eb1)
2024-01-07 00:15:43 +01:00
Juergen Hoeller 1b4a4ac51f Polishing 2024-01-06 23:21:57 +01:00
Juergen Hoeller dd0d26b4ba Refine exception handling for type not present versus access exception
Includes TypeVariable bypass for reflection-free annotation retrieval.
Includes info log message for annotation attribute retrieval failure.

Closes gh-27182

(cherry picked from commit 70247c4a94)
2024-01-06 23:10:30 +01:00
Juergen Hoeller d074f660a1 Default time zone resolution from scheduler-wide Clock
Closes gh-31948
2024-01-05 10:19:03 +01:00
Stéphane Nicoll 1b8baffbd7 Upgrade CI to Ubuntu Jammy 20231211.1 2024-01-05 09:43:01 +01:00
Brian Clozel 56c63c779f Fix HandlerMappingIntrospector uri matching
Prior to this commit, the `HandlerMappingIntrospector` would comparea
request with a cached request by using `String#matches` on their String
URI. This could lead to `PatternSyntaxException` exceptions at runtime
if the request URI contained pattern characters.

This commit fixes this typo to use `String#equals` instead.

Fixes gh-31946
2024-01-04 17:06:17 +01:00
Juergen Hoeller 198cf063fd Polishing 2023-12-30 11:45:34 +01:00
Yanming Zhou b1b6b544a2 Add missing @Test
See gh-31914
2023-12-28 11:41:18 +01:00
Brian Clozel 9d13ea290f Reject invalid forwarded requests in ForwardedHeaderFilter
Prior to this commit, the `ForwardedHeaderFilter` and the forwarded
header utils would throw `IllegalArgumentException` and
`IllegalStateException` when request headers are invalid and cannot be
parsed for Forwarded handling.

This commit aligns the behavior with the WebFlux counterpart by
rejecting such requests with HTTP 400 responses directly.

Fixes gh-31894
2023-12-22 17:51:27 +01:00
Sébastien Deleuze c9163b77df Add support for @Async Kotlin function returning Unit?
Closes gh-31891
2023-12-22 15:35:56 +01:00
Juergen Hoeller 033c8df53f Polishing 2023-12-22 12:54:16 +01:00
Arjen Poutsma b272f4e615 Correctly set capacity of remainder in DefaultDataBuffer::split
This commit ensures that the capacity of the remainder buffer after a
split operation is set directly on the field. Calling capacity(int)
caused a new buffer to be allocated.

See gh-31848
Closes gh-31859
2023-12-18 11:50:30 +01:00
Spring Builds bafff5079f Next development version (v6.0.16-SNAPSHOT) 2023-12-14 08:52:04 +00:00
Juergen Hoeller ccaecab500 Polishing 2023-12-14 08:32:08 +01:00
Sam Brannen 67e03105b5 Introduce test for XML replaced-method element without explicit arg-type
This commit introduces an integration test for the regression fixed in
the previous commit (76bc9cf325).

See gh-31826
Closes gh-31828

(cherry picked from commit 8d4deca2a6)
2023-12-13 15:12:29 +01:00
Juergen Hoeller 76bc9cf325 Prepare method overrides when bean class gets resolved
See gh-31826
See gh-31828

(cherry picked from commit cd64e6676c)
2023-12-13 15:11:29 +01:00
rstoyanchev db52c77cca Minor updates in HandlerMappingIntrospector
Required by Spring Security to complete work on
https://github.com/spring-projects/spring-security/issues/14128

The setCache and resetCache methods used from createCacheFilter are now
public. Generally they don't need to be used outside of the Filter if
only making checks against the current request. Spring Security, however,
makes additional checks against requests with alternative paths.
2023-12-12 20:22:29 +00:00
Sam Brannen 1e742aae34 Scan annotations on method in interface hierarchy only once
Prior to this commit, the AnnotationsScanner used in the
MergedAnnotations infrastructure found duplicate annotations on methods
within multi-level interface hierarchies.

This commit addresses this issue by scanning methods at a given level
in the interface hierarchy using ReflectionUtils#getDeclaredMethods
instead of Class#getMethods, since the latter includes public methods
declared in super-interfaces which will anyway be scanned when
processing super-interfaces recursively.

Closes gh-31803

(cherry picked from commit 75da9c3c47)
2023-12-12 18:39:38 +01:00
Sam Brannen 20dd585c93 Polish MergedAnnotation tests
(cherry picked from commit 952223dcf9)
2023-12-12 18:38:06 +01:00
Juergen Hoeller 707eb701dc Polishing 2023-12-12 14:02:02 +01:00
Juergen Hoeller 2c97996796 Upgrade to Reactor 2022.0.14
Includes Groovy 4.0.16 and Mockito 5.8

Closes gh-31815
2023-12-12 14:01:55 +01:00
rstoyanchev 3a068b807b Update link to stompjs library
Closes gh-28409
2023-12-12 12:32:21 +00:00
Stéphane Nicoll f54b19ff90 Start building against Reactor 2022.0.14 snapshots
See gh-31815
2023-12-11 15:07:32 +01:00
Stéphane Nicoll 494d2ab727 Remove .mailmap file
See gh-31740
2023-12-11 11:08:31 +01:00
Juergen Hoeller 627d9cf8be Polishing 2023-12-10 00:26:22 +01:00
Arjen Poutsma dd3a67c7ab Process tokens after each feed in Jackson2Tokenizer
This commit ensures that we process after each fed buffer in
Jackson2Tokenizer, instead of after all fed buffers.

See gh-31747
Closes gh-31772
2023-12-06 14:49:08 +01:00
Sam Brannen 85cc229063 Fix and polish Javadoc for MimeTypeUtils
(cherry picked from commit 1afea0b144)
2023-12-06 14:31:35 +01:00
Johnny Lim fa95f12be0 Fix condition for "Too many elements" in MimeTypeUtils.sortBySpecificity()
See gh-31254
See gh-31769
Closes gh-31773

(cherry picked from commit 7b95bd72f7)
2023-12-06 14:31:16 +01:00
Sam Brannen 035cc72fc8 Polishing 2023-12-06 12:40:49 +01:00
Arjen Poutsma 29a39b617e Support empty part in DefaultPartHttpMessageReader
This commit fixes a bug in DefaultPartHttpMessageReader's
MultipartParser, due to which the last token in a part window was not
properly indicated.

See gh-30953
Closes gh-31766
2023-12-06 12:21:28 +01:00
Sébastien Deleuze a1471a9266 Document @ModelAttribute usage with native images
Closes gh-31767
2023-12-06 12:18:42 +01:00
Sam Brannen 21793b4f93 Suppress warnings in Gradle build
(cherry picked from commit c05b4ce776)
2023-12-01 15:55:36 +01:00
Sam Brannen 2d255c4d5e Upgrade to Gradle 8.5
Closes gh-31734

(cherry picked from commit 3a53446a2b)
2023-12-01 15:54:40 +01:00
Juergen Hoeller 10391586d1 PathEditor considers single-letter URI scheme as NIO path candidate
Closes gh-29881

(cherry picked from commit c56c304536)
2023-11-30 14:16:37 +01:00
Brian Clozel edadc79835 Fix reactive HTTP server Observation instrumentation
Prior to this commit, regressions were introduced with gh-31417:

1. the observation keyvalues would be inconsistent with the HTTP response
2. the observation scope would not cover all controller handlers, causing
  traceIds to be missing

The first issue is caused by the fact that in case of error signals, the
observation was stopped before the response was fully committed, which
means further processing could happen and update the response status.
This commit delays the stop event until the response is committed in
case of errors.

The second problem is caused by the change from a `contextWrite`
operator to using the `tap` operator with a `SignalListener`. The
observation was started in the `doOnSubscription` callback, which is too
late in some cases. If the WebFlux controller handler is synchronous
non-blocking, the execution of the handler is performed before the
subscription happens. This means that for those handlers, the
observation was not started, even if the current observation was
present in the reactor context. This commit changes the
`doOnSubscription` to `doFirst` to ensure that the observation is
started at the right time.

Fixes gh-31715
Fixes gh-31716
2023-11-29 14:55:57 +01:00
Stéphane Nicoll 3783d31c09 Quote name attribute if necessary
This commit updates MetadataNamingStrategy to quote an ObjectName
attribute value if necessary. For now, only the name attribute is
handled as it is usually a bean name, and we have no control over
its structure.

Closes gh-31708
2023-11-28 17:05:36 +01:00
Sam Brannen 87730f76b1 Include scroll() in SharedEntityManagerCreator's queryTerminatingMethods
This commit supports the scroll() and scroll(ScrollMode) methods from
Hibernate's Query API in SharedEntityManagerCreator's query-terminating
methods set.

See gh-31682
Closes gh-31683

(cherry picked from commit a15f472898)
2023-11-26 12:14:33 +01:00
Juergen Hoeller 6fae3e150e Consider generics in equals method (for ConversionService caching)
Closes gh-31672

(cherry picked from commit 710373d286)
2023-11-24 23:29:02 +01:00
Juergen Hoeller ad44e8ab0a Filter candidate methods by name first (for more efficient sorting)
Closes gh-28377

(cherry picked from commit 0599320bd8)
2023-11-24 23:28:59 +01:00
Juergen Hoeller aadf96ba92 Properly return loaded type even if identified as reloadable
Closes gh-31668

(cherry picked from commit 8921be18de)
2023-11-24 23:28:57 +01:00
Brian Clozel 2baf064d04 Add current observation context in ClientRequest
Prior to this commit, `ExchangeFilterFunction` could only get the
current observation from the reactor context. This is particularly
useful when such filters want to add KeyValues to the observation
context.

This commit makes this use case easier by adding the context of the
current observation as a request attribute. This also aligns the
behavior with other instrumentations.

Fixes gh-31646
2023-11-24 17:37:04 +01:00
Brian Clozel 6121e2f526 Remove API diff Gradle plugin configuration
We have not published API diffs for a while now so we should remove the
configuration entirely from our build.
2023-11-23 15:53:35 +01:00
Brian Clozel 8e33805d29 Fix ordering of releasing resources in JSON Encoder
Prior to this commit, the Jackson 2.x encoders, in case of encoding a
stream of data, would first release the `ByteArrayBuilder` and then the
`JsonGenerator`. This order is inconsistent with the single value
variant (see `o.s.h.codec.json.AbstractJackson2Encoder#encodeValue`) and
invalid since the `JsonGenerator` uses internally the
`ByteArrayBuilder`.

In case of a CSV Encoder, the codec can buffer data to write the column
names of the CSV file. Writing an empty Flux with this Encoder would not
fail but still log a NullPointerException ignored by the reactive
pipeline.

This commit fixes the order and avoid such issues at runtime.

Fixes gh-31656
2023-11-22 20:56:37 +01:00
rstoyanchev 1f19bb2311 Update STOMP WebSocket transport reference docs
Closes gh-31616
2023-11-22 15:32:49 +00:00
Juergen Hoeller 2784410cc6 Polishing 2023-11-22 13:01:03 +01:00
Juergen Hoeller f4ac323409 Test for mixed order across bean factory hierarchy
See gh-28374

(cherry picked from commit 48f3c08395)
2023-11-22 12:46:36 +01:00
rstoyanchev 6db00e63c7 WebSocketMessageBrokerStats implements SmartInitializingSingleton
Closes gh-26536
2023-11-21 17:58:32 +00:00
“7fantasy7” ed613e767a Skip buffer in StreamUtils#copy(String)
(cherry picked from commit 54f87f1ff7)
2023-11-20 21:30:01 +01:00
Juergen Hoeller 65781046cf Polishing
(cherry picked from commit fff50657d2)
2023-11-20 21:23:46 +01:00
Juergen Hoeller 0ee36095e7 Restore outdated local/remote-slsb attributes for declaration compatibility
Legacy EJB attributes are ignored since 6.0 due to being bound to a plain JndiObjectFactoryBean - but can still be declared now, e.g. when validating against the common versions of spring-jee.xsd out there.

Closes gh-31627

(cherry picked from commit 695559879e)
2023-11-20 21:23:42 +01:00
Stéphane Nicoll 0fc38117df Handle default package with AOT processing
Adding generated code in the default package is not supported as we
intend to import it, most probably from another package, and that is
not supported. While this situation is hard to replicate with Java,
Kotlin is unfortunately more lenient and users can end up in that
situation if they forget to add a package statement.

This commit checks for the presence of a valid package, and throws
a dedicated exception if necessary.

Closes gh-31629
2023-11-20 11:54:55 +01:00
Sam Brannen 86b8a70ce6 Ensure PathResourceResolvers log warnings for non-existent resources
Prior to this commit, the getResource() methods in PathResourceResolver
implementations allowed an exception thrown from Resource#getURL() to
propagate instead of logging a warning about the missing resource as
intended.

This commit modifies the getResource() methods in PathResourceResolver
implementations so that the log messages include the output of the
toString() implementations of the underlying resources instead of their
getURL() implementations, which may throw an exception.

Furthermore, logging the toString() output of resources aligns with the
existing output for "allowed locations" in the same log message.

Note that the toString() implementations could potentially also throw
exceptions, but that is considered less likely.

See gh-31623
Closes gh-31624

(cherry picked from commit 7d2ea7e7e1)
2023-11-20 11:50:51 +01:00
Spring Builds 4bf759d872 Next development version (v6.0.15-SNAPSHOT) 2023-11-16 14:07:29 +00:00
rstoyanchev 770cbd2fb5 Revise exception handling in HandlerMappingIntrospector
See gh-31588
2023-11-16 11:15:29 +00:00
Juergen Hoeller e5f04e5ddf Polishing 2023-11-16 11:34:31 +01:00
Brian Clozel c18784678d Reduce allocations in server conventions
This commit optimizes the default observation conventions to reduce
`KeyValues` allocations.
2023-11-16 09:00:24 +01:00
Stéphane Nicoll 51cdff591c Merge pull request #31612 from PiotrFLEURY
* pr/31612:
  Polish "Provide invalid class name in exception message"
  Provide invalid class name in exception message

Closes gh-31612
2023-11-15 20:49:55 +01:00
Stéphane Nicoll d93114df9a Polish "Provide invalid class name in exception message"
See gh-31612
2023-11-15 20:45:24 +01:00
PiotrFLEURY 5ac4c3bd76 Provide invalid class name in exception message
See gh-31612
2023-11-15 20:40:45 +01:00
rstoyanchev 05c3ffb2fb Use InvalidMimeTypeException in MimeTypeUtils#sortBySpecificity
Closes gh-31254
2023-11-15 18:57:23 +00:00
rstoyanchev 19e8ed130c Cache Filter for HandlerMappingIntrospector and log warnings
See gh-31588
2023-11-15 18:57:23 +00:00
Stéphane Nicoll 4464251754 Add missing runtime hints for ProblemDetail mixins
Closes gh-31606
2023-11-15 18:44:17 +01:00
Arjen Poutsma 8868fe2ea5 Fix position bug in NettyDataBuffer::toByteBuffer
Closes gh-31605
2023-11-15 14:23:43 +01:00
Juergen Hoeller c373f496f3 Consistent ordering of overloaded operations 2023-11-15 13:29:35 +01:00
Juergen Hoeller eb1883bdc4 Upgrade to Reactor 2022.0.13 and Netty 4.1.101
Includes RxJava 3.1.8, Apache HttpComponents Core Reactive 5.2.3, POI 5.2.4, Commons IO 2.15, WebJars Locator 0.55, OpenPDF 1.3.33, JRuby 9.4.5, H2 2.2.224, ActiveMQ 5.17.6, Checkstyle 10.12.5

Closes gh-31585
2023-11-15 13:29:13 +01:00
Stéphane Nicoll df6f66110f Fix wrong nullability requirement
Closes gh-31610
2023-11-15 12:01:26 +01:00
rstoyanchev ac235a0c43 Fix checkstyle violation 2023-11-14 20:00:16 +00:00
rstoyanchev a4e3af5cbe Revise HandlerMappingIntrospector caching
Expose methods to set and reset cache to use from a Filter instead
of a method to create such a Filter. Also use cached results only
if they match by dispatcher type and requestURI.

See gh-31588
2023-11-14 19:24:29 +00:00
Sam Brannen e71117dcdf Polish contribution
See gh-31598
2023-11-14 14:46:34 +01:00
Jason d5874ab99e Avoid duplicate resources in PathMatchingResourcePatternResolver on Windows
This commit updates PathMatchingResourcePatternResolver to avoid
returning duplicate resources on MS Windows when searching using the
`classpath*:` prefix and a wildcard pattern that matches resources
which are directly present in a JAR as well as present via classpath
manifest entries.

Closes gh-31598
2023-11-14 14:39:48 +01:00
Juergen Hoeller 99327b7db1 Preserve nested square brackets within parameter name
Closes gh-31596
2023-11-14 12:51:19 +01:00
Juergen Hoeller 3e06441d97 Cache SpEL-loaded types in StandardTypeLocator
Closes gh-31579
2023-11-14 12:46:16 +01:00
Brian Clozel 01f2925048 Upgrade to Micrometer 1.10.13
Closes gh-31586
2023-11-13 14:28:45 +01:00
rstoyanchev 44a37000ec HandlerMappingIntrospector exposes Filter for caching
Closes gh-31588
2023-11-10 17:43:52 +00:00
rstoyanchev 53fe5fafed Minor refactoring in HandlerMappingIntrospector
See gh-31588
2023-11-10 17:27:54 +00:00
rstoyanchev b9bd98fc5b Polishing in HandlerMappingIntrospector
See gh-31588
2023-11-10 11:27:44 +00:00
rstoyanchev 7714110940 Polishing in DefaultWebClient 2023-11-09 12:53:15 +00:00
rstoyanchev 75d1278bde Include port when logging URI in DefaultWebClient
Closes gh-30519
2023-11-09 12:53:15 +00:00
Sébastien Deleuze 620f558547 Register hints for superclass in BindingReflectionHintsRegistrar
Closes gh-31552
2023-11-09 13:11:36 +01:00
Juergen Hoeller 1e78cc35e5 Log4jLog re-resolves ExtendedLogger on deserialization
This is necessary for compatibility with Log4J 2.21, analogous to the existing re-resolution in Spring's SLF4J adapter.

Closes gh-31582
2023-11-09 11:46:22 +01:00
Juergen Hoeller 11fdb5ba17 Upgrade to Log4J 2.21.1, Tomcat 10.1.15, Jetty 11.0.18, Undertow 2.3.10, EclipseLink 3.0.4, Mockito 5.7 2023-11-09 10:53:47 +01:00
Juergen Hoeller 9957bb6918 Check for procedure vs function constants in CallMetaDataContext
Closes gh-31550
2023-11-09 10:52:51 +01:00
lorenzsimon 6a7a0bddb7 Restore support for recursive annotations in Kotlin
This commit reinstates support for recursive annotations in Kotlin.

See gh-28012
See gh-28618
See gh-31400
Closes gh-31518
2023-11-08 13:28:28 +01:00
rstoyanchev 5c012bbb0c Set maxAge correctly when expiring WebSession
Closes gh-31214
2023-11-08 11:44:36 +00:00
rstoyanchev 5df6e8825d Polishing in CookieWebSessionIdResolver
See gh-31214
2023-11-06 11:31:39 +00:00
rstoyanchev 654e822676 Fix Javadoc link 2023-11-03 14:38:53 +00:00
Stéphane Nicoll e943058b18 Merge pull request #31571 from izeye
* pr/31571:
  Add Javadoc since to ProblemDetail.setProperties()

Closes gh-31571
2023-11-08 08:04:10 +01:00
Johnny Lim cafb38ad1d Add Javadoc since to ProblemDetail.setProperties()
See gh-31571
2023-11-08 08:02:57 +01:00
Sam Brannen e778d2e908 Polish duplicate key exception error code support for SAP HANA database for R2DBC
See gh-31554
2023-11-07 17:12:29 +01:00
Sam Brannen c5bcfc7682 Polish contribution
See gh-31554
2023-11-07 17:08:44 +01:00
Sam Brannen 5752e03d97 Polishing 2023-11-07 16:58:21 +01:00
Arjen Poutsma dc26d3b0ec Defer cleanup in DefaultServerWebExchange
This commit ensures that the multipartRead flag is read in a deferred
block, and is not evaluated too early.

Closes gh-31567
2023-11-07 15:00:20 +01:00
Stéphane Nicoll 7f94c64b72 Merge pull request #31554 from baratrax
* pr/31554:
  Polish "Add SAP HANA duplicate key exception error code"
  Add SAP HANA duplicate key exception error code

Closes gh-31554
2023-11-07 10:37:14 +01:00
Stéphane Nicoll 50e55d5219 Polish "Add SAP HANA duplicate key exception error code"
See gh-31554
2023-11-07 10:33:14 +01:00
Fabrizio De Felice fcd4ba2f1f Add SAP HANA duplicate key exception error code
See gh-31554
2023-11-07 10:27:51 +01:00
Stéphane Nicoll e73107341c Document that pertypewithin is supported by Spring AOT
Closes gh-25887
2023-11-02 15:39:45 +01:00
rstoyanchev f8a33cd66e Remove outdated reference to Netty in rest-clients section
Closes gh-31526
2023-11-01 13:25:16 +00:00
CroBurnt f088d4a05b Fix link text in @⁠Transactional section of ref docs
Closes gh-31519
2023-10-30 13:29:30 +01:00
Stéphane Nicoll 84c28995fb Improve documentation for the default profile
Closes gh-29071
2023-10-25 11:20:21 +02:00
Juergen Hoeller 925fa0272b Polishing 2023-10-24 22:53:44 +02:00
Juergen Hoeller 09aa59f9e7 Avoid ResolvableType for simple assignability check in copyProperties
Closes gh-27246
2023-10-24 22:53:00 +02:00
Sébastien Deleuze 7874a59771 Remove invalid domain integration tests
Closes gh-31119
2023-10-24 17:54:39 +02:00
rstoyanchev 4dab35205d Avoid super.doTrace for ERROR dispatches
Closes gh-31457
2023-10-24 12:58:11 +01:00
rstoyanchev 5c6b9be3a1 Send 400 for PathVariable that is null after conversion
This implies a value was actually sent, but is not something
that can be converted to the expected type.

Closes gh-31382
2023-10-24 12:53:25 +01:00
Stéphane Nicoll 33fba8ea0c Merge pull request #31483 from bernie-schelberg-invicara
* pr/31483:
  Polish "Return consistent collection type for matrix variables"
  Return consistent collection type for matrix variables

Closes gh-31483
2023-10-24 10:56:36 +02:00
Stéphane Nicoll 9aa707ec4b Polish "Return consistent collection type for matrix variables"
See gh-31483
2023-10-24 10:55:42 +02:00
Bernie Schelberg ea30c8fb5b Return consistent collection type for matrix variables
See gh-31483
2023-10-24 10:27:47 +02:00
Juergen Hoeller 6bdf7ad36a Polishing 2023-10-23 17:32:45 +02:00
Juergen Hoeller d2108d2db6 Test for @Resource @Lazy fallback type match
See gh-31447
2023-10-23 17:32:35 +02:00
Juergen Hoeller f9be717602 Avoid getObjectType exception for uninitialized ProxyFactoryBean
Closes gh-31473
2023-10-23 17:32:25 +02:00
Stéphane Nicoll bb446a3905 Merge pull request #31433 from martin-lukas
* pr/31433:
  Polish "Ignore @Value on record property"
  Ignore @Value on record property

Closes gh-31433
2023-10-23 11:33:57 +02:00
Stéphane Nicoll f3dce4bb9a Polish "Ignore @Value on record property"
See gh-31433
2023-10-23 11:20:49 +02:00
Martin Lukas 70cb96c1d8 Ignore @Value on record property
See gh-31433
2023-10-23 11:15:24 +02:00
Brian Clozel 6ec264252b Ensure consistent value count in ConcurrentReferenceHashMap#Segment
Prior to this commit, the `ConcurrentReferenceHashMap#Segment` would
recalculate its element count during the restructure phase by
subtracting the number of polled elements from the queue to the current
count.
Later, the newly restructured `references` array would only contain
references that 1) are not in the set of elements to purge and
2) that hold a non-null value.

The issues with this approach are multiple. The newly calculated count
is only an estimate, as some situations can make it invalid, even
temporarily.

* since we initially collected all elements to be purged from the queue,
  the GC might have collected new values. This means that we might
  filter out more references that we initially intended to

* because the restructure operation re-creates new references for all
  elements in the original array, we might later get references from the
  queue that are not in the array anymore. This could lead to
  "duplicate" removals for the same value

Because several methods in the Segment class have special no-op behavior
when `count == 0`, an invalid count can lead to keys appearing missing
when they are actually still present. In some scenarios, this can
decrease the performance of the cache since values need to be
recalculated.

This commit fixes this inconsistency count issue by first using an
estimate in order to decide whether the array needs a resize and then by
counting the actual numbers of elements inserted in the restructured
array as the new count.

Fixes gh-31373
2023-10-19 15:54:31 +02:00
Brian Clozel 187b4e5ea6 Upgrade CI image to ubuntu:jammy-20231004 2023-10-19 10:02:15 +02:00
Brian Clozel 3bc607df53 Upgrade CI to JDK 17.0.9 2023-10-19 10:01:20 +02:00
Stéphane Nicoll 69c92f9ac7 Document when to use multiple property placeholder configurers
This commit adds a warning in the reference guide to address the
use cases where users might be tempted to use several property
placeholder configurers.

Closes gh-14623
2023-10-18 10:12:26 +02:00
Sébastien Deleuze 875eeabb6f Add a properties setter to ProblemDetail
Mainly to allow Kotlin idiomatic properties assignment.

Closes gh-31430
2023-10-17 14:11:24 +02:00
Juergen Hoeller 7a60e2024b BeanCopier sets name prefix for public classes as well
Includes consistent formatting of Spring-patched files.

Closes gh-28699
2023-10-15 16:09:17 +02:00
Brian Clozel da95542d8f Prevent duplicate HTTP server observations
Prior to this commit, HTTP server observations for Spring WebFlux could
be recorded twice for a single request in some cases. The "COMPLETE" and
"CANCEL" signals would race in the reactive pipeline and would trigger
both the `doOnComplete()` and ` `doOnCancel()` operators, each calling
`observation.stop()` on the current observation.
This would in fact publish two different observations for the same
request.

This commit ensures that the instrumentation uses the `Mono#tap`
operator to guard against this case and only call `Observation#stop`
once for each request.

Fixes gh-31417
2023-10-13 14:56:40 +02:00
Stéphane Nicoll 6669ab1ae7 Merge pull request #31416 from GVictorG7
* pr/31416:
  Polish "Replace deprecated method getBuildDir()"
  Replace deprecated method getBuildDir()

Closes gh-31416
2023-10-12 16:19:41 +02:00
Stéphane Nicoll d05ac097dd Polish "Replace deprecated method getBuildDir()"
See gh-31416
2023-10-12 16:14:23 +02:00
Victor Georgescu 35103b0cd1 Replace deprecated method getBuildDir()
See gh-31416
2023-10-12 16:10:40 +02:00
Spring Builds 3b50f992fe Next development version (v6.0.14-SNAPSHOT) 2023-10-12 09:28:10 +00:00
Brian Clozel 4bd54dffbc Upgrade to concourse-release-scripts 0.4.0-SNAPSHOT 2023-10-11 19:16:06 +02:00
Juergen Hoeller 86650d1a39 Polishing 2023-10-11 16:10:53 +02:00
Juergen Hoeller 87424cd605 Upgrade to SLF4J 2.0.9 and AspectJ 1.9.20.1 2023-10-11 15:44:07 +02:00
Juergen Hoeller 80e82cd43f Do not close transactional Connection in doReleaseConnection
Closes gh-28133
2023-10-11 15:43:02 +02:00
Juergen Hoeller 66ce8c9a25 Properly return SQLExceptionTranslator-provided exception
Closes gh-31409
2023-10-11 13:13:22 +02:00
Brian Clozel e9fcb21d55 Refine status KeyValue for HTTP server observations
Prior to this commit, a cancelled exchange would always result in an
`"status":"UNKNOWN"` KeyValue. This only applied to reactive variants,
as cancelled exchanges are not currently detected for Servlet
implementations.

In some cases, exchanges can be cancelled by clients before they are
completed, but the response was actually received by the client. The
response status information has been set by the application and the
response has been committed. For those cases, we shouldn't assume an
"UNKNOWN" value.

This commit assumes that committed responses have a response status set
by the application and that the observations should reflect that. From
now on, we only assume an "UNKNOWN" status if the response has not been
commited.

Fixes gh-31388
2023-10-11 11:17:38 +02:00
Arjen Poutsma ee9dff30c5 Updated Java 17 version in sdkmanrc 2023-10-11 10:36:29 +02:00
Sébastien Deleuze 2158410853 Revert "Support Jackson's DatatypeFeature in Jackson2ObjectMapperBuilder"
This reverts commit 5f053401e2.
2023-10-11 10:10:36 +02:00
Juergen Hoeller e0a55c2caa Upgrade to Micrometer 1.10.12 and Reactor 2022.0.12
Includes Context Propagation 1.0.6, Netty 4.1.100, Jetty 11.0.17, Tomcat 10.1.14, Groovy 4.0.15, Mockito 5.6, Checkstyle 10.12.4

Closes gh-31404
Closes gh-31405
2023-10-11 00:13:51 +02:00
Juergen Hoeller 0b96da4b6d Revise javadoc for LifecycleProcessor bean etc 2023-10-10 23:36:08 +02:00
Juergen Hoeller 387a16bd4e Revise transaction annotation recommendations
Closes gh-23538
2023-10-10 21:56:14 +02:00
Juergen Hoeller 8b5d993e61 Throw IllegalArgumentException for null SQL String
Closes gh-31391
2023-10-10 21:55:12 +02:00
Juergen Hoeller 5459304a4b Re-introduce support for annotation declarations with self references
Closes gh-31400
2023-10-10 21:54:58 +02:00
Stéphane Nicoll 00d4830e5c Merge pull request #31396 from wfouche
* pr/31396:
  Upgrade to gradle-versions-plugin 0.49.0

Closes gh-31396
2023-10-10 20:33:53 +02:00
Werner Fouché 3c2e21a578 Upgrade to gradle-versions-plugin 0.49.0
See gh-31396
2023-10-10 20:33:14 +02:00
Bram Hagens 5f053401e2 Support Jackson's DatatypeFeature in Jackson2ObjectMapperBuilder
Closes gh-31380
2023-10-10 10:13:52 +02:00
Sébastien Deleuze 63770fb074 Document Kotlin declaration-site variance subtleties
Closes gh-31370
2023-10-09 12:42:36 +02:00
Sam Brannen 9df4bce043 Upgrade to Gradle 8.4
Closes gh-31375
2023-10-08 16:08:29 +02:00
Stéphane Nicoll 19fd8159b2 Improve Javadoc of MethodParameter#getAnnotatedElement
This commit adds a reference to the method that can be used to get
the AnnotatedElement at the parameter level.

Closes gh-30397
2023-10-05 16:56:37 +02:00
Sam Brannen 147abc91a5 Polish BeanPropertyRowMapper Javadoc 2023-10-02 17:29:26 +02:00
Stéphane Nicoll e12eb9436d Fix description of default behavior in BeanPropertyRowMapper
Closes gh-29285
2023-10-02 15:07:09 +02:00
rstoyanchev 23162bb306 Undo optimization from 12fe2c that can cause regression
Closes gh-31327
2023-09-29 17:15:23 +01:00
rstoyanchev a2c5fed494 Make targetType in UknownContentTypeException transient
Closes gh-31283
2023-09-28 16:52:03 +01:00
rstoyanchev 957b6b2caf Use URI String as fallback in ReactorClientHttpConnector
Closes gh-31033
2023-09-27 14:01:35 +01:00
Sam Brannen 35f458fa5f Improve diagnostics for negative repeated text count in SpEL
Due to the changes in gh-31341, if the repeat count in a SpEL
expression (using the repeat operator '*') is negative, we throw a
SpelEvaluationException with the MAX_REPEATED_TEXT_SIZE_EXCEEDED
message which is incorrect and misleading.

Prior to gh-31341, a negative repeat count resulted in an
IllegalArgumentException being thrown by String#repeat(), which was
acceptable in terms of diagnostics, but that did not make it
immediately clear to the user what the underlying cause was.

In light of the above, this commit improves diagnostics for a negative
repeated text count in SpEL expressions by throwing a
SpelEvaluationException with a new NEGATIVE_REPEATED_TEXT_COUNT error
message.

Closes gh-31342
2023-09-29 17:45:21 +02:00
Sam Brannen 8e83f93bcb Improve diagnostics for repeated text size overflow in SpEL
If the resulting size of repeated text in a SpEL expression (using the
repeat operator '*') would exceed MAX_REPEATED_TEXT_SIZE, we currently
throw a SpelEvaluationException with the
MAX_REPEATED_TEXT_SIZE_EXCEEDED message.

However, if the calculation of the repeated text size results in
integer overflow, our max size check fails to detect that, and
String#repeat(int) throws a preemptive OutOfMemoryError from which the
application immediately recovers.

To improve diagnostics for users, this commit ensures that we
consistently throw a SpelEvaluationException with the
MAX_REPEATED_TEXT_SIZE_EXCEEDED message when integer overflow occurs.

Closes gh-31341
2023-09-29 16:50:19 +02:00
Juergen Hoeller 407113945d Polishing 2023-09-29 14:58:02 +02:00
Juergen Hoeller 4cf5c7796d Explicit note on local bean access within @PostConstruct method
Closes gh-27876
2023-09-29 14:57:40 +02:00
Juergen Hoeller 847e8a2b23 Restore auto-commit mode if not done by driver
Closes gh-31268
2023-09-29 14:57:17 +02:00
Sam Brannen 9aab4a60f5 Support safe navigation operator with void methods in SpEL
Prior to this commit the Spring Expression Language (SpEL) was able to
properly parse an expression that uses the safe navigation operator
(?.) with a method that has a `void` return type (for example,
"myObject?.doSomething()"); however, SpEL was not able to evaluate or
compile such expressions.

This commit addresses the evaluation issue by selectively not boxing
the exit type descriptor (for inclusion in the generated bytecode) when
the method's return type is `void`.

This commit addresses the compilation issue by pushing a null object
reference onto the stack in the generated byte code when the method's
return type is `void`.

Closes gh-27421
2023-09-29 13:49:48 +02:00
Sam Brannen 1fe2216c59 Test status quo for null-safe Void method references in SpEL 2023-09-29 13:36:38 +02:00
Sam Brannen 5ff9e6955c Test status quo for void function references in SpEL 2023-09-29 13:36:38 +02:00
Sam Brannen 0cb4043aac Polishing 2023-09-29 13:36:38 +02:00
Stéphane Nicoll 6030e62766 Merge pull request #31330 from jihuayu
* pr/31330:
  Add missing `conversionService` field in doc example

Closes gh-31330
2023-09-28 09:32:20 +02:00
纪华裕 867b9f61b2 Add missing conversionService field in doc example
See gh-31330
2023-09-28 09:30:50 +02:00
Sam Brannen 6300fb37ad Include '?' for null-safe navigation in SpEL AST representations
Prior to this commit, if a Spring Expression Language (SpEL) expression
contained property, field, or method references using the null-safe
navigation operator (?.), the generated AST String representation
incorrectly omitted the '?' characters.

For example, 'myProperty?.myMethod()' had a generated AST string
representation of 'myProperty.myMethod()'.

This commit addresses this by introducing isNullSafe() in
MethodReference and reworking the logic in
CompoundExpression.toStringAST().

Closes gh-31326
2023-09-27 16:42:27 +02:00
Sam Brannen 0d22569422 Polishing 2023-09-27 16:34:18 +02:00
Sam Brannen 06658c3c71 Restore zero capacity support in ConcurrentLruCache
Since the rewrite of ConcurrentLruCache in Spring Framework 6.0, an
attempt to create a ConcurrentLruCache with zero capacity results in an
IllegalArgumentException even though the documentation states that zero
capacity indicates "no caching, always generating a new value".

This commit restores the ability to configure a ConcurrentLruCache with
zero capacity and introduces corresponding tests (which were first
verified against the 5.3.x branch to ensure backward compatibility).

See gh-26320
Closes gh-31317
2023-09-27 13:18:30 +02:00
Stéphane Nicoll a37abd5e54 Provide best-effort toString for Lazy resolved message
Previously, MessagingMessageListenerAdapter or any adapter relying on
the default MessagingMessageConverter would log an incoming message
with a toString of the Message that does not provide any extra
information. This is due to the default implementation providing a
lazy resolution message that only attempts to extract the payload
when necessary.

This commit implements a toString method that uses the raw JMS message
if the payload is not available. If it is, the payload is used instead.

Closes gh-21265
2023-09-26 12:29:00 +02:00
Sam Brannen 18456dec52 Reintroduce FastClass in CGLIB class names for @⁠Configuration classes
Given a @⁠Configuration class named org.example.AppConfig which
contains @⁠Bean methods, in Spring Framework 5.3.x and previous
versions, the following classes were created when generating the CGLIB
proxy.

org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa
org.example.AppConfig$$FastClassBySpringCGLIB$$3fec86e
org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa$$FastClassBySpringCGLIB$$82534900

Those class names indicate that 1 class was generated for the proxy for
the @⁠Configuration class itself and that 2 additional FastClass
classes were generated to support proxying of @⁠Bean methods in
superclasses.

However, since Spring Framework 6.0, the following classes are created
when generating the CGLIB proxy.

org.example.AppConfig$$SpringCGLIB$$0
org.example.AppConfig$$SpringCGLIB$$1
org.example.AppConfig$$SpringCGLIB$$2

The above class names make it appear that 3 proxy classes are generated
for each @⁠Configuration class, which is misleading.

To address that and to align more closely with how such generated
classes were named in previous versions of the framework, this commit
modifies SpringNamingPolicy so that generated class names once again
include "FastClass" when the generated class is for a CGLIB FastClass
as opposed to the actual proxy for the @⁠Configuration class.

Consequently, with this commit the following classes are created when
generating the CGLIB proxy.

org.example.AppConfig$$SpringCGLIB$$0
org.example.AppConfig$$SpringCGLIB$$FastClass$$0
org.example.AppConfig$$SpringCGLIB$$FastClass$$1

Closes gh-31272
2023-09-25 20:17:10 +02:00
Sam Brannen d17c75a7ef Test status quo for SpringNamingPolicy
See gh-31272
2023-09-25 20:14:29 +02:00
Sam Brannen f547b6ad2a Polishing 2023-09-25 20:14:29 +02:00
Stéphane Nicoll e1bd13d3d6 Fix note on CGLIB supported method visibility
CGLIB do support package-private and protected methods now so the
note in the reference doc should be changed accordingly.

Closes gh-25001
2023-09-25 15:27:07 +02:00
Sam Brannen 08237da4b4 Simplify equals() implementation in PerTargetInstantiationModelPointcut
For equivalence, we only need to compare the preInstantiationPointcut
fields since they include the declaredPointcut fields. In addition, we
should not compare the aspectInstanceFactory fields since
LazySingletonAspectInstanceFactoryDecorator does not implement equals().

See gh-31238
2023-09-23 12:40:28 +02:00
Sam Brannen f7496a393d Expand scope of equals() in PerTargetInstantiationModelPointcut
This commit expands the scope of equality checks in the implementation
of equals() for PerTargetInstantiationModelPointcut to include all
fields instead of just the pointcut expression for the declared
pointcut.

See gh-31238
2023-09-22 18:17:07 +02:00
Brian Clozel 0f92ba1663 Fix typo in ref docs for pattern comparison
Closes gh-31294
2023-09-22 11:32:50 +02:00
Sam Brannen 865fa33927 Cache CGLIB proxy classes properly again
The introduction of AdvisedSupport.AdvisorKeyEntry in Spring Framework
6.0.10 resulted in a regression regarding caching of CGLIB generated
proxy classes. Specifically, equality checks for the proxy class cache
became based partially on identity rather than equivalence. For
example, if an ApplicationContext was configured to create a
class-based @Transactional proxy, a second attempt to create the
ApplicationContext resulted in a duplicate proxy class for the same
@Transactional component.

On the JVM this went unnoticed; however, when running Spring
integration tests within a native image, if a test made use of
@⁠DirtiesContext, a second attempt to create the test
ApplicationContext resulted in an exception stating, "CGLIB runtime
enhancement not supported on native image." This is because Test AOT
processing only refreshes a test ApplicationContext once, and the
duplicate CGLIB proxy classes are only requested in subsequent
refreshes of the same ApplicationContext which means that duplicate
proxy classes are not tracked during AOT processing and consequently
not included in a native image.

This commit addresses this regression as follows.

- AdvisedSupport.AdvisorKeyEntry is now based on the toString()
  representations of the ClassFilter and MethodMatcher in the
  corresponding Pointcut instead of the filter's and matcher's
  identities.

- Due to the above changes to AdvisorKeyEntry, ClassFilter and
  MethodMatcher implementations are now required to implement equals(),
  hashCode(), AND toString().

- Consequently, the following now include proper equals(), hashCode(),
  and toString() implementations.

  - CacheOperationSourcePointcut
  - TransactionAttributeSourcePointcut
  - PerTargetInstantiationModelPointcut

Closes gh-31238
2023-09-20 16:56:09 +02:00
Sam Brannen 9120f87897 Consolidate AspectJ test fixtures 2023-09-20 16:47:05 +02:00
Sam Brannen edd1e9134f Polishing 2023-09-20 16:47:05 +02:00
Stéphane Nicoll fef3cf8e58 Review AOT-generated code for beanClass and targetType
This commit reviews when an AOT-generated bean definition defines a
beanClass or targetType. Previously, a beanClass was not consistently
set which could lead to issues.

Closes gh-31242
2023-09-18 16:58:01 +02:00
Sébastien Deleuze ce0923b946 Remove Reactor Netty 2 from integration tests
Closes gh-31243
2023-09-15 18:15:26 +02:00
Brian Clozel 227049824c Fix RuntimeHintsPredicates matching rules
Prior to this commit, the `RuntimeHintsPredicates` would assume that
registering introspection or invocation hints for "all declared methods"
on a type would also include "all public methods". This is not true, as
the Java reflection API itself behaves differently.
`getDeclaredMethods()` does not return a superset of `getMethods()`, as
the latter can return inherited methods, but not the former.
Same reasoning applies to fields.

This commit fixes the hints predicates to only match if the correct hint
has been registered.

Fixes gh-31224
2023-09-15 17:50:53 +02:00
Arjen Poutsma 8f130316d2 MultipartParser should respect read position
This commit ensures that the MultipartParser takes a buffer's read
position into account.

Closes gh-31110
2023-09-15 13:46:04 +02:00
Juergen Hoeller 54c4f1b226 Reset findLoadedClassMethod in case of makeAccessible failing
Closes gh-31232
2023-09-14 16:45:16 +02:00
Spring Builds 062c6241e1 Next development version (v6.0.13-SNAPSHOT) 2023-09-14 08:03:11 +00:00
Juergen Hoeller a51eb29e50 Clarify IN clause resolution with List/Iterable parameter
Closes gh-31228
2023-09-14 09:24:18 +02:00
Stephane Nicoll 50d4a44dfc Upgrade to Context Propagation 1.0.5
Closes gh-31223
2023-09-13 18:19:06 +02:00
Stephane Nicoll ebf2cef94e Upgrade to Reactor 2022.0.11
Closes gh-31222
2023-09-13 18:17:52 +02:00
Stephane Nicoll c89002a0fb Upgrade to Micrometer 1.10.11
Closes gh-31221
2023-09-13 18:16:59 +02:00
Sébastien Deleuze 29a4dabbe7 Support @ModelAttribute with suspending function in WebFlux
Closes gh-30894
2023-09-13 17:59:39 +02:00
Sam Brannen f5f8eab405 Remove duplicated section links for test annotations
Since the auto-generated "Section Summary" includes the exact same
links, there's no need to manually duplicate them.
2023-09-13 17:50:12 +02:00
Juergen Hoeller 659500bc1f Polishing 2023-09-13 17:27:32 +02:00
Juergen Hoeller 4235a11c4f Throw IllegalArgumentException for unsupported Duration values
Closes gh-31210
2023-09-13 17:15:32 +02:00
Juergen Hoeller 966b0a92c6 Defensively call Resource.getFile() for fallback resolution
Closes gh-31216
2023-09-13 17:14:04 +02:00
Sam Brannen 4ca70256d6 Backport polishing 2023-09-13 16:09:59 +02:00
Sébastien Deleuze c892ce5537 Refine CORS documentation for wildcard processing
This commit adds a reference documentation section dedicated
to CORS credentialed requests and related wildcard processing.

Closes gh-31143
2023-09-11 18:07:47 +02:00
Sébastien Deleuze 76b8bb2c75 Refine CORS documentation for wildcard processing
This commit refines CORS wildcard processing Javadoc to
provides more details on how wildcards are handled for
Access-Control-Allow-Methods, Access-Control-Allow-Headers
and Access-Control-Expose-Headers CORS headers.

For Access-Control-Expose-Headers, it is not possible to copy
the response headers which are not available at the point
when the CorsProcessor is invoked. Since all the major browsers
seem to support wildcard including on requests with credentials,
and since this is ultimately the user-agent responsibility to
check on client-side what is authorized or not, Spring Framework
continues to support this use case.

See gh-31143
2023-09-11 18:07:31 +02:00
Juergen Hoeller db7654225e Polishing 2023-09-11 17:36:57 +02:00
Juergen Hoeller 78fce80c43 AnnotationUtils.clearCache() includes all annotation caches
Closes gh-31170
2023-09-11 17:36:32 +02:00
Juergen Hoeller 268043e9c9 Align abstract method signatures with original Commons Logging API
Closes gh-31166
2023-09-11 17:36:07 +02:00
Juergen Hoeller 2880e6fba5 Consistently release savepoint after nested transaction
Closes gh-31133
2023-09-11 17:36:00 +02:00
Zakaria Shahen 11dc11e989 Fix typo in comment in XML configuration example
Closes gh-31194
2023-09-10 14:36:17 +02:00
Sam Brannen 10de295a72 Document StandardTypeLocator configuration to support user types
Prior to this commit, it was unclear to users and third parties that it
is necessary to manually configure a StandardTypeLocator with a
specific ClassLoader to ensure that the SpEL expression parser is able
to reliably locate user types.

For example, the StandardBeanExpressionResolver in the spring-context
module configures a StandardTypeLocator using the bean ClassLoader of
the corresponding BeanFactory.

This commit improves the documentation to raise awareness of this fact.

Closes gh-26253
2023-09-08 17:19:51 +02:00
Sam Brannen 1227fe5774 Polishing 2023-09-08 16:30:53 +02:00
Sam Brannen ea41051651 Do not invoke [Map|Collection].isEmpty() in nullSafeConciseToString()
gh-30810 introduced explicit support for collections and maps in
ObjectUtils.nullSafeConciseToString() by invoking isEmpty() on a Map or
Collection to determine which concise string representation should be
used. However, this caused a regression in which an exception was
thrown if the Map or Collection was a proxy generated by
AbstractFactoryBean to support <util:set />, <util:list />, and
<util:map /> in XML configuration.

This commit addresses this set of regressions by always returning
"[...]" or "{...}" for a Collection or Map, respectively, disregarding
whether the map is empty or not.

Closes gh-31138
2023-09-08 16:03:00 +02:00
Sam Brannen 311c58ea2d Polish [Standard]TypeLocator 2023-09-08 15:21:48 +02:00
Sam Brannen 40f1cf67bd Polish DefaultClientResponseTests and suppress "unchecked" warnings 2023-09-08 15:21:48 +02:00
Sam Brannen 6da9aed055 Update copyright header 2023-09-08 15:21:48 +02:00
Sébastien Deleuze 12a01a680b Document some non-nullable Kotlin extensions can throw NoSuchElementException
Closes gh-31189
2023-09-08 13:07:58 +02:00
rstoyanchev 740f3b797f Polishing
See gh-31185
2023-09-08 10:07:21 +01:00
Sébastien Deleuze ab48b88f91 Refine BeanValidationBeanRegistrationAotProcessor logging
This commit prints a log message at debug level without
a stacktrace for TypeNotPresentException and uses
warn level instead of error level for other exceptions
since the processing of such bean will just be skipped.

Closes gh-31147
2023-09-08 10:50:57 +02:00
rstoyanchev eda35e8074 Add note to the interceptor section of the MVC config
Closes gh-31185
2023-09-08 09:17:59 +01:00
Brian Clozel e4887f3ed9 Upgrade Ubuntu in CI image
Upgrade to ubuntu:jammy-20230816
2023-09-07 17:27:41 +02:00
Sam Brannen 1cdbd68aec Revise FilePatternResourceHintsRegistrar API and improve documentation
This commit revises the FilePatternResourceHintsRegistrar API and
introduces List<String> overrides of various var-args methods used with
the new builder API.

Closes gh-29161
2023-09-07 16:45:50 +02:00
Sam Brannen 453c0e5191 Backport changes from main 2023-09-07 16:45:50 +02:00
rstoyanchev a6b567a630 Polishing 2023-09-07 15:27:40 +01:00
rstoyanchev 7a516170ef WebClientResponseException supports decoding empty content
Closes gh-31179
2023-09-07 15:27:40 +01:00
shin-mallang 249f6f2da5 Polish resolveArgument method in RequestResponseBodyMethodProcessor
Closes gh-31175
2023-09-07 13:09:40 +02:00
Johnny Lim 73766c01e6 Add Javadoc since tags in FilePatternResourceHintsRegistrar
See gh-29161
Closes gh-31174
2023-09-05 16:31:46 +02:00
Juergen Hoeller 278f228688 Upgrade to Groovy 4.0.14, Tomcat 10.1.13, Jetty 11.0.16, Netty 4.1.97, Undertow 2.3.8, Mockito 5.5 2023-09-03 01:25:47 +02:00
Juergen Hoeller c0c4298048 Polishing 2023-09-03 01:14:55 +02:00
Juergen Hoeller 61f89a1f04 Refine note on listener container setup with CachingConnectionFactory
Closes gh-25503
2023-09-03 01:13:51 +02:00
Sam Brannen 3e3f05109f Polishing 2023-09-02 19:06:10 +02:00
Sam Brannen 2d1d14b145 Add /framework-*/build to .gitignore
Due to the introduction of the `framework-api` project in the main branch,
we now have 3 `framework-*` projects that should be ignored. I have
therefore removed `/framework-bom/build` and `/framework-docs/build` and
added `/framework-*/build` to ignore all 3 framework projects.

See gh-31049
2023-09-02 18:28:24 +02:00
Sébastien Deleuze 1641cb75e2 Refine Reactor field precomputing on native
This commit refines Reactor field precomputing on native
to only compute at build-time fields in the reactor.core
package, since doing so in reactor.netty has unwanted side
effects like Epoll always disabled.

Closes gh-31141
2023-09-01 12:52:27 +02:00
Sam Brannen c01e1b8901 Document purpose of the name attribute in @PropertySource
Closes gh-30195
2023-08-31 13:39:22 +02:00
Sam Brannen 2e4e43b5bd Polish org.springframework.core.env.PropertySource
See gh-30195
2023-08-31 13:38:13 +02:00
Sam Brannen 6876c284f4 Upgrade to Checkstyle 10.12.3 2023-08-28 14:43:40 +02:00
Sam Brannen b167152108 Upgrade to spring-javaformat-checkstyle 0.0.39 2023-08-28 14:43:05 +02:00
Sam Brannen bbf73848b5 Update warning for use of convention-based annotation attribute overrides
See gh-28761
2023-08-27 19:02:57 +02:00
Stephane Nicoll 1af259f928 Merge pull request #29753 from perlun
* pr/29753:
  Polish "Make sure NoUniqueBeanDefinitionException to be serializable"
  Make sure NoUniqueBeanDefinitionException to be serializable

Closes gh-29753
2023-08-27 18:03:44 +02:00
Stephane Nicoll 1396daa4b6 Polish "Make sure NoUniqueBeanDefinitionException to be serializable"
See gh-29753
2023-08-27 17:59:27 +02:00
Per Lundberg 1b409d5290 Make sure NoUniqueBeanDefinitionException to be serializable
See gh-29753
2023-08-27 17:56:58 +02:00
Stephane Nicoll ca14202d78 Merge pull request #27115 from gnagy
* pr/27115:
  Update copyright of changed file
  Allow null attribute value in Model.set()

Closes gh-27115
2023-08-26 16:41:05 +02:00
Stephane Nicoll 7231f22c23 Update copyright of changed file
See gh-27115
2023-08-26 16:39:25 +02:00
Gergely Nagy 3470240ef0 Allow null attribute value in Model.set()
See gh-27115
2023-08-26 16:38:19 +02:00
Sam Brannen 7598bca799 Revise Checkstyle rules to prohibit use of assertions other than AssertJ
Closes gh-31116
2023-08-26 15:28:25 +02:00
Sam Brannen f9588de247 Reinstate FailingBeforeAndAfterMethodsTestNGTests
The tests were ignored due to "Fails against TestNG 6.11"; however,
these tests pass against the current version of TestNG that we build
against (7.8.0).
2023-08-26 15:22:38 +02:00
Stephane Nicoll 2b3539a6de Merge pull request #26761 from 1zg12
* pr/26761:
  Polish "Restore customization of PropertyResolver"
  Restore customization of PropertyResolver

Closes gh-26761
2023-08-26 10:17:45 +02:00
Stephane Nicoll 2731d4f100 Polish "Restore customization of PropertyResolver"
See gh-26761
2023-08-26 10:17:02 +02:00
lwpro2 00fffb7ab0 Restore customization of PropertyResolver
This commit reintroduces the ability to customize the PropertyResolver
to use in PropertySourcesPropertyResolver

See gh-26761
2023-08-26 10:09:42 +02:00
Sam Brannen 89b7a6bf47 Skip searching of nonexistent directory in PathMatchingResourcePatternResolver
Prior to this commit, when PathMatchingResourcePatternResolver
processed a `file:` pattern (for example, `file:/app-config/**`) for a
`rootPath` that did not exist in the filesystem, the resolver attempted
to search the directory and logged a WARNING message similar to the
following when it failed to do so.

Failed to search in directory [/app-config/] for files matching pattern
[**]: java.nio.file.NoSuchFileException: /app-config/

To avoid unnecessary attempts to search a nonexistent directory,
PathMatchingResourcePatternResolver now skips searching of a nonexistent
directory and preemptively logs an INFO message similar to the
following.

Skipping search for files matching pattern [**]: directory [/app-config]
does not exist

Closes gh-31111
2023-08-25 16:54:10 +02:00
Sam Brannen 19570338c9 Ensure doFindPathMatchingFileResources() returns a mutable Set
This commit ensures that PathMatchingResourcePatternResolver's
doFindPathMatchingFileResources() method returns a mutable Set in order
to comply with the documented contract.
2023-08-25 16:53:00 +02:00
Juergen Hoeller 906a9f7982 Polishing 2023-08-23 18:52:55 +02:00
Juergen Hoeller 6fed3a0d6b Consistently throw ParseException instead of IllegalStateException
Closes gh-31097
2023-08-23 18:50:52 +02:00
Sébastien Deleuze 8934eb8464 Optimize ClassUtils#getMostSpecificMethod
This commit optimizes ClassUtils#getMostSpecificMethod which is
a method frequently invoked in typical Spring applications.

It refines ClassUtils#isOverridable by considering static and
final modifiers as non overridable and optimizes its implementation.

Closes gh-30272
2023-08-23 18:07:54 +02:00
Stephane Nicoll 4b9f89101d Clarify handling of several representations for JOpt options
See gh-22168
2023-08-23 10:46:21 +02:00
Stephane Nicoll b204f2e396 Merge pull request #30107 from izeye
* pr/30107:
  Use IllegalStateException in ReactiveTestTransactionManager.doCommit()

Closes gh-30107
2023-08-22 17:01:15 +02:00
Johnny Lim 112f755e17 Use IllegalStateException in ReactiveTestTransactionManager.doCommit()
See gh-30107
2023-08-22 17:00:11 +02:00
Stephane Nicoll 542d0ef0b4 Merge pull request #31091 from aahlenst
* pr/31091:
  Fix invalid type name in RSocket code example

Closes gh-31091
2023-08-22 16:57:21 +02:00
Andreas Ahlenstorf 452b2df849 Fix invalid type name in RSocket code example
See gh-31091
2023-08-22 16:55:59 +02:00
Sam Brannen 229b4782ee Add @Nullable in doSetValue() in Argument[Type]PreparedStatementSetter
This commit adds @Nullable to the argValue parameters in the
doSetValue() methods in ArgumentPreparedStatementSetter and
ArgumentTypePreparedStatementSetter.

Closes gh-31086
2023-08-21 16:01:42 +02:00
Sam Brannen ad1554a631 Polishing 2023-08-21 16:01:22 +02:00
Juergen Hoeller 8be77cc650 Revise documentation for cache infrastructure setup
Closes gh-28250
2023-08-21 15:42:50 +02:00
Sam Brannen d0d0ed0578 Update copyright headers 2023-08-21 15:18:04 +02:00
Sam Brannen 9911d91f08 Add implementation note
See gh-31083
2023-08-21 15:17:57 +02:00
Sam Brannen 620a87bcbc Polishing 2023-08-21 14:17:05 +02:00
Yanming Zhou 368036cab4 Allow overriding dynamic property from enclosing class in nested test class
Prior to this commit, a dynamic property registered via a
@DynamicPropertySource method in a @Nested test class was not able to
override a property registered via a @DynamicPropertySource method in
the enclosing class.

See gh-26091
Closes gh-31083
2023-08-21 14:03:24 +02:00
Juergen Hoeller 8a6c0cd221 Polishing 2023-08-21 12:37:58 +02:00
Juergen Hoeller b0fc2fe473 Document destroy method inference more prominently
Closes gh-29546
2023-08-21 12:32:45 +02:00
Juergen Hoeller 2952cb95f5 Document custom SimpleApplicationEventMulticaster setup
Closes gh-29996
2023-08-21 12:32:33 +02:00
Sébastien Deleuze c91708c1c0 Add missing proxy hints for Hibernate native query
This commit contributes proxy hints needed by
SharedEntityManagerCreator for
org.hibernate.query.sql.internal.NativeQueryImpl interfaces.

A related smoke test has been contributed via
spring-projects/spring-aot-smoke-tests#188.

Closes gh-29603
2023-08-18 17:22:57 +02:00
Stephane Nicoll 47b1a2bc55 Clarify usage of FilePatternResourceHintsRegistrar
This commit review the API using a builder to make it more clear what
the registrar does.

Closes gh-29161
2023-08-18 15:35:20 +02:00
Sébastien Deleuze e6565c600a Refine type conversion errors in ModelAttributeMethodProcessor
This commit turns TypeMismatchException thrown in
ModelAttributeMethodArgumentResolver#createAttribute into
proper ServerWebInputException in order get HTTP response
with 400 Bad Request status code instead of 500 Internal error.

Closes gh-31045
2023-08-18 14:31:43 +02:00
Sébastien Deleuze 8af9648c43 Polish ModelAttributeMethodArgumentResolverTests 2023-08-18 12:47:44 +02:00
Juergen Hoeller c5bdd9d79d Optimize whitespace checks in StringUtils
Closes gh-31067
2023-08-18 11:25:48 +02:00
Sam Brannen 9efa99e0d8 Update link to "Method visibility and @Transactional in proxy mode"
See gh-31057
See gh-25582
2023-08-17 17:54:44 +02:00
Sam Brannen 957eb021d7 Upgrade to Gradle 8.3
Closes gh-31061
2023-08-17 17:32:05 +02:00
Juergen Hoeller c8a4026512 Revise note on non-public transactional methods for 6.0
Closes gh-31057
See gh-25582
2023-08-17 10:24:03 +02:00
Juergen Hoeller 2111bf9b9d Upgrade to Caffeine 3.1.8 and Apache HttpComponents Core Reactive 5.2.2 2023-08-16 17:53:02 +02:00
Juergen Hoeller c72dd1ff66 Change "!void" pointcut expression to "int" for AspectJ 1.9.20 2023-08-16 17:32:26 +02:00
Juergen Hoeller 43bd78913c Polishing 2023-08-16 16:52:53 +02:00
Juergen Hoeller 5458e0dccc Upgrade to Tomcat 10.1.12 and AspectJ 1.9.20 2023-08-16 16:52:45 +02:00
Sébastien Deleuze 78a73e5f57 Add missing Hibernate 6.2 proxy hints
This commit contributes proxy hints needed by
SharedEntityManagerCreator for
org.hibernate.query.sqm.internal.QuerySqmImpl interfaces.

Until Hibernate 6.1, those hints were erroneously provided
at GraalVM reachability metadata level. As of Hibernate 6.2,
they are not, hence the need to contribute them at Spring
Framework level.

A related smoke test has been contributed via
spring-projects/spring-aot-smoke-tests#188.

Closes gh-31050
2023-08-16 15:57:05 +02:00
Juergen Hoeller c7269feeaa Align validation metadata handling in PayloadMethodArgumentResolver
Reuses ValidationAnnotationUtils which is slightly optimized for the detection of Spring's Validated annotation now, also to the benefit of common web scenarios.

Closes gh-21852
2023-08-16 12:48:06 +02:00
Juergen Hoeller 1e75041b00 Consistent references to scalar values vs Parameter objects
See gh-27282
2023-08-16 11:00:17 +02:00
Juergen Hoeller 08bc7ed8f0 Polishing 2023-08-15 23:51:41 +02:00
Juergen Hoeller 2ce75dc415 Polishing 2023-08-14 19:28:19 +02:00
Juergen Hoeller 8b3ddeed05 Test factory-bean/method placeholders as well
See gh-20189
2023-08-14 19:28:12 +02:00
Juergen Hoeller 389238f622 Add registerReactiveTypeOverride method to ReactiveAdapterRegistry
Closes gh-31047
2023-08-14 15:14:22 +02:00
Sam Brannen 6f2a13fafd Polishing 2023-08-12 15:14:05 +02:00
Juergen Hoeller 6baa60d454 Polishing 2023-08-12 14:51:02 +02:00
Juergen Hoeller 92410395e3 Remove outdated documentation references to WebLogic/WebSphere
See gh-22093
2023-08-12 14:50:45 +02:00
Juergen Hoeller d03af15516 Explicit note on connection pool deadlock with REQUIRES_NEW
Closes gh-26250
2023-08-12 14:50:36 +02:00
Juergen Hoeller d781f299c0 Use extracted attributes instead of annotation access
See gh-31034
2023-08-12 11:34:25 +02:00
Juergen Hoeller 6fc4898a1b Find TransactionalEventListener annotation on target method
Closes gh-31034
2023-08-12 11:19:21 +02:00
Sébastien Deleuze 0c15be004e Use Any? in ProceedingJoinPoint Kotlin examples
This commit changes Any to Any? in ProceedingJoinPoint
Kotlin examples in order to be consistent with Java
and avoid a "NullPointerException: pjp.proceed() must
not be null" error.

Closes gh-31015
2023-08-10 19:12:55 +02:00
AlmostFamiliar 1c6ef3fe38 Use Any? in ProceedingJoinPoint Kotlin examples
This commit changes Any to Any? in ProceedingJoinPoint
Kotlin examples in order to be consistent with Java
and avoid a "NullPointerException: pjp.proceed() must
not be null" error.

See gh-31015
2023-08-10 19:12:42 +02:00
Juergen Hoeller d254bff197 Polishing 2023-08-09 23:53:40 +02:00
Juergen Hoeller 6fc5a78252 Cancel without interruption of currently running tasks
Leave potential interruption up to scheduler shutdown.

Closes gh-31019
2023-08-09 23:53:35 +02:00
Juergen Hoeller d58e48d9f5 Explicit note on FactoryBean resolution with MBeanExporter
Closes gh-21676
2023-08-08 20:11:28 +02:00
Juergen Hoeller 8973d1ad8a Polishing 2023-08-08 20:10:23 +02:00
Juergen Hoeller 2aae0a4e0c Polishing 2023-08-07 14:51:58 +02:00
Juergen Hoeller 156b3696a7 Reinstate Introspector.flushFromCaches() call for JDK ClassInfo cache
Closes gh-27781
2023-08-07 14:51:49 +02:00
Juergen Hoeller c36174b263 Polishing 2023-08-06 14:59:44 +02:00
Juergen Hoeller 6e5af9dccb Polishing 2023-08-06 14:25:39 +02:00
Sam Brannen 4a81814dbb Check exception cause for @PropertySource(ignoreResourceNotFound) support
Prior to this commit, the ignoreResourceNotFound flag in
@PropertySource was ignored by PropertySourceProcessor if a
PropertySourceFactory threw an exception which wrapped an exception
that would otherwise be ignored -- for example, a FileNotFoundException.

To address this issue, this commit updates PropertySourceFactory so
that it catches RuntimeException and IOException and then checks if the
exception or its cause is an "ignorable" exception in terms of
ignoreResourceNotFound semantics.

Closes gh-22276
2023-08-05 10:19:43 +03:00
Sam Brannen 1451f30781 Polish PropertySourceProcessor 2023-08-05 10:19:43 +03:00
Sam Brannen 4b54ca46d3 Polish PropertySourceDescriptor 2023-08-05 10:19:43 +03:00
Sam Brannen 169392e132 Polish StringHttpMessageConverterTests 2023-08-04 15:53:37 +03:00
Sam Brannen c050642290 Polish contribution
See gh-30942
2023-08-04 15:50:07 +03:00
Patrick Strawderman 7636eecb48 Use readNBytes in StringHttpMessageConverter when contentLength is available
When the content length is known, use readNBytes on the InputStream in
StringHttpMessageConverter, which avoids some extra copying and allocations.

Closes gh-30942
2023-08-04 15:43:10 +03:00
Sam Brannen d890827bae Fisk asterisk formatting in Asciidoc 2023-08-04 15:41:39 +03:00
xumengqi 07a1aea9c7 Skip array sort when the length of array not greater than 1
Closes gh-30934
2023-08-04 15:25:46 +03:00
Sébastien Deleuze da7b68a643 Support Kotlin Serialization custom serializers
This commit updates WebMVC converters and WebFlux
encoders/decoders to support custom serializers
with Kotlin Serialization when specified via
a custom SerialFormat.

It also turns the serializers cache to a non-static
field in order to allow per converter/encoder/decoder
configuration.

Closes gh-30870
2023-08-04 11:25:40 +02:00
Brian Clozel e83793ba7f Batch SSE events writes when possible
Prior to this commit, the `SseEventBuilder` would be used to create SSE
events and write them to the connection using the `ResponseBodyEmitter`.
This would send each data item one by one, effectively writing and
flushing to the network for each. Since multiple data lines are prepared
by the `SseEventBuilder`, a typical write of an SSE event performs
multiple flushes operations.

This commit adds a method on `ResponseBodyEmitter` to perform batch
writes (given a `Set<DataWithMediaType>`) and only flush once all
elements of the set have been written.
This also applies in case of early writes, where now all buffered
elements are written then flushed altogether.

Fixes gh-30912
2023-08-04 10:31:43 +02:00
Juergen Hoeller 18966d048c Consistent equals/hashCode style (and related polishing) 2023-08-04 02:39:31 +02:00
Juergen Hoeller 7e6612a920 Sort multiple @Autowired methods on same bean class via ASM
Closes gh-30359
2023-08-04 00:47:18 +02:00
Juergen Hoeller 9333ed22f6 Avoid repeated FactoryBean targetType check
See gh-30987
2023-08-04 00:47:04 +02:00
Juergen Hoeller 4b6fabbd2f Polishing 2023-08-03 18:10:13 +02:00
Juergen Hoeller cba2b6eaf4 Check FactoryBean targetType for generic type as well
Closes gh-30987
2023-08-03 18:10:07 +02:00
Sam Brannen 34747baed0 Fix broken links to AOT sections 2023-08-03 11:27:16 +03:00
Sam Brannen 7c5b2db5bf Suppress warnings in tests 2023-08-02 11:09:56 +03:00
Sam Brannen 2e07a72119 Delete duplicate DummyFactory 2023-08-02 11:09:15 +03:00
Sam Brannen 9ba5622efd Update outdated Javadoc for PathPatternParser.defaultInstance
Spring Framework 6.0 changed the default value of
matchOptionalTrailingSeparator from true to false.

Closes gh-30976
2023-08-02 10:35:00 +03:00
Sam Brannen 3ff81a47c9 Polish PathPatternParser 2023-08-02 10:33:34 +03:00
Sam Brannen dcec61ab7a Remove obsolete dependency on picocli
The dependency on picocli was removed from the code in commit 019785a72e.

This commit removes the dependency management from the build.

See gh-28825
2023-08-02 09:54:32 +03:00
Philippe Marschall 4922e0e439 Give spring-core access to org.jboss.vfs for VfsUtils support on WildFly
This commit gives spring-core access to the org.jboss.vfs module to make
VfsUtils work out of the box on WildFly 28+.

Closes gh-30973
2023-08-02 09:45:28 +03:00
Juergen Hoeller 7adacd5ce5 Upgrade to Netty 4.1.96 2023-08-02 01:34:18 +02:00
Juergen Hoeller 08d89f7aac Avoid Aalto XML parser override 2023-08-02 01:32:29 +02:00
Juergen Hoeller d250a5155a Consistent dependency declarations 2023-08-02 00:56:50 +02:00
Juergen Hoeller 52176edcbf Polishing 2023-08-02 00:06:49 +02:00
Juergen Hoeller ae279eaced Polishing 2023-08-01 23:52:48 +02:00
Juergen Hoeller 18e72d5c01 Always use given fallback producer in case of TypeBootstrapContext
Closes gh-30924
2023-08-01 23:52:33 +02:00
Sam Brannen 148f5c459e Update copyright headers 2023-08-01 14:54:09 +03:00
Juergen Hoeller abbea39855 Polishing 2023-07-27 21:47:54 +02:00
Juergen Hoeller 6fd40a8f60 Upgrade to Caffeine 3.1.7 and H2 2.2.220 2023-07-26 14:15:58 +02:00
Juergen Hoeller 333249e7b0 Polishing 2023-07-26 14:07:08 +02:00
Juergen Hoeller 2573ba4a50 Polishing 2023-07-26 12:07:11 +02:00
Juergen Hoeller bbde68c49e Polishing 2023-07-25 19:12:07 +02:00
Juergen Hoeller fdf1418dfb Polishing 2023-07-24 11:21:13 +02:00
Juergen Hoeller 5bcf5c6f7c Clarify DataAccessException/ScriptException declarations for R2DBC
Closes gh-30932
2023-07-24 11:21:07 +02:00
Juergen Hoeller 87d4afda81 Upgrade to Netty 4.1.95 2023-07-22 00:31:19 +02:00
Juergen Hoeller 3a9e0ea8a7 Polishing 2023-07-22 00:31:09 +02:00
Juergen Hoeller 4ce1ac0dcb Polishing 2023-07-21 20:36:43 +02:00
Juergen Hoeller 8cc6dd629a Polishing 2023-07-19 22:58:27 +02:00
Juergen Hoeller 391d7f2c6a Polishing 2023-07-19 22:47:20 +02:00
Juergen Hoeller c64a322e19 Polishing 2023-07-19 01:25:20 +02:00
Juergen Hoeller 2f33e77ab4 Consistent equals/hashCode style (and related polishing) 2023-07-19 00:35:19 +02:00
Juergen Hoeller bbcc788f60 Decouple exception messages for sync=true from @Cacheable 2023-07-18 22:02:09 +02:00
Juergen Hoeller 038dda97f8 Document EntityManager injection via constructors/@Autowired
Closes gh-15076
2023-07-18 22:01:57 +02:00
Juergen Hoeller 1ac0549881 Polishing 2023-07-18 12:55:32 +02:00
Juergen Hoeller 616f728afa MethodIntrospector handles overriding bridge method correctly
Closes gh-30906
2023-07-18 12:54:59 +02:00
Juergen Hoeller 161a717639 Avoid synchronization for shortcut re-resolution
See gh-30883
2023-07-16 16:22:17 +02:00
Sam Brannen 28e63e9279 Polishing 2023-07-16 14:35:22 +02:00
Sam Brannen 11de70ed08 Update Javadoc for SimpleTriggerFactoryBean.setMisfireInstructionName()
org.quartz.Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY is also
supported.
2023-07-16 14:34:42 +02:00
Sam Brannen 9283fd2162 Update Javadoc for CronTriggerFactoryBean.setMisfireInstructionName()
org.quartz.Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY is also
supported.
2023-07-16 14:05:24 +02:00
Sam Brannen 544f594592 Update copyright headers 2023-07-15 18:23:37 +02:00
jongwooo c21a8aa8b0 Wrap ternary operator within parentheses as outlined in Code Style
Closes gh-30358
2023-07-15 18:04:01 +02:00
Sam Brannen 30d6ec3398 Update copyright headers 2023-07-15 16:01:15 +02:00
Johnny Lim ab83972c3e Add missing @Nullable annotations in AbstractResourceResolver subclasses
See gh-30601
Closes gh-30893
2023-07-15 16:00:32 +02:00
Sam Brannen 9e3f3bee71 Consistently throw TestContextAotException in TestContextAotGenerator
See gh-30898
2023-07-15 14:55:26 +02:00
Sam Brannen 2ba9939bd8 Revise changes to DefaultGenerationContext and GeneratedClasses
In order to reduce the surface area of published APIs in the affected
classes, this commit:

- Reverts the changes made to GeneratedClasses in c354b1014d.

- Reverts the changes made to DefaultGenerationContext in a28ec3a0a8.

- Makes the DefaultGenerationContext(DefaultGenerationContext, String)
  constructor protected.

- Reworks the internals of TestContextGenerationContext to align with
  the above changes.

See gh-30861
Closes gh-30895
Closes gh-30897
2023-07-15 14:43:39 +02:00
Juergen Hoeller 3a278cc66d Polishing 2023-07-15 14:20:00 +02:00
Juergen Hoeller 6183f06846 Cache DependencyDescriptor per autowired constructor argument
Aligned with shortcut handling in AutowiredAnnotationBeanPostProcessor.
Includes minor MethodInvoker optimization for pre-resolved targetClass.

Closes gh-30883
2023-07-15 14:17:52 +02:00
Sam Brannen a34f9fa66c Update copyright headers 2023-07-15 13:10:46 +02:00
Sam Brannen f5db8bd1e8 Retain existing feature name as prefix in test AOT processing
Prior to this commit, test AOT processing failed if a feature name for
generated class names was used for more than one ApplicationContext.

For example, when generating code for org.example.MessageService with a
"Management" feature name, the "BeanDefinitions" class was named as
follows (without a uniquely identifying TestContext###_ feature name
prefix).

org/example/MessageService__ManagementBeanDefinitions.java

When another attempt was made to generate code for the MessageService
using the same "Management" feature name, a FileAlreadyExistsException
was thrown denoting that the class/file name was already in use.

To avoid such naming collisions, this commit introduces a
TestContextGenerationContext which provides a custom implementation of
withName(String) that prepends an existing feature name (if present) to
a new feature name, thereby treating any existing feature name as a
prefix to a new, nested feature name.

Consequently, code generation for the above example now results in
unique class/file names like the following (which retain the uniquely
identifying TestContext###_ prefixes).

org/example/MessageService__TestContext002_ManagementBeanDefinitions.java
org/example/MessageService__TestContext003_ManagementBeanDefinitions.java

Closes gh-30861
2023-07-15 12:02:11 +02:00
Sam Brannen 317c6fbec2 Introduce failOnError flag in TestContextAotGenerator
This commit introduces a `failOnError` flag in TestContextAotGenerator.
When set to `true`, any error encountered during AOT processing will
result in an exception that fails the overall process. When set to
`false` (the default), the previous behavior remains unchanged: a DEBUG
or WARN message will be logged, and processing will continue.

This feature is currently only used for internal testing.

See gh-30861
Closes gh-30898
2023-07-15 12:02:04 +02:00
Sam Brannen c354b1014d Make GeneratedClasses#withFeatureNamePrefix(String) public
See gh-30861
Closes gh-30897
2023-07-15 12:01:56 +02:00
Sam Brannen a28ec3a0a8 Make DefaultGenerationContext(<classes>,<files>,<hints>) constructor protected
See gh-30861
Closes gh-30895
2023-07-15 12:01:49 +02:00
Juergen Hoeller 6ad647d7ce Explicit hints for @PostConstruct methods (preventing deadlocks)
Closes gh-25074
2023-07-14 16:43:23 +02:00
Juergen Hoeller 384246c360 Polishing 2023-07-14 14:37:34 +02:00
Juergen Hoeller e30391661d Document repeatable annotation semantics for @Scheduled
Closes gh-23959
2023-07-14 14:37:28 +02:00
Juergen Hoeller 75f5dac16b Polishing 2023-07-14 12:16:37 +02:00
Spring Builds bddd3feb83 Next development version (v6.0.12-SNAPSHOT) 2023-07-13 08:37:04 +00:00
Juergen Hoeller c873a597c7 Polishing 2023-07-12 19:21:44 +02:00
Stephane Nicoll 4dc93bc485 Avoid ambiguous call with BeanInstanceSupplier#withGenerator
Previously, BeanInstanceSupplier had three variants of the
`withGenerator` callback, one with a bi function, one with a function,
and with a supplier. This could lead to compilation failure when the
target type has a method with the same name and a number of arguments
that match another variant.

It turns out the supplier-based variant is only used a shortcut. This
commit deprecates it and update ghe code generation to use the function
instead.

Closes gh-29278
2023-07-12 17:23:08 +02:00
Sam Brannen 68f2b0ca59 Rely on auto-boxing in tests 2023-07-12 11:49:02 +02:00
Sam Brannen 1edc0d8002 Remove outdated Javadoc cross references 2023-07-12 10:36:02 +02:00
Sam Brannen a6dc020dc4 Remove since tag 2023-07-12 10:33:24 +02:00
Sam Brannen 07422d709e Remove getAutodetectMode() in MBeanExporter
After further consideration, the team has decided to remove the
getAutodetectMode() method since its return type conflicts with the
parameter type in setAutodetectMode(int), making it an invalid bean
property.

See gh-30855
2023-07-12 10:30:38 +02:00
Brian Clozel 768fc7e341 Upgrade to Reactor 2022.0.9
Closes gh-30871
2023-07-12 08:41:46 +02:00
Johnny Lim 8ecedb81b3 Add missing @Nullable annotations in ContentDisposition.Builder
Closes gh-30820
2023-07-11 19:58:29 +02:00
Juergen Hoeller f19433f2d8 Polishing 2023-07-11 18:01:07 +02:00
Juergen Hoeller 0b02a5e073 Avoid illegal reflective access in ContextOverridingClassLoader
Closes gh-22791
2023-07-11 17:51:55 +02:00
Juergen Hoeller e2b24f3c12 Improve diagnostics for LinkageError in case of ClassLoader mismatch
Closes gh-25940
2023-07-11 17:50:44 +02:00
Juergen Hoeller c375fb1f70 Deprecate setAllowResultAccessAfterCompletion and document it as broken
Closes gh-26557
2023-07-11 17:50:31 +02:00
Sam Brannen ad3e5425d4 Reduce WARN level log output during test AOT processing
Closes gh-30867
2023-07-11 16:35:07 +02:00
Sam Brannen c418118683 Polishing 2023-07-11 15:37:55 +02:00
Sam Brannen fb3f30832c Delete obsolete constant in AnnotationConfigUtils
See gh-30695
2023-07-11 15:33:28 +02:00
Sébastien Deleuze a275d942d2 Update STOMP documentation with the new guidelines
This commit changes the documentation to advise using
https://github.com/stomp-js/stompjs library on client
side and to configure by default WebSocket without
SockJS as browsers and proxies now have a pretty good
WebSocket support.

Closes gh-30857
2023-07-11 14:07:15 +02:00
rstoyanchev 20afa3265a Encapsulate full path initialization 2023-07-11 11:10:20 +01:00
Sam Brannen df50c8db3e Upgrade to micrometer-bom 1.10.9 and context-propagation 1.0.4
Closes gh-30860
2023-07-11 10:58:11 +02:00
Sam Brannen 679b668bbb Avoid need for reflection hints for MBeanExporter in native image
Prior to this commit, MBeanExporter used
org.springframework.core.Constants which used reflection to find
constant fields in the MBeanExporter class. Consequently, one had to
register reflection hints in order to use MBeanExporter in a GraalVM
native image.

This commit addresses this by replacing the use of the `Constants`
class with a simple java.util.Map which maps constant names to constant
values for the autodetect constants defined in MBeanExporter.

See gh-30851
Closes gh-30846
2023-07-10 19:01:44 +02:00
Sam Brannen 676daa990b Reorganize methods in MBeanExporter 2023-07-10 18:28:45 +02:00
Sam Brannen 7c7fa69558 Introduce getAutodetectMode() in MBeanExporter
Closes gh-30855
2023-07-10 18:26:33 +02:00
Sam Brannen 9ad92b16b0 Polish MBeanExporterTests 2023-07-10 18:20:39 +02:00
Juergen Hoeller 3b899fe7e2 Handle JDBC warnings in case of a statement exception as well
Closes gh-23106
2023-07-10 17:17:30 +02:00
Sébastien Deleuze c91041b675 Improve RSocketClientToServer*IntegrationTests reliability
Those new delays seems to make tests more reliable.

Closes gh-30844
2023-07-09 18:39:50 +02:00
Juergen Hoeller a17cf742b2 Polishing 2023-07-09 16:55:21 +02:00
Juergen Hoeller a102cd5f32 Tolerate isCandidateClass call with null as annotation type
Closes gh-30842
2023-07-09 16:52:54 +02:00
Juergen Hoeller d03b6aa1d6 Reinstate support for legacy JSR-250 Resource annotation
This merges the existing support for the legacy JSR-250 PostConstruct/PreDestroy annotations into CommonAnnotationBeanPostProcessor itself, opening up the InitDestroyAnnotationBeanPostProcessor base class for multiple init/destroy methods in a single post-processor. This removes the need for a separate JSR-250 InitDestroyAnnotationBeanPostProcessor in AnnotationConfigUtils.

Closes gh-30695
2023-07-09 16:52:17 +02:00
Sam Brannen b32b4f3a59 Polish DefaultSingletonBeanRegistryTests 2023-07-09 15:32:20 +02:00
Sam Brannen 502997d8e9 Further simplify DefaultSingletonBeanRegistry.isDependent()
See gh-30839
2023-07-09 15:32:20 +02:00
bnbakp0582 fb4ad2f3ba Simplify DefaultSingletonBeanRegistry.isDependent()
Move `alreadySeen` handling out of for-loop.

Closes gh-30839
2023-07-09 15:22:35 +02:00
Sébastien Deleuze b3de1b8e95 Use consistently *KotlinTests naming for Kotlin tests
Closes gh-30837
2023-07-08 11:02:20 +02:00
Sébastien Deleuze fb17e283d1 Replace @link by proper KDoc class reference in tests
Closes gh-30836
2023-07-08 10:44:40 +02:00
Juergen Hoeller 0b7a24fc14 Polishing 2023-07-08 00:58:20 +02:00
Sam Brannen 75b540f25c Update copyright headers 2023-07-07 15:03:09 +02:00
Sam Brannen 8bf79cc9c4 Polish contribution
Closes gh-30593
2023-07-07 15:02:38 +02:00
Heo YounHaeng 7ff80bc09d Fix example in Javadoc for MultipartBodyBuilder
See gh-30593
2023-07-07 15:00:47 +02:00
Valery Yatsynovich 8d6b0eb191 Fix typo in UriUtils Javadoc
Closes gh-30598
2023-07-07 14:50:46 +02:00
Juergen Hoeller 35c7e3960e Polishing 2023-07-07 13:46:57 +02:00
Juergen Hoeller 8e8c3f5a7c Polishing 2023-07-07 13:14:40 +02:00
Sam Brannen f50b230fb3 Emphasize that a ContextCustomizer must implement equals() and hashCode() 2023-07-06 17:28:24 +02:00
Sam Brannen 02ba06953f Polish grammar and formatting 2023-07-06 17:21:30 +02:00
Brian Clozel df22ba39f8 Warn against direct usage of Servlet API in WebFlux apps
Closes gh-28872
2023-07-06 17:11:24 +02:00
Sam Brannen 826776f321 Improve assertions in DefaultConversionServiceTests
Specifically, we now check the actual type of a converted collection in
various assertions to ensure that converters adhere to their contracts.
2023-07-06 14:01:26 +02:00
Sam Brannen 29f92c8a2b Polish observability docs 2023-07-06 13:27:20 +02:00
Brian Clozel 64e04b7bc2 Document limitations of Servlet Filter observations
This commit documents the fact that the Servlet Filter based
observations for MVC applications is limited by the Servlet Filter
contract in the first place. All processing and logging that happens
outside of the scope of the filter is not observed.
Log statements from the catalina engine (in the case of Tomcat), or any
container-specific infrastructure, is not covered by the
instrumentation.

Closes gh-29398
2023-07-06 13:09:41 +02:00
Sam Brannen ad05b02ff5 Update Javadoc for ObjectUtils.nullSafeConciseToString()
See gh-30810
2023-07-06 12:26:47 +02:00
Brian Clozel 430a24e6bc Further document ShallowEtagHeaderFilter limitations
This commit improves the documentation for the
`ShallowEtagHeaderFilter`, stating that it is only meant to support a
subset of conditional HTTP requests: GET requests with "If-None-Match"
headers. Other headers and state changing HTTP methods are not supported
here, as the filter only operates on the content of the response and has
no knowledge of the resource being served.

Closes gh-30517
2023-07-06 09:39:57 +02:00
Juergen Hoeller b7b9f2cb6b Expand tests for array to Collection/Set/List interface
See gh-28048
2023-07-05 20:15:10 +02:00
Sam Brannen b76664e757 Support arrays, collections, & maps in ObjectUtils.nullSafeConciseToString()
Prior to this commit, there was no explicit support for arrays,
collections, and maps in nullSafeConciseToString(). This lead to string
representations such as the following, regardless of whether the array,
collection, or map was empty.

- char[]@1623b78d
- java.util.ImmutableCollections$List12@74fe5c40
- java.util.ImmutableCollections$MapN@10e31a9a

This commit introduces explicit support for arrays, collections, and
maps in nullSafeConciseToString(), which results in the following
empty/non-empty string representations.

- array: {} / {...}
- collection: [] / [...]
- map: {} / {...}

The reason a string representation of an array uses "{}" instead of
"[]" (like in Arrays.toString(...)) is that
ObjectUtils.nullSafeToString(<array>) already follows that convention,
and the implementation of nullSafeConciseToString() aligns with that
for the sake of consistency.

Closes gh-30810
2023-07-05 17:01:01 +02:00
Sam Brannen ae13823851 Polishing 2023-07-05 15:33:15 +02:00
Sam Brannen 58b4286216 Polish MockHttpServletRequest 2023-07-05 13:59:47 +02:00
Sam Brannen df079feea9 Update copyright header 2023-07-05 13:48:13 +02:00
Patrick Strawderman 372282457f Use Collections.emptyEnumeration() where appropriate
Closes gh-30803
2023-07-05 13:47:11 +02:00
Juergen Hoeller 79df1da792 Clarify ReactiveTransactionManager exception declarations
Avoid misleading "throws TransactionException" declarations but preserve javadoc "@throws" notes for specific exceptions (with reactive propagation semantics).

Closes gh-30817
2023-07-05 12:51:45 +02:00
Juergen Hoeller c5771bc7c8 Discuss JdbcTransactionManager vs DataSourceTransactionManager
Includes doc update for 6.0 default exception translation etc.

Closes gh-30802
2023-07-05 12:51:10 +02:00
Juergen Hoeller 2365581265 Upgrade to HSQLDB 2.7.2 and WebJars Locator 0.53 2023-07-04 21:35:37 +02:00
Juergen Hoeller c1a8b9a14d Polishing 2023-07-04 21:24:35 +02:00
rstoyanchev e945e7426e Update AspectJ Javadoc link after permanent redirect 2023-07-04 18:09:55 +01:00
Juergen Hoeller f07b9fd217 Polishing 2023-07-04 16:52:44 +02:00
Juergen Hoeller 80a20488fd Make File/Path tests pass on Windows
See gh-30806
2023-07-04 16:52:39 +02:00
Juergen Hoeller 1dc9dffc70 Restore full representation of rejected value in FieldError.toString()
We would preferably use ObjectUtils.nullSafeConciseToString(rejectedValue) here but revert to the full nullSafeToString representation for strict backwards compatibility (programmatic toString calls as well as exception messages).

Closes gh-30799
2023-07-04 15:58:46 +02:00
Juergen Hoeller 0226580773 Refresh cached value after unexpected mismatch (e.g. null vs non-null)
In addition to the previously addressed removal of bean definitions, this is able to deal with prototype factory methods returning non-null after null or also null after non-null. Stale cached values are getting refreshed rather than bypassed.

Closes gh-30794
2023-07-04 15:58:30 +02:00
Sam Brannen 3ef1b7d83c Extend supported types in ObjectUtils.nullSafeConciseToString()
This commit extends the list of explicitly supported types in
ObjectUtils.nullSafeConciseToString() with the following.

- Optional
- File
- Path
- InetAddress
- Charset
- Currency
- TimeZone
- ZoneId
- Pattern

Closes gh-30805
2023-07-04 13:27:47 +02:00
Sam Brannen 08bce69d3d Add tests for status quo in ObjectUtils.nullSafeConciseToString() 2023-07-04 13:15:56 +02:00
Yanming Zhou 56b60120fe Stop using deprecated AbstractArchiveTask.archivePath in Gradle build
This commit addresses the following warning in the build.

The AbstractArchiveTask.archivePath property has been deprecated. This
is scheduled to be removed in Gradle 9.0. Please use the archiveFile
property instead. See
https://docs.gradle.org/8.1.1/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.html#org.gradle.api.tasks.bundling.AbstractArchiveTask:archivePath
for more details.

Closes gh-30697
2023-07-03 17:09:48 +02:00
Sam Brannen 1364a179a9 Upgrade to Gradle 8.2
Closes gh-30791
2023-07-03 16:24:34 +02:00
Sam Brannen 2161e865d7 Update copyright header 2023-07-03 15:53:43 +02:00
Vladyslav Baidak 0b2c2d04b2 Fix typo in Javadoc for BeanDefinitionDsl.kt
Closes gh-30798
2023-07-03 15:49:28 +02:00
Sam Brannen 07fe8eea83 Improve error message for wrong version of micrometer-observation
This commit also reverts to using ReflectionUtils.findMethod in order
to make the check more robust in case the Micrometer team refactors the
code base and declares the `getObservationRegistry()` method in a super
type.
2023-07-03 14:48:53 +02:00
Sam Brannen 5aac35b99e Check deps only once in MicrometerObservationRegistryTestExecutionListener
Prior to this commit, the required runtime dependencies were checked
via reflection each time an attempt was made to instantiate
MicrometerObservationRegistryTestExecutionListener.

Since it's sufficient to check for the presence of required runtime
dependencies only once, this commit caches the results of the
dependency checks in a static field.

This commit also introduces automated tests for the runtime dependency
checks in MicrometerObservationRegistryTestExecutionListener.

See gh-30747
2023-07-02 16:40:41 +02:00
Sam Brannen 040ea0a97c Remove @Aspect for classes containing only @Pointcut declarations in ref docs
Closes gh-30790
2023-07-01 17:41:55 +02:00
Sam Brannen 3c05679a97 Polishing
See gh-30762
2023-06-30 14:04:37 +02:00
Yanming Zhou d8729a7c67 Polish variable name in ReschedulingRunnable
As a variable name, `initDelay` is applicable for `scheduleAtFixedRate`
and `scheduleWithFixedDelay` but not for `schedule`.

Closes gh-30762
2023-06-30 13:57:46 +02:00
Sam Brannen c95426a616 Polishing 2023-06-30 13:55:34 +02:00
Juergen Hoeller 1e403d1606 Upgrade to Groovy 4.0.13 and Checkstyle 10.12.1 2023-06-30 12:58:28 +02:00
Juergen Hoeller f1567fb21a Raise beforeCompletion/afterCompletion exception log level to error
Closes gh-30776
2023-06-30 12:47:30 +02:00
Juergen Hoeller 60865eae4b Align ConcurrentMapCacheManager locking behavior with CaffeineCacheManager
Closes gh-30780
2023-06-30 10:39:53 +02:00
Juergen Hoeller 0c39fff831 Polishing 2023-06-29 18:04:08 +02:00
Juergen Hoeller e902f9551a Improve condition assertions 2023-06-29 12:05:07 +02:00
Juergen Hoeller 0a20c8a44a Restore defensive access to volatile field in getBeanClassName()
Closes gh-30773
2023-06-29 12:04:53 +02:00
Juergen Hoeller 3cb746c358 Consistently handle invocation exceptions in TypeProxyInvocationHandler
Closes gh-30764
2023-06-28 15:45:40 +02:00
Juergen Hoeller 6526e79eea Polishing 2023-06-26 19:28:38 +02:00
Juergen Hoeller b77d4d01c5 Adapt no-arg value from interface-based InvocationHandler callback
Closes gh-30756
2023-06-26 19:28:19 +02:00
Juergen Hoeller 599ac58baa Avoid arithmetic overflow for large delay/period values
Closes gh-30754
2023-06-26 19:28:08 +02:00
Juergen Hoeller 449174c7d4 Polishing 2023-06-26 12:35:09 +02:00
Juergen Hoeller 9266e6d29e Remove outdated javadoc notes on getMessage and printStackTrace
Closes gh-30748
2023-06-26 12:34:59 +02:00
Juergen Hoeller 062d701ae1 Consistently use mutable ArrayList for modulesToInstall vs modules
Closes gh-30751
2023-06-26 12:34:54 +02:00
Sébastien Deleuze 7137b22e6b Fix test compilation warnings
Closes gh-30753
2023-06-26 12:03:27 +02:00
Sam Brannen acb786d359 Improve logging in MicrometerObservationRegistryTestExecutionListener
Prior to this commit, dependency checks in the static initialization
block for MicrometerObservationRegistryTestExecutionListener resulted
in an ExceptionInInitializerError which led to verbose logging in
TestContextFailureHandler.

This commit improves the logging for missing dependencies in
MicrometerObservationRegistryTestExecutionListener by moving the
dependency checks to the constructor and by throwing a
NoClassDefFoundError instead of an IllegalStateException. This allows
TestContextFailureHandler to log a concise DEBUG message denoting that
the listener is being skipped due to missing dependencies.

This commit also now checks for the presence of
io.micrometer.context.ThreadLocalAccessor in addition to
io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor.

Furthermore, this commit now explicitly mentions the need for
io.micrometer:context-propagation in the error message.

The following demonstrate the generated DEBUB message when
ObservationThreadLocalAccessor and ThreadLocalAccessor are missing,
respectively.

Skipping candidate TestExecutionListener [org.springframework.test.context.observation.MicrometerObservationRegistryTestExecutionListener] due to a missing dependency. Specify custom TestExecutionListener classes or make the default TestExecutionListener classes and their required dependencies available. Offending class: io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor. MicrometerObservationRegistryTestExecutionListener requires io.micrometer:micrometer-observation:1.10.8 or higher and io.micrometer:context-propagation:1.0.3 or higher.

Skipping candidate TestExecutionListener [org.springframework.test.context.observation.MicrometerObservationRegistryTestExecutionListener] due to a missing dependency. Specify custom TestExecutionListener classes or make the default TestExecutionListener classes and their required dependencies available. Offending class: io.micrometer.context.ThreadLocalAccessor. MicrometerObservationRegistryTestExecutionListener requires io.micrometer:micrometer-observation:1.10.8 or higher and io.micrometer:context-propagation:1.0.3 or higher.

Closes gh-30747
2023-06-25 18:49:57 +02:00
Sam Brannen fa7300c1de Remove unused test code and polish 2023-06-25 15:31:15 +02:00
Sam Brannen db17a97ce8 Polishing 2023-06-25 15:18:59 +02:00
Johnny Lim 55f946c5a0 Fix incomplete AssertJ assertions
Closes gh-30743
2023-06-25 15:18:52 +02:00
Sam Brannen 3181dca5ef Support [package-]private init/destroy methods in AOT mode
Prior to this commit, private (and non-visible package-private)
init/destroy methods were not supported in AOT mode. The reason is that
such methods are tracked using their fully-qualified method names, and
the AOT support for init/destroy methods previously did not take
fully-qualified method names into account. In addition, the invocation
order of init/destroy methods differed vastly between standard JVM mode
and AOT mode.

This commit addresses these issues in the following ways.

- AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(),
  DisposableBeanAdapter.determineDestroyMethod(), and
  BeanDefinitionPropertiesCodeGenerator.addInitDestroyHint() now parse
  fully-qualified method names to locate the correct init/destroy
  methods.

- AbstractAutowireCapableBeanFactory and DisposableBeanAdapter delegate
  to a new MethodDescriptor record which encapsulates the parsing of
  fully-qualified method names; however,
  BeanDefinitionPropertiesCodeGenerator duplicates this logic since it
  resides in a different package, and we do not currently want to make
  MethodDescriptor public.

- Init/destroy methods detected via annotations (such as @PostConstruct
  and @PreDestroy) are now invoked prior to init/destroy methods that
  are explicitly configured by name or convention. This aligns with the
  invocation order in standard JVM mode; however,
  InitializingBean#afterPropertiesSet() and DisposableBean#destroy()
  are still invoked before annotated init/destroy methods in AOT mode
  which differs from standard JVM mode.

- Unit and integration tests have been updated to test the revised
  behavior.

Closes gh-30692
2023-06-24 14:22:17 +02:00
Sam Brannen f86a69ebfb Update copyright headers and polish 2023-06-24 14:14:02 +02:00
Sam Brannen 6d63890c56 Use Assumptions.abort() where appropriate 2023-06-24 14:13:22 +02:00
Sam Brannen 489c89b912 Remove unused test code 2023-06-24 14:12:58 +02:00
Sam Brannen 39bc7566df Stop printing to System.out in tests 2023-06-24 14:10:12 +02:00
Sébastien Deleuze d3a249e34d Reduce the delay used for Coroutines in tests
Closes gh-30731
2023-06-23 14:17:56 +02:00
Sébastien Deleuze 81f1edbaf2 Change InvocableHandlerMethod#invokeSuspendingFunction return type
This commits changes the return type from Publisher<?> to
Object in order to avoid potential compatibility issues when
the Reactive Streams dependency is not in the classpath.

Closes gh-30716
2023-06-23 14:17:56 +02:00
Sébastien Deleuze 23ecb50137 Optimize KotlinReflectionParameterNameDiscoverer
This commit removes the intermediate list allocation.

Closes gh-30725
2023-06-23 14:17:56 +02:00
Sam Brannen 3d33d2baa9 Polish contribution 2023-06-23 13:35:16 +02:00
Xiu Hong Kooi 3745224646 Remove redundant assertion in ReactorServerHttpResponse constructor
See gh-30686
Closes gh-30696
2023-06-23 13:34:31 +02:00
Sam Brannen 3bf78d6f8c Fix AbstractMessageListenerContainer Javadoc regarding error log level
This commit updates AbstractMessageListenerContainer's Javadoc
regarding the log level used in invokeErrorHandler() so that the
documentation aligns with the implementation, namely that errors will
logged at WARN level if no ErrorHandler has been registered.

Closes gh-30730
2023-06-23 12:45:52 +02:00
Sam Brannen 563b2a8505 Polish AbstractMessageListenerContainer Javadoc 2023-06-23 12:44:57 +02:00
Sam Brannen 9ccbeec947 Ignore null message when introspecting resource cleanup failure
This commit fixes a regression introduced in conjunction with gh-27572.

See gh-30597
Closes gh-30729
2023-06-23 12:01:16 +02:00
Sam Brannen 29248dff15 Use correct ClassLoader in MicrometerObservationRegistryTestExecutionListener
In the original implementation of
MicrometerObservationRegistryTestExecutionListener I accidentally
imported JUnit 5's org.junit.platform.launcher.TestExecutionListener
instead Spring's
org.springframework.test.context.TestExecutionListener. The code
therefore attempts to use the ClassLoader for the JUnit Platform's
TestExecutionListener which may fail to see the required types. In
addition, if the JUnit Platform's TestExecutionListener is not on the
classpath, the attempt to access its ClassLoader will fail.

This commit addresses this by properly using the ClassLoader for
Spring's TestExecutionListener to detect dependencies of the
MicrometerObservationRegistryTestExecutionListener.

Closes gh-30726
2023-06-22 15:55:46 +02:00
Sam Brannen 65d450ab6d Document that RowCallbackHandler can be used w/ NamedParameterJdbcTemplate
Closes gh-30705
2023-06-22 15:27:41 +02:00
Johnny Lim 271f2dc665 Polish
This commit polishes a bit.

Closes gh-30691
2023-06-22 15:06:05 +02:00
Sam Brannen da323d3335 Update copyright headers 2023-06-22 14:55:23 +02:00
Sam Brannen 32f061a3e0 Polishing 2023-06-22 13:48:07 +02:00
Anton Gubenko 9b5cbc1334 Fix link text from "null" to "Component Classes" in Testing chapter
Closes gh-30714
2023-06-22 11:35:23 +02:00
Johnny Lim 40e378a5a6 Upgrade to me.champeau.jmh 0.7.1
Closes gh-30690
2023-06-22 11:31:32 +02:00
Juergen Hoeller 8eb0a0b94e Upgrade to Tomcat 10.1.10, Netty 4.1.94, Mockito 5.4 2023-06-21 18:52:02 +02:00
Juergen Hoeller 09cf489c6b Test for supportsEventType mismatch with unrelated event type
See gh-30712
2023-06-21 18:24:38 +02:00
Sam Brannen 9a5290ea27 Apply project conventions to formatting 2023-06-21 17:50:42 +02:00
Sam Brannen b3176208e2 Remove invalid Javadoc link 2023-06-21 17:36:36 +02:00
Juergen Hoeller 1dfe737d0e Avoid ResolvableType creation for interface/superclass check
See gh-30713
2023-06-21 17:17:58 +02:00
Juergen Hoeller dc2f513619 Correct supportsEventType checks for payload events
See gh-30712
2023-06-21 17:17:03 +02:00
Sam Brannen 0eb33d09ac Ensure package-private init/destroy methods are always invoked
Prior to this commit, if an init/destroy method was package-private and
declared in a superclass in a package different from the package in
which the registered bean resided, a local init/destroy method with the
same name would effectively "shadow" the method from the different
package, resulting in only the local init/destroy method being invoked.

This commit addresses this issue by tracking package-private init
methods from different packages using their fully-qualified method
names, analogous to the existing support for private init/destroy
methods.

Closes gh-30718
2023-06-21 16:18:19 +02:00
Sam Brannen f67f98a1a7 Polishing 2023-06-21 15:56:50 +02:00
Stephane Nicoll 6c42f374c8 Consistently set target type in generated code
Previously, a bean definition that is optimized AOT could have
different metadata based on whether its resolved type had a generic or
not. This is due to RootBeanDefinition taking either a Class or a
ResolvableType doing fundamentally different things. While the former
sets the bean class which is to little use with an instance supplier,
the latter specifies the target type of the bean.

This commit sets the target type of the bean, using the existing
setter methods that take either a class or a ResolvableType and set the
same attribute consistently.

Closes gh-30689
2023-06-21 14:45:19 +02:00
Sam Brannen 4879b56bb9 Test status quo for private init/destroy methods in AOT mode
This commit only tests which init/destroy methods are "registered" in
AOT mode.

This commit does NOT test that the registered methods can actually be
invoked in AOT mode: that will be addressed in a separate commit.

See gh-30692
2023-06-21 14:19:13 +02:00
Sam Brannen 2fd83aa764 Polish InitDestroyAnnotationBeanPostProcessor internals, etc. 2023-06-21 14:19:00 +02:00
Juergen Hoeller 93218a06ba Cache hasUnresolvableGenerics result for repeated checks
Closes gh-30713
2023-06-21 13:16:04 +02:00
Juergen Hoeller 714c3c59eb Accept unresolvable generics as long as raw event class matches
Closes gh-30712
2023-06-21 13:15:35 +02:00
Juergen Hoeller adcdefce43 Upgrade to Jetty 12.0.0.beta2 2023-06-21 09:49:26 +02:00
Juergen Hoeller 049a024dea Deprecate RootBeanDefinition(ResolvableType) constructor
Closes gh-30704
2023-06-21 09:48:00 +02:00
Juergen Hoeller 20bbebb299 Ensure Spring LogFactory contains all public methods from Apache LogFactory
Closes gh-30668
2023-06-21 09:47:16 +02:00
Sébastien Deleuze 26f006509f Polish CoWebFilter javadoc 2023-06-20 20:56:47 +02:00
Stephane Nicoll 089503aab7 Fix typo 2023-06-20 17:32:24 +02:00
Stephane Nicoll 74155e3d88 Do not invoke AspectJ hints generation if AspectJ is not present
See gh-28711
2023-06-20 17:26:08 +02:00
Sam Brannen 564f33d5ef Polishing 2023-06-20 15:47:41 +02:00
Stephane Nicoll 83acd5b050 Document JPA configuration best practices with AOT
Closes gh-30498
2023-06-20 15:21:12 +02:00
Sam Brannen 67798a7b52 Fix CSS classes in Javadoc HTML tables due to upgrade to Java 17
Closes gh-30701
2023-06-20 13:24:03 +02:00
Stephane Nicoll 2b981651e1 Merge pull request #30601 from cwatzl
* pr/30601:
  Update copyright year of changed file
  Flag PathResourceResolver#resolve*Internal as @Nullable

Closes gh-30601
2023-06-19 15:47:12 +02:00
Stephane Nicoll 294cdba80c Update copyright year of changed file
See gh-30601
2023-06-19 15:44:04 +02:00
cwatzl 072a86149d Flag PathResourceResolver#resolve*Internal as @Nullable
See gh-30601
2023-06-19 15:37:16 +02:00
Sam Brannen 8bb4c167e4 Polishing
See gh-30280
2023-06-17 13:36:37 +02:00
Juergen Hoeller dff7aa4d4b Fall back to type-based creation if no bean of the given name exists
Closes gh-30683
2023-06-17 11:38:57 +02:00
Juergen Hoeller c634acd9ff Recognize error code 2628 as data integrity violation (MSSQL 2019)
Closes gh-30681
2023-06-17 11:38:41 +02:00
Sam Brannen ed5c19f53e Document that @Sql requires spring-jdbc & spring-tx on the classpath
Closes gh-30280
2023-06-16 13:39:35 +02:00
Sébastien Deleuze 03420f811b Add reflection hints for AspectJ advice methods
Closes gh-28711
2023-06-16 11:33:57 +02:00
Sam Brannen 4565bcd757 Update copyright headers 2023-06-15 16:19:58 +02:00
Sam Brannen f22f439a68 Suppress deprecation warning due to upgrade to context-propagation 1.0.3
See gh-30657
2023-06-15 16:18:38 +02:00
Sam Brannen 5672284f53 Remove code duplication in RootBeanDefinition 2023-06-15 16:11:40 +02:00
Spring Builds 367f381fea Next development version (v6.0.11-SNAPSHOT) 2023-06-15 08:31:33 +00:00
Juergen Hoeller b9221656cc Declare ClassLoader for DeserializingConverter constructor as nullable
Closes gh-30670
2023-06-14 22:27:07 +02:00
Juergen Hoeller c30f6aa427 Polishing 2023-06-14 22:17:39 +02:00
Sam Brannen aa2028127f Overhaul TestExecutionListener for Micrometer ObservationRegistry
This commit overhauls the TestExecutionListener for Micrometer's
ObservationRegistry that was introduced in the previous commit.

Specifically, this commit:

- Renames the listener to MicrometerObservationRegistryTestExecutionListener
  since the use of a ThreadLocal is an implementation detail that may
  change over time.

- Makes the listener package-private instead of public in order to
  allow the team greater flexibility in evolving this feature.

- Eagerly loads the ObservationThreadLocalAccessor class and verifies
  that it has a getObservationRegistry() method to ensure that the
  listener is properly skipped when SpringFactoriesLoader attempts to
  load it, if Micrometer 1.10.8+ is not on the classpath.

- Switches the listener's automatic registration order to 2500 in order
  to register it after the DependencyInjectionTestExecutionListener.

- Only tracks the previous ObservationRegistry in beforeTestMethod() if
  the test's ApplicationContext contains an ObservationRegistry bean.

- Properly removes the TestContext attribute for the previous
  ObservationRegistry in afterTestMethod().

- Introduces DEBUG logging for diagnostics.

- Adds an entry in the Javadoc for TestExecutionListener as well as in
  the Testing chapter in the reference manual.

Closes gh-30658
2023-06-14 14:36:05 +02:00
Marcin Grzejszczak a82659c837 Introduce TestExecutionListener for Micrometer ObservationRegistry
Prior to this commit, there was no way to specify the
ObservationRegistry that is registered in the given test's
ApplicationContext as the one that should be used by Micrometer's
ObservationThreadLocalAccessor for context propagation.

This commit introduces a TestExecutionListener for Micrometer's
ObservationRegistry in the Spring TestContext Framework. Specifically,
this listener obtains the ObservationRegistry registered in the test's
ApplicationContext, stores it in ObservationThreadLocalAccessor for the
duration of each test method execution, and restores the original
ObservationRegistry in ObservationThreadLocalAccessor after each test.

Co-authored-by: Sam Brannen <sam@sambrannen.com>
See gh-30658
2023-06-14 14:35:53 +02:00
Juergen Hoeller 3415b04c73 Use nanosecond precision for scheduling (aligned with calculations)
Closes gh-30666
2023-06-14 12:57:17 +02:00
Arjen Poutsma a73ad52a8a Clarify removal of ResponseEntity::getStatusCodeValue 2023-06-14 11:29:21 +02:00
Juergen Hoeller 13c32d80ba Upgrade to Undertow 2.3.7 and JRuby 9.4.3 2023-06-14 11:18:37 +02:00
Juergen Hoeller 3171a8b0e2 Align with 5.3.28 javadoc for isSimpleValueType
See gh-30661
2023-06-14 11:18:18 +02:00
Juergen Hoeller 927d27b121 Consider UUID as simple value type with concise toString output
Closes gh-30661
2023-06-14 09:31:35 +02:00
Juergen Hoeller 1df5e9f30c Upgrade to Reactor 2022.0.8
Closes gh-30655
2023-06-14 09:31:02 +02:00
Sam Brannen ed74b04520 Move web-related test for BeanUtilsRuntimeHints to spring-web
The dependency on spring-web from spring-beans makes it impossible to
import the projects in Eclipse IDE due to cycles between projects.

This commit therefore moves the web-related test for
BeanUtilsRuntimeHints to spring-web.

See gh-30491
2023-06-13 17:12:38 +02:00
Sam Brannen 6cfb11a360 Upgrade to Micrometer BOM 1.10.8 and context-propagation 1.0.3
Cloes gh-30657
2023-06-13 16:21:26 +02:00
Juergen Hoeller 3b263c5c3d Synchronize transaction begin for non-lazy default transactions as well
Lazy and read-only database transactions remain exposed to potential isolation level mismatches in case of concurrent transactions with custom isolation levels.

Closes gh-29997
2023-06-13 12:40:57 +02:00
Sam Brannen f18a85e193 Polish null-safety documentation 2023-06-13 11:57:41 +02:00
rstoyanchev f7d195782f Revert "Temporarily re-enable ReactorNetty2StompBrokerRelayIntegrationTests"
This reverts commit 7e52b803be.
2023-06-12 16:11:42 +01:00
rstoyanchev bbab4faf7a Method level only, empty RequestMapping matches "" and "/"
Closes gh-30293
2023-06-12 16:11:42 +01:00
Sam Brannen 3fb98b6a97 Polishing 2023-06-12 16:43:56 +02:00
Roland Weisleder dc4f46df9f Fix markup issue in Javadoc of QuartzCronField
Closes gh-30646
2023-06-12 16:40:11 +02:00
Sébastien Deleuze 80af7bedef Polish null-safety reference documentation 2023-06-12 16:00:13 +02:00
Juergen Hoeller f8c8873c99 Document which @Scheduled attributes support SpEL expressions
Closes gh-29290
2023-06-12 12:57:10 +02:00
Juergen Hoeller cc8c852c2b Specific check for parent of MethodInvocationInfo ClassLoader
See gh-30389
2023-06-12 12:57:10 +02:00
Sébastien Deleuze fe7f8e2de5 Polish CoWebFilter 2023-06-12 12:48:01 +02:00
Juergen Hoeller 0a5aff1b60 Specific check for parent of spring-aop ClassLoader
Also applied to getProxyClass now.

Closes gh-30389
2023-06-12 10:48:57 +02:00
Vedran Pavic 3d61d9e0d8 Handle custom JMS acknowledgment modes as client acknowledge (#30619)
This commit updates JmsAccessor to handle custom JMS acknowledgment
modes as client acknowledge, which is useful when working with JMS
providers that provide non-standard variations of CLIENT_ACKNOWLEDGE,
such as AWS SQS and its UNORDERED_ACKNOWLEDGE mode.
2023-06-12 10:46:22 +02:00
Sam Brannen 1a26e17f41 Ensure context cache stats are logged when ApplicationContext fails to load
Closes gh-30635
2023-06-11 15:46:28 +02:00
Sébastien Deleuze 439bcd6715 Polishing 2023-06-09 15:19:42 +02:00
Sébastien Deleuze 4e33d0c293 Add missing hint for ResourceEditor
Closes gh-30628
2023-06-09 15:19:18 +02:00
Sébastien Deleuze 9b4e0e9837 Add missing hint for converting String to URI
Closes gh-30627
2023-06-09 14:14:54 +02:00
Sébastien Deleuze 071d6a2a5a Introduce hints for finding hints by conventions
Closes gh-30491
2023-06-09 14:14:54 +02:00
Sam Brannen d7d0292654 Document @DirtiesContext semantics when declared at class & method level
Closes gh-30623
2023-06-09 11:49:15 +02:00
Sam Brannen 2817dce78f Polish @DirtiesContext Javadoc 2023-06-09 11:40:31 +02:00
Sam Brannen 698acd32a7 Configure logger per concrete @DirtiesContext TestExecutionListener 2023-06-09 11:38:36 +02:00
Sam Brannen f36327b380 Exclude commons-logging dependency in spring-test 2023-06-09 11:37:08 +02:00
Johnny Lim ea9c0ae6c0 Fix test fixture value in QualifierConfiguration
Closes gh-30624
2023-06-09 10:29:39 +02:00
Juergen Hoeller c16f582ed8 Consistent equals implementations in AOP support classes 2023-06-08 17:42:49 +02:00
Juergen Hoeller 6931106c5e Redesign inner Pointcut implementations as standalone classes
Avoids exposure of implicit Advisor instance state in Pointcut instance.

See gh-30621
2023-06-08 17:42:49 +02:00
Juergen Hoeller 045df81f14 Reduce ProxyCallbackFilter to key-only role after class generation
Avoids memory leaks from ProxyCallbackFilter-contained Advisors.
Includes consistent ProxyCallbackFilter#equals/hashCode methods.

Closes gh-26266
Closes gh-30615
2023-06-08 17:42:49 +02:00
Juergen Hoeller e210f08dce Declare Advisor#isPerInstance() as default method
Includes INSTANCE constants on default factory classes.

Closes gh-30614
2023-06-08 17:42:49 +02:00
Vedran Pavic 2317bef021 Add missing @Nullable in DefaultJmsListenerContainerFactory
Closes gh-30620
2023-06-08 17:32:59 +02:00
Arjen Poutsma ce5189a0a0 Default ServerWebExchange::cleanupMultipart implementation
This commit provided a default implementation for ServerWebExchange::cleanupMultipart.

See gh-30590
2023-06-08 16:31:53 +02:00
Johnny Lim 7a4ed38cd4 This PR adds Javadoc for RegisteredBean.resolveAutowiredArgument()
See gh-30401
Closes gh-30609
2023-06-08 16:06:14 +02:00
Arjen Poutsma c1fe57135e Clean multipart up only when data is read
This commit ensures that any storage used for multipart handling only
gets cleaned up if multipart data is actually retrieved via
ServerWebExchange::getMultipartData.

Closes gh-30590
2023-06-08 14:23:47 +02:00
Juergen Hoeller 2c8d1b7bff Polishing 2023-06-07 17:21:59 +02:00
Juergen Hoeller bd63c35b0b DefaultMessageListenerContainer tests for stop-and-restart
See gh-30612
2023-06-07 17:21:53 +02:00
Juergen Hoeller c052a02592 Ignore null message when introspecting resource cleanup failure
Closes gh-30597
2023-06-07 17:21:41 +02:00
Sam Brannen 5ad853ef5b Do not precede indexed access with a dot in SpEL AST representation
Prior to this commit, if a Spring Expression Language (SpEL) expression
contained indexed access to an object, the generated AST String
representation incorrectly included a dot ('.') before the index access.

For example, 'property[0]' had a generated AST string representation of
'property.[0]'.

This commit addresses this by reworking the logic in
CompoundExpression.toStringAST().

Closes gh-30610
2023-06-07 14:45:52 +02:00
Sam Brannen dfbed616ba Update copyright headers 2023-06-07 13:17:14 +02:00
Sam Brannen 94214562d0 Polish contribution
See gh-30283
2023-06-07 13:15:12 +02:00
SW be94e1a2fb Replace switch statements with enhanced switch statements for consistency
Closes gh-30283
2023-06-07 13:02:08 +02:00
Sam Brannen f2ae106c32 Update deprecation Javadoc regarding "for removal in 6.2"
See gh-30608
2023-06-07 12:00:27 +02:00
Sam Brannen 7b20aefecf Improve error message for unsupported character in SpEL expression
Prior to this commit, when an unsupported character such as "ü" was
encountered in a SpEL expression, the error message was:

Cannot handle (252) 'ü'

With this commit, the error message is now similar to:

Unsupported character 'ü' (252) encountered at position 5 in expression.

See gh-30580
Closes gh-30602
2023-06-06 12:45:05 +02:00
Juergen Hoeller cdc4497664 Restore creation of plain HashSet/HashMap for direct HashSet/HashMap type
Closes gh-30596
2023-06-05 13:57:59 +02:00
Juergen Hoeller 6cc084dbde Consistent javadoc references to JdbcTransactionManager 2023-06-05 10:52:33 +02:00
Juergen Hoeller 974e10379a Add nested propagation support to R2dbcTransactionManager
Closes gh-30134
2023-06-05 10:45:47 +02:00
Juergen Hoeller 22ef48bec2 Shorten constant names to BUILD and RUN (for consistent spelling)
See gh-30511
2023-06-05 10:45:02 +02:00
Juergen Hoeller 4be813bbee Upgrade to Groovy 4.0.12, Tomcat 10.1.9, Netty 4.1.93, Undertow 2.3.6, Protobuf 3.23.2, Picocli 4.7.4, Checkstyle 10.12 2023-06-04 18:42:21 +02:00
Juergen Hoeller 65617f1e75 Add isolation level test and restore null return value from beginTransaction
See gh-29997
2023-06-04 18:41:38 +02:00
Juergen Hoeller aaebf5749c Set and reset shared isolation value within synchronized transaction begin
Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to immediately restore the original value after the current value got picked up for JDBC Connection access inside of EclipseLink. In order to not interfere with concurrent transactions, we need to use synchronization around the transaction begin sequence in such a case.

Closes gh-29997
2023-06-04 17:19:27 +02:00
Sam Brannen 24fa8793b1 Update copyright headers 2023-06-04 16:36:52 +02:00
Sam Brannen 4f10f559f7 Suppress warnings 2023-06-04 16:36:20 +02:00
Sam Brannen 2f35e7756b Integration test status quo for SpEL 'selector' support in messaging
See gh-30550
2023-06-04 16:25:21 +02:00
Sam Brannen cc50af08e4 Enhance unit tests for status quo for SpEL 'selector' support in messaging
See gh-30550
2023-06-04 16:23:42 +02:00
Sam Brannen d08e4081c2 Polishing 2023-06-04 15:59:12 +02:00
Juergen Hoeller 9751987dc1 Avoid unnecessary auto-commit check for proper transaction begin
Closes gh-30508
2023-06-03 17:17:47 +02:00
Juergen Hoeller d2906253f1 Fall back to plain setObject call for non-supported SQL type
Closes gh-30556
2023-06-03 17:16:36 +02:00
Juergen Hoeller 4b8adf2dcc Polishing 2023-06-02 23:28:14 +02:00
Juergen Hoeller c68552556f Revise TargetSource implementations for proper nullability
Includes hashCode optimization in AbstractBeanFactoryBasedTargetSource.
Includes ThreadLocal naming fix in ThreadLocalTargetSource.

Closes gh-30576
Closes gh-30581
2023-06-02 23:26:58 +02:00
Juergen Hoeller b738a20233 Consistently publish events from CompletableFuture
Closes gh-30578
2023-06-02 23:25:35 +02:00
Juergen Hoeller cca8fbd3de Log warning in case of standard Commons Logging discovery
Closes gh-30575
2023-06-02 23:25:08 +02:00
Sam Brannen 21397a67c6 Test status quo for SpEL 'selector' support in messaging
Prior to this commit, the tests we had in place for SpEL 'selector'
support did not assert what happens when a selector expression does not
match or when a selector header is not present.

See gh-30550
2023-06-01 14:57:50 +02:00
Sam Brannen e8ab53e76d Polishing 2023-06-01 14:57:50 +02:00
Stephane Nicoll 5b471a5349 Merge pull request #30570 from kihyuk-sung
* pr/30570:
  Polish "Fix invalid link in transaction resources"
  Fix invalid link in transaction resources

Closes gh-30570
2023-05-31 12:26:48 +02:00
Stephane Nicoll 08240bbcac Polish "Fix invalid link in transaction resources"
See gh-30570
2023-05-31 12:26:32 +02:00
K d719f3fc06 Fix invalid link in transaction resources
See gh-30570
2023-05-31 12:20:06 +02:00
rstoyanchev 938dff7bbe Remove (recently committed) erroneous character in test 2023-05-30 17:35:50 +01:00
rstoyanchev 162ccdd155 Consistent handling of parts in HttpRequestValues
Closes gh-30520
2023-05-30 17:17:31 +01:00
rstoyanchev f1594312cd Polishing in HttpRequestValues and tests
See gh-30520
2023-05-30 17:17:31 +01:00
rstoyanchev 7629ea5672 Update docs to mention Boot's HttpMessageConverters
Closes gh-30538
2023-05-30 17:17:31 +01:00
rstoyanchev 454a85978f Allow fallback on subclass of ProblemDetail
Closes gh-30533
2023-05-30 17:17:31 +01:00
Sébastien Deleuze 2cbc7eed73 Always use MethodArgumentNotValidException(MethodParameter, BindingResult) constructor
gh-23846 introduced a new
MethodArgumentNotValidException(Executable, BindingResult)
constructor that can be advantageously replaced by using
MethodArgumentNotValidException(MethodParameter, BindingResult)
in ModelAttributeMethodProcessor.

This commit updates ModelAttributeMethodProcessor accordingly,
and deprecates MethodArgumentNotValidException(Executable,
BindingResult) in favor of
MethodArgumentNotValidException(MethodParameter, BindingResult).

Closes gh-30558
2023-05-30 12:41:30 +02:00
Sébastien Deleuze 7a05f81844 Polish ModelAttributeMethodProcessor#constructAttribute Javadoc 2023-05-30 12:07:52 +02:00
Brian Clozel 71b2154ec8 Remove libs-spring-framework-build repository
This commit removes the build configuration for the repository
"libs-spring-framework-build", as it is not needed anymore for the
dependencies it contains.
2023-05-30 10:36:53 +02:00
Stephane Nicoll a716391aab Merge pull request #30554 from scordio
* pr/30554:
  Update copyright year of changed file
  Fix `FileSystemUtils::deleteRecursively` Javadoc

Closes gh-30554
2023-05-30 09:15:43 +02:00
Stephane Nicoll 09b2e5d0fb Update copyright year of changed file
See gh-30554
2023-05-30 09:13:29 +02:00
Stefano Cordio c6b2d2e1d9 Fix FileSystemUtils::deleteRecursively Javadoc
See gh-30554
2023-05-30 09:11:48 +02:00
Sébastien Deleuze 1cf6d1dd9d Refine GraalVM tracing agent detection
This commit refines how GraalVM tracing agent detection works
for both test and application executions.

It rolls back the introduction of TestAotDetector done in 111309605c
and instead updates AotDetector.useGeneratedArtifacts()
to only detect "buildtime" and "runtime" imagecode system
property values by leveraging a new method
NativeDetector.inNativeImage(NativeDetector.Context...).

This commit also adds a workaround for
https://github.com/oracle/graal/issues/6691.

Closes gh-30511
2023-05-26 19:10:21 +02:00
Juergen Hoeller 8b8d147480 Avoid Autowired shortcut resolution for NullBean values
Includes getBean documentation against NullBean values.

Closes gh-30485
2023-05-26 11:03:10 +02:00
Brian Clozel 8fe21b8ef9 Build Antora docs as part of CI check job
This commit adds the "antora" task to the check-project script in order
to check for documentation failures when pushing to the current branch.
The actual documentation is build is performed on the docs-build branch.

Closes gh-30528
2023-05-25 20:12:04 +02:00
Brian Clozel 7c9f5d05db Remove asciidoctor Gradle plugins
This part of the build has been replaced with Antora.
2023-05-25 20:07:50 +02:00
Brian Clozel 110b809b7d Update CI pipeline 2023-05-25 19:15:32 +02:00
Juergen Hoeller 5e625c8d2e Polishing 2023-05-25 18:45:32 +02:00
Juergen Hoeller 3f648f54c5 Set hibernate.cdi.extensions (for SpringBeanContainer on Hibernate 6.2)
Closes gh-30545
2023-05-25 18:45:27 +02:00
Sam Brannen d61074268a Polish Javadoc for StatementFilterFunction 2023-05-25 13:58:00 +02:00
Sam Brannen cfb3a45479 Improve Javadoc for ExchangeFilterFunction
See gh-30543
2023-05-25 13:47:37 +02:00
galingerv 7d7d7bcced Fix typos in Javadoc for ExchangeFilterFunction
Closes gh-30543
2023-05-25 13:40:18 +02:00
Sam Brannen 6dfd330fa5 Polish JavaMailSenderTests 2023-05-24 16:54:44 +02:00
Evgeny Nikonchuk 7f9349b7ae Remove non-empty filename check in ContentDisposition builder
This commit ensures that the ContentDisposition.Builder is consistent
with ContentDisposition and accepts null/empty filenames.

Closes gh-30537
2023-05-24 13:53:46 +02:00
Juergen Hoeller 4c8f1910c8 Align HibernateJpaVendorAdapter with Hibernate ORM 6.2
Includes documentation and test revisions.

Closes gh-30288
2023-05-23 20:33:19 +02:00
rstoyanchev 3b364c2a3d Add cached-antora-playbook.yml back to .gitignore
See gh-30481
2023-05-23 15:12:35 +01:00
rstoyanchev 0930407d0e Revert "Download the playbook to build dir"
This reverts commit d8f6567c89.

See gh-30481
2023-05-23 15:05:11 +01:00
Sam Brannen 4bb12c4ba4 Update copyright headers 2023-05-23 15:10:08 +02:00
Sam Brannen 8d6d99731f Delete unused code 2023-05-23 15:09:38 +02:00
Sam Brannen b5902f4fbf Suppress unused warnings in tests 2023-05-23 15:09:10 +02:00
Sam Brannen a455317122 Treat directly registered class as configuration 'lite' mode candidate
Prior to this commit, if a non-annotated [1] class was registered
directly with an ApplicationContext -- for example, via
AnnotatedBeanDefinitionReader, AnnotationConfigApplicationContext, or
@ContextConfiguration -- it was not considered a configuration class in
'lite' mode unless @Bean methods were declared locally. In other words,
if the registered class didn't declare local @Bean methods but rather
extended a class that declared @Bean methods, then the registered class
was not parsed as a @Configuration class in 'lite' mode, and the @Bean
methods were ignored.

Whereas, a non-annotated class registered via @Import is always
considered to be a configuration class candidate.

To address this discrepancy between @Import'ed classes and classes
registered directly with an ApplicationContext, this commit treats any
class registered via AnnotatedBeanDefinitionReader as a @Configuration
class candidate with @Bean 'lite' mode semantics.

[1] In this context, "non-annotated" means a class not annotated (or
meta-annotated) with @Component, @ComponentScan, @Import, or
@ImportResource.

Closes gh-30449
2023-05-23 12:19:58 +02:00
Sam Brannen a8b400803b Upgrade to TestNG 7.8.0 2023-05-23 11:36:25 +02:00
greg.lee fa85657801 Introduce method in MockHttpServletRequestBuilder to set remote address
Co-authored-by: Sam Brannen <sam@sambrannen.com>
See gh-30510
Closes gh-30497
2023-05-23 11:26:26 +02:00
Sébastien Deleuze 424daede2f Add missing EntityManagerFactory hints for SharedEntityManagerCreator
Closes gh-30523
2023-05-23 11:18:54 +02:00
Sébastien Deleuze e92c9c5619 Disable Hibernate reflection optimizer with native
Closes gh-30521
2023-05-23 09:10:47 +02:00
Stephane Nicoll 7660dbfd77 Merge pull request #30512 from izeye
* pr/30512:
  Add Javadoc since to InjectedElement.shouldInject()

Closes gh-30512
2023-05-22 15:30:33 +02:00
Johnny Lim 15a7f43c7b Add Javadoc since to InjectedElement.shouldInject()
See gh-30512
2023-05-22 15:30:05 +02:00
Simon Baslé 1721e42988 Remove JBossAS catch-all javadoc external link
This commit removes the JBoss Application Server external javadoc link,
which covers too many packages and can thus problematically take
precedence for said packages and lead to dead links.

It is replaced by Hibernate javadocs for `org.hibernate.*` packages,
JakartaEE and jsr305 for annotations. We lose a limited number of links
around org.xnio classes and Hibernate-and-JTA-related classes, as a
trade-off.

See gh-30455
See gh-30428
2023-05-16 15:04:34 +02:00
Simon Baslé eabb846d07 Improve how the build deals with javadoc invalid references
This commit improves how the build deals with javadoc invalid references
in two ways.

Link/see references that are temporarily invalid during javadoc
generation of individual modules are better masked by using the option
`Xdoclint:syntax` instead of `Xdoclint:none` (warnings were still
visible in some cases, e.g. when individually building the javadoc for
a specific module).

Global javadoc-building task `api` now combines `syntax` and `reference`
`Xdoclint` groups, allowing to raise truly invalid references even when
all the modules have been aggregated.

This commit also fixes the 20+ errors which appeared following the later
change in doclet configuration.

Closes gh-30428
2023-05-16 15:04:10 +02:00
Jan Mewes 280b0de646 Docs: Remove duplicate in SpEL feature list
Closes gh-30404
2023-05-15 15:22:44 +02:00
Sam Brannen 2738b3e50f Polishing
See gh-30482
2023-05-15 15:09:06 +02:00
Anyuruf 169795d673 Fix wording in r2dbc Statement Filters section of ref docs
Co-authored-by: Sam Brannen <sam@sambrannen.com>
Closes gh-30482
2023-05-15 15:08:58 +02:00
Sébastien Deleuze 085565a771 Skip class transformer in PersistenceUnitInfoDescriptor for native images
In order to restore native support with Hibernate 6.2, this
change updates the PersistenceUnitInfoDescriptor instance
created by SpringHibernateJpaPersistenceProvider in order to
skip the class transformer for native images.

Closes gh-30492
2023-05-15 11:48:56 +02:00
rstoyanchev 806519f78a Comment out check->antora dependency
See gh-30481
2023-05-12 10:19:52 +01:00
Stephane Nicoll c3c5eaf914 Align AOT contributions for injection with the runtime behavior
Bean post processors that use InjectionMetadata checks if a property
value for the element it is about to inject is set and skip it, so
that the property value is used. Previously, the AOT contribution for
the same behavior did not check if a matching property value is set
and therefore override the user-defined value.

This commit introduces an additional method that filters the injected
element list so that only the elements that should be processed are
defined.

Closes gh-30476
2023-05-12 08:49:22 +02:00
Stephane Nicoll a9b94241af Fix typo
Closes gh-30473
2023-05-11 16:35:20 +02:00
Spring Builds 7066dc4ba7 Next development version (v6.0.10-SNAPSHOT) 2023-05-11 12:47:00 +00:00
Juergen Hoeller 3f889e997c Clarify RootBeanDefinition vs GenericBeanDefinition
Closes gh-30444
2023-05-10 18:50:27 +02:00
Juergen Hoeller 6622a3c7d6 Consistent package-info declarations for CGLIB fork
Closes gh-30461
2023-05-10 18:50:17 +02:00
Rob Winch d8f6567c89 Download the playbook to build dir
Closes gh-30465
2023-05-10 17:39:40 +01:00
Sam Brannen 111309605c Support Test AOT processing with GraalVM tracing agent and NBT
Prior to this commit, test AOT processing failed when using the GraalVM
tracing agent and GraalVM Native Build Tools (NBT) plugins for Maven
and Gradle.

The reason is that the AOT support in the TestContext framework (TCF)
relied on AotDetector.useGeneratedArtifacts() which delegates
internally to NativeDetector.inNativeImage() which does not
differentiate between values stored in the
"org.graalvm.nativeimage.imagecode" JVM system property.

This commit addresses this issue by introducing a TestAotDetector
utility that is specific to the TCF. This detector considers the
current runtime to be in "AOT runtime mode" if the "spring.aot.enabled"
Spring property is set to "true" or the GraalVM
"org.graalvm.nativeimage.imagecode" JVM system property is set to any
non-empty value other than "agent".

Closes gh-30281
2023-05-10 17:39:46 +02:00
Sam Brannen 89bcee68bb Add author tag 2023-05-10 17:39:46 +02:00
Juergen Hoeller c8927ae753 Polishing 2023-05-10 17:18:31 +02:00
Juergen Hoeller e228f4ba64 Consistent pre-resolution of event type vs payload type
Restores proper event type propagation to parent context.
Selectively applies payload type to given payload object.
Also reuses cached type for regular ApplicationEvent now.

Closes gh-30360
2023-05-10 17:17:48 +02:00
Simon Baslé c733ae0f22 Fix ApplicationListenerMethodAdapter#supportsEventType check
This commit fixes the check by avoiding a fallback to eventType's
hasUnresolvableGenerics(). This could previously lead to checking a
generic event type `A<T>` against a listener which accepts unrelated
`B` and return `true` despite the inconsistency.

Note that this wouldn't necessarily surface to the user because there is
a `catch (ClassCastException e)` down the line, which was primarily put
in place to deal with lambda-based listeners but happens to catch an
exception thrown due to the bad result of `supportsEventType`.

The `supportsEventType` now matches generic `PayloadApplicationEvent`
types with a raw counterpart, using the above fallback only in that case
and otherwise ultimately returning `false`.

Closes gh-30399
2023-05-10 15:00:11 +02:00
Sam Brannen aefcb9d2d6 Make maximum SpEL expression length configurable
Closes gh-30380
2023-05-10 14:35:36 +02:00
Stephane Nicoll 120c228b70 Handle injection of several persistence units
This commit adapts the generated code so that each injection point has
a dedicated namespace in the form of a private method. That prevents
the same variable to be reused twice which lead to a compilation failure
previously.

Closes gh-30437
2023-05-10 13:55:26 +02:00
rstoyanchev bd66c70b2b Potential fix for flaky STOMP integration tests
When ReactorNetty2StompBrokerRelayIntegrationTests fail, typically there
are multiple exceptions "Connection refused: /127.0.0.1:61613" that
appear after we've conneted, sent CONNECT, and expecting CONNECTED, but
that does not come within the 10 second timeout.

61613 is the default port for STOMP. However, in all integration tests
we start ActiveMQ with port 0 which results in a random port. Moreover,
the stacktrace is for Netty 4 (not 5), and the eventloop thread id's
are different than the one where the connection to the correct, random
port was established.

The suspicion is that these are log messages from
MessageBrokerConfigurationTests which focuses on testing configuration
but nevertheless as a bean starts and attempts to connect to the default
port and fails. Perhaps those attempts to connect on the default port
somehow affect the ActiveMQ server, and it stops responding.

This change adds a no-op TcpClient in MessageBrokerConfigurationTests
to avoid unnecessary attempts to connect that are not needed.

See gh-29287
2023-05-10 11:42:45 +01:00
rstoyanchev e737980033 Ensure chunks released on cancel in StringDecoder
The current test were not catching the issue because they request 1
via StepVerifier, wait for it, and then cancel. In the case of
StringDecoder it means all chunks are used up to produce that first
String and so the cancel doesn't catch any cached chunks.

Closes gh-30299
2023-05-09 19:58:36 +01:00
Stephane Nicoll 93fa01004c Document AOT best practices
This commit augment the AOT section with best practices we have
experienced while working on the AOT engine. In particular, it describes
how a FactoryBean with an unresolved generic should be handled.

Closes gh-30434
2023-05-09 16:25:36 +02:00
Stephane Nicoll c1f6d7197b Add support for InjectionPoint with AOT
This commit reviews BeanInstanceSupplier to reuse more code from
ConstructorResolver. Previously, the autowired argument resolution was
partially duplicated and this commit introduces a new common path via
RegisteredBean#resolveAutowiredArgument.

Closes gh-30401
2023-05-09 14:52:23 +02:00
Arjen Poutsma a133aae8d6 Document @ResponseStatus behavior
This commit documents that the ResponseStatus annotation does not
override the status set through other means.

Closes gh-30305
See gh-18019
2023-05-09 14:01:33 +02:00
Rob Winch 3a0a19cff8 Fix migration to asciidoctor tabs
The automation to asciidoctor tabs did not migrate properly for all
cases this commit fixes the migration.

See gh-30435
2023-05-09 12:15:43 +01:00
Juergen Hoeller 6930d4d531 Upgrade to Reactor 2022.0.7 and Micrometer 1.10.7
Includes Protobuf 3.23, Woodstox 6.5.1, Caffeine 3.1.6, Picocli 4.7.3, BlockHound 1.0.8, ActiveMQ 5.17.4

Closes gh-30450
Closes gh-30451
2023-05-09 12:55:44 +02:00
Brian Clozel 6bc674b2dd Upgrade CI image to Ubuntu Jammy 2023-05-09 09:34:16 +02:00
Juergen Hoeller 4aa8619ac2 Upgrade to Tomcat 10.1.8, Jetty 11.0.15 / 12.0.0.beta1, Netty 4.1.92, Jackson 2.14.3, Mockito 5.3.1, Checkstyle 10.10 2023-05-08 13:06:19 +02:00
Juergen Hoeller 2c7e8661cf Respect TaskDecorator configuration on DefaultManagedTaskExecutor
Closes gh-30442
2023-05-08 12:02:25 +02:00
Juergen Hoeller c09055b83a Consistent support for MultiValueMap and common Map implementations
Closes gh-30440
2023-05-08 12:01:58 +02:00
Sébastien Deleuze 2c15dcc56b Fix native support for generic array parameters
This commit adds a workaround for oracle/graal#6529
triggered by b374824319.

When the GraalVM fix will have reached a wide enough
audience, it should be removed via gh-30394.

Closes gh-30407
2023-05-05 18:20:08 +02:00
Rob Winch 06f16f15ed Remove PDF Link
See gh-30430
2023-05-05 16:56:25 +01:00
Stephane Nicoll da37deec1b Merge pull request #30423 from izeye
* pr/30423:
  Polish "Introduce internal constants for implicit bounds in TypeUtils"
  Introduce internal constants for implicit bounds in TypeUtils

Closes gh-30423
2023-05-05 15:03:58 +02:00
Stephane Nicoll 88361a4f3e Polish "Introduce internal constants for implicit bounds in TypeUtils"
See gh-30423
2023-05-05 15:01:46 +02:00
Johnny Lim 92cf7f1a7f Introduce internal constants for implicit bounds in TypeUtils
See gh-30423
2023-05-05 14:58:24 +02:00
rstoyanchev 8a8fb31f4a Update target repository for Antora
See gh-30414
2023-05-04 15:37:21 +01:00
Rob Winch 719553f627 Fix Web Reactive link on the landing page 2023-05-04 15:35:05 +01:00
Rob Winch 993447deb0 Remove invalid deploy-docs.yml 2023-05-04 15:35:05 +01:00
Rob Winch 88c9b0f467 Use the shared antora playbook 2023-05-04 15:35:05 +01:00
Rob Winch 39146f9066 Migrate to Asciidoctor Tabs 2023-05-04 15:35:05 +01:00
Rob Winch 71154fd16b Add ./github/workflow/deploy-docs.yml 2023-05-04 15:35:05 +01:00
Rob Winch 7b0ba0188f Structural Fixes 2023-05-04 15:35:05 +01:00
Rob Winch 3774e9be7a Trim IDs with parent 2023-05-04 15:35:05 +01:00
Rob Winch 9c38f8c3c6 Make local build (temporary) 2023-05-04 15:35:05 +01:00
Rob Winch 26171d9efb Fix Title in antora.yml 2023-05-04 15:35:05 +01:00
Rob Winch 68235464fc Use include-code Macro 2023-05-04 15:35:05 +01:00
Rob Winch 51ada4e19d Fix invalid nav elements 2023-05-04 15:35:05 +01:00
Rob Winch 1a8e0031fe Fix index Overview link 2023-05-04 15:35:05 +01:00
Rob Winch d8bcbd53e1 Fix invalid attributes 2023-05-04 15:35:05 +01:00
Rob Winch 6993a9eee4 fix antora.yml attributes 2023-05-04 15:35:05 +01:00
Rob Winch d2720741a5 Fix antora.yml gradle command 2023-05-04 15:35:05 +01:00
Rob Winch 067e6c2a9e fix framework-docs.gradle 2023-05-04 15:35:05 +01:00
Rob Winch 35229c8bff Enable Section Summary TOC for small pages 2023-05-04 15:35:05 +01:00
Rob Winch 139cde47e2 Fix cross references 2023-05-04 15:35:05 +01:00
Rob Winch 6b341ddf19 Remove includes 2023-05-04 15:35:05 +01:00
Rob Winch 5aecfb1878 Generate a default navigation 2023-05-04 15:35:05 +01:00
Rob Winch 9f49d24833 Split files 2023-05-04 15:35:05 +01:00
Rob Winch ac69a5dac3 Copy default antora files 2023-05-04 15:35:05 +01:00
Rob Winch 7f9061a3cb Fix image::image 2023-05-04 15:35:05 +01:00
Rob Winch a05ff6c126 Remove unnecessary asciidoc attributes 2023-05-04 15:35:05 +01:00
Rob Winch 9ceb75b228 Insert explicit ids for headers 2023-05-04 15:35:05 +01:00
Rob Winch 3fe7c65218 Migrate Structure 2023-05-04 15:35:05 +01:00
Rob Winch a78836c18b Remove duplicated testing from .adoc file path 2023-05-04 15:35:05 +01:00
Rob Winch 2a4a1cc550 Remove -languages suffix from .adoc files 2023-05-04 15:35:05 +01:00
Rob Winch c762c07290 Remove integration- prefix from .adoc files 2023-05-04 15:35:05 +01:00
Rob Winch 957467aa32 Remove data-access- prefix from .adoc files 2023-05-04 15:35:04 +01:00
Rob Winch 49a4734cfa Remove core- prefix from .adoc files 2023-05-04 15:35:04 +01:00
Stephane Nicoll 44b427c3e1 Add AOT support for Qualifiers
This commit handles AutowiredCandidateQualifier instances, rather than
relying on qualifiers being statically defined and meta-annotated with
`@Qualifier`.

Closes gh-30410
2023-05-04 12:17:07 +02:00
Sam Brannen aabd685225 Update major/minor version properties in MockServletContext
ServletContext has sets of major/minor version properties that we have
not updated in MockServletContext in several years.

Since we upgraded the baseline to Servlet 6.0 in Spring Framework 6.0,
now seems like a good time to update those version properties.

Closes gh-30395
2023-04-28 15:43:29 +02:00
Sébastien Deleuze cefb734763 Restore native support for record beans
After b374824319 related
to gh-29246, `"queryAllDeclaredMethods": true` is now added
on all registered beans.

This legit change triggers oracle/graal#6510. This
commit workarounds this GraalVM bug, and should be
removed once the GraalVM fix has reached a wide enough
audience.

Closes gh-30383
2023-04-28 09:57:22 +02:00
Stephane Nicoll 82e5464972 Avoid extra "__BeanDefinitions" suffix for inner classes
This commit makes AOT class names for bean definitions shorter.
Previously, the "__BeanDefinitions" suffix was applied for all
classes, but it was unnecessary for inner classes as the container
class already has the qualifier.

Closes gh-29846
2023-04-26 16:52:46 +02:00
Stephane Nicoll 02132bd060 Infer resource hints for PropertySource#value
This commit adds a resource hints for the target(s) of a @PropertySource
declaration.

Closes gh-30376
2023-04-26 14:13:19 +02:00
Stephane Nicoll f6875b11ff Generate missing hints for custom PropertySource factories
Closes gh-30175
2023-04-26 13:40:48 +02:00
Sam Brannen 230840a41c Upgrade to JUnit 5.9.3 2023-04-26 10:26:56 +02:00
Sam Brannen 3b8a9b18f9 Upgrade to Gradle 8.1.1
Closes gh-30351
2023-04-25 19:51:54 +02:00
Sam Brannen d023b94a42 Introduce Environment.matchesProfiles() for profile expressions
Environment.acceptsProfiles(String...) was deprecated in 5.1 in
conjunction with gh-17063 which introduced a new
acceptsProfiles(Profiles) method to replace it. The deprecated method
only supports OR semantics; whereas, the new method supports profile
expressions. Thus, the goal was to encourage people to use the more
powerful profile expressions instead of the limited OR support with
profile names.

However, there are use cases where it is difficult (if not impossible)
to provide a Profiles instance, and there are use cases where it is
simply preferable to provide profile expressions directly as strings.

To address these issues, this commit introduces a new matchesProfiles()
method in Environment that accepts a var-args list of profile
expressions.

Closes gh-30206
2023-04-25 18:10:50 +02:00
Sam Brannen 47ba819f96 Polish Environment and StandardEnvironmentTests
See gh-30206
2023-04-25 18:10:39 +02:00
Sam Brannen ea4c64ebc4 Polish ProfilesParser internals 2023-04-25 15:08:03 +02:00
Sam Brannen de113f1d11 Reject null and empty SpEL expressions
Prior to gh-30325, supplying a null reference for a SpEL expression was
effectively equivalent to supplying the String "null" as the
expression. Consequently, evaluation of a null reference expression
always evaluated to a null reference. However, that was accidental
rather than by design.

Due to the introduction of the checkExpressionLength(String) method in
InternalSpelExpressionParser (in conjunction with gh-30325), an attempt
to evaluate a null reference as a SpEL expression now results in a
NullPointerException.

To address both of these issues,
TemplateAwareExpressionParser.parseExpression() and
SpelExpressionParser.parseRaw() now reject null and empty SpEL
expressions.

Closes gh-30371
2023-04-25 13:46:30 +02:00
Sam Brannen ca13b5cbca Polish SpelParserTests and TemplateExpressionParsingTests 2023-04-25 13:46:30 +02:00
James Yuzawa 5dacf50b9b Optimize MultiValueMap iteration operations
* use forEach and putIfAbsent to copy headers in DefaultClientRequestBuilder
* use forEach in ReactorClientHttpRequest and ReactorNetty2ClientHttpRequest
* circumvent ReadOnlyHttpHeaders.entrySet()
* ensure the fast path to LinkedCaseInsensitiveMap for forEach and putIfAbsent exists

Closes gh-29972
2023-04-25 09:57:26 +02:00
Arjen Poutsma beb23b5da6 Updated CI image JDK 2023-04-24 12:56:18 +02:00
Arjen Poutsma d07df24adc Updated sdkmanrc 2023-04-24 12:30:02 +02:00
Sam Brannen 2d1ddbb65c Polish contribution
See gh-30282
2023-04-20 16:18:08 +02:00
David Szigecsan af54ee9eba Polish ClassUtils and TypeUtils
Closes gh-30282
2023-04-20 15:51:25 +02:00
Stephane Nicoll 7a78092934 Merge pull request #30343 from divcon
* pr/30343:
  Polish contribution
  Use putIfAbsent in Netty5HeadersAdapter

Closes gh-30343
2023-04-20 15:48:52 +02:00
Stephane Nicoll ea0340f892 Polish contribution
See gh-30343
2023-04-20 15:46:12 +02:00
divcon f79d145b4c Use putIfAbsent in Netty5HeadersAdapter
See gh-30343
2023-04-20 15:45:56 +02:00
Stephane Nicoll 5deab3afd0 Merge pull request #30357 from izeye
* pr/30357:
  Polish

Closes gh-30357
2023-04-20 15:43:07 +02:00
Johnny Lim 66bd891a0b Polish
See gh-30357
2023-04-20 15:42:01 +02:00
Arjen Poutsma 685548b58b Merge pull request #30252 from luozhenyu:content-disposition
* gh-30252:
  Polish contribution
  Quote question marks in content-disposition
2023-04-18 15:33:52 +02:00
Arjen Poutsma 74d3268656 Polish contribution
This commit polishes an external contribution, ensuring that not just
spaces are encoded as underscores, and that underscores are encoded
as non-printable.

See gh-30252
2023-04-18 15:30:31 +02:00
luozhenyu 5a4a46af78 Quote question marks in content-disposition
This commit ensures that question marks are encoded, in accordance
with RFC 2047, section 4.2, rule (3).

Closes gh-30252
2023-04-18 14:47:57 +02:00
Brian Clozel a465b16f7c Set current version to 6.0.9-SNAPSHOT 2023-04-14 12:35:24 +02:00
Brian Clozel 5d1abfbc2d Update CI pipeline to 6.0.x branch 2023-04-13 12:46:06 +02:00
Sam Brannen be17c8d85f Disable variable assignment in SimpleEvaluationContext
This commit introduces infrastructure to differentiate between
programmatic setting of a variable in an EvaluationContext versus the
assignment of a variable within a SpEL expression using the assignment
operator (=). In addition, this commit disables variable assignment
within expressions when using the SimpleEvaluationContext.

Closes gh-30326
2023-04-13 09:40:23 +02:00
Sam Brannen b73f5fcac2 Limit SpEL expression length
This commit enforces a limit of the maximum size of a single SpEL
expression.

Closes gh-30325
2023-04-13 09:39:53 +02:00
Sam Brannen bc1511d667 Limit string concatenation in SpEL expressions
This commit introduces support for limiting the maximum length of a
string resulting from the concatenation operator (+) in SpEL
expressions.

Closes gh-30324
2023-04-13 09:39:32 +02:00
Sam Brannen db9b139cf0 Change max regex length in SpEL expressions to 1000
This commit changes the max regex length in SpEL expressions from 1024
to 1000 in order to consistently use "round" numbers for recently
introduced limits.

See gh-30265
2023-04-13 09:39:27 +02:00
rstoyanchev bd029b9218 Ensure RestClientResponseException is serializable
Closes gh-30224
2023-04-12 15:38:27 +01:00
rstoyanchev 5f2264816a Polishing contribution
Closes gh-30294
2023-04-12 15:22:57 +01:00
Yanming Zhou a8f31f5b9e Improve ProblemDetail equals and hashCode
Lazy computed title property should be taken into account

See gh-30294
2023-04-12 15:07:22 +01:00
Stephane Nicoll 90627b4345 Upgrade to Micrometer 1.10.6
Closes gh-30317
2023-04-12 14:45:54 +02:00
Juergen Hoeller 4acc71b282 Upgrade to Reactor 2022.0.6 and Netty 4.1.91
Includes Checkstyle 10.9.3 and Mockito 5.3.0

Closes gh-30316
2023-04-12 13:36:01 +02:00
kyuarl21 cd0379a67f Modified to slf4j2-impl in build.gradle
due to slf4j-api versions 1.7 x or earlier issue
2023-04-12 13:11:48 +02:00
Simon Baslé e262e98bab ConstructorResolver error hints about mixing indexed and named args
This commit adds a note to an exception in `ConstructorResolver`'s
`autowireConstructor` method hinting that attention should be paid to
cases that mix indexed arguments and named arguments. This is especially
when inheriting bean definitions in xml.

Closes gh-29976
Close gh-PR
2023-04-12 13:09:28 +02:00
SW 59c65fa940 Replace Collections.unmodifiableList(new ArrayList(..)) with List.copyOf() (#30166) 2023-04-12 13:07:20 +02:00
Stephane Nicoll 695601aa06 Merge pull request #30308 from izeye
* pr/30308:
  Add since tags to sameSite() and attribute() in CookieResultMatchersDsl

Closes gh-30308
2023-04-11 14:57:13 +02:00
Johnny Lim 8f5a1fe7e2 Add since tags to sameSite() and attribute() in CookieResultMatchersDsl
See gh-30308
2023-04-11 14:56:55 +02:00
rstoyanchev 073226d792 Polishing contribution
Closes gh-30120
2023-04-11 11:43:24 +01:00
Aleksandrs Jansons 1abe155663 Ensure WebSocket disconnect msg reaches the client
In some application setups, the WebSocket server does not transmit
the disconnect message to the client, so that the client has no idea
that the established connection has been terminated.

This issue arises when the application uses SimpleBrokerMessageHandler
and the error handler is set to the instance of
StompSubProtocolErrorHandler or an extended class that does not
override the handleErrorMessageToClient method.

The commit fixes disconnect message population so that
`java.lang.IllegalArgumentException: No StompHeaderAccessor` exception
is not thrown in the handleErrorMessageToClient method in
StompSubProtocolErrorHandler class.

See gh-30120
2023-04-11 11:43:23 +01:00
divcon 33ef9107e0 Minor refactoring in PayloadMethodArgumentResolver
Closes gh-30168
2023-04-11 11:36:41 +01:00
rstoyanchev 8463eade33 Polishing contribution
Closes gh-30192
2023-04-10 21:24:25 +01:00
James Yuzawa e77faf7484 Improve performance of canRead() in HttpMessageReader's
Use MimeType.WILDCARD_TYPE for faster String.equals().
Move cheaper checks to the front of the canRead implementations.

See gh-30192
2023-03-25 12:21:10 -04:00
Sam Brannen b23cc01cb7 Revise "Ignore nonexistent default-destroy-method in XML config"
This commit revises the fix in c811428512.

Closes gh-30301
2023-04-07 18:48:52 +02:00
Brian Clozel 01f97887ea Improve WebClient observations handling of CANCEL signal
Prior to this commit, `WebClient` observations would be recorded as
aborted (with tags "outcome":"UNKNOWN", "status":"CLIENT_ERROR")
for use cases like this:

```
Flux<String> result = client.get()
    .uri("/path")
    .retrieve()
    .bodyToFlux(String.class)
    .take(1);
```

This is due to operators like `take` or `next` that consume *some*
`onNext` signals and then cancels the subscription before completion.
This means the subscriber is only partially interested in the response
and we should not count this as a client error.

This commit ensures that observations are only recorded as aborted if
the response was not published at the time the CANCEL signal was
received.

The code snippet above will now publish observations with
"outcome":"SUCCESS" and "status":"200" tags, for example.

Closes gh-30070
2023-04-07 16:37:09 +02:00
Sam Brannen cef597bedd Update copyright headers 2023-04-07 14:24:22 +02:00
Sam Brannen 01fabfe66d Suppress warnings in tests 2023-04-07 14:23:55 +02:00
Sam Brannen c811428512 Ignore nonexistent default-destroy-method in XML config
Prior to this commit, DisposableBeanAdapter attempted to invoke a
configured default-destroy-method on every bean, including beans that
do not declare the named destroy method, resulting in a
NullPointerException being thrown and logged at WARN level.

This commit addresses this by effectively ignoring any nonexistent
destroy method.

Closes gh-30301
2023-04-07 13:58:49 +02:00
Sébastien Deleuze b5b115e52c Fix SSE with indenting serializer in WebMvc.fn
This commit ensures that HTTP headers like "text/event-stream"
are correctly forwarded to the converter used in
SseServerResponse for proper pretty print handling.

Close gh-30277
2023-04-07 11:25:47 +02:00
Sam Brannen 310344cf61 Increase max regex length in SpEL expressions
This commit increases the max regex length in SpEL expressions from 256
to 1024 in order to support use cases where a regex may be rather long
without necessarily increasing the complexity of the regex.

Closes gh-30265
2023-04-06 17:53:03 +02:00
Sam Brannen 2bac371c5b Improve Javadoc for ObjectUtils.nullSafeConciseToString() 2023-04-06 17:35:50 +02:00
Arjen Poutsma cef9166833 Encode IPV6 Zone IDs in ReactorServerHttpRequest
This commit ensures that the zone id in the ReactorServerHttpRequest is
properly encoded.

Closes gh-30188
2023-04-06 11:32:44 +02:00
Simon Baslé d6460e0d57 Add Cookie attributes + SameSite CookieResultMatchers in MockMvc
This commit adds assertions to MockMvc's CookieresultMatchers:
 - `attribute` for arbitrary attributes
 - `sameSite` for the SameSite well-known attribute

Note that the `sameSite` methods delegate to their `attribute`
counterparts. Note also that Jakarta's `Cookie#getAttribute` method is
case-insensitive, which is reflected in the documentation of the
`attribute` assertion method and the tests.

Closes gh-30285
2023-04-05 17:02:38 +02:00
Sam Brannen 842490beeb Add tests for corner cases
See gh-30290
See gh-30286
2023-04-05 15:05:25 +02:00
Sam Brannen e746230de6 Introduce ObjectUtils.nullSafeConciseToString()
ObjectUtils.nullSafeToString(Object) exists for generating a string
representation of various objects in a "null-safe" manner, including
support for object graphs, collections, etc.

However, there are times when we would like to generate a "concise",
null-safe string representation that does not include an entire object
graph (or potentially a collection of object graphs).

This commit introduces ObjectUtils.nullSafeConciseToString(Object) to
address this need and makes use of the new feature in FieldError and
ConversionFailedException.

Closes gh-30286
2023-04-05 14:13:28 +02:00
Sam Brannen 8161316b1d Introduce StringUtils.truncate()
StringUtils.truncate() serves as central, consistent way for truncating
strings used in log messages and exception failure messages, for
immediate use in LogFormatUtils and ObjectUtils.

See gh-30286
Closes gh-30290
2023-04-05 13:50:13 +02:00
Krzysztof Krasoń 1734deca1e Refactor AssertJ assertions into more idiomatic ones
This commit refactors some AssertJ assertions into more idiomatic and
readable ones. Using the dedicated assertion instead of a generic one
will produce more meaningful error messages. 

For instance, consider collection size:
```
// expected: 5 but was: 2
assertThat(collection.size()).equals(5);
// Expected size: 5 but was: 2 in: [1, 2]
assertThat(collection).hasSize(5);
```

Closes gh-30104
2023-04-04 17:34:07 +02:00
Justin Tay dd97ee4e99 Support SameSite cookie attribute in MockMvcHttpConnector
Closes gh-30264
2023-04-04 16:57:21 +02:00
Simon Baslé 90b0f451f0 Add a couple missing java.time types to StatementCreatorUtils
This commit adds mapping for two types from the `java.time` package,
complementing the types that are already translatable to Sql types
TIME, DATE and TIMESTAMP:
 - `OffsetTime` maps to a `TIME_WITH_TIMEZONE`
 - `OffsetDateTime` maps to a `TIMESTAMP_WITH_TIMEZONE`

This is in accordance with the B.4 table provided in the JDBC 4.2
specification.

When preparing statements, these `java.time` types use the `setObject`
method. Tests covering the 5 `java.time` classes have also been added.

See gh-28778
See gh-28527
Closes gh-30123
2023-04-04 16:51:24 +02:00
Sam Brannen 9fb61c57ae Sync MockCookie implementations
See gh-30263
2023-04-04 16:32:30 +02:00
Sam Brannen f9cb0eba87 Update Javadoc regarding Servlet 6 baseline for mocks 2023-04-04 16:29:51 +02:00
Sam Brannen d1d2d5943e Polish contribution
See gh-30263
2023-04-04 16:29:03 +02:00
Justin Tay 281736f14e Update MockCookie to use Servlet 6.0 APIs and semantics for "attributes"
Closes gh-30263
2023-04-04 16:13:37 +02:00
Sam Brannen 6bfc70b61e Polishing 2023-04-04 16:02:54 +02:00
Simon Baslé 95883b9eb7 Rename MockMVC matcher methods to prevent regression in user tests
This commit changes the name of two recently introduced methods in the
`MockRestRequestMatchers` class for header and queryParam. These have
been found to cause false negatives in user tests, due to the new
overload taking precedence in some cases.

Namely, using a `Matcher` factory method which can apply to both `List`
and `String` will cause the compiler to select the newest list overload,
by instantiating a `Matcher<Object>`.

This can cause false negatives in user tests, failing tests that used
to pass because the Matcher previously applied to the first String in
the header or queryParam value list. For instance, `equalsTo("a")`.

The new overloads are recent enough and this has enough potential to
cause an arbitrary number of user tests to fail that we break the API
to eliminate the ambiguity, by renaming the methods with a `*List`
suffix.

Closes gh-30220
Closes gh-30238
See gh-29953
See gh-28660
2023-04-04 15:06:14 +02:00
Arjen Poutsma f0eb43a6af Merge pull request #30157 from srivatsa-cfp:main
* gh-30157:
  Add non-null assertions in DefaultServerResponseBuilder
2023-04-04 12:42:39 +02:00
Vatsa 6c8ebc7f7e Add non-null assertions in DefaultServerResponseBuilder
This commit adds various non-null assertions to
DefaultServerResponseBuilder, in both Spring MVC and WebFlux.

Closes gh-30157
2023-04-04 12:36:46 +02:00
Sam Brannen 69c8f8e9c7 Update copyright headers 2023-04-03 16:45:49 +02:00
Sam Brannen 02f2d94f57 Polish contribution
See gh-30271
2023-04-03 16:45:49 +02:00
wizard 7fcbc869a6 Specify initial capacity when creating ArrayList in SpringFactoriesLoader
Closes gh-30271
2023-04-03 16:42:00 +02:00
Sam Brannen 4eed2ced74 Polishing 2023-04-03 14:42:38 +02:00
Sébastien Deleuze 98f1287f3a Fix HttpServiceMethod support for suspending functions
This commit fixes nested type handling for suspending
functions in HttpServiceMethod.

Closes gh-30266
2023-04-03 10:30:49 +02:00
Brian Clozel 8234fa2a13 Fix JDK20 env variable declaration in CI pipeline
See gh-30185
2023-04-03 09:43:37 +02:00
Filip Blondeel 8b9d2e3f95 Fix incorrect jakarta.inject artifact version
Closes gh-30270
2023-04-03 09:36:22 +02:00
hongxue.zou 534d1cd35b Polishing
This commit includes a null-safety fix in
HttpComponentsHeadersAdapter.

Closes gh-30267
2023-04-03 09:04:39 +02:00
Sam Brannen ca545ac3d4 Upgrade dependencies 2023-04-02 19:20:49 +02:00
Sam Brannen ca7c2779bf Suppress warnings displayed in Gradle build for test source code 2023-04-01 18:36:56 +02:00
Sam Brannen 4a90257a84 Upgrade to Gradle 8
This commit upgrades the build to use Gradle 8.0.2 and Dokka 1.8.10.

Closes gh-30000
2023-04-01 18:36:28 +02:00
Sam Brannen 49a4ed2ffa Improve Javadoc for @PropertySource 2023-04-01 18:15:19 +02:00
Sam Brannen 717d03a29d Fix grammar 2023-04-01 18:15:19 +02:00
1993heqiang 2b427efe7f Fix PathVariable reference documentation code snippets
Closes gh-30243
2023-03-31 15:51:56 +02:00
Sam Brannen 3632bea51e Polishing 2023-03-31 13:52:05 +02:00
Brian Clozel 1efa162cf0 WebClient defaultStatusHandler do not apply to exchangeTo*
This commit documents the fact that default status handlers configured
on the `WebClient` are not applied to `exchangeTo*` methods as those
variants give full access to the client response.

Applying them here would restrict the ability to adapt the behavior
depending on the HTTP response status.

Closes gh-30059
2023-03-31 11:19:40 +02:00
Harry Yang a8b7a5e037 Refine initRequestBuilder in DefaultWebClient
Closes gh-30254
2023-03-31 10:53:51 +02:00
Sébastien Deleuze 807325916f Add class hints for Jackson annotations on fields and methods
Before this commit, only class level annotations were
processed.

Closes gh-30208
2023-03-31 10:39:18 +02:00
Brian Clozel d451d6adcc Ensure that client responses are observed when filters fail
Prior to this commit, an error thrown by a `ExchangeFilterFunction`
configured on a `WebClient` instance would be recorded as such by the
client observation, but the response details would be missing from the
observation.
All filter functions and the exchange function (performing the HTTP
call) would be merged into a single `ExchangeFunction`; this instance
was instrumented and osberved. As a result, the instrumentation would
only get the error signal returned by the filter function and would not
see the HTTP response even if it was received. This means that the
recorded observation would not have the relevant information for the
HTTP status.

This commit ensures that between the configured `ExchangeFilterFunction`
and the `ExchangeFunction`, an instrumentation `ExchangeFilterFunction`
is inserted. This allows to set the client response to the observation
context, even if a later error signal is thrown by a filter function.

Note that with this change, an error signal sent by a filter function
will be still recorded in the observation.

See gh-30059
2023-03-30 20:04:48 +02:00
Juergen Hoeller 8fca258207 Propagate HttpStreamResetException itself if cause is null
Closes gh-30245
2023-03-30 19:22:30 +02:00
Sébastien Deleuze d126b99c91 Refine generic type management in AbstractMessageWriterResultHandler
This commit updates AbstractMessageWriterResultHandler#writeBody in
order to use the declared bodyParameter instead of
ResolvableType.forInstance(body) when the former has unresolvable
generics.

Closes gh-30214
2023-03-30 18:07:01 +02:00
Sébastien Deleuze c5f0f7bb11 Refine DisposableBeanAdapter method discovery for native
After this commit, DisposableBeanAdapter can find destruction related methods
even when hints are just specified at interface level, which is typically the
case when a bean is exposed via one of its interfaces.

Closes gh-29545
2023-03-30 15:28:50 +02:00
Brian Clozel 3a36d51473 Polish
See gh-29246
2023-03-30 14:49:11 +02:00
Brian Clozel fe6589d5af Add runtime hint test for inherited destroy methods
This commit ensures that init/destroy methods that are provided as
default methods from interfaces are properly covered by runtime hints at
runtime.

Closes gh-29246
2023-03-30 14:42:19 +02:00
Brian Clozel b374824319 Contribute introspection hints on registered beans
Prior to this commit, reflection hints registered for beans was
selectively applied to only consider the methods that we'll actually
need reflection on at runtime. This would rely on an undocumented
behavior of GraalVM Native where calling `getDeclaredMethods` on a type
would only return known metadata at runtime, ignoring the ones that were
not registered during native compilation.

As of oracle/graal#5171, this behavior is now fixed in GraalVM and
aligns with the JVM behavior: all methods will be returned. This means
that if during native compilation, introspection was not registered for
the type a new `MissingReflectionMetadataException` will be raised.

As a follow up of #29205, this commit contributes the "introspection on
declared method" reflection hint for all registered beans.

Closes gh-29246
2023-03-29 21:16:59 +02:00
Juergen Hoeller 7e905e3e00 Use JdkDynamicAopProxy class loader instead of JDK bootstrap/platform loader
Closes gh-30115
2023-03-29 13:46:29 +02:00
Juergen Hoeller 491ae1e3be Use MethodInvocationInfo class loader in case of JDK platform loader as well
Closes gh-30210
2023-03-29 13:46:18 +02:00
Brian Clozel 66cdf43b56 Polish
Closes gh-30223
2023-03-29 10:55:48 +02:00
James Yuzawa 2ba206f8ba Order metric labels in ObservationConventions
See gh-30223
2023-03-29 10:55:34 +02:00
James Yuzawa 5ba6944145 Remove String.formatter from DefaultServerRequestObservationConvention
Closes gh-30218
2023-03-28 20:24:55 +02:00
Arjen Poutsma 5609e67100 Improve Javadoc of MultipartBodyBuilder
This commit improves the Javadoc of MultipartBodyBuilder, to make it
clear that it is intended for multipart/form-data.

See gh-30179
2023-03-28 14:04:09 +02:00
Juergen Hoeller b2be07c73c Polishing 2023-03-28 13:26:29 +02:00
Juergen Hoeller ce2689eead Use MethodInvocationInfo class loader in case of core JDK interface type
Closes gh-30210
2023-03-28 13:20:49 +02:00
Johnny Lim 2184d4e80e Fix incomplete assertions
Closes gh-30209
2023-03-28 10:56:41 +02:00
Ed .d 50d01ce405 feat: Add support for Vavr's Try monad to trigger transaction rollbacks
Updated the Spring Framework documentation to include an example of using Vavr's Try monad to trigger transaction rollbacks when a @Transactional-annotated method returns a Failure. The modified documentation demonstrates how to use Try in a transactional method and how to check if an exception has been wrapped inside a Try.Failure instance. Additionally, a link to the official Vavr documentation was added to provide more information on the Try method.
2023-03-28 10:38:03 +02:00
Sam Brannen 0c0cda9815 Polish contribution
See gh-30189
2023-03-27 19:31:35 +02:00
Harry Yang 47aca90c58 Optimize array creation in SpEL ConstructorReference
- Create primitive arrays directly instead of using Array#newInstance.

- Replace if-else blocks with enhanced switch statement.

Closes gh-30189
2023-03-27 19:31:35 +02:00
Sam Brannen ddd6b123bb Polish TypeCode 2023-03-27 19:31:35 +02:00
heqiang ec270c7135 Use diamond operator in examples in reference manual
Closes gh-30204
2023-03-27 18:27:29 +02:00
Sébastien Deleuze 7cc72ddf7a Add HttpMethod reflection hint to ObjectToObjectConverterRuntimeHints
This commit adds a reflection hint for HttpMethod#valueOf in order
to be able to support conversion required for Spring Boot
configuration properties binding as described in
https://github.com/spring-projects/spring-boot/issues/34483.

Closes gh-30201
2023-03-27 15:13:15 +02:00
Sam Brannen 5f0ee2e4dd Polish ConstructorReference 2023-03-25 17:40:00 +01:00
Johnny Lim 43031509c8 Update versions in Javadoc
Closes gh-30170
2023-03-25 17:13:36 +01:00
ghostg00 e66c80667f Fix example in Javadoc for @EnableWebSocket
The `echoWebSocketHandler()` method is not defined in the
`WebSocketConfigurer` interface and should therefore be annotated with
`@Bean` instead of `@Override`.

Closes gh-30183
2023-03-24 17:54:33 +01:00
Sam Brannen 84714fbae9 Allow JDK 20 builds to pass by using legacy locale data
After setting up a JDK 20 CI build pipeline, numerous tests involving
date/time parsing and formatting began to fail [0]. (The failing JPA
tests are not specific to JDK 20.)

For example, we encounter visually confusing assertion failures such as
the following.

org.opentest4j.AssertionFailedError:
	expected: "12:00 PM"
	but was:  "12:00 PM"

The expected string contains a normal space (which has always been the
case prior to JDK 20); whereas, the actual string now contains a narrow
non-breaking space.

The cause of this is mentioned in the JDK 20 Release Notes [1] as "NBSP
prefixed to a, instead of a normal space". Note, however, that the
links for the first two bullet points in that section are mixed up.
"NBSP prefixed to a, instead of a normal space" should point to [2].
Furthermore, the new whitespace character is not a non-breaking space
(NBSP) but rather a narrow non-breaking space (NNBSP). In addition, the
second bullet point should technically read "NNBSP prefixed to `a`,
instead of a normal space" -- even though `a` provides limited value to
most readers.

The downside for the Java community is that this constitutes a breaking
change for parsing and formatting date/time values that include "AM"
and "PM" units (any may potentially apply to other date/time
parsing/formatting scenarios). In Spring Framework's test suite we have
witnessed this in conjunction with Spring's @DateTimeFormat and
DateTimeFormatterFactory infrastructure as well as with Google's
Gson-to-JSON support.

A colleague who works at Oracle graciously informed me that one can use
"legacy locale data" by supplying `-Djava.locale.providers=COMPAT` as a
JVM argument, noting however that this option limits some newer
functionalities (but without enumerating which new functionalities one
might be missing when using this option).

In any case, this commit adds that JVM argument to our Gradle toolchain
builds so that our test suite passes on JDK 20, and we will continue to
investigate further options for our builds and for our users.

Note, however, that one must manually configure the
`-Djava.locale.providers=COMPAT` JVM argument when running affected
tests within an IDE.

See gh-30185

[0] https://ge.spring.io/s/kmiq2bz2afafs/tests/overview?outcome=failed
[1] https://jdk.java.net/20/release-notes#JDK-8284840
[2] https://unicode-org.atlassian.net/browse/CLDR-14032
2023-03-24 16:08:38 +01:00
Sam Brannen 0ca02ce677 Disable affected tests on Java 18+/19+
See gh-30185
2023-03-24 16:05:40 +01:00
Sam Brannen db29b65399 Polishing 2023-03-24 16:05:40 +01:00
Sam Brannen 18adf905a8 Polishing 2023-03-23 17:04:41 +01:00
Sam Brannen ce9a72f95c Update copyright headers 2023-03-23 16:56:20 +01:00
Sam Brannen dfb4a951ae Suppress deprecation warnings instead of deprecating tests 2023-03-23 16:55:12 +01:00
Brian Clozel d9776941bf Update Java version for compatibility tests in CI
This commit configures Java 20 for compatibility tests in our CI,
replacing Java 19.
2023-03-23 15:47:06 +01:00
Giuseppe 24b359d519 Handle all exceptions for stored proc out param retrieval in SharedEntityManagerCreator
Prior to this commit, the EntityManager was not closed in
SharedEntityManagerCreator.DeferredQueryInvocationHandler's
invoke(Object, Method, Object[]) method if an invocation of
getOutputParameterValue(*) threw an exception other than
IllegalArgumentException, which could lead to a connection leak.

This commit addresses this by catching RuntimeException instead of
IllegalArgumentException.

Closes gh-30161
2023-03-22 15:39:53 +01:00
Arjen Poutsma ae70bf7c38 Merge pull request #30138 from yuzawa-san:LiteralPathElement-string-equals
* gh-30138:
  Polish external contribution
  Use String.equals() in LiteralPathElement
2023-03-22 12:13:45 +01:00
Arjen Poutsma c68e986b75 Polish external contribution
This commit removes the text char[] in favor of the text String
introduced through the PR.

Closes gh-30138
2023-03-22 12:10:18 +01:00
James Yuzawa 2bc1aa7827 Use String.equals() in LiteralPathElement 2023-03-22 12:10:18 +01:00
Kukri 570d21ebbd Fix anchor in link to "Web on Reactive Stack" chapter
Closes gh-30158
2023-03-22 11:30:35 +01:00
James Yuzawa 800b13492b Optimize some iterations in BodyExtractor and BodyInserter
This commit turns some stream-based iterations back into simpler
enhanced for loops.

For simple use cases like these, where the stream API is merely used to
map/filter + collect to a List, a for loop is more efficient.
This is especially true for small collections like the ones we deal
with in BodyInserters/BodyExtractors here (in the order of 50ns/op vs
5ns/op). These cases are also simple enough that they don't lose in
readability after the conversion.

Closes gh-30136
2023-03-22 11:04:54 +01:00
Сергей Цыпанов 4e896c8125 Use InputStream.readAllBytes() in FileCopyUtils.copyToByteArray()
InputStream.readAllBytes() allows us to avoid the creation of an
intermediate ByteArrayOutputStream and is likely to perform better.

Closes gh-30155
2023-03-21 15:37:26 +01:00
Arjen Poutsma 9421fe1d75 Merge pull request #30139 from yuzawa-san:cache-reactor-request-methods
* gh-30139:
  Cache ServerHttpRequest::getMethod in AbstractServerHttpRequest
  cache reactor request methods
2023-03-21 11:36:11 +01:00
Arjen Poutsma 37a4e84450 Cache ServerHttpRequest::getMethod in AbstractServerHttpRequest
This commit ensures that the HttpMethod, exposed through
ServerHttpRequest::getMethod, is cached in AbstractServerHttpRequest so
that potentially expensive HTTP method lookups are only done once.

Closes gh-30139
2023-03-21 11:29:32 +01:00
James Yuzawa c27a5687dc cache reactor request methods 2023-03-21 09:39:04 +01:00
Spring Builds 4e8162c6dd Next development version (v6.0.8-SNAPSHOT) 2023-03-20 09:53:24 +00:00
rstoyanchev 202fa5cdb3 Polishing and minor refactoring in HandlerMappingIntrospector
Closes gh-30127
2023-03-20 08:36:40 +00:00
Sam Brannen 8010de8b63 Improve diagnostics in SpEL for matches operator
Supplying a large regular expression to the `matches` operator in a
SpEL expression can result in errors that are not very helpful to the
user.

This commit improves the diagnostics in SpEL for the `matches` operator
by throwing a SpelEvaluationException with a meaningful error message
to better assist the user.

Closes gh-30144
2023-03-19 23:57:55 +01:00
Sam Brannen 5529294ec9 Improve diagnostics in SpEL for repeated text
Attempting to create repeated text in a SpEL expression using the
repeat operator can result in errors that are not very helpful to the
user.

This commit improves the diagnostics in SpEL for the repeat operator by
throwing a SpelEvaluationException with a meaningful error message in
order to better assist the user.

Closes gh-30142
2023-03-19 23:57:55 +01:00
Sam Brannen 935c29e3dd Increase scope of regex pattern cache for the SpEL matches operator
Prior to this commit, the pattern cache for the SpEL `matches` operator
only applied to expressions such as the following where the same
`matches` operator is invoked multiple times with different input:

  "map.keySet().?[#this matches '.+xyz']"

The pattern cache did not apply to expressions such as the following
where the same pattern ('.+xyz') is used in multiple `matches`
operations:

  "foo matches '.+xyz' AND bar matches '.+xyz'"

This commit addresses this by moving the instance of the pattern cache
map from OperatorMatches to InternalSpelExpressionParser so that the
cache can be reused for all `matches` operations for the given parser.

Closes gh-30140
2023-03-19 23:57:55 +01:00
Sam Brannen 4a3518b4d6 Polishing 2023-03-19 23:55:45 +01:00
Sam Brannen dd4a34778b Stop printing to System.out in SpEL tests 2023-03-19 23:55:36 +01:00
Brian Clozel 46bd6add15 Mention JAR signing key in SECURITY.md
This commit adds a link to the now published information on spring.io
about the GPG key used to sign the Spring artifacts published on Maven
Central.

Closes gh-23434
2023-03-17 22:32:33 +01:00
Juergen Hoeller 19384ac8ad Polishing 2023-03-17 17:37:23 +01:00
Juergen Hoeller a0358a4650 Upgrade to Reactor 2022.0.5 and Netty 4.1.90
Includes Checkstyle 10.9.1 and Mockito 5.2.0

Closes gh-30133
2023-03-17 17:36:51 +01:00
Juergen Hoeller 88bc504625 Skip validation constraint hint inference if no provider available
Closes gh-30130
2023-03-17 17:36:31 +01:00
Brian Clozel 3af8efbdc7 Add anchor rewrites in the reference documentation
This commit adds an `anchor-rewrite.properties` file in the reference
documentation sources. This allows to redirect from one anchor to
another when they are renamed.

This also populates the file with anchors that were renamed in the AOT
section of the documentation.

Closes gh-30132
2023-03-17 17:28:12 +01:00
Brian Clozel 2e08a07d7c Add a list of produced observations
This commit adds a list observations produced by Spring Framework in the
reference documentation.

Closes gh-30060
2023-03-17 17:27:11 +01:00
Sam Brannen df4e7d1929 Polishing 2023-03-15 15:08:47 +01:00
Brian Clozel 2a5eab4b89 Ignore quality factor when filtering out "*/*"
Prior to this commit, the `RequestedContentTypeResolverBuilder` would
create a `RequestedContentTypeResolver` that internally delegates to a
list of resolvers. Each resolver would either return the list of
requested media types, or a singleton list with the "*/*" media type; in
this case this signals that the resolver cannot find a specific media
type requested and that we should continue with the next resolver in the
list.

Media Types returned by resolvers can contain parameters, such as the
quality factor. If the HTTP client requests "*/*;q=0.8", the
`HeaderContentTypeResolver` will return this as a singleton list. While
this has been resolved from the request, such a media type should not be
selected over other media types that could be returned by other
resolvers.

This commit changes the `RequestedContentTypeResolverBuilder` so that it
does not select "*/*;q=0.8" as the requested media type, but instead
continues delegating to other resolvers in the list. This means we need
to remove the quality factor before comparing it to the "*/*" for
equality check.

Fixes gh-29915
2023-03-15 10:16:27 +01:00
Sam Brannen 1de36abc07 Revise contribution
See gh-25316
2023-03-14 17:28:12 +01:00
mrcoffee77 97b5af8a55 Ensure methods declared in Object can be invoked on a JDK proxy in SpEL
This commit ensures that methods declared in java.lang.Object (such as
toString() can be invoked on a JDK proxy instance in a SpEL expression.

Closes gh-25316
2023-03-14 17:19:06 +01:00
Sam Brannen 4751769a7c Polishing 2023-03-14 17:18:43 +01:00
Arjen Poutsma 1f8e9f5c55 Support Windows path in ContentDisposition::parse
This commit makes sure that ContentDisposition::parse supports Windows
path with a backslash.

Closes gh-30111
2023-03-14 14:19:33 +01:00
rstoyanchev c3ce847871 Polishing contribution
Closes gh-30092
2023-03-14 11:10:02 +00:00
James Yuzawa cd8955fa72 Remove extra copy in WebClient headers/cookies
See gh-30092
2023-03-14 10:49:53 +00:00
rstoyanchev d18bcb3f3d Raise MethodArgumentNotValidException consistently
Closes gh-30100
2023-03-14 09:08:57 +00:00
Sam Brannen e17f5c50a8 Update copyright headers 2023-03-13 21:53:40 +01:00
Sam Brannen 00be19c647 Consistently declare Object::equals argument as @Nullable 2023-03-13 21:43:21 +01:00
Sam Brannen a6dab10309 Update code regarding null-safety semantics
See gh-30083
2023-03-13 21:19:46 +01:00
Sam Brannen b617e16d8d Polishing 2023-03-13 21:16:02 +01:00
Sam Brannen 9cf7b0e230 Polishing 2023-03-12 18:38:50 +01:00
Juergen Hoeller 3431b2330a Avoid unnecessary parameter name inspection for factory method type check
Closes gh-30103
See gh-29612
2023-03-10 19:19:19 +01:00
Sam Brannen 99e54fec3a Ensure all packages declare package-info.java with null-safety annotations
This commit picks up where the two previous commits left off.

Specifically, this commit:

- Removes the "severity=warning" configuration to ensure that violations
  actually fail the build.
- Fixes regular expressions for suppressions by matching forward
  slashes using `[\\/]` instead of `\/`.
- Moves the configuration for newly introduced checks to locations in
  checkstyle.xml that align with the existing organization of that file.
- Renames the IDs for RegexpSinglelineJava checks from
  javaDocPackageNonNullApiAnnotation/javaDocPackageNonNullFieldsAnnotation
  to packageLevelNonNullApiAnnotation/packageLevelNonNullFieldsAnnotation,
  respectively, since these checks are not related to Javadoc.
- Simplifies the null-safety annotation checks to match against
  imported annotation types, which enforces consistency across
  package-info.java files for the annotation declarations.
- Simplifies the RegEx for JavadocPackage suppressions to only exclude
  packages not under src/main/java (vs src/main) and those in the
  framework-docs module.
- Consistently suppresses all checks for the `asm`, `cglib`, `objenesis`,
  and `javapoet` packages in spring-core.
- Adds explicit suppressions for null-safety annotations for the `lang`
  package in spring-core.
- Adds explicit suppressions for null-safety annotations for the
  `org.aopalliance` package in spring-aop.
- Revises the RegEx for null-safety annotation suppressions to only
  exclude package-info.java files not under src/main/java and
  additionally to exclude package-info.java files in the framework-docs
  module as well as those in the spring-context-indexer,
  spring-instrument, and spring-jcl modules.
- Adds all missing package-info.java files.
- Adds null-safety annotations to package-info.java files where
  appropriate.

Closes gh-30069
2023-03-10 17:33:52 +01:00
Ed .d 7e32f504b0 Configure Checkstyle to require package-level null-safety annotations
This commit updates the project's checkstyle configuration to check
that package-info.java files contain the @NonNullApi and @NonNullFields
null-safety annotations.

See gh-30069
2023-03-10 16:12:07 +01:00
Ed .d 268e3fec99 Configure Checkstyle to require package-info.java files
This commit updates the project's checkstyle configuration to require
the existence of a package-info.java file for all packages within the
src/main directory while excluding the framework-docs module and
certain packages inside the spring-core module. A missing
package-info.java file will result in emitting a warning.

See gh-30069
2023-03-10 16:09:17 +01:00
Simon Baslé 9b50c0d590 Ensure reactive transaction rollback on commit error
This change fixes a situation where error handling was skipped during
`processCommit()` in case the `doCommit()` failed. The error handling
was set up via an `onErrorResume` operator that was nested inside a
`then(...)`, applied to an inner `Mono.empty()`. As a consequence,
it would never receive an error signal (effectively decoupling the
onErrorResume from the main chain).

This change simply moves the error handling back one level up. It also
simplifies the `doCommit` code a bit by getting rid of the steps that
artificially introduce a `Mono<Object>` return type, which is not really
needed.

A pre-existing test was missing the fact that the rollback didn't occur,
which is now fixed. Another dedicated test is introduced building upon
the `ReactiveTestTransactionManager` class.

Closes gh-30096
2023-03-10 12:23:44 +01:00
Sam Brannen 2e5d0470dc Polishing 2023-03-09 14:19:59 +01:00
liupeng d2868f5dd0 Use Set to track ignored properties in BeanUtils.copyProperties()
Closes gh-30088
2023-03-09 14:11:22 +01:00
Abel Salgado Romero 1acbc97b16 Fix minor spacings in webflux docs
Closes gh-30078
2023-03-09 11:58:16 +01:00
Arjen Poutsma e88ec06a36 Disable flaky unit test for undertow 2023-03-09 10:03:07 +01:00
Juergen Hoeller 2302358606 Upgrade to Log4J 2.20, Tomcat 10.1.7, Jetty 11.0.14, Undertow 2.3.4 2023-03-08 16:53:43 +01:00
Juergen Hoeller d213522dfc Polishing 2023-03-08 16:49:32 +01:00
Juergen Hoeller 95710646d1 Pass pre-determined merged bean definition into InstanceSupplier (for inner beans)
Replaces useless protected obtainFromSupplier method with obtainInstanceFromSupplier.
Moves InstanceSupplier handling to appropriate subclass (DefaultListableBeanFactory).
BeanInstanceSupplier throws BeanInstantiationException instead of BeanCreationException.

Closes gh-29803
2023-03-08 16:49:25 +01:00
Brian Clozel 6cd67412cc Avoid lock contention in CaffeineCacheManager
Prior to this commit, using a dynamic `CaffeineCacheManager` would rely
on `ConcurrentHashMap#computeIfAbsent` for retrieving and creating cache
instances as needed. It turns out that using this method concurrently
can cause lock contention even when all known cache instances are
instantiated.

This commit avoids using this method if the cache instance already
exists and avoid storing `null` entries in the map. This change reduces
lock contention and the overall HashMap size in the non-dynamic case.

Fixes gh-30066
2023-03-08 16:23:32 +01:00
Arjen Poutsma e427ea8086 Merge pull request #30046 from srivatsa-cfp:main
* gh-30046:
  Add non-null assertions in DefaultServerRequestBuilder
2023-03-08 15:36:37 +01:00
Vatsa d8fbd35467 Add non-null assertions in DefaultServerRequestBuilder
This commit adds various non-null assertions to
DefaultServerRequestBuilder, in both Spring MVC and WebFlux.

Closes gh-30046
2023-03-08 12:50:02 +01:00
Sam Brannen a31cfba992 Apply "instanceof pattern matching" in remainder of spring-websocket module
See gh-30067
2023-03-07 19:18:25 +01:00
Sébastien Deleuze 14973fd6f3 Unset reproducibleFileOrder and preserveFileTimestamps Gradle flags
This commit reverts the changes done via 50a0094a47
in order to ensure consistency across modules (those changes were specific to
spring-core).

Reproducible builds are likely desirable, but it is a complex topic
(see gradle/gradle#14819) that needs to be addressed portfolio wide, with
a better control than what Gradle currently allows (for example to allow
using EPOCH instead of the current 1980 date).

Basic tests did not show an obvious impact on testing avoidance with modern
Gradle versions.

Closes gh-29633
2023-03-07 18:54:19 +01:00
Sam Brannen ffe7ec4a99 Apply "instanceof pattern matching" in remainder of spring-webmvc module
See gh-30067
2023-03-07 18:23:15 +01:00
Sam Brannen 9b811a01f6 Polishing 2023-03-07 15:20:10 +01:00
Sam Brannen 2b23d1693d Remove unused service package 2023-03-07 15:20:10 +01:00
Sam Brannen 9011ce9c68 Apply "instanceof pattern matching" in remainder of spring-web module
See gh-30067
2023-03-07 15:20:10 +01:00
Sam Brannen 29fe0a3c6a Update TODO for linking to JUnit 5 docs
See gh-27497
2023-03-07 13:28:25 +01:00
Sébastien Deleuze c20efba45c End javadoc generated AOT with a period consistently
Closes gh-29357
2023-03-07 11:20:37 +01:00
Sam Brannen fa95bf4dc1 Apply "instanceof pattern matching" in remainder of spring-test module
See gh-30067
2023-03-06 17:49:26 +01:00
Sam Brannen eea000d034 Apply "instanceof pattern matching" in remainder of spring-r2dbc module
See gh-30067
2023-03-06 17:21:28 +01:00
Sam Brannen a6338fcc43 Update copyright headers 2023-03-06 17:20:42 +01:00
Sam Brannen dafc7a2aab Apply "instanceof pattern matching" in remainder of spring-oxm module
See gh-30067
2023-03-06 17:07:49 +01:00
Sam Brannen b7288a4073 Apply "instanceof pattern matching" in remainder of spring-orm module
See gh-30067
2023-03-06 17:03:02 +01:00
Sam Brannen 004a144bdc Apply "instanceof pattern matching" in remainder of spring-messaging module
See gh-30067
2023-03-06 16:23:10 +01:00
Sam Brannen 09b60220d8 Apply "instanceof pattern matching" in remainder of spring-jms module
See gh-30067
2023-03-06 15:32:07 +01:00
Sam Brannen 7f1b81ff53 Apply "instanceof pattern matching" in remainder of spring-jdbc module
See gh-30067
2023-03-06 15:18:05 +01:00
Sam Brannen 8175a3bf09 Polishing 2023-03-06 15:17:39 +01:00
Sam Brannen 7eadedae36 Apply "instanceof pattern matching" in spring-jcl module
See gh-30067
2023-03-06 14:56:53 +01:00
Sam Brannen cb4f93561e Apply "instanceof pattern matching" in remainder of spring-expression module
See gh-30067
2023-03-06 14:45:28 +01:00
Sam Brannen f3cb331e4e Optimize find[Getter|Setter]ForProperty() in ReflectivePropertyAccessor 2023-03-06 14:45:28 +01:00
Sam Brannen 74f6725a37 Update copyright headers 2023-03-06 13:56:33 +01:00
Enric Sala edf0ae77e5 Avoid rollback after a commit failure in TransactionalOperator
A failure to commit a reactive transaction will complete the
transaction and clean up resources. Executing a rollback at
that point is invalid, which causes an
IllegalTransactionStateException that masks the cause of the
commit failure.

This change restructures TransactionalOperatorImpl and
ReactiveTransactionSupport to avoid executing a rollback after
a failed commit. While there, the Mono transaction handling in
TransactionalOperator is simplified by moving it to a default
method on the interface.

Closes gh-27572
2023-03-06 10:05:59 +01:00
Sam Brannen 95481018d0 Apply "instanceof pattern matching" in spring-core-test
See gh-30067
2023-03-05 19:37:59 +01:00
Sam Brannen 56523d5014 Polishing 2023-03-05 19:37:11 +01:00
Sam Brannen 8ebd746d69 Apply "instanceof pattern matching" in remainder of spring-core module
See gh-30067
2023-03-05 19:09:32 +01:00
Sam Brannen 162c09d036 Apply "instanceof pattern matching" in remainder of spring-context-support module
See gh-30067
2023-03-05 19:09:32 +01:00
Sam Brannen 7766b518d3 Apply "instanceof pattern matching" in spring-context-indexer module
See gh-30067
2023-03-05 19:09:32 +01:00
Sam Brannen 24de8c6f4c Apply "instanceof pattern matching" in remainder of spring-context module
See gh-30067
2023-03-05 19:09:32 +01:00
Sam Brannen d9500e60a1 Apply "instanceof pattern matching" in remainder of spring-beans module
See gh-30067
2023-03-05 19:09:32 +01:00
Sam Brannen e5d20a4f9d Convert EventExpressionRootObject to a record 2023-03-05 19:09:32 +01:00
Sam Brannen 37458d28d9 Covert InterceptorAndDynamicMethodMatcher to a record 2023-03-05 19:09:32 +01:00
Juergen Hoeller c9aba1eaad Enable Jetty 12 support in WebFlux
Closes gh-29575
2023-03-04 17:37:26 +01:00
Sam Brannen 3854861a8a Polishing 2023-03-03 15:39:24 +01:00
Spring Builds 3dd0fbfb57 Next development version (v6.0.7-SNAPSHOT) 2023-03-02 17:45:24 +00:00
Sam Brannen 57b838ddda Upgrade to spring-asciidoctor-backends 0.0.5 2023-03-02 16:50:48 +01:00
Sam Brannen 8c784085d2 Update copyright dates 2023-03-02 16:22:53 +01:00
Sam Brannen c0a1e1718e Polishing 2023-03-02 16:22:42 +01:00
Sam Brannen fe29e734ae Revise documentation for @AspectJ argument name resolution algorithm
Closes gh-30026
2023-03-02 15:26:21 +01:00
rstoyanchev 50c3a62589 Upgrade to Reactor Netty 2022.0.4
Closes gh-30063
2023-03-02 13:58:57 +00:00
Juergen Hoeller a936a6a8ce Javadoc-only reference to SubscribeMapping from simp package (-> package dependency cycle)
See gh-30002
2023-03-02 13:57:17 +01:00
Juergen Hoeller 8d112b8514 Test for explicit URI decoding in convertClassLoaderURL
See gh-30031
2023-03-02 13:33:53 +01:00
Juergen Hoeller f8cb0fa2a0 Custom resolution of preferred constructors for createBean(Class)
Avoids side effects of traditional AUTOWIRE_CONSTRUCTOR algorithm.

Closes gh-30041
2023-03-02 12:54:26 +01:00
rstoyanchev c56c16d7ba Polishing contribution
Closes gh-30010
2023-03-02 11:28:16 +00:00
Patrick Strawderman df1f8139cc Use Content-Length for optimal read to byte[]
If content-length is available, pass it to readNBytes in
ByteArrayHttpMessageConverter. When the content length is less than
the internal buffer size in InputStream (8192), this avoids a copy,
as readNBytes will return the buffer directly. When the content length
is greater than the buffer size used in InputStream, passing the
content-length at least avoids over-allocating the final buffer (e.g.,
if the content length were 8193 bytes, 1 byte more than the default
buffer size).

If the content length isn't present or is too large to represent as
an integer, fall back to the default behavior of readAllBytes by
passing in Integer.MAX_VALUE.

See gh-30010
2023-03-02 11:19:57 +00:00
rstoyanchev 9624ea392a Resolve baseUrl to String vs temporary URI
Along the lines of what was suggested in #30047.

Closes gh-30062
2023-03-02 10:20:05 +00:00
Violeta Georgieva 682a4d5353 Prefer request hostName and hostPort in ReactorServerHttpRequest
See gh-30062
2023-03-02 10:20:05 +00:00
Juergen Hoeller 4419d56178 Explicit URI decoding for FileSystemResource in convertClassLoaderURL
Also raising the log level to warn for file system retrieval failures.

Closes gh-30031
2023-03-02 10:18:13 +01:00
Sam Brannen 244c97993b Update documentation for @AspectJ argument name resolution algorithm
Closes gh-30026
2023-03-01 17:06:38 +01:00
Sam Brannen 9d28fe90f5 Simplify AbstractAspectJAdvisorFactory internals 2023-03-01 16:04:43 +01:00
Sébastien Deleuze d2a4ac519c Update build badge and link 2023-03-01 15:51:07 +01:00
Sébastien Deleuze dbbebf541d Refine reflection hints handling for anonymous class
Before this commit, anonymous classes could throw an
unexpected NullPointerException in
ReflectionsHint#registerType and lambdas entries could
be created in the related generated reflect-config.json.

This commit refines how anonymous classes are handled by
explicitly checking for null class and canonical name in
ReflectionTypeReference#of, while skipping such class in
ReflectionHints#registerType in order to keep a lenient
behavior.

Closes gh-29774
2023-03-01 15:41:30 +01:00
rstoyanchev fe73c630da Use URI String if necessary in ReactorClientHttpConnector
Closes gh-30053
2023-03-01 11:47:49 +00:00
Sam Brannen 3456fd054f Remove obsolete MetadataAwareAspectInstanceFactory Javadoc
We no longer have any JDK 5 related limitations imposed on us as was
the case when MetadataAwareAspectInstanceFactory was introduced; however,
MetadataAwareAspectInstanceFactory will remain as a specialized
sub-interface of AspectInstanceFactory.
2023-02-28 16:42:57 +01:00
Sam Brannen 5fd75dd27b Add missing package-info.java file for autoproxy.target package 2023-02-28 16:38:03 +01:00
Sam Brannen 6c29a5779e Fix .gitignore pattern for Maven "target" folders
Rationale: changes in org.springframework.aop.framework.autoproxy.target
were previously ignored since the "target" package was ignored by the
previous "eager" pattern for "target" folders.
2023-02-28 16:36:32 +01:00
Sam Brannen e9413b93c6 Apply "instanceof pattern matching" in BeanFactoryAdvisorRetrievalHelper 2023-02-28 16:33:56 +01:00
Radek Kraus 4cc02fe3bc Protect JMS connection creation against prepareConnection errors
This commit uses a local variable for the creation of a new JMS
Connection so that a rare failure in prepareConnection(...) does not
leave the connection field in a partially initialized state.

If such a JMSException occurs, the intermediary connection is closed.
This commit further defends against close() failures at that point,
by logging the close exception at DEBUG level. As a result, the original
JMSException is always re-thrown.

Closes gh-29116
See gh-29115
2023-02-28 16:10:05 +01:00
Sam Brannen b1cf832c28 Apply "instanceof pattern matching" in spring-tx
This commit applies "instanceof pattern matching" to the rest of the
code in spring-tx.

See gh-30019
2023-02-28 16:03:37 +01:00
Sam Brannen 34e5ce9360 Fix Checkstyle violations
See gh-30019
2023-02-28 16:03:37 +01:00
diguage 375114defa Apply "instanceof pattern matching" in spring-tx
Closes gh-30019
2023-02-28 15:33:59 +01:00
Sam Brannen 00c2c1d2a1 Polish "Support @Value for record injection"
See gh-28774
2023-02-28 13:12:15 +01:00
nanfeng 7c9fc575ff Support @Value for record injection
Add @Value support for record injection by disabling populateBean() for
records, since records are immutable.

See gh-28770
Closes gh-28774
2023-02-28 13:01:13 +01:00
rstoyanchev c859211f7a Polishing contribution
Closes gh-29691
2023-02-27 17:37:28 +00:00
Baljit Singh 4dbe9d6709 Use ContextView in ServerWebExchangeContextFilter 2023-02-27 17:20:16 +00:00
rstoyanchev acedbfbaba Polishing contribution
Closes gh-30014
2023-02-27 17:18:53 +00:00
Sergiu Prodan 5d6f151031 Update Javadoc of ServletRequestPathFilter
See gh-30014
2023-02-27 17:10:27 +00:00
Sam Brannen a09495d4e9 Polish contribution
See gh-30034
2023-02-27 16:38:55 +01:00
1993heqiang 5cab6a1f3a Fix "Configuring a Global Date and Time Format" example
Closes gh-30034
2023-02-27 16:33:38 +01:00
Sébastien Deleuze a02a017e6e Add tests for SpEL on Kotlin suspending function parameters
This was broken at some point but seems to work now.
This commit adds related tests.

Closes gh-26867
2023-02-27 16:09:43 +01:00
Sébastien Deleuze 9f2f93129b Move HttpServiceProxyFactoryExtensions.kt to spring-web module
HttpServiceProxyFactoryExtensions.kt has been mistakenly created
in spring-webflux module instead of spring-web, breaking JPMS for
WebFlux users.

This commit moves this file and related tests to the spring-web
module.

Closes gh-30042
2023-02-27 14:48:28 +01:00
Johnny Lim 475ac6ef5d Fix KotlinCoroutinesUtilsTests.invokeNonSuspendingFunctionWithContext()
Closes gh-30029
2023-02-27 14:02:49 +01:00
Sébastien Deleuze 79f43041ad Catch defensively validator exceptions in AOT processing
An ArrayIndexOutOfBoundsException is thrown by
Validator.getConstraintsForClass when processing Kotlin beans
with extensions functions (Kotlin or Hibernate Validator bug).

This commit catches those exceptions and report them as warning
without the full stactrace, and report as well other
ones thrown as errors with the full stracktrace.

Closes gh-30037
2023-02-27 12:06:37 +01:00
Sam Brannen edb4a3467a Update copyright headers 2023-02-26 18:37:18 +01:00
Sam Brannen 024d02225c Apply "instanceof pattern matching" to remaining Validation classes 2023-02-26 18:37:18 +01:00
Sam Brannen 9305a64a50 Polish contribution
See gh-29994
2023-02-26 18:30:14 +01:00
divcon 40672c3715 Apply "instance of patten matching" in context and messaging modules
Closes gh-29994
2023-02-26 18:30:14 +01:00
Sam Brannen 7c50464bba Polishing 2023-02-26 18:30:14 +01:00
Patrick Strawderman 0d10d4beee Initialize ArrayList with exact size in HttpHeaders 2023-02-24 17:09:58 +00:00
Sébastien Deleuze f60bec986f Add missing @Nullable annotations to LogMessage methods
Closes gh-30006
2023-02-24 17:45:50 +01:00
Sébastien Deleuze 6825a842b5 Support package private methods on CGLIB proxies with AOT
Closes gh-29582
Closes gh-29764
2023-02-24 17:00:41 +01:00
Sam Brannen 7ace9aa429 Polish AspectJAdviceParameterNameDiscoverer
This commit also converts PointcutBody to a record.
2023-02-24 11:40:34 +01:00
Sam Brannen 8979ac789f Fix layout in "Determining Argument Names" section 2023-02-24 11:40:34 +01:00
Sébastien Deleuze 9cb4c5565a Fix proxy hint Kotlin extensions
Closes gh-30025
2023-02-24 10:46:27 +01:00
Sam Brannen 08f38c52c7 Revise AspectJ examples in the reference manual
The extensive use of shared pointcuts can be confusing to users who
read a given AspectJ example without having read the "Sharing Common
Pointcut Definitions" section of the AOP chapter.

The primary purpose of this commit is therefore to reduce the extensive
use of shared pointcuts in AspectJ examples by favoring "inline
pointcuts" over shared "named pointcuts" and by cross referencing the
declaration of shared pointcuts when they are used.

Since the affected parts of the documentation are intertwined, this
commit also refactors the examples to use a common "com.xyz" package
namespace for greater clarity.

In order to avoid the need to escape asterisks (\*) in examples, this
commit also removes the `subs="quotes"` configuration for code blocks.

Closes gh-30003
2023-02-24 10:21:32 +01:00
Sam Brannen afa936e985 Polish AOP chapter 2023-02-24 10:21:32 +01:00
AlexElin 3677d3597b Improve @Lazy's javadoc by adding @code tag 2023-02-23 17:27:01 +00:00
Sam Brannen 76bc7deb8e Polish AOP chapter 2023-02-22 17:30:20 +01:00
Sam Brannen 6c3cb5d2e0 Revise chomp and fold settings in reference documentation
This commit overrides the `chomp` and `fold` settings for
spring-asciidoctor-backends on a per-block basis.

Closes gh-30001
2023-02-22 12:49:20 +01:00
Sam Brannen 3ce71932c0 Polish reference docs 2023-02-22 12:48:40 +01:00
Sam Brannen 3a9c7524f0 Polishing 2023-02-22 11:21:00 +01:00
Sam Brannen ce66b251ab Fix Javadoc for MockRestRequestMatchers 2023-02-21 22:13:41 +01:00
Sébastien Deleuze 626a7fc52a Add native support for @SubscribeMapping and @MessageExceptionHandler
Closes gh-30002
2023-02-21 18:47:30 +01:00
Sébastien Deleuze 3d8455b257 Add unit tests for CoroutinesUtils
Closes gh-29968
2023-02-21 10:20:00 +01:00
Sébastien Deleuze fd38c23699 Refine CoroutinesUtils#invokeSuspendingFunction contract
This commit refines CoroutinesUtils#invokeSuspendingFunction in order
to clarify the behavior when used on a non suspending function, and
support usages with or without the Continuation argument.

Closes gh-30005
2023-02-21 10:20:00 +01:00
Sam Brannen e47418c948 Polish attributes.adoc 2023-02-20 17:23:07 +01:00
Sam Brannen d6de374424 Restore package & import statements in AOP examples in ref docs
See gh-30001
2023-02-20 17:23:07 +01:00
Sam Brannen b437b7be34 Introduce test for perthis with @Aspect and shared pointcut
This commit modifies PerThisAspect (which is used indirectly in
AspectJAutoProxyCreatorTests.perThisAspect()) so that it uses a shared
@Pointcut for both the @Aspect and @Around declarations, in order to
refute claims made in gh-29998 that the documentation in the reference
manual is incorrect.
2023-02-20 17:23:07 +01:00
Sam Brannen 2d56505ea9 Polishing 2023-02-20 16:49:27 +01:00
Sam Brannen 8a44b6445d Revise queryParam() and header() support in MockRestRequestMatchers
See gh-29953
See gh-29964
2023-02-19 18:52:44 +01:00
Sam Brannen 6d24e62e83 Polishing 2023-02-19 17:43:31 +01:00
Johnny Lim 2d62be8590 Fix Javadoc since for MockRestRequestMatchers queryParam() and header() (#29986)
See gh-29953
See gh-29964
2023-02-19 16:04:53 +01:00
Sam Brannen 2e1374b459 Update copyright headers 2023-02-19 13:41:36 +01:00
Sam Brannen bb6150e44e Use correct Kotlin file extension in update_copyright_headers.sh 2023-02-19 13:41:36 +01:00
Sam Brannen 38a4f23f16 Polishing 2023-02-19 13:41:36 +01:00
Johnny Lim 6739ca82ce Polishing
See gh-23846
See gh-29955
Closes gh-29992
2023-02-19 13:41:36 +01:00
Arjen Poutsma 88e6544d9d Fix regression in WebFlux support for WebDAV methods
This commit ensures that WebFlux's RequestMethodsRequestCondition
supports HTTP methods that are not in the RequestMethod enum.

- RequestMethod::resolve is introduced, to convert from a HttpMethod
(name) to enum values.
- RequestMethod::asHttpMethod is introduced, to convert from enum value
to HttpMethod.
- HttpMethod::valueOf replaced Map-based lookup to a switch statement
- Enabled tests that check for WebDAV methods

See gh-27697
Closes gh-29981
2023-02-17 12:46:26 +01:00
Spring Builds 1999c78350 Next development version (v6.0.6-SNAPSHOT) 2023-02-15 16:20:19 +00:00
Arjen Poutsma afd67a0deb Fix DataBufferUtils::write AsynchronousFileChannel race condition
See gh-29943
2023-02-15 15:38:48 +01:00
Jerome Prinet dcaddddbc5 Update Gradle Enterprise plugin
Closes gh-29969
2023-02-15 14:43:31 +01:00
Johnny Lim ce3be72e7f Polish 2023-02-15 22:22:58 +09:00
Juergen Hoeller 3e3f046dc9 Polishing 2023-02-15 12:57:44 +01:00
rstoyanchev 5847454aa4 Prefer local hostAddress in ReactorServerHttpRequest
Closes gh-28601
2023-02-15 10:26:49 +00:00
Sébastien Deleuze 569df6eecc Refine ModelAttributeMethodProcessor Kotlin exception handling
This commit refines ModelAttributeMethodProcessor Kotlin exception
handling in order to throw a proper MethodArgumentNotValidException
instead of a NullPointerException when Kotlin null-safety constraints
are not fulfilled, translating to an HTTP error with 400 status code
(Bad Request) instead of 500 (Internal Server Error).

Closes gh-23846
2023-02-15 11:02:46 +01:00
Juergen Hoeller 979118c1eb Polishing 2023-02-15 10:13:16 +01:00
Juergen Hoeller f87a87e29d Consistent ordering of Resource methods
See gh-24651
2023-02-15 10:13:03 +01:00
Juergen Hoeller 0619e19140 Upgrade to Reactor 2022.0.3
Closes gh-29900
2023-02-15 10:12:48 +01:00
Sébastien Deleuze ac521a366a Refine instance supplier check in BeanDefinitionMethodGenerator
This commit refines the instance supplier check in
BeanDefinitionMethodGenerator constructor in order to allow
overriding by an AOT contribution.

Closes gh-29556
2023-02-15 09:32:00 +01:00
rstoyanchev 9a4df5a97d DefaultHandlerExceptionResolver respects custom ModelAndView
Closes gh-29971
2023-02-14 20:13:15 +00:00
rstoyanchev f54e1ef880 Initialize propertyName
MethodArgumentTypeMismatchException and
MethodArgumentConversionNotSupportedException are TypeMismatchException
subclasses with MethodParameter information and should initialize
propertyName in TypeMismatchInformation.

Closes gh-29959
2023-02-14 18:12:48 +00:00
rstoyanchev a3efcabe0c Polishing contribution
Closes gh-29954
2023-02-14 17:40:12 +00:00
James Yuzawa dd3dc2d0d0 Pass URI to Reactor Netty HttpClient
See gh-29954
2023-02-14 17:40:12 +00:00
Brian Clozel 2578e3894e Upgrade to Micrometer 1.10.4
Closes gh-29899
2023-02-14 17:10:10 +01:00
Brian Clozel 5335778d8d Polish
See gh-29955
2023-02-14 17:08:24 +01:00
Toshiaki Maki 616e7779e0 Add RFC-8246 support to CacheControl
This commit adds the "immutable" Cache-Control directives in `CacheControl`.

Closes gh-29955
2023-02-14 17:08:24 +01:00
Juergen Hoeller 84c7f07364 Consistent @Bean method return type for equivalence with XML example
Closes gh-29338
2023-02-14 16:36:31 +01:00
Juergen Hoeller ac429a4ef7 Restore fallback to request attributes in FreeMarker template model
Closes gh-29787
2023-02-14 16:36:07 +01:00
Arjen Poutsma 12d4dc1bae Polishing external contribution
This commit makes several changes to PR #24651.

- Add byte[] getContentAsByteArray() on Resource.
- Remove getContentAsString() from Resource, as it relied on the default
charset which is not reliable.
- Add getContentAsString() to EncodedResource, as a charset is provided
through the constructor.

See gh-24651
2023-02-14 14:56:34 +01:00
Derrick Anderson 4da2499613 Introduce Resource::getContentAsString
This commit introduces the getContentAsString method to Resource,
returning the string contents of the resource.

Closes gh-24651
2023-02-14 14:37:40 +01:00
rstoyanchev 18896aceca Adapt empty path to "/" in MockMvc
Closes gh-29933
2023-02-14 12:01:59 +00:00
Juergen Hoeller d7824c7831 Polishing 2023-02-14 11:00:01 +01:00
Juergen Hoeller f91b2249b3 Upgrade to Netty 4.1.89 2023-02-14 10:58:15 +01:00
Juergen Hoeller 33b329e13a Latest patch from ASM master
See gh-29910
2023-02-14 10:58:03 +01:00
rstoyanchev b23316302d Avoid blocking in InMemoryWebSessionStore#changeSessionId
Closes gh-29212
2023-02-13 18:39:19 +00:00
rstoyanchev dc843adb45 Improve docs on {@code Accept-Language} negotiation
Closes gh-28673
2023-02-13 18:39:19 +00:00
rstoyanchev 9fcafd2650 WebSocketConnectionManager accepts prepared URI
Closes gh-28524
2023-02-13 18:39:19 +00:00
rstoyanchev ccbb4bdd27 PayloadMethodArgumentResolver supports Optional
Closes gh-28945
2023-02-13 18:39:19 +00:00
rstoyanchev 5b79a57f14 Polishing
See gh-28945
2023-02-13 18:39:19 +00:00
Simon Baslé 189d4e3e4c Allow MockRest to match header/queryParam value list with one Matcher
This commit adds a `header` variant and a `queryParam` variant to the
`MockRestRequestMatchers` API which take a single `Matcher` over the
list of values.

Contrary to the vararg variants, the whole list is evaluated and the
caller can choose the desired semantics using readily-available iterable
matchers like `everyItem`, `hasItems`, `hasSize`, `contains` or
`containsInAnyOrder`...

The fact that the previous variants don't strictly check the size of the
actual list == the number of provided matchers or expected values is
now documented in their respective javadocs.

See gh-28660
Closes gh-29953
2023-02-13 17:51:01 +01:00
Arjen Poutsma 79a1fcb099 Polishing DataBuffer::write(CharSequence, Charset)
See gh-29943
2023-02-13 16:34:04 +01:00
Sébastien Deleuze 026be04b75 Polish CoroutinesAnnotationTransactionInterceptorTests 2023-02-13 15:34:01 +01:00
Sébastien Deleuze 45ae00fda3 Propagate the context in Coroutines transactions
This commit ensures that CoroutineContext is properly
propagated in transactional suspending functions. Both
annotation and functional variants are supported.

Closes gh-27308
2023-02-13 15:34:01 +01:00
Arjen Poutsma 3e2f58cdd2 Offer restricted access to DataBuffer's ByteBuffer
This commit introduces DataBuffer::readableByteBuffers and
DataBuffer::writableByteBuffers, allowing restricted access to the
ByteBuffer used internally by DataBuffer implementations.

Closes gh-29943
2023-02-13 15:28:29 +01:00
Boris Fox 72926c29f9 Temporarily set LocaleContextHolder to provide validation message interpolator with locale context (fixes SPR-17231). 2023-02-13 11:45:45 +00:00
rstoyanchev f5c1e2ffa1 Polishing contribution
Includes small refactoring in DefaultServerWebExchange and adjustment
of initMultipartData to get involved for any "multipart/" prefixed
media type.

In addition, "multipart/related" is now in the list of media types
supported by FormHttpMessageConverter, which aligns it with
MultipartHttpMessageReader.

Closes gh-29671
2023-02-13 11:40:36 +00:00
Ronny Perinke 67df0756cd Support multipart/mixed and related in DefaultServerWebExchange
See gh-29671
2023-02-13 10:39:23 +00:00
rstoyanchev 17bc3facaa Polishing contribution
Closes gh-29220
2023-02-13 09:16:33 +00:00
Anatolii Zhmaiev 1de9426df0 Set reason for WebSocket CloseStatus.SESSION_NOT_RELIABLE
See gh-29220
2023-02-13 09:16:33 +00:00
rstoyanchev 27fdf56ed5 Polishing contribution
Closes gh-29949
2023-02-13 07:52:01 +00:00
Yanming Zhou 55392dfbd7 Define xml namespace as constant
See gh-29949
2023-02-13 07:51:30 +00:00
Juergen Hoeller ca9439657e Detect MSSQL code 2601 as duplicate key (aligned with sql-error-codes.xml)
Closes gh-29950
2023-02-09 14:59:09 +01:00
Sébastien Deleuze 5819d76d98 Document AOT limitation regarding to @Bean type
Closes gh-29944
2023-02-09 10:34:42 +01:00
Johnny Lim 431ae03447 Polish
Closes gh-29928
2023-02-09 09:54:19 +01:00
rstoyanchev a7ec6b4a2a Unwrap session before selecting stats counter
See gh-29375
2023-02-08 18:12:42 +00:00
rstoyanchev e5ff54955f ProblemDetail XML support via Jackson
Closes gh-29927
2023-02-08 10:39:41 +00:00
rstoyanchev 9c0b28ffdc Fix StringIndexOutOfBoundsException
Closes gh-29588
2023-02-07 20:17:07 +00:00
Sam Brannen 08e7f5a292 Clearly document that DataClassRowMapper supports Java records
Closes gh-29814
2023-02-07 19:05:47 +01:00
Sam Brannen 5f458e2578 Polish RowMapper tests 2023-02-07 19:05:38 +01:00
Sam Brannen 7584dfc79a Avoid confusing terminology in BeanPropertyRowMapper
Prior to this commit, the term "field" was sometimes used to refer to a
database column and sometimes used to refer to a bean property, which
lead to confusion in the Javadoc as well as within the code.

This commit addresses this by avoiding use of the term "field".
2023-02-07 18:31:50 +01:00
Juergen Hoeller dc2c33e0ab Upgrade to Hibernate ORM 5.6.15, FreeMarker 2.3.32, TestNG 7.7.1, XMLUnit 2.9.1 2023-02-07 17:20:11 +01:00
Juergen Hoeller dbf360997a Convert non-pattern ClassLoader results to FileSystemResource if possible
Closes gh-29934
2023-02-07 17:19:23 +01:00
Juergen Hoeller b719a87061 Suggest AOP proxy or CGLIB_CLASS_SEPARATOR check instead of isCglibProxyClass
See gh-22706
2023-02-07 17:19:12 +01:00
Sam Brannen 97e557c886 Update copyright headers 2023-02-07 16:37:18 +01:00
Manthan Bhatt 89c170b095 Restrict forwards in MockMvcWebConnection to 100
This change restricts the maximum number of forwards in MockMvcWebConnection to 100,
in case a forward is configured in a way that causes a loop. This is necessary in HtmlUnit
backed tests, unlike in classic MockMvc tests in which the forwards are not actually resolved.

Closes gh-29483
Closes gh-29557

Co-authored-by: Simon Baslé <sbasle@vmware.com>
2023-02-07 16:23:56 +01:00
Sam Brannen 482482f62b Revise Testcontainers examples based on feedback
Closes gh-29939
2023-02-07 15:55:00 +01:00
Sébastien Deleuze a2a676241c Introduce HttpServiceProxyFactory#createClient Kotlin extension
Closes gh-29942
2023-02-07 15:50:30 +01:00
Johnny Lim 28602ad012 Add MockMvc.multipart() Kotlin extensions with HttpMethod
See gh-28545
See gh-28631
Closes gh-28634
2023-02-07 15:13:17 +01:00
Sam Brannen 8e9dc3590d Update @DynamicPropertySource examples regarding changes in Testcontainers
Closes gh-29939
2023-02-07 13:34:22 +01:00
Sébastien Deleuze b8a7aa9395 Refine ControllerMappingReflectiveProcessor documentation
Closes gh-29938
2023-02-07 12:00:07 +01:00
Sébastien Deleuze cb63164593 Refine Coroutines support in HttpServiceProxyFactory
Closes gh-29527
2023-02-07 11:07:30 +01:00
Sébastien Deleuze 9f061f1eec Refine KotlinWebClientHttpServiceProxyTests
See gh-29527
2023-02-07 11:07:30 +01:00
Donghyeon Kim 1d4bf58e8d Support Coroutines in HttpServiceProxyFactory
See gh-29527
2023-02-07 11:07:29 +01:00
rstoyanchev ce85fdc5c7 Always use application/problem+json with ProblemDetail
See gh-gh-29588
2023-02-07 08:57:24 +00:00
rstoyanchev 7851994a17 Refine empty path handling in MvcUriComponentsBuilder
Return "" from methods that obtain controller or method mapping to
avoid side effect of a trailing slash appearing.

Closes gh-29897
2023-02-07 08:57:24 +00:00
Sam Brannen 84bc1dfa89 Polish RowMapper tests 2023-02-03 17:47:50 +01:00
Sam Brannen 159a3e71f2 Clarify semantics of primitivesDefaultedForNullValue in BeanPropertyRowMapper
Closes gh-29923
2023-02-03 17:47:50 +01:00
Sam Brannen adbba712d6 Polish Javadoc for RowMappers 2023-02-03 17:47:50 +01:00
danu e050c37158 Release R2DBC connection when cleanup fails in transaction
When using R2dbcTransactionManager, connection will not be released if
it encounters error while doing `afterCleanup` steps. As `afterCleanup`
can use a database connection when doing `setAutoCommit(true)`, it can
fail under some conditions where the connection is not reliable.

This leads to the Connection not being released.

This commit ensures that inner steps of the `doCleanupAfterCompletion`
are protected against errors, logging the errors and continuing the
cleanup until the last step, which releases the connection.

Closes gh-29703

Co-authored-by: Simon Baslé <sbasle@vmware.com>
2023-02-03 17:33:55 +01:00
Brian Clozel eff1a1a664 Upgrade to Artifactory Resource 0.0.18 2023-02-03 00:38:57 +01:00
Brian Clozel 8838e0d825 Use Docker Hub credentials for CI release tasks 2023-02-03 00:34:58 +01:00
Brian Clozel 0d21f0b1d4 Remove Java 18 from CI image 2023-02-02 21:02:01 +01:00
Brian Clozel 41aeb07585 Rely only on Docker Hub for fetching OCI images 2023-02-02 20:56:50 +01:00
Sam Brannen 70aaec2a8d Use static imports for AssertJ assertions in Kotlin tests 2023-02-02 20:12:42 +01:00
Sam Brannen 3029b7b9be Fix build 2023-02-02 20:12:18 +01:00
Brian Clozel 708f600afe Document how to mark an observation as an error
The `ServerHttpObservationFilter` implementations record observations
for processed HTTP exchanges. The `Observation.Context` contains various
metadata contributed by the observation convention. The instrumentation
can also mark the observation as an error by setting any `Throwable` on
the context.

Because the instrumentation is done as filters, only exceptions reaching
the filter can be considered. Any error handled at a lower level by the
Framework can, or cannot be considered as an error for an observation.

This commit documents how a web application should opt-in for
considering a handled exception as an error for the current observation.

Closes gh-29848
2023-02-02 18:19:17 +01:00
Sébastien Deleuze f7418704de Add ResponseEntity.ofNullable()
To deal with non-Optional nullable objects.

Closes gh-29117
2023-02-02 16:42:42 +01:00
Brian Clozel 7440afe571 Document how to enable HTTP client Observation instrumentation
This commit documents how Observation instrumentation should be
activated for `RestTemplate` and `WebClient`: they both need an
`ObservationRegistry` configured to create and record actual
observations.
This is being done automatically in Spring Boot if auto-configured
builders (`RestTemplateBuilder`, `WebClient.Builder`) are used.

Closes gh-29904
2023-02-02 16:03:11 +01:00
Sam Brannen bc583ea74f Polish "Use switch expressions in SpEL's CodeFlow"
See gh-29020
2023-02-02 15:14:34 +01:00
Roman Ivanov dcda127b60 Use switch expressions in SpEL's CodeFlow
Closes gh-29020
2023-02-02 15:02:10 +01:00
Sam Brannen ac6385025b Polishing 2023-02-02 15:02:10 +01:00
Sébastien Deleuze e170c16b02 Refine TransactionalOperator.executeAndAwait nullability
Before this commit, TransactionalOperator.executeAndAwait had a rigid
null-safety handling. This commit takes advantage of Kotlin capability
to allow to deal with both non-null and nullable depending on the
nullability of the lambda.

Closes gh-29919
2023-02-02 14:39:33 +01:00
Olga Maciaszek-Sharma 4beb05ddb3 Add native support for RSocketExchange.
This commit introduces new AOT processors that look for
`@RSocketExchange` annotated methods on interfaces implemented by beans
and registers reachability metadata accordingly:

* JDK proxies for the beans themselves
* invocation reflection for annotated methods
* binding reflection for arguments and return types

This allows to compile such clients to Native Images.

Closes gh-29877
2023-02-01 18:22:33 +01:00
Juergen Hoeller 06fd6ecf1f Upgrade to Groovy 4.0.8, Tomcat 10.1.5, Netty 4.1.87, Undertow 2.3.3, Jackson 2.14.2, Woodstox 6.5, Mockito 5.1.1, AssertJ 3.24.2, HtmlUnit 2.70, Checkstyle 10.7 2023-02-01 18:18:52 +01:00
Juergen Hoeller b8827d8e11 Clarify postProcessBeanFactory lifecycle state
Closes gh-29064
2023-02-01 18:18:37 +01:00
Sam Brannen 23a60aeb27 Sync MockHttpServletRequest implementations 2023-02-01 16:28:38 +01:00
Arjen Poutsma 58fbf60d2d Include quoted printable filename in ContentDisposition::toString
This commit ensures the ContentDisposition class prints the filename in
both in the regular filename parameter and the extended filename*
parameter (RFC 5987).
Quoted printable (RFC 2047) is used to encode any non-ASCII characters
in the regular filename parameter.

Closes gh-29861
2023-02-01 13:40:03 +01:00
Sébastien Deleuze ebca9f726f Provide Kotlin extensions for RuntimeHints
To be able to register hints using for example registerType<MyClass>()
instead of registerType(MyClass::class.java).

Closes gh-29831
2023-02-01 12:04:18 +01:00
Brian Clozel 5fd73f0bae Fix MockHttpServletRequest InputStream for empty body
Prior to this commit, a recent change applied in gh-29125 changed the
behavior of `MockHttpServletRequest` instances. In case of an empty
request body, the returned `InputStream` would be static and could not
be reused across requests.
This could result in `java.io.IOException: Stream closed` exceptions if
a previous request was read.

This commit ensures that a new instance of an empty stream is returned
for each request instance.

Fixes gh-29901
2023-01-31 19:28:15 +01:00
Juergen Hoeller 16937c7ce5 Polishing 2023-01-31 18:15:28 +01:00
Juergen Hoeller c0c9ba5c2c Polishing 2023-01-31 16:14:32 +01:00
Juergen Hoeller 4d6249811e Explicit target ClassLoader for interface-based infrastructure proxies
Includes direct JDK Proxy usage instead of ProxyFactory where possible.

Closes gh-29913
2023-01-31 16:11:34 +01:00
Juergen Hoeller 3a08d643ed Upgrade to ASM master (including early support for Java 21 bytecode)
Closes gh-29910
2023-01-31 16:06:33 +01:00
Juergen Hoeller a74b86e812 Lazily load ContextLoader.properties (and lazily fail if not present)
Closes gh-29905
2023-01-31 16:05:07 +01:00
Juergen Hoeller 7c9dca3d2e Declare no-op close() method in order to avoid container-triggered shutdown call
Closes gh-29892
2023-01-31 16:03:26 +01:00
Brian Clozel 64219783f6 Start building with Reactor 2022.0.3-SNAPSHOT
See gh-29900
2023-01-31 15:37:04 +01:00
Brian Clozel 846a54aef4 Start building with Micrometer 1.10.4-SNAPSHOT
See gh-29899
2023-01-31 15:36:24 +01:00
Chen Jianbin 9e735d4f0f Normalize and optimize internals of CGLIB ParallelSorter
Closes gh-29516
2023-01-31 12:20:45 +01:00
Arjen Poutsma 0ddb394fd0 Register callback for HttpComponentsClientHttpConnector
This commit ensures that we register a result callback when executing
the request (next to the existing response callback), which gets
notified of invalid hosts and other connection issues.

Closes gh-29156
2023-01-31 12:16:43 +01:00
Sam Brannen f5a39308a0 Polishing 2023-01-31 11:54:21 +01:00
Johnny Lim e4ceb80678 Use EnumMap for DateFormatter.ISO_PATTERNS again
This commit changes to use `EnumMap` for `DateFormatter.ISO_PATTERNS`
again by partially reverting commit ba136dcf40.

See gh-29321
Closes gh-29485
2023-01-31 11:52:25 +01:00
Sam Brannen 64b89429cb Update copyright headers 2023-01-31 11:52:25 +01:00
Arjen Poutsma 8e843c242a Merge pull request #29853 from ThomHurks:cors-configuration-small-memory-optimization
* gh-29853:
  Polish external contribution
  Optimize CorsConfiguration::checkHeaders
2023-01-31 10:30:46 +01:00
Arjen Poutsma 635f010de3 Polish external contribution 2023-01-31 10:28:42 +01:00
Thom Hurks aac1ed6ee5 Optimize CorsConfiguration::checkHeaders
In the checkHeaders method, if allowedHeaders contains * the result
size can be requestHeaders.size(), but if this is not the case
then the result size can only be as big as the minimum value
of requestHeaders.size() and allowedHeaders.size().
requestHeaders.size() can be potentially big (user input) and
allowedHeaders.size() could be small, so this saves memory in
that case.

Closes gh-29853
2023-01-31 10:28:42 +01:00
Sam Brannen d5b0782700 Polishing 2023-01-31 10:10:44 +01:00
Sam Brannen ebe717ff6c Update release version due to backport
See gh-29790
See gh-29902
2023-01-31 10:00:18 +01:00
Sébastien Deleuze 89c7c6e9dd Fix bean validation on suspending function parameters
This commit leverages Hibernate Validator's own internal use
of standard Java reflection to perform validation on suspending
function, which fixes the ArrayIndexOutOfBoundsException previously
observed.

Validation of suspending function return values remains unsupported
as Hibernate Validator is not Coroutines aware.

Closes gh-23499
2023-01-31 09:41:47 +01:00
rstoyanchev 9c6fd3ed06 Consistently list supported media types
Add constructors to HttpMediaTypeNotSupportedException and
UnsupportedMediaTypeStatusException for a parse error that also accept
the list of supported media types to include in the response headers.

Closes gh-28062
2023-01-30 17:46:08 +00:00
rstoyanchev e564a0de46 Provide access to interceptors in AbstractHandlerMapping
Closes gh-28985
2023-01-30 17:46:08 +00:00
rstoyanchev 17f1eadb6f Polishing contribution
Closes gh-29610
2023-01-30 17:46:08 +00:00
divcon 09991f2492 Polishing in ResponseEntityResultHandler
See gh-files
2023-01-30 17:46:08 +00:00
rstoyanchev 15931532cd Polishing contribution
Closes gh-29868
2023-01-30 17:46:08 +00:00
Eden Tyler-Moss aa9f445422 Add @Nullable to ProblemDetail.setProperty argument
See gh-29868
2023-01-30 17:46:08 +00:00
rstoyanchev b578ff1296 Polishing contribution
Closes gh-29696
2023-01-30 17:46:08 +00:00
Kevin Yue cf9fc69d6b Don't swallow exception when logging response status
See gh-29696
2023-01-30 17:46:08 +00:00
Sam Brannen 04321d0577 Revise generated default name for @JmsListener subscription
The previous commit changed the generated default name for a JMS
subscription to <FQCN>#<method name> -- for example:

- org.example.MyListener#myListenerMethod

However, the JMS spec does not guarantee that '#' is a supported
character. This commit therefore changes '#' to '.' as the separator
between the class name and method name -- for example:

- org.example.MyListener.myListenerMethod

This commit also introduces tests and documentation for these changes.

See gh-29790
2023-01-30 17:42:00 +01:00
Sam Brannen 67c141f15b Polishing 2023-01-30 15:33:47 +01:00
fml2 ad4e0d9ad7 Improve generated default name for a @JmsListener subscription
Prior to this commit, when using durable subscribers with @JmsListener
methods that do not specify a custom subscription name the generated
default subscription name was always
org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.
Consequently, multiple such @JmsListener methods were assigned the
same subscription name which violates the uniqueness requirement.

To address this, MessagingMessageListenerAdapter now implements
SubscriptionNameProvider and generates the subscription name based on
the following rules.

- if the InvocableHandlerMethod is present, the subscription name will
  take the form of handlerMethod.getBeanType().getName() + "#" +
  handlerMethod.getMethod().getName().
- otherwise, getClass().getName() is used, which is analogous to the
  previous behavior.

Closes gh-29790
2023-01-30 15:19:45 +01:00
Arjen Poutsma c13dfc5144 Merge pull request #29889 from xavier-b:main
* gh-29889:
  Use DataBuffer::toString instead of CharBuffer
2023-01-30 15:03:04 +01:00
xavier-b b7d53ac9a4 Use DataBuffer::toString instead of CharBuffer
This commit ensures that converting DataBuffers to a String does not
use an expensive ByteBuffer allocation.

Closes gh-29889
2023-01-30 14:58:48 +01:00
Arjen Poutsma f9884e08af Polish external contribution 2023-01-30 14:19:41 +01:00
Vatsa 9819cb3eb5 Update HandlerFunctionAdapter::setAsyncRequestTimeout Javadoc
Closes gh-29882
2023-01-30 14:19:41 +01:00
Sam Brannen 9b0929c392 Update copyright headers 2023-01-30 13:00:22 +01:00
Arjen Poutsma af21ebe6c6 Fix CronExpression::parse javadoc
Closes gh-29884
2023-01-30 11:49:34 +01:00
Johnny Lim 0b446a94c5 Add Javadoc since for CLIENT_NAME enums
See gh-29839
Closes gh-29893
2023-01-30 10:10:31 +01:00
Brian Clozel 5dfa61eb0b Restrict "uri" KeyValue for client observations
Prior to this commit, the "uri" KeyValue for low cardinality metadata
would contain the entire uri template given to the HTTP client when
creating the request. This was a breaking change for existing metrics
dashboards, as previous support was removing the protocol, host and port
parts of the URI.
Indeed, this information is available in the "client.name" and
"http.uri" KayValue.

This commit parses and removes the protocol+host+port information from
the uri template for the "uri" KeyValue.

Fixes gh-29885
2023-01-30 10:09:45 +01:00
Brian Clozel b267547fb4 Contribute "uri" KeyValue for "/" client requests
Prior to this commit, client HTTP requests performed by `WebClient`
could miss the "uri" KeyValue for simple "/" requests.
This can happen when the baseUri is configured for the client with a
host and a root base path like "https://example.org/"; given the nature
of the `WebClient` API, in these cases, one can perform requests like
this:

```
WebClient client = WebClient.builder()
    .observationRegistry(registry)
    .baseUrl("https://example.org/")
    .build();

String response = client.get().retrieve().bodyToMono(String.class).block();
```

Such a call would contribute a `"none"` value for the `"uri"` KeyValue.

While only templates should be allowed for this keyvalue, we can assume
that requests to `"/"` should be recorded anyway and won't cause
cardinality explosion.

Fixes gh-29879
2023-01-30 10:09:41 +01:00
Sam Brannen e0f60dc09d Apply "instanceof pattern matching" in spring-context and polishing
See gh-29222
2023-01-29 14:21:15 +01:00
Adam Ostrožlík 8783075e40 Apply "instanceof pattern matching" and minor refactorings in spring-context
Closes gh-29222
2023-01-29 13:52:43 +01:00
Adam Ostrožlík f2cdced501 Apply minor polishing in spring-aop
Closes gh-28984
2023-01-29 13:32:33 +01:00
Sam Brannen 33a0e65135 Fix build due to Jackson Javadoc publication changes
The Jackson project no longer publishes Javadoc at
https://fasterxml.github.io which breaks the `javadoc` and `api` build
tasks due to their dependency on that web site for external Javadoc links.

As a workaround, we now reference Jackson's Javadoc via
https://www.javadoc.io.

See https://github.com/FasterXML/jackson-databind/issues/3440
Closes gh-29894
2023-01-29 12:35:13 +01:00
Sam Brannen e3fb0a39a2 Clean up compiler warnings 2023-01-28 21:18:19 +01:00
Sam Brannen 57fb072215 Include all Hibernate methods in SharedEntityManagerCreator's queryTerminatingMethods
Prior to this commit, we included Hibernate's Query.list() method in
SharedEntityManagerCreator's queryTerminatingMethods set but did not
include all of Hibernate's query-terminating methods.

To address this, this commit additionally includes the stream(),
uniqueResult(), and uniqueResultOptional() methods from Hibernate's
Query API in SharedEntityManagerCreator's query-terminating methods set.

Closes gh-29886
2023-01-28 20:42:21 +01:00
Sam Brannen 75046bbea0 Update copyright headers 2023-01-28 20:42:21 +01:00
Sam Brannen 8e2eeb5364 Apply "instanceof pattern matching" in spring-beans 2023-01-27 17:54:03 +01:00
Sam Brannen 556863d401 Polishing 2023-01-27 17:54:03 +01:00
rstoyanchev 6a6a35a0b9 Support method validation for interface-only proxies
Closes gh-29782
2023-01-27 14:46:22 +00:00
Brian Clozel 7da6e93597 Set WebClient Observation as current in reactor context
Prior to this commit, the `DefaultWebClient` would be instrumented for
client observations and would start/stop a `"http.client.requests"`
observation. This would not set this new observation as the current one
in the Reactor context under `ObservationThreadLocalAccessor.KEY`.
This means that potential child observations would not detect it as
their parent; this can happen if the Reactor Netty `HttpClient`
observation is enabled.

This commit ensures that the reactor context is properly populated for
upstream operators.

Fixes gh-29891
2023-01-27 14:42:08 +01:00
Brian Clozel 963274a915 Polish 2023-01-27 09:52:24 +01:00
Simon Baslé d72df5ace4 DatabaseClient uses SQL Supplier more lazily
This commit modifies the `DefaultDatabaseClient` implementation in order
to ensure lazier usage of the `Supplier<String>` passed to the sql
method (`DatabaseClient#sql(Supplier)`).

Since technically `DatabaseClient` is an interface that could have 3rd
party implementations, the lazyness expectation is only hinted at in the
`DatabaseClient#sql` javadoc.

Possible caveat: some log statements attempt to reflect the now lazily
resolved SQL string. Similarly, some exceptions can capture the SQL that
caused the issue if known. We expect that these always occur after the
execution of the statement has been attempted (see `ResultFunction`).
At this point the SQL string will be accessible and logs and exceptions
should reflect it as before. Keep an eye out for such strings turning
into `null` after this change, which would indicate the opposite.

Closes gh-29367
2023-01-26 14:35:31 +01:00
Brian Clozel 767f59a3ae Make client.name low cardinality keyvalue for client observations
Prior to this commit, the `"client.name"` key value for the
`"http.client.requests"` client HTTP observations would be considered as
high cardinality, as the URI host is technically unbounded.
In practice, the number of hosts used by a client in a given application
can be considered as low cardinality. This commit moves this keyvalue to
low cardinality so that it's present for both metrics and traces.

Closes gh-29839
2023-01-25 20:51:15 +01:00
Sam Brannen da088e58c3 Increase number of TOC levels to 4 in generated PDF documentation
Closes gh-29781
2023-01-24 15:31:14 +01:00
Arjen Poutsma 5502e61519 Support Optional in AbstractJackson2HttpMessageConverter
This commit introduces support for Optional in the
AbstractJackson2HttpMessageConverter, similar the existing support for
collection types were supported.

Closes gh-24498
2023-01-24 13:08:21 +01:00
Sébastien Deleuze ab9bea1d93 Polish RouterFunctionDsl KDoc 2023-01-23 13:28:10 +01:00
Sébastien Deleuze e6397c8a38 Infer reflection hints for Jackson annotation class attributes
Closes gh-29646
Closes gh-29386
2023-01-23 13:21:34 +01:00
Sébastien Deleuze 1e47f31210 Support code generation for Set with non-comparable elements
Closes gh-29792
2023-01-23 10:55:34 +01:00
Sébastien Deleuze 57b6f7e494 Infer hints for custom constraint validators
This commit introduces a BeanValidationBeanRegistrationAotProcessor
which adds reflection hints for custom ConstraintValidator discovered
on beans constructors, methods and properties.

Closes gh-29823
2023-01-23 10:15:58 +01:00
Brian Clozel d37ef61b30 Resolve static resources without wildcard pattern
Prior to this commit, the reactive `ResourceWebHandler` would only look
at the path within the current mapping when resolving static resources
to be served. This means that when registering a handler at
`"/resources/**"` with a `"classpath:/static/"` location, the handler
would process a `"GET /resources/file.txt"` as the `"/static/file.txt"`
classpath location.

When a developer registers a fixed pattern like `"/resources/file.txt"`
with the same location, the path within the handler mapping is empty as
there is no dynamic part in the given pattern. While the typical use
case for this feature is to register multiple resources at once with a
pattern, we should support a single registration like this.

This commit ensures that if the matching `PathPattern` for the current
request does not have a pattern syntax (i.e. no regexp, no wildcard), we
can use it to match the resource directly. Otherwise, we can use the
path within the handler mapping to resolve the resource as before.

Closes gh-29739
2023-01-20 17:15:52 +01:00
Sam Brannen 3f148c2aaa Avoid warnings / Polishing 2023-01-20 15:22:47 +01:00
Sam Brannen fa1ef1dc85 Deprecate obsolete ConcurrentExecutorAdapter for removal in 6.1
Closes gh-29865
2023-01-20 14:20:18 +01:00
Sam Brannen 58872c79ee Update copyright headers 2023-01-20 14:17:53 +01:00
Sam Brannen 24f18275dd Stop referring to "Spring 3.x" features in documentation and code 2023-01-20 14:13:18 +01:00
Sébastien Deleuze 8f94c4e933 Remove WebClientIntegrationTests#exchangeWithRelativeUrl outdated test
This test can fail when a web server runs on port 80 and
is not relevant anymore due to the removal of related feature
via 6e936a4081.

Closes gh-28902
2023-01-20 13:59:39 +01:00
Arjen Poutsma 20c79e1481 Support double-quoted in HttpHeaders::getValuesAsList
This commit introduces support for double-quoted HTTP header values in
HttpHeaders::getValuesAsList, as described in RFC 9110 section 5.5.

Closes gh-29785
2023-01-20 13:42:51 +01:00
Sébastien Deleuze fb0aa5abb3 Fix WebClientIntegrationTests flaky Jetty tests
Ensure the port used by the client in malformedResponseChunksOnBodilessEntity
and malformedResponseChunksOnEntityWithBody has correctly been set.

Closes gh-29862
2023-01-20 11:38:22 +01:00
Sam Brannen 86a40716bd Polishing 2023-01-20 10:28:25 +01:00
Sam Brannen 7f48d1b55a Remove obsolete Tiles documentation from Javadoc
See gh-29852
2023-01-20 10:27:48 +01:00
Sébastien Deleuze fd84b0997a Refine Jackson2ObjectMapperBuilder#configureFeature exception handling
This commit changes the FatalBeanException previously thrown for
an IllegalArgumentException which seems more suitable for that
use case.

Closes gh-29859
2023-01-20 10:17:17 +01:00
Juergen Hoeller 0e8838db90 Flexible constructor resolution in AutowireCapableBeanFactory.createBean(Class)
Closes gh-29855
See gh-29823
2023-01-19 17:10:42 +01:00
Sébastien Deleuze 94fc24b6fb Document that bean instance suppliers are not supported with AOT/native
Closes gh-29835
2023-01-19 16:45:52 +01:00
Sébastien Deleuze ab0d1c395d Fail explicitly in AOT transformations of instance supplier
It is by design not possible to generate code that handles
bean definitions with user-provided instance suppliers because
the JVM does not allow to get a stable reference reusable at
runtime on the lambda or method reference in the code generated
AOT.

Before this commit, such instance supplier was ignored.
After this commit, an IllegalArgumentException is thrown,
allowing projects to be aware this is not supported and enforce
related refactorings.

The related issue gh-29555 describes how this limitation could
be relaxed in the future.

Closes gh-29556
2023-01-19 16:45:52 +01:00
Sam Brannen 047f660572 Remove obsolete Tiles documentation from reference manual
Tiles support was officially removed in conjunction with gh-27423.

Closes gh-29852
2023-01-19 16:43:51 +01:00
Sam Brannen 22323072fd Polishing 2023-01-19 16:32:29 +01:00
Thom Hurks a34b1af49e Remove extra empty line in DefaultCorsProcessor (#29854) 2023-01-19 16:28:18 +01:00
Sam Brannen 1ace42f245 Enable JRubyScriptTemplateTests 2023-01-19 16:20:03 +01:00
Sam Brannen 0502d18e3d Update copyright headers 2023-01-19 16:20:03 +01:00
Sam Brannen c4c786596f Migrate to Mockito.mock(T...) where feasible 2023-01-19 16:20:02 +01:00
Sam Brannen c3d123fef7 Allow @Aspect classes to extend concrete @Aspect classes
Closes gh-29830
2023-01-19 14:35:27 +01:00
Sam Brannen e4b25ab480 Polishing 2023-01-19 14:35:27 +01:00
Arjen Poutsma 1680502313 Updated Java 17 version in sdkmanrc 2023-01-19 10:03:18 +01:00
Brian Clozel e725e3a51b Update Java versions and remove Java 18 build 2023-01-19 09:40:25 +01:00
Johnny Lim 2fe75c1a24 Polish HttpStatus 103 EARLY_HINTS javadocs (#29841)
This commit polishes the EARLY_HINTS javadocs a bit:
 - fix a typo
 - fix `since` tags to include the patch version

See gh-29816
2023-01-18 14:50:02 +01:00
Arjen Poutsma 9ebd1e8d64 Fix IllegalStateException in empty ProducesRequestCondition
When comparing empty ProducesRequestCondition, compareTo would throw an
IllegalStateException if the Accept header was invalid. This commit
fixes that behavior.

Closes gh-29794
2023-01-18 10:38:09 +01:00
Sam Brannen 64de6de725 Update copyright headers 2023-01-17 15:49:26 +01:00
Sam Brannen c3e8ff9ce7 Do not use Mockito to mock ReactiveAdapterRegistry 2023-01-17 15:44:57 +01:00
Brian Clozel 5448e81021 Deprecate Base64Utils in favor of Java's Base64
Originally, `Base64Utils` was providing base64 encoding and decoding
utilities, bridging to commons-codecs or Java 8, if available. Since
then, only the Java 8 variant remains and Spring Framework 6 requires
now Java 17. This utility class doesn't provide additional checks or
syntactic sugar over what's in Java already.

As a result, this commit deprecates this class in favor of `Base64` and
schedules the removal of this class completely.

Closes gh-28434
2023-01-17 15:30:45 +01:00
j3graham f7e07322ab Simplify Base64Utils by using java.util.Base64
This commit simplifies the `Base64Utils` implementation by relying more
on the `Base64` methods that perform similar work.

See gh-28434
2023-01-17 15:29:58 +01:00
정준영 37217a63e1 Remove unnecessary calls to Reference::clear
Prior to this commit, `ConcurrentReferenceHashMap` subclasses extending
`Reference` would call `Reference::clear` right next to
`Reference::enqueue`; this is not needed as the latter calls it already.

Closes gh-28863
2023-01-17 14:44:39 +01:00
Sam Brannen ad5c636aff Upgrade to Mockito 5.0 2023-01-17 14:31:11 +01:00
Brian Clozel ebdc82b86b Add serialization hint for ProblemDetail
Prior to this commit, a Spring web application would not be able to
serialize a `ProblemDetail` object instance in a Native Image, as
serialization hints would be missing.

This commit adds a RuntimeHints registrar that processes the
`ProblemDetail` type accordingly during the AOT phase.

Fixes gh-29801
2023-01-17 10:59:52 +01:00
Sam Brannen a12c9a0430 Update copyright headers 2023-01-16 19:24:30 +01:00
Sam Brannen 0d14c3bc1a Polish Javadoc in spring-jms 2023-01-16 19:24:30 +01:00
Sam Brannen 8be542016b Apply "instanceof pattern matching" in spring-jms 2023-01-16 19:24:30 +01:00
Arjen Poutsma 3a585f8c29 Introduce CoWebFilter
This commit introduces the CoWebFilter, an abstract WebFilter
implementation that allows for coroutine usage.

Closes gh-29672
2023-01-16 15:45:08 +01:00
Minsoo Cheong(Merlin) c0e38a2f1e Fix R2dbcTransactionManager debug log: don't log a Mono (#29800)
When logging the current connection inside R2dbcTransactionManager
doBegin, the mono object was logged instead of the connection lambda
parameter.

Other similar debug-level logs do use the actual Connection object,
so this commit does the same.
2023-01-16 11:29:43 +01:00
Simon Baslé 5de1460f88 Deprecate HttpStatus 103 CHECKPOINT in favor of new EARLY_HINTS (#29816)
This commit takes rfc8297 into account and introduces a newer code 103
HttpStatus value which uses `Early Hints` as the more correct reason
phrase, deprecating the outdated `CHECKPOINT` enum value for 103.

Additionally:
  - `HttpStatus.valueOf(103)` will return the new enum value
  - `HttpStatusCode#isSameCodeAs(HttpStatusCode)` is introduced to ease
  comparison of deprecated enums vs their newer counterparts (or any
  instance of a more generic `HttpStatusCode`) by comparing the integer
  `value()`
  - `HttpStatusTests` covers the new deprecation as well as the three
  previously deprecated codes, including a check with the above new
  method to ensure they have comparable integer values

Supersedes and Closes gh-27960
2023-01-16 11:22:43 +01:00
rstoyanchev 312db36849 Combined, empty RequestMapping matches both "" and "/"
Closes gh-29625
2023-01-13 14:58:11 +00:00
Sam Brannen 46875c91ce Update copyright year in reference manual 2023-01-11 17:32:31 +01:00
Sam Brannen 86305c45a9 Upgrade to spring-asciidoctor-backends 0.0.4 2023-01-11 17:30:02 +01:00
Sam Brannen 1342837686 Upgrade to nohttp 0.0.11 2023-01-11 17:26:35 +01:00
Sam Brannen 012b8f18c6 Add Simon to mailmap 2023-01-11 15:26:31 +01:00
Brian Clozel 5ea310452c Add Simon to the Changelog generator configuration
This prevents Simon from being listed as an external contributor.
2023-01-11 14:12:03 +01:00
Sam Brannen a4956dfe26 Update copyright headers 2023-01-11 13:52:20 +01:00
Sam Brannen 0415975dd1 Polish contribution and related code 2023-01-11 13:52:20 +01:00
Krzysztof Krason afb8a0d1b1 Use new Java features (switch expressions, text blocks, new JDK methods)
Closes gh-29747
2023-01-11 13:51:28 +01:00
Spring Builds 48abd493fe Next development version (v6.0.5-SNAPSHOT) 2023-01-11 12:25:34 +00:00
2958 changed files with 118349 additions and 91814 deletions
@@ -0,0 +1,20 @@
name: Await HTTP Resource
description: Waits for an HTTP resource to be available (a HEAD request succeeds)
inputs:
url:
description: 'The URL of the resource to await'
required: true
runs:
using: composite
steps:
- name: Await HTTP resource
shell: bash
run: |
url=${{ inputs.url }}
echo "Waiting for $url"
until curl --fail --head --silent ${{ inputs.url }} > /dev/null
do
echo "."
sleep 60
done
echo "$url is available"
+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-early-access:
required: false
default: 'false'
description: 'Whether the Java version is in early access'
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-early-access: ${{ inputs.java-early-access }}
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
@@ -17,4 +17,12 @@ changelog:
- "type: dependency-upgrade"
contributors:
exclude:
names: ["bclozel", "jhoeller", "poutsma", "rstoyanchev", "sbrannen", "sdeleuze", "snicoll"]
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-early-access:
required: false
default: 'false'
description: 'Whether the Java version is in early access'
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-early-access == 'true' && 'temurin' || 'liberica' }}
java-version: |
${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '17' || '' }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
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,43 @@
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@105617d23456a69a92485207c4f28ae12297581d # v4.2.1
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
uses: ./.github/actions/await-http-resource
with:
url: ${{ format('https://repo.maven.apache.org/maven2/org/springframework/spring-context/{0}/spring-context-{0}.jar', inputs.spring-framework-version) }}
@@ -0,0 +1,20 @@
{
"files": [
{
"aql": {
"items.find": {
"$and": [
{
"@build.name": "${buildName}",
"@build.number": "${buildNumber}",
"path": {
"$nmatch": "org/springframework/framework-docs/*"
}
}
]
}
},
"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.0.x
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-deploy-snapshot:
name: Build and Deploy Snapshot
runs-on: ubuntu-latest
timeout-minutes: 60
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.0.x'
repository: 'libs-snapshot-local'
folder: 'deployment-repository'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
artifact-properties: |
/**/framework-docs-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-docs-*-docs.zip::zip.type=docs
/**/framework-docs-*-dist.zip::zip.type=dist
/**/framework-docs-*-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 }}
+53
View File
@@ -0,0 +1,53 @@
name: CI
on:
push:
branches:
- 6.0.x
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
ci:
name: '${{ matrix.os.name}} | Java ${{ matrix.java.version}}'
runs-on: ${{ matrix.os.id }}
timeout-minutes: 60
if: ${{ github.repository == 'spring-projects/spring-framework' }}
strategy:
matrix:
os:
- id: ubuntu-latest
name: Linux
java:
- version: 17
toolchain: false
- version: 21
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-early-access: ${{ matrix.java.early-access || 'false' }}
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) }}
+34
View File
@@ -0,0 +1,34 @@
name: Deploy Docs
on:
push:
branches:
- 'main'
- '*.x'
- '!gh-pages'
tags:
- 'v*'
repository_dispatch:
types: request-build-reference # legacy
workflow_dispatch:
permissions:
actions: write
jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: docs-build
fetch-depth: 1
- name: Dispatch (partial build)
if: github.ref_type == 'branch'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
- name: Dispatch (full build)
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
@@ -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
+95
View File
@@ -0,0 +1,95 @@
name: Release
on:
push:
tags:
- v6.0.[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:
uri: 'https://repo.spring.io'
username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
build-name: ${{ format('spring-framework-{0}', steps.build-and-publish.outputs.version)}}
repository: 'libs-staging-local'
folder: 'deployment-repository'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
artifact-properties: |
/**/framework-docs-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-docs-*-docs.zip::zip.type=docs
/**/framework-docs-*-dist.zip::zip.type=dist
/**/framework-docs-*-schema.zip::zip.type=schema
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@105617d23456a69a92485207c4f28ae12297581d # v4.2.1
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@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
+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@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
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) }}
+6 -3
View File
@@ -21,15 +21,14 @@ derby.log
/build
buildSrc/build
/spring-*/build
/framework-bom/build
/framework-docs/build
/framework-*/build
/integration-tests/build
/src/asciidoc/build
spring-test/test-output/
# Maven artifacts
pom.xml
target/
/target/
# Eclipse artifacts, including WTP generated manifests
bin
@@ -50,3 +49,7 @@ atlassian-ide-plugin.xml
# VS Code
.vscode/
cached-antora-playbook.yml
node_modules
-34
View File
@@ -1,34 +0,0 @@
Juergen Hoeller <jhoeller@vmware.com>
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@pivotal.io>
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@gopivotal.com>
Rossen Stoyanchev <rstoyanchev@vmware.com>
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@pivotal.io>
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@gopivotal.com>
Phillip Webb <pwebb@vmware.com>
Phillip Webb <pwebb@vmware.com> <pwebb@pivotal.io>
Phillip Webb <pwebb@vmware.com> <pwebb@gopivotal.com>
Chris Beams <cbeams@vmware.com>
Chris Beams <cbeams@vmware.com> <cbeams@pivotal.io>
Chris Beams <cbeams@vmware.com> <cbeams@gopivotal.com>
Arjen Poutsma <poutsmaa@vmware.com>
Arjen Poutsma <poutsmaa@vmware.com> <apoutsma@pivotal.io>
Arjen Poutsma <poutsmaa@vmware.com> <apoutsma@gopivotal.com>
Arjen Poutsma <poutsmaa@vmware.com> <poutsma@mac.com>
Arjen Poutsma <poutsmaa@vmware.com> <apoutsma@vmware.com>
Oliver Drotbohm <odrotbohm@vmware.com>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@vmware.com>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@pivotal.io>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@gopivotal.com>
Dave Syer <dsyer@vmware.com>
Dave Syer <dsyer@vmware.com> <dsyer@pivotal.io>
Dave Syer <dsyer@vmware.com> <dsyer@gopivotal.com>
Dave Syer <dsyer@vmware.com> <david_syer@hotmail.com>
Andy Clement <aclement@vmware.com>
Andy Clement <aclement@vmware.com> <aclement@pivotal.io>
Andy Clement <aclement@vmware.com> <aclement@gopivotal.com>
Andy Clement <aclement@vmware.com> <andrew.clement@gmail.com>
Sam Brannen <sbrannen@vmware.com>
Sam Brannen <sbrannen@vmware.com> <sbrannen@pivotal.io>
Sam Brannen <sbrannen@vmware.com> <sam@sambrannen.com>
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
Nick Williams <nicholas@nicholaswilliams.net>
+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.5-librca
java=17.0.11-librca
+1 -1
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-5.3.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build") [![Revved up by Gradle Enterprise](https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-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.0.x)](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3A6.0.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".
+5
View File
@@ -1,5 +1,10 @@
# Security Policy
## JAR signing
Spring Framework JARs released on Maven Central are signed.
You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt
## Supported Versions
Please see the
+23 -33
View File
@@ -1,16 +1,14 @@
plugins {
id 'io.spring.nohttp' version '0.0.10'
id 'io.freefair.aspectj' version '6.5.0.3' apply false
id 'io.spring.nohttp' version '0.0.11'
id 'io.freefair.aspectj' version '8.0.1' apply false
// kotlinVersion is managed in gradle.properties
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka' version '1.7.20'
id 'org.asciidoctor.jvm.convert' version '3.3.2' apply false
id 'org.asciidoctor.jvm.pdf' version '3.3.2' apply false
id 'org.jetbrains.dokka' version '1.8.20'
id 'org.unbroken-dome.xjc' version '2.0.0' apply false
id 'com.github.ben-manes.versions' version '0.42.0'
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
id 'de.undercouch.download' version '5.1.0'
id 'me.champeau.jmh' version '0.6.8' apply false
id 'com.github.ben-manes.versions' version '0.51.0'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
id 'de.undercouch.download' version '5.4.0'
id 'me.champeau.jmh' version '0.7.2' apply false
}
ext {
@@ -28,7 +26,6 @@ configure(allprojects) { project ->
includeGroup 'io.projectreactor.netty'
}
}
maven { url "https://repo.spring.io/libs-spring-framework-build" }
if (version.contains('-')) {
maven { url "https://repo.spring.io/milestone" }
}
@@ -78,7 +75,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.6.0"
toolVersion = "10.12.7"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -105,42 +102,35 @@ configure([rootProject] + javaProjects) { project ->
testRuntimeOnly("org.junit.platform:junit-platform-suite-engine")
testRuntimeOnly("org.apache.logging.log4j:log4j-core")
testRuntimeOnly("org.apache.logging.log4j:log4j-jul")
testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j-impl")
testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl")
// JSR-305 only used for non-required meta-annotations
compileOnly("com.google.code.findbugs:jsr305")
testCompileOnly("com.google.code.findbugs:jsr305")
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.31")
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.42")
}
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
"https://www.ibm.com/docs/api/v1/content/SSEQTP_8.5.5/com.ibm.websphere.javadoc.doc/web/apidocs/",
"https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"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/",
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.14.1/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.14.1/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/2.14.1/",
"https://hc.apache.org/httpcomponents-client-5.2.x/current/httpclient5/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
// TODO Uncomment link to JUnit 5 docs once we have sorted out
// the following warning in the build.
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
// See https://github.com/spring-projects/spring-framework/issues/27497
//
// warning: The code being documented uses packages in the unnamed module, but the packages defined in https://junit.org/junit5/docs/5.9.2/api/ are in named modules.
//
// "https://junit.org/junit5/docs/5.9.2/api/",
// "https://junit.org/junit5/docs/5.9.3/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/",
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
// The external Javadoc link for JSR 305 must come last to ensure that types from
// JSR 250 (such as @PostConstruct) are still supported. This is due to the fact
// that JSR 250 and JSR 305 both define types in javax.annotation, which results
// in a split package, and the javadoc tool does not support split packages
// across multiple external Javadoc sites.
// Previously there could be a split-package issue between JSR250 and JSR305 javax.annotation packages,
// but since 6.0 JSR 250 annotations such as @Resource and @PostConstruct have been replaced by their
// JakartaEE equivalents in the jakarta.annotation package.
"https://www.javadoc.io/doc/com.google.code.findbugs/jsr305/3.0.2/"
] as String[]
}
@@ -153,15 +143,15 @@ configure(rootProject) {
description = "Spring Framework"
apply plugin: "io.spring.nohttp"
apply plugin: 'org.springframework.build.api-diff'
nohttp {
source.exclude "**/test-output/**"
source.exclude "**/.gradle/**"
allowlistFile = project.file("src/nohttp/allowlist.lines")
def rootPath = file(rootDir).toPath()
def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/buildSrc"
projectDirs.forEach { dir ->
[ 'bin', 'build', 'out', '.settings' ]
[ 'bin', 'build', 'out', '.settings', 'node_modules' ]
.collect { rootPath.relativize(new File(dir, it).toPath()) }
.forEach { source.exclude "$it/**" }
[ '.classpath', '.project' ]
-15
View File
@@ -22,21 +22,6 @@ but doesn't affect the classpath of dependent projects.
This plugin does not provide a `provided` configuration, as the native `compileOnly` and `testCompileOnly`
configurations are preferred.
### API Diff
This plugin uses the [Gradle JApiCmp](https://github.com/melix/japicmp-gradle-plugin) plugin
to generate API Diff reports for each Spring Framework module. This plugin is applied once on the root
project and creates tasks in each framework module. Unlike previous versions of this part of the build,
there is no need for checking out a specific tag. The plugin will fetch the JARs we want to compare the
current working version with. You can generate the reports for all modules or a single module:
```
./gradlew apiDiff -PbaselineVersion=5.1.0.RELEASE
./gradlew :spring-core:apiDiff -PbaselineVersion=5.1.0.RELEASE
```
The reports are located under `build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/`.
### RuntimeHints Java Agent
+1 -6
View File
@@ -19,16 +19,11 @@ ext {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:${kotlinVersion}")
implementation "me.champeau.gradle:japicmp-gradle-plugin:0.3.0"
implementation "org.gradle:test-retry-gradle-plugin:1.4.1"
implementation "org.gradle:test-retry-gradle-plugin:1.5.6"
}
gradlePlugin {
plugins {
apiDiffPlugin {
id = "org.springframework.build.api-diff"
implementationClass = "org.springframework.build.api.ApiDiffPlugin"
}
conventionsPlugin {
id = "org.springframework.build.conventions"
implementationClass = "org.springframework.build.ConventionsPlugin"
@@ -26,8 +26,8 @@ import org.gradle.testretry.TestRetryTaskExtension;
* Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the
* plugin is applied:
* <ul>
* <li>The {@link TestRetryPlugin Test Retry} plugins is applied so that flaky tests
* are retried 3 times when running on the CI.
* <li>The {@link TestRetryPlugin Test Retry} plugin is applied so that flaky tests
* are retried 3 times when running on the CI server.
* </ul>
*
* @author Brian Clozel
@@ -41,7 +41,7 @@ class TestConventions {
private void configureTestConventions(Project project) {
project.getTasks().withType(Test.class,
(test) -> project.getPlugins().withType(TestRetryPlugin.class, (testRetryPlugin) -> {
test -> project.getPlugins().withType(TestRetryPlugin.class, testRetryPlugin -> {
TestRetryTaskExtension testRetry = test.getExtensions().getByType(TestRetryTaskExtension.class);
testRetry.getFailOnPassedAfterRetry().set(true);
testRetry.getMaxRetries().set(isCi() ? 3 : 0);
@@ -1,140 +0,0 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.build.api;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import me.champeau.gradle.japicmp.JapicmpPlugin;
import me.champeau.gradle.japicmp.JapicmpTask;
import org.gradle.api.GradleException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.jvm.tasks.Jar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link Plugin} that applies the {@code "japicmp-gradle-plugin"}
* and create tasks for all subprojects named {@code "spring-*"}, diffing the public API one by one
* and creating the reports in {@code "build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/"}.
* <p>{@code "./gradlew apiDiff -PbaselineVersion=5.1.0.RELEASE"} will output the
* reports for the API diff between the baseline version and the current one for all modules.
* You can limit the report to a single module with
* {@code "./gradlew :spring-core:apiDiff -PbaselineVersion=5.1.0.RELEASE"}.
*
* @author Brian Clozel
*/
public class ApiDiffPlugin implements Plugin<Project> {
private static final Logger logger = LoggerFactory.getLogger(ApiDiffPlugin.class);
public static final String TASK_NAME = "apiDiff";
private static final String BASELINE_VERSION_PROPERTY = "baselineVersion";
private static final List<String> PACKAGE_INCLUDES = Collections.singletonList("org.springframework.*");
private static final URI SPRING_MILESTONE_REPOSITORY = URI.create("https://repo.spring.io/milestone");
@Override
public void apply(Project project) {
if (project.hasProperty(BASELINE_VERSION_PROPERTY) && project.equals(project.getRootProject())) {
project.getPluginManager().apply(JapicmpPlugin.class);
project.getPlugins().withType(JapicmpPlugin.class,
plugin -> applyApiDiffConventions(project));
}
}
private void applyApiDiffConventions(Project project) {
String baselineVersion = project.property(BASELINE_VERSION_PROPERTY).toString();
project.subprojects(subProject -> {
if (subProject.getName().startsWith("spring-")) {
createApiDiffTask(baselineVersion, subProject);
}
});
}
private void createApiDiffTask(String baselineVersion, Project project) {
if (isProjectEligible(project)) {
// Add Spring Milestone repository for generating diffs against previous milestones
project.getRootProject()
.getRepositories()
.maven(mavenArtifactRepository -> mavenArtifactRepository.setUrl(SPRING_MILESTONE_REPOSITORY));
JapicmpTask apiDiff = project.getTasks().create(TASK_NAME, JapicmpTask.class);
apiDiff.setDescription("Generates an API diff report with japicmp");
apiDiff.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP);
apiDiff.setOldClasspath(createBaselineConfiguration(baselineVersion, project));
TaskProvider<Jar> jar = project.getTasks().withType(Jar.class).named("jar");
apiDiff.setNewArchives(project.getLayout().files(jar.get().getArchiveFile().get().getAsFile()));
apiDiff.setNewClasspath(getRuntimeClassPath(project));
apiDiff.setPackageIncludes(PACKAGE_INCLUDES);
apiDiff.setOnlyModified(true);
apiDiff.setIgnoreMissingClasses(true);
// Ignore Kotlin metadata annotations since they contain
// illegal HTML characters and fail the report generation
apiDiff.setAnnotationExcludes(Collections.singletonList("@kotlin.Metadata"));
apiDiff.setHtmlOutputFile(getOutputFile(baselineVersion, project));
apiDiff.dependsOn(project.getTasks().getByName("jar"));
}
}
private boolean isProjectEligible(Project project) {
return project.getPlugins().hasPlugin(JavaPlugin.class)
&& project.getPlugins().hasPlugin(MavenPublishPlugin.class);
}
private Configuration createBaselineConfiguration(String baselineVersion, Project project) {
String baseline = String.join(":",
project.getGroup().toString(), project.getName(), baselineVersion);
Dependency baselineDependency = project.getDependencies().create(baseline + "@jar");
Configuration baselineConfiguration = project.getRootProject().getConfigurations().detachedConfiguration(baselineDependency);
try {
// eagerly resolve the baseline configuration to check whether this is a new Spring module
baselineConfiguration.resolve();
return baselineConfiguration;
}
catch (GradleException exception) {
logger.warn("Could not resolve {} - assuming this is a new Spring module.", baseline);
}
return project.getRootProject().getConfigurations().detachedConfiguration();
}
private Configuration getRuntimeClassPath(Project project) {
return project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
}
private File getOutputFile(String baseLineVersion, Project project) {
Path outDir = Paths.get(project.getRootProject().getBuildDir().getAbsolutePath(),
"reports", "api-diff",
baseLineVersion + "_to_" + project.getRootProject().getVersion());
return project.file(outDir.resolve(project.getName() + ".html").toString());
}
}
-57
View File
@@ -1,57 +0,0 @@
== Spring Framework Concourse pipeline
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.0.x[Spring Framework 6.0.x].
=== Setting up your development environment
If you're part of the Spring Framework project on GitHub, you can get access to CI management features.
First, you need to go to https://ci.spring.io and install the client CLI for your platform (see bottom right of the screen).
You can then login with the instance using:
[source]
----
$ fly -t spring login -n spring-framework -c https://ci.spring.io
----
Once logged in, you should get something like:
[source]
----
$ fly ts
name url team expiry
spring https://ci.spring.io spring-framework Wed, 25 Mar 2020 17:45:26 UTC
----
=== Pipeline configuration and structure
The build pipelines are described in `pipeline.yml` file.
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
You'll find in this folder the following resources:
* `pipeline.yml` the build pipeline
* `parameters.yml` the build parameters used for the pipeline
* `images/` holds the container images definitions used in this pipeline
* `scripts/` holds the build scripts that ship within the CI container images
* `tasks` contains the task definitions used in the main `pipeline.yml`
=== Updating the build pipeline
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
The pipeline can be deployed using the following command:
[source]
----
$ fly -t spring set-pipeline -p spring-framework-6.0.x -c ci/pipeline.yml -l ci/parameters.yml
----
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
-10
View File
@@ -1,10 +0,0 @@
logging:
level:
io.spring.concourse: DEBUG
spring:
main:
banner-mode: off
sonatype:
exclude:
- 'build-info\.json'
- '.*\.zip'
-21
View File
@@ -1,21 +0,0 @@
== CI Images
These images are used by CI to run the actual builds.
To build the image locally run the following from this directory:
----
$ docker build --no-cache -f <image-folder>/Dockerfile .
----
For example
----
$ docker build --no-cache -f spring-framework-ci-image/Dockerfile .
----
To test run:
----
$ docker run -it --entrypoint /bin/bash <SHA>
----
-12
View File
@@ -1,12 +0,0 @@
FROM ubuntu:focal-20220922
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh
ENV JAVA_HOME /opt/openjdk/java17
ENV JDK17 /opt/openjdk/java17
ENV JDK18 /opt/openjdk/java18
ENV JDK19 /opt/openjdk/java19
ENV PATH $JAVA_HOME/bin:$PATH
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
set -e
case "$1" in
java17)
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.5+8/bellsoft-jdk17.0.5+8-linux-amd64.tar.gz"
;;
java18)
echo "https://github.com/bell-sw/Liberica/releases/download/18.0.2.1%2B1/bellsoft-jdk18.0.2.1+1-linux-amd64.tar.gz"
;;
java19)
echo "https://github.com/bell-sw/Liberica/releases/download/19.0.1%2B11/bellsoft-jdk19.0.1+11-linux-amd64.tar.gz"
;;
*)
echo $"Unknown java version"
exit 1
esac
-40
View File
@@ -1,40 +0,0 @@
#!/bin/bash
set -ex
###########################################################
# UTILS
###########################################################
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
dpkg-reconfigure --frontend noninteractive tzdata
rm -rf /var/lib/apt/lists/*
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
###########################################################
# JAVA
###########################################################
mkdir -p /opt/openjdk
pushd /opt/openjdk > /dev/null
for jdk in java17 java18 java19
do
JDK_URL=$( /get-jdk-url.sh $jdk )
mkdir $jdk
pushd $jdk > /dev/null
curl -L ${JDK_URL} | tar zx --strip-components=1
test -f bin/java
test -f bin/javac
popd > /dev/null
done
popd
###########################################################
# GRADLE ENTERPRISE
###########################################################
cd /
mkdir ~/.gradle
echo 'systemProp.user.name=concourse' > ~/.gradle/gradle.properties
-14
View File
@@ -1,14 +0,0 @@
github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
sonatype-staging-profile: "org.springframework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "main"
milestone: "6.0.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
registry-mirror-host: docker.repo.spring.io
registry-mirror-username: ((artifactory-username))
registry-mirror-password: ((artifactory-password))
task-timeout: 1h00m
-480
View File
@@ -1,480 +0,0 @@
anchors:
git-repo-resource-source: &git-repo-resource-source
uri: ((github-repo))
username: ((github-username))
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))
sonatype-task-params: &sonatype-task-params
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE: ((sonatype-staging-profile))
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
build-project-task-params: &build-project-task-params
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
registry-mirror-vars: &registry-mirror-vars
registry-mirror-host: ((registry-mirror-host))
registry-mirror-username: ((registry-mirror-username))
registry-mirror-password: ((registry-mirror-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
body: generated-changelog/changelog.md
github-task-params: &github-task-params
GITHUB_USERNAME: ((github-username))
GITHUB_TOKEN: ((github-ci-release-token))
resource_types:
- name: registry-image
type: registry-image
source:
repository: concourse/registry-image-resource
tag: 1.5.0
- name: artifactory-resource
type: registry-image
source:
repository: springio/artifactory-resource
tag: 0.0.17
- name: github-release
type: registry-image
source:
repository: concourse/github-release-resource
tag: 1.5.5
- name: github-status-resource
type: registry-image
source:
repository: dpb587/github-status-resource
tag: master
- name: pull-request
type: registry-image
source:
repository: teliaoss/github-pr-resource
tag: v0.23.0
- name: slack-notification
type: registry-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
- name: git-repo
type: git
icon: github
source:
<<: *git-repo-resource-source
- name: ci-images-git-repo
type: git
icon: github
source:
uri: ((github-repo))
branch: ((branch))
paths: ["ci/images/*"]
- name: ci-image
type: registry-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
- 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
source:
uri: ((artifactory-server))
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: git-pull-request
type: pull-request
icon: source-pull
source:
access_token: ((github-ci-pull-request-token))
repository: ((github-repo-name))
base_branch: ((branch))
ignore_paths: ["ci/*"]
- 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-jdk18-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk18-build
- name: repo-status-jdk19-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk19-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
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: true
release: false
- name: github-release
type: github-release
icon: briefcase-download
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: false
jobs:
- name: build-ci-images
plan:
- get: git-repo
- get: ci-images-git-repo
trigger: true
- task: build-ci-image
privileged: true
file: git-repo/ci/tasks/build-ci-image.yml
output_mapping:
image: ci-image
vars:
ci-image-name: ci-image
<<: *registry-mirror-vars
- 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-docs-*.zip"
properties:
"zip.name": "spring-framework"
"zip.displayname": "Spring Framework"
"zip.deployed": "false"
- include:
- "/**/framework-docs-*-docs.zip"
properties:
"zip.type": "docs"
- include:
- "/**/framework-docs-*-dist.zip"
properties:
"zip.type": "dist"
- include:
- "/**/framework-docs-*-schema.zip"
properties:
"zip.type": "schema"
get_params:
threads: 8
- name: jdk18-build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk18-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: 18
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk18-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk18-build
params: { state: "success", commit: "git-repo" }
- name: jdk19-build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk19-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: 19
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk19-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk19-build
params: { state: "success", commit: "git-repo" }
- name: build-pull-requests
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
resource: git-pull-request
trigger: true
version: every
- do:
- put: git-pull-request
params:
path: git-repo
status: pending
- task: build-pr
image: ci-image
file: git-repo/ci/tasks/build-pr.yml
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
on_success:
put: git-pull-request
params:
path: git-repo
status: success
on_failure:
put: git-pull-request
params:
path: git-repo
status: failure
- name: stage-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: M
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-milestone]
params:
download_artifacts: false
save_build_info: true
- task: promote
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: M
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: M
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RC
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-rc]
params:
download_artifacts: false
save_build_info: true
- task: promote
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RC
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RC
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-release]
params:
download_artifacts: true
save_build_info: true
- task: promote
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *artifactory-task-params
<<: *sonatype-task-params
- name: create-github-release
serial: true
plan:
- get: ci-image
- get: git-repo
- get: artifactory-repo
trigger: true
passed: [promote-release]
params:
download_artifacts: false
save_build_info: true
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RELEASE
<<: *github-task-params
- put: github-release
params:
<<: *changelog-task-params
groups:
- name: "builds"
jobs: ["build", "jdk18-build", "jdk19-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
- name: "pull-requests"
jobs: [ "build-pull-requests" ]
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
popd > /dev/null
-9
View File
@@ -1,9 +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 --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,JDK18 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
popd > /dev/null
-2
View File
@@ -1,2 +0,0 @@
source /opt/concourse-java.sh
setup_symlinks
-12
View File
@@ -1,12 +0,0 @@
#!/bin/bash
set -e
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
java -jar /github-changelog-generator.jar \
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
${version} generated-changelog/changelog.md
echo ${version} > generated-changelog/version
echo v${version} > generated-changelog/tag
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
java -jar /concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
echo "Promotion complete"
echo $version > version/version
-50
View File
@@ -1,50 +0,0 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
git fetch --tags --all > /dev/null
popd > /dev/null
git clone git-repo stage-git-repo > /dev/null
pushd stage-git-repo > /dev/null
snapshotVersion=$( awk -F '=' '$1 == "version" { print $2 }' gradle.properties )
if [[ $RELEASE_TYPE = "M" ]]; then
stageVersion=$( get_next_milestone_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RC" ]]; then
stageVersion=$( get_next_rc_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RELEASE" ]]; then
stageVersion=$( get_next_release $snapshotVersion)
nextVersion=$( bump_version_number $snapshotVersion)
else
echo "Unknown release type $RELEASE_TYPE" >&2; exit 1;
fi
echo "Staging $stageVersion (next version will be $nextVersion)"
sed -i "s/version=$snapshotVersion/version=$stageVersion/" gradle.properties
git config user.name "Spring Builds" > /dev/null
git config user.email "spring-builds@users.noreply.github.com" > /dev/null
git add gradle.properties > /dev/null
git commit -m"Release v$stageVersion" > /dev/null
git tag -a "v$stageVersion" -m"Release v$stageVersion" > /dev/null
./gradlew --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
git reset --hard HEAD^ > /dev/null
if [[ $nextVersion != $snapshotVersion ]]; then
echo "Setting next development version (v$nextVersion)"
sed -i "s/version=$snapshotVersion/version=$nextVersion/" gradle.properties
git add gradle.properties > /dev/null
git commit -m"Next development version (v$nextVersion)" > /dev/null
fi;
echo "Staging Complete"
popd > /dev/null
-32
View File
@@ -1,32 +0,0 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: concourse/oci-build-task
tag: 0.10.0
registry_mirror:
host: ((registry-mirror-host))
username: ((registry-mirror-username))
password: ((registry-mirror-password))
inputs:
- name: ci-images-git-repo
outputs:
- name: image
caches:
- path: ci-image-cache
params:
CONTEXT: ci-images-git-repo/ci/images
DOCKERFILE: ci-images-git-repo/ci/images/ci-image/Dockerfile
DOCKER_HUB_AUTH: ((docker-hub-auth))
run:
path: /bin/sh
args:
- "-c"
- |
mkdir -p /root/.docker
cat > /root/.docker/config.json <<EOF
{ "auths": { "https://index.docker.io/v1/": { "auth": "$DOCKER_HUB_AUTH" }}}
EOF
build
-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
-20
View File
@@ -1,20 +0,0 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: springio/github-changelog-generator
tag: '0.0.8'
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: generated-changelog
params:
GITHUB_ORGANIZATION:
GITHUB_REPO:
GITHUB_USERNAME:
GITHUB_TOKEN:
RELEASE_TYPE:
run:
path: git-repo/ci/scripts/generate-changelog.sh
-23
View File
@@ -1,23 +0,0 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: springio/concourse-release-scripts
tag: '0.3.4'
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: version
params:
RELEASE_TYPE:
ARTIFACTORY_SERVER:
ARTIFACTORY_USERNAME:
ARTIFACTORY_PASSWORD:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE:
run:
path: git-repo/ci/scripts/promote-version.sh
-17
View File
@@ -1,17 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: stage-git-repo
- name: distribution-repository
params:
RELEASE_TYPE:
CI: true
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
caches:
- path: gradle
run:
path: git-repo/ci/scripts/stage-version.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
+32
View File
@@ -0,0 +1,32 @@
name: framework
version: true
title: Spring Framework
nav:
- modules/ROOT/nav.adoc
ext:
collector:
run:
command: gradlew -q -PbuildSrc.skipTests=true "-Dorg.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError" :framework-docs:generateAntoraResources
local: true
scan:
dir: ./build/generated-antora-resources
asciidoc:
attributes:
attribute-missing: 'warn'
# FIXME: the copyright is not removed
# FIXME: The package is not renamed
chomp: 'all'
include-java: 'example$docs-src/main/java/org/springframework/docs'
spring-framework-main-code: 'https://github.com/spring-projects/spring-framework/tree/main'
docs-site: 'https://docs.spring.io'
docs-spring: "{docs-site}/spring-framework/docs/{spring-version}"
docs-spring-framework: '{docs-site}/spring-framework/docs/{spring-version}'
api-spring-framework: '{docs-spring-framework}/javadoc-api/org/springframework'
docs-graalvm: 'https://www.graalvm.org/22.3/reference-manual'
docs-spring-boot: '{docs-site}/spring-boot/docs/current/reference'
docs-spring-gemfire: '{docs-site}/spring-gemfire/docs/current/reference'
docs-spring-security: '{docs-site}/spring-security/reference'
gh-rsocket: 'https://github.com/rsocket'
gh-rsocket-extensions: '{gh-rsocket}/rsocket/blob/master/Extensions'
gh-rsocket-java: '{gh-rsocket}/rsocket-java{gh-rsocket}/rsocket-java'
+39 -84
View File
@@ -1,24 +1,39 @@
plugins {
id 'kotlin'
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
id 'org.antora' version '1.0.0'
}
description = "Spring Framework Docs"
apply plugin: 'kotlin'
apply plugin: 'org.asciidoctor.jvm.convert'
apply plugin: 'org.asciidoctor.jvm.pdf'
apply from: "${rootDir}/gradle/publications.gradle"
configurations {
asciidoctorExtensions
antora {
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
environment = [
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
]
}
dependencies {
api(project(":spring-context"))
api(project(":spring-web"))
api("jakarta.servlet:jakarta.servlet-api")
implementation(project(":spring-core-test"))
implementation("org.assertj:assertj-core")
tasks.named("generateAntoraYml") {
asciidocAttributes = project.provider( {
return ["spring-version": project.version ]
} )
}
tasks.create("generateAntoraResources") {
dependsOn 'generateAntoraYml'
}
// Commented out for now:
// https://github.com/spring-projects/spring-framework/issues/30481
// tasks.named("check") {
// dependsOn 'antora'
// }
jar {
enabled = false
}
@@ -27,16 +42,21 @@ javadoc {
enabled = false
}
dependencies {
asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.3"
}
repositories {
maven {
url "https://repo.spring.io/release"
}
}
dependencies {
api(project(":spring-context"))
api(project(":spring-web"))
api("jakarta.servlet:jakarta.servlet-api")
implementation(project(":spring-core-test"))
implementation("org.assertj:assertj-core")
}
/**
* Produce Javadoc for all Spring Framework modules in "build/docs/javadoc"
*/
@@ -67,7 +87,7 @@ task api(type: Javadoc) {
overview = "framework-docs/src/docs/api/overview.html"
splitIndex = true
links(project.ext.javadocLinks)
addBooleanOption('Xdoclint:syntax', true) // only check syntax with doclint
addBooleanOption('Xdoclint:syntax,reference', true) // only check syntax and reference with doclint
addBooleanOption('Werror', true) // fail build on Javadoc warnings
}
source moduleProjects.collect { project ->
@@ -88,69 +108,10 @@ rootProject.tasks.dokkaHtmlMultiModule.configure {
outputDirectory.set(project.file("$buildDir/docs/kdoc"))
}
asciidoctorj {
version = '2.4.3'
fatalWarnings ".*"
options doctype: 'book', eruby: 'erubis'
attributes([
icons: 'font',
idprefix: '',
idseparator: '-',
revnumber: project.version,
sectanchors: '',
sectnums: '',
'spring-version': project.version
])
}
/**
* Generate the Spring Framework Reference documentation from
* "src/docs/asciidoc" in "build/docs/ref-docs/html5".
* Zip all Java docs (javadoc & kdoc) into a single archive
*/
asciidoctor {
baseDirFollowsSourceDir()
configurations "asciidoctorExtensions"
sources {
include '*.adoc'
}
resources {
from(sourceDir) {
include 'images/*.png'
}
}
outputDir "$buildDir/docs/ref-docs/html5"
outputOptions {
backends "spring-html"
}
forkOptions {
jvmArgs += ["--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED"]
}
logDocuments = true
}
asciidoctor.mustRunAfter "check"
/**
* Generate the Spring Framework Reference documentation from "src/docs/asciidoc"
* in "build/docs/ref-docs/pdf".
*/
asciidoctorPdf {
baseDirFollowsSourceDir()
configurations 'asciidoctorExtensions'
sources {
include 'spring-framework.adocbook'
}
outputDir "$buildDir/docs/ref-docs/pdf"
forkOptions {
jvmArgs += ["--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED"]
}
logDocuments = true
}
/**
* Zip all docs (API and reference) into a single archive
*/
task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', rootProject.tasks.dokkaHtmlMultiModule]) {
task docsZip(type: Zip, dependsOn: ['api', rootProject.tasks.dokkaHtmlMultiModule]) {
group = "Distribution"
description = "Builds -${archiveClassifier} archive containing api and reference " +
"for deployment at https://docs.spring.io/spring-framework/docs/."
@@ -163,12 +124,6 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', root
from (api) {
into "javadoc-api"
}
from ("$asciidoctor.outputDir") {
into "reference/html"
}
from ("$asciidoctorPdf.outputDir") {
into "reference/pdf"
}
from (rootProject.tasks.dokkaHtmlMultiModule.outputDirectory) {
into "kdoc-api"
}
@@ -257,4 +212,4 @@ publishing {
artifact distZip
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

@@ -0,0 +1,612 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 spring-overview.svg Page-1 -->
<svg
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6.4728541in"
height="5.9522467in"
viewBox="0 0 466.04561 428.56238"
xml:space="preserve"
class="st5"
id="svg5499"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="mvc-splitted-contexts.svg"
style="font-size:12px;overflow:visible;color-interpolation-filters:sRGB;fill:none;fill-rule:evenodd;stroke-linecap:square;stroke-miterlimit:3"
inkscape:export-filename="/Users/seb/Workspace/spring-framework/src/asciidoc/images/mvc-splitted-contexts.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><metadata
id="metadata5713"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="https://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs5711"><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker9162"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path9164" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8834"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path8836" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8518"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path8520" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8214"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path8216" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7922"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path7924" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7641"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path7644" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7373"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path7375" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7117"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path7119" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6873"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path6875" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6641"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path6643" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6421"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path6423" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6213"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path6215" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6017"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path6019" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5833"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5835" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5661"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5663" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5501"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5503" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5353"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5355" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5217"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5219" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5093"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path5095" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4981"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path4983" /></marker><marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mend"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always"><path
id="path7394"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8121"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path8123"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8033"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path8035"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker7957"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7959"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7376"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7388"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7370"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" /></marker></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="1005"
id="namedview5709"
showgrid="false"
inkscape:zoom="1.1640492"
inkscape:cx="134.86698"
inkscape:cy="203.59898"
inkscape:window-x="84"
inkscape:window-y="176"
inkscape:window-maximized="0"
inkscape:current-layer="g5503"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" /><v:documentProperties
v:langID="1033"
v:viewMarkup="false" /><style
type="text/css"
id="style5501"><![CDATA[
.st1 {fill:#969696;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st3 {fill:#000000;font-family:Arial;font-size:2.50001em;font-weight:bold}
.st4 {font-size:0.333333em;font-weight:normal}
.st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]></style><g
v:mID="0"
v:index="1"
v:groupContext="foregroundPage"
id="g5503"
transform="matrix(0.99998201,0,0,1.0824094,-40.812382,-98.908648)"><rect
style="fill:#dde2cd;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6599"
width="382.68423"
height="146.09897"
x="87.884865"
y="148.26482" /><v:userDefs><v:ud
v:nameU="SchemeName"
v:val="VT4(Default)" /></v:userDefs><rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5725"
width="464.31128"
height="374.11411"
x="41.684383"
y="112.3262" /><title
id="title5505">Page-1</title><v:pageProperties
v:drawingScale="0.0393701"
v:pageScale="0.0393701"
v:drawingUnits="24"
v:shadowOffsetX="8.50394"
v:shadowOffsetY="-8.50394" /><v:layer
v:name="Connector"
v:index="0" /><rect
style="fill:#dde2cd;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.53790233;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5715"
width="322.8194"
height="43.63184"
x="119.95335"
y="-135.66222"
transform="scale(1,-1)" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.7580471px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="168.843"
y="124.32391"
id="text5717"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan5719"
x="168.843"
y="124.32391"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif">DispatcherServlet</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="89.770851"
y="181.20923"
id="text6589"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6591"
x="89.770851"
y="181.20923"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif">Servlet WebApplicationContext</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="260.00443"
y="198.41273"
id="text6593"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6595"
x="260.00443"
y="198.41273"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle">(containing controllers, view resolvers,</tspan><tspan
sodipodi:role="line"
x="260.00443"
y="212.83057"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
id="tspan6597">and other web-related beans)</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6620"
width="82.040657"
height="36.72575"
x="114.52653"
y="-259.43161"
transform="scale(1,-1)" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.89166164;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6622"
width="87.843979"
height="36.697304"
x="223.39864"
y="-287.19809"
transform="scale(1,-1)" /><rect
transform="scale(1,-1)"
y="-264.81918"
x="117.92834"
height="36.72575"
width="82.040657"
id="rect6614"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="121.24728"
y="260.14957"
id="text6616"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6618"
x="121.24728"
y="260.14957"
style="font-size:11.53426838px">Controllers</tspan></text>
<text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6624"
y="282.70709"
x="219.61203"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px"
y="282.70709"
x="219.61203"
id="tspan6626"
sodipodi:role="line">ViewResolver</tspan></text>
<rect
transform="scale(1,-1)"
y="-259.30249"
x="332.5405"
height="36.577778"
width="114.4539"
id="rect6628"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.0161339;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="327.51276"
y="255.28464"
id="text6630"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6632"
x="327.51276"
y="255.28464"
style="font-size:11.53426838px">HandlerMapping</tspan></text>
<rect
y="338.69724"
x="87.803261"
height="121.5683"
width="382.84744"
id="rect6634"
style="fill:#dde2cd;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6636"
y="376.61673"
x="108.61351"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif"
y="376.61673"
x="108.61351"
id="tspan6638"
sodipodi:role="line">Root WebApplicationContext</tspan></text>
<text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6640"
y="395.35812"
x="260.93863"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan6644"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
y="395.35812"
x="260.93863"
sodipodi:role="line">(containing middle-tier services, datasources, etc.)</tspan></text>
<rect
transform="scale(1,-1)"
y="-440.06805"
x="164.32933"
height="36.72575"
width="82.040657"
id="rect6648"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6650"
width="82.040657"
height="36.72575"
x="167.73116"
y="-445.45563"
transform="scale(1,-1)" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6652"
y="448.55054"
x="175.87148"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px"
y="448.55054"
x="175.87148"
id="tspan6654"
sodipodi:role="line">Services</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.88435173;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6656"
width="86.393044"
height="36.704323"
x="306.86328"
y="-439.60837"
transform="scale(1,-1)" /><rect
transform="scale(1,-1)"
y="-444.99475"
x="310.26624"
height="36.701977"
width="86.876686"
id="rect6658"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.88679528;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="305.30771"
y="448.55054"
id="text6660"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6662"
x="305.30771"
y="448.55054"
style="font-size:11.53426838px">Repositories</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.76895118px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 265.33234,295.60379 c 0,42.65169 0,42.65169 0,0 z"
id="path7643"
inkscape:connector-curvature="0" /><path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.46028023;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
d="m 270.43505,294.70585 c 0,39.4721 0,39.87903 0,39.87903"
id="path7645"
inkscape:connector-curvature="0" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="352.55331"
y="333.03622"
id="text4963"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
x="352.55331"
y="333.03622"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
id="tspan4965">Delegates if no bean found</tspan></text>
</g></svg>

After

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+1
View File
@@ -0,0 +1 @@
../../../src
+434
View File
@@ -0,0 +1,434 @@
* xref:overview.adoc[Overview]
* xref:core.adoc[]
** xref:core/beans.adoc[]
*** xref:core/beans/introduction.adoc[]
*** xref:core/beans/basics.adoc[]
*** xref:core/beans/definition.adoc[]
*** xref:core/beans/dependencies.adoc[]
**** xref:core/beans/dependencies/factory-collaborators.adoc[]
**** xref:core/beans/dependencies/factory-properties-detailed.adoc[]
**** xref:core/beans/dependencies/factory-dependson.adoc[]
**** xref:core/beans/dependencies/factory-lazy-init.adoc[]
**** xref:core/beans/dependencies/factory-autowire.adoc[]
**** xref:core/beans/dependencies/factory-method-injection.adoc[]
*** xref:core/beans/factory-scopes.adoc[]
*** xref:core/beans/factory-nature.adoc[]
*** xref:core/beans/child-bean-definitions.adoc[]
*** xref:core/beans/factory-extension.adoc[]
*** xref:core/beans/annotation-config.adoc[]
**** xref:core/beans/annotation-config/autowired.adoc[]
**** xref:core/beans/annotation-config/autowired-primary.adoc[]
**** xref:core/beans/annotation-config/autowired-qualifiers.adoc[]
**** xref:core/beans/annotation-config/generics-as-qualifiers.adoc[]
**** xref:core/beans/annotation-config/custom-autowire-configurer.adoc[]
**** xref:core/beans/annotation-config/resource.adoc[]
**** xref:core/beans/annotation-config/value-annotations.adoc[]
**** xref:core/beans/annotation-config/postconstruct-and-predestroy-annotations.adoc[]
*** xref:core/beans/classpath-scanning.adoc[]
*** xref:core/beans/standard-annotations.adoc[]
*** xref:core/beans/java.adoc[]
**** xref:core/beans/java/basic-concepts.adoc[]
**** xref:core/beans/java/instantiating-container.adoc[]
**** xref:core/beans/java/bean-annotation.adoc[]
**** xref:core/beans/java/configuration-annotation.adoc[]
**** xref:core/beans/java/composing-configuration-classes.adoc[]
*** xref:core/beans/environment.adoc[]
*** xref:core/beans/context-load-time-weaver.adoc[]
*** xref:core/beans/context-introduction.adoc[]
*** xref:core/beans/beanfactory.adoc[]
** xref:core/resources.adoc[]
** xref:core/validation.adoc[]
*** xref:core/validation/validator.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[]
*** xref:core/validation/beanvalidation.adoc[]
** xref:core/expressions.adoc[]
*** xref:core/expressions/evaluation.adoc[]
*** xref:core/expressions/beandef.adoc[]
*** xref:core/expressions/language-ref.adoc[]
**** xref:core/expressions/language-ref/literal.adoc[]
**** xref:core/expressions/language-ref/properties-arrays.adoc[]
**** xref:core/expressions/language-ref/inline-lists.adoc[]
**** xref:core/expressions/language-ref/inline-maps.adoc[]
**** xref:core/expressions/language-ref/array-construction.adoc[]
**** xref:core/expressions/language-ref/methods.adoc[]
**** xref:core/expressions/language-ref/operators.adoc[]
**** xref:core/expressions/language-ref/types.adoc[]
**** xref:core/expressions/language-ref/constructors.adoc[]
**** xref:core/expressions/language-ref/variables.adoc[]
**** xref:core/expressions/language-ref/functions.adoc[]
**** xref:core/expressions/language-ref/bean-references.adoc[]
**** xref:core/expressions/language-ref/operator-ternary.adoc[]
**** xref:core/expressions/language-ref/operator-elvis.adoc[]
**** xref:core/expressions/language-ref/operator-safe-navigation.adoc[]
**** xref:core/expressions/language-ref/collection-selection.adoc[]
**** xref:core/expressions/language-ref/collection-projection.adoc[]
**** xref:core/expressions/language-ref/templating.adoc[]
*** xref:core/expressions/example-classes.adoc[]
** xref:core/aop.adoc[]
*** xref:core/aop/introduction-defn.adoc[]
*** xref:core/aop/introduction-spring-defn.adoc[]
*** xref:core/aop/introduction-proxies.adoc[]
*** xref:core/aop/ataspectj.adoc[]
**** xref:core/aop/ataspectj/aspectj-support.adoc[]
**** xref:core/aop/ataspectj/at-aspectj.adoc[]
**** xref:core/aop/ataspectj/pointcuts.adoc[]
**** xref:core/aop/ataspectj/advice.adoc[]
**** xref:core/aop/ataspectj/introductions.adoc[]
**** xref:core/aop/ataspectj/instantiation-models.adoc[]
**** xref:core/aop/ataspectj/example.adoc[]
*** xref:core/aop/schema.adoc[]
*** xref:core/aop/choosing.adoc[]
*** xref:core/aop/mixing-styles.adoc[]
*** xref:core/aop/proxying.adoc[]
*** xref:core/aop/aspectj-programmatic.adoc[]
*** xref:core/aop/using-aspectj.adoc[]
*** xref:core/aop/resources.adoc[]
** xref:core/aop-api.adoc[]
*** xref:core/aop-api/pointcuts.adoc[]
*** xref:core/aop-api/advice.adoc[]
*** xref:core/aop-api/advisor.adoc[]
*** xref:core/aop-api/pfb.adoc[]
*** xref:core/aop-api/concise-proxy.adoc[]
*** xref:core/aop-api/prog.adoc[]
*** xref:core/aop-api/advised.adoc[]
*** xref:core/aop-api/autoproxy.adoc[]
*** xref:core/aop-api/targetsource.adoc[]
*** xref:core/aop-api/extensibility.adoc[]
** xref:core/null-safety.adoc[]
** xref:core/databuffer-codec.adoc[]
** xref:core/spring-jcl.adoc[]
** xref:core/aot.adoc[]
** xref:core/appendix.adoc[]
*** xref:core/appendix/xsd-schemas.adoc[]
*** xref:core/appendix/xml-custom.adoc[]
*** xref:core/appendix/application-startup-steps.adoc[]
* xref:testing.adoc[]
** xref:testing/introduction.adoc[]
** xref:testing/unit.adoc[]
** xref:testing/integration.adoc[]
** xref:testing/support-jdbc.adoc[]
** xref:testing/testcontext-framework.adoc[]
*** xref:testing/testcontext-framework/key-abstractions.adoc[]
*** xref:testing/testcontext-framework/bootstrapping.adoc[]
*** xref:testing/testcontext-framework/tel-config.adoc[]
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/inheritance.adoc[]
**** xref:testing/testcontext-framework/ctx-management/env-profiles.adoc[]
**** xref:testing/testcontext-framework/ctx-management/property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web-mocks.adoc[]
**** xref:testing/testcontext-framework/ctx-management/caching.adoc[]
**** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[]
*** xref:testing/testcontext-framework/fixture-di.adoc[]
*** xref:testing/testcontext-framework/web-scoped-beans.adoc[]
*** xref:testing/testcontext-framework/tx.adoc[]
*** xref:testing/testcontext-framework/executing-sql.adoc[]
*** xref:testing/testcontext-framework/parallel-test-execution.adoc[]
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/spring-mvc-test-framework.adoc[]
*** xref:testing/spring-mvc-test-framework/server.adoc[]
*** xref:testing/spring-mvc-test-framework/server-static-imports.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-options.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-steps.adoc[]
*** xref:testing/spring-mvc-test-framework/server-performing-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-defining-expectations.adoc[]
*** xref:testing/spring-mvc-test-framework/async-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-streaming-response.adoc[]
*** xref:testing/spring-mvc-test-framework/server-filters.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-resources.adoc[]
*** xref:testing/spring-mvc-test-framework/server-htmlunit.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/geb.adoc[]
** xref:testing/spring-mvc-test-client.adoc[]
** xref:testing/appendix.adoc[]
*** xref:testing/annotations.adoc[]
**** xref:testing/annotations/integration-standard.adoc[]
**** xref:testing/annotations/integration-spring.adoc[]
***** xref:testing/annotations/integration-spring/annotation-bootstrapwith.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-webappconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contexthierarchy.adoc[]
***** xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[]
***** xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[]
***** xref:testing/annotations/integration-spring/annotation-commit.adoc[]
***** xref:testing/annotations/integration-spring/annotation-rollback.adoc[]
***** xref:testing/annotations/integration-spring/annotation-beforetransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-aftertransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sql.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlconfig.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[]
**** xref:testing/annotations/integration-junit4.adoc[]
**** xref:testing/annotations/integration-junit-jupiter.adoc[]
**** xref:testing/annotations/integration-meta.adoc[]
*** xref:testing/resources.adoc[]
* xref:data-access.adoc[]
** xref:data-access/transaction.adoc[]
*** xref:data-access/transaction/motivation.adoc[]
*** xref:data-access/transaction/strategies.adoc[]
*** xref:data-access/transaction/tx-resource-synchronization.adoc[]
*** xref:data-access/transaction/declarative.adoc[]
**** xref:data-access/transaction/declarative/tx-decl-explained.adoc[]
**** xref:data-access/transaction/declarative/first-example.adoc[]
**** xref:data-access/transaction/declarative/rolling-back.adoc[]
**** xref:data-access/transaction/declarative/diff-tx.adoc[]
**** xref:data-access/transaction/declarative/txadvice-settings.adoc[]
**** xref:data-access/transaction/declarative/annotations.adoc[]
**** xref:data-access/transaction/declarative/tx-propagation.adoc[]
**** xref:data-access/transaction/declarative/applying-more-than-just-tx-advice.adoc[]
**** xref:data-access/transaction/declarative/aspectj.adoc[]
*** xref:data-access/transaction/programmatic.adoc[]
*** xref:data-access/transaction/tx-decl-vs-prog.adoc[]
*** xref:data-access/transaction/event.adoc[]
*** xref:data-access/transaction/application-server-integration.adoc[]
*** xref:data-access/transaction/solutions-to-common-problems.adoc[]
*** xref:data-access/transaction/resources.adoc[]
** xref:data-access/dao.adoc[]
** xref:data-access/jdbc.adoc[]
*** xref:data-access/jdbc/choose-style.adoc[]
*** xref:data-access/jdbc/packages.adoc[]
*** xref:data-access/jdbc/core.adoc[]
*** xref:data-access/jdbc/connections.adoc[]
*** xref:data-access/jdbc/advanced.adoc[]
*** xref:data-access/jdbc/simple.adoc[]
*** xref:data-access/jdbc/object.adoc[]
*** xref:data-access/jdbc/parameter-handling.adoc[]
*** xref:data-access/jdbc/embedded-database-support.adoc[]
*** xref:data-access/jdbc/initializing-datasource.adoc[]
** xref:data-access/r2dbc.adoc[]
** xref:data-access/orm.adoc[]
*** xref:data-access/orm/introduction.adoc[]
*** xref:data-access/orm/general.adoc[]
*** xref:data-access/orm/hibernate.adoc[]
*** xref:data-access/orm/jpa.adoc[]
** xref:data-access/oxm.adoc[]
** xref:data-access/appendix.adoc[]
* xref:web.adoc[]
** xref:web/webmvc.adoc[]
*** xref:web/webmvc/mvc-servlet.adoc[]
**** xref:web/webmvc/mvc-servlet/context-hierarchy.adoc[]
**** xref:web/webmvc/mvc-servlet/special-bean-types.adoc[]
**** xref:web/webmvc/mvc-servlet/config.adoc[]
**** xref:web/webmvc/mvc-servlet/container-config.adoc[]
**** xref:web/webmvc/mvc-servlet/sequence.adoc[]
**** xref:web/webmvc/mvc-servlet/handlermapping-path.adoc[]
**** xref:web/webmvc/mvc-servlet/handlermapping-interceptor.adoc[]
**** xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[]
**** xref:web/webmvc/mvc-servlet/viewresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/localeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/themeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/multipart.adoc[]
**** xref:web/webmvc/mvc-servlet/logging.adoc[]
*** xref:web/webmvc/filters.adoc[]
*** xref:web/webmvc/mvc-controller.adoc[]
**** xref:web/webmvc/mvc-controller/ann.adoc[]
**** xref:web/webmvc/mvc-controller/ann-requestmapping.adoc[]
**** xref:web/webmvc/mvc-controller/ann-methods.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/arguments.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/return-types.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/matrix-variables.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestparam.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestheader.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/cookievalue.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/sessionattributes.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/sessionattribute.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestattrib.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/redirecting-passing-data.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/flash-attributes.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/multipart-forms.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestbody.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/httpentity.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/responsebody.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/responseentity.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/jackson.adoc[]
**** xref:web/webmvc/mvc-controller/ann-modelattrib-methods.adoc[]
**** xref:web/webmvc/mvc-controller/ann-initbinder.adoc[]
**** xref:web/webmvc/mvc-controller/ann-exceptionhandler.adoc[]
**** xref:web/webmvc/mvc-controller/ann-advice.adoc[]
*** xref:web/webmvc-functional.adoc[]
*** xref:web/webmvc/mvc-uri-building.adoc[]
*** xref:web/webmvc/mvc-ann-async.adoc[]
*** xref:web/webmvc-cors.adoc[]
*** xref:web/webmvc/mvc-ann-rest-exceptions.adoc[]
*** xref:web/webmvc/mvc-security.adoc[]
*** xref:web/webmvc/mvc-caching.adoc[]
*** xref:web/webmvc-view.adoc[]
**** xref:web/webmvc-view/mvc-thymeleaf.adoc[]
**** xref:web/webmvc-view/mvc-freemarker.adoc[]
**** xref:web/webmvc-view/mvc-groovymarkup.adoc[]
**** xref:web/webmvc-view/mvc-script.adoc[]
**** xref:web/webmvc-view/mvc-jsp.adoc[]
**** xref:web/webmvc-view/mvc-feeds.adoc[]
**** xref:web/webmvc-view/mvc-document.adoc[]
**** xref:web/webmvc-view/mvc-jackson.adoc[]
**** xref:web/webmvc-view/mvc-xml-marshalling.adoc[]
**** xref:web/webmvc-view/mvc-xslt.adoc[]
*** xref:web/webmvc/mvc-config.adoc[]
**** xref:web/webmvc/mvc-config/enable.adoc[]
**** xref:web/webmvc/mvc-config/customize.adoc[]
**** xref:web/webmvc/mvc-config/conversion.adoc[]
**** xref:web/webmvc/mvc-config/validation.adoc[]
**** xref:web/webmvc/mvc-config/interceptors.adoc[]
**** xref:web/webmvc/mvc-config/content-negotiation.adoc[]
**** xref:web/webmvc/mvc-config/message-converters.adoc[]
**** xref:web/webmvc/mvc-config/view-controller.adoc[]
**** xref:web/webmvc/mvc-config/view-resolvers.adoc[]
**** xref:web/webmvc/mvc-config/static-resources.adoc[]
**** xref:web/webmvc/mvc-config/default-servlet-handler.adoc[]
**** xref:web/webmvc/mvc-config/path-matching.adoc[]
**** xref:web/webmvc/mvc-config/advanced-java.adoc[]
**** xref:web/webmvc/mvc-config/advanced-xml.adoc[]
*** xref:web/webmvc/mvc-http2.adoc[]
** xref:web/webmvc-client.adoc[]
** xref:web/webmvc-test.adoc[]
** xref:web/websocket.adoc[]
*** xref:web/websocket/server.adoc[]
*** xref:web/websocket/fallback.adoc[]
*** xref:web/websocket/stomp.adoc[]
**** xref:web/websocket/stomp/overview.adoc[]
**** xref:web/websocket/stomp/benefits.adoc[]
**** xref:web/websocket/stomp/enable.adoc[]
**** xref:web/websocket/stomp/server-config.adoc[]
**** xref:web/websocket/stomp/message-flow.adoc[]
**** xref:web/websocket/stomp/handle-annotations.adoc[]
**** xref:web/websocket/stomp/handle-send.adoc[]
**** xref:web/websocket/stomp/handle-simple-broker.adoc[]
**** xref:web/websocket/stomp/handle-broker-relay.adoc[]
**** xref:web/websocket/stomp/handle-broker-relay-configure.adoc[]
**** xref:web/websocket/stomp/destination-separator.adoc[]
**** xref:web/websocket/stomp/authentication.adoc[]
**** xref:web/websocket/stomp/authentication-token-based.adoc[]
**** xref:web/websocket/stomp/authorization.adoc[]
**** xref:web/websocket/stomp/user-destination.adoc[]
**** xref:web/websocket/stomp/ordered-messages.adoc[]
**** xref:web/websocket/stomp/application-context-events.adoc[]
**** xref:web/websocket/stomp/interceptors.adoc[]
**** xref:web/websocket/stomp/client.adoc[]
**** xref:web/websocket/stomp/scope.adoc[]
**** xref:web/websocket/stomp/configuration-performance.adoc[]
**** xref:web/websocket/stomp/stats.adoc[]
**** xref:web/websocket/stomp/testing.adoc[]
** xref:web/integration.adoc[]
* xref:web-reactive.adoc[]
** xref:web/webflux.adoc[]
*** xref:web/webflux/new-framework.adoc[]
*** xref:web/webflux/reactive-spring.adoc[]
*** xref:web/webflux/dispatcher-handler.adoc[]
*** xref:web/webflux/controller.adoc[]
**** xref:web/webflux/controller/ann.adoc[]
**** xref:web/webflux/controller/ann-requestmapping.adoc[]
**** xref:web/webflux/controller/ann-methods.adoc[]
***** xref:web/webflux/controller/ann-methods/arguments.adoc[]
***** xref:web/webflux/controller/ann-methods/return-types.adoc[]
***** xref:web/webflux/controller/ann-methods/typeconversion.adoc[]
***** xref:web/webflux/controller/ann-methods/matrix-variables.adoc[]
***** xref:web/webflux/controller/ann-methods/requestparam.adoc[]
***** xref:web/webflux/controller/ann-methods/requestheader.adoc[]
***** xref:web/webflux/controller/ann-methods/cookievalue.adoc[]
***** xref:web/webflux/controller/ann-methods/modelattrib-method-args.adoc[]
***** xref:web/webflux/controller/ann-methods/sessionattributes.adoc[]
***** xref:web/webflux/controller/ann-methods/sessionattribute.adoc[]
***** xref:web/webflux/controller/ann-methods/requestattrib.adoc[]
***** xref:web/webflux/controller/ann-methods/multipart-forms.adoc[]
***** xref:web/webflux/controller/ann-methods/requestbody.adoc[]
***** xref:web/webflux/controller/ann-methods/httpentity.adoc[]
***** xref:web/webflux/controller/ann-methods/responsebody.adoc[]
***** xref:web/webflux/controller/ann-methods/responseentity.adoc[]
***** xref:web/webflux/controller/ann-methods/jackson.adoc[]
**** xref:web/webflux/controller/ann-modelattrib-methods.adoc[]
**** xref:web/webflux/controller/ann-initbinder.adoc[]
**** xref:web/webflux/controller/ann-exceptions.adoc[]
**** xref:web/webflux/controller/ann-advice.adoc[]
*** xref:web/webflux-functional.adoc[]
*** xref:web/webflux/uri-building.adoc[]
*** xref:web/webflux-cors.adoc[]
*** xref:web/webflux/ann-rest-exceptions.adoc[]
*** xref:web/webflux/security.adoc[]
*** xref:web/webflux/caching.adoc[]
*** xref:web/webflux-view.adoc[]
*** xref:web/webflux/config.adoc[]
*** xref:web/webflux/http2.adoc[]
** xref:web/webflux-webclient.adoc[]
*** xref:web/webflux-webclient/client-builder.adoc[]
*** xref:web/webflux-webclient/client-retrieve.adoc[]
*** xref:web/webflux-webclient/client-exchange.adoc[]
*** xref:web/webflux-webclient/client-body.adoc[]
*** xref:web/webflux-webclient/client-filter.adoc[]
*** xref:web/webflux-webclient/client-attributes.adoc[]
*** xref:web/webflux-webclient/client-context.adoc[]
*** xref:web/webflux-webclient/client-synchronous.adoc[]
*** xref:web/webflux-webclient/client-testing.adoc[]
** xref:web/webflux-http-interface-client.adoc[]
** xref:web/webflux-websocket.adoc[]
** xref:web/webflux-test.adoc[]
** xref:rsocket.adoc[]
** xref:web/webflux-reactive-libraries.adoc[]
* xref:integration.adoc[]
** xref:integration/rest-clients.adoc[]
** xref:integration/jms.adoc[]
*** xref:integration/jms/using.adoc[]
*** xref:integration/jms/sending.adoc[]
*** xref:integration/jms/receiving.adoc[]
*** xref:integration/jms/jca-message-endpoint-manager.adoc[]
*** xref:integration/jms/annotated.adoc[]
*** xref:integration/jms/namespace.adoc[]
** xref:integration/jmx.adoc[]
*** xref:integration/jmx/exporting.adoc[]
*** xref:integration/jmx/interface.adoc[]
*** xref:integration/jmx/naming.adoc[]
*** xref:integration/jmx/jsr160.adoc[]
*** xref:integration/jmx/proxy.adoc[]
*** xref:integration/jmx/notifications.adoc[]
*** xref:integration/jmx/resources.adoc[]
** xref:integration/email.adoc[]
** xref:integration/scheduling.adoc[]
** xref:integration/cache.adoc[]
*** xref:integration/cache/strategies.adoc[]
*** xref:integration/cache/annotations.adoc[]
*** xref:integration/cache/jsr-107.adoc[]
*** xref:integration/cache/declarative-xml.adoc[]
*** xref:integration/cache/store-configuration.adoc[]
*** xref:integration/cache/plug.adoc[]
*** xref:integration/cache/specific-config.adoc[]
** xref:integration/observability.adoc[]
** xref:integration/appendix.adoc[]
* xref:languages.adoc[]
** xref:languages/kotlin.adoc[]
*** xref:languages/kotlin/requirements.adoc[]
*** xref:languages/kotlin/extensions.adoc[]
*** xref:languages/kotlin/null-safety.adoc[]
*** xref:languages/kotlin/classes-interfaces.adoc[]
*** xref:languages/kotlin/annotations.adoc[]
*** xref:languages/kotlin/bean-definition-dsl.adoc[]
*** xref:languages/kotlin/web.adoc[]
*** xref:languages/kotlin/coroutines.adoc[]
*** xref:languages/kotlin/spring-projects-in.adoc[]
*** xref:languages/kotlin/getting-started.adoc[]
*** xref:languages/kotlin/resources.adoc[]
** xref:languages/groovy.adoc[]
** xref:languages/dynamic.adoc[]
* xref:appendix.adoc[]
* https://github.com/spring-projects/spring-framework/wiki[Wiki]
@@ -1,7 +1,5 @@
[[appendix]]
= Appendix
include::attributes.adoc[]
include::page-layout.adoc[]
This part of the reference documentation covers topics that apply to multiple modules
within the core Spring Framework.
@@ -27,12 +25,12 @@ The following table lists all currently supported Spring properties.
| `spring.beaninfo.ignore`
| Instructs Spring to use the `Introspector.IGNORE_ALL_BEANINFO` mode when calling the
JavaBeans `Introspector`. See
{api-spring-framework}++/beans/CachedIntrospectionResults.html#IGNORE_BEANINFO_PROPERTY_NAME++[`CachedIntrospectionResults`]
{api-spring-framework}++/beans/StandardBeanInfoFactory.html#IGNORE_BEANINFO_PROPERTY_NAME++[`CachedIntrospectionResults`]
for details.
| `spring.expression.compiler.mode`
| The mode to use when compiling expressions for the
<<core.adoc#expressions-compiler-configuration, Spring Expression Language>>.
xref:core/expressions/evaluation.adoc#expressions-compiler-configuration[Spring Expression Language].
| `spring.getenv.ignore`
| Instructs Spring to ignore operating system environment variables if a Spring
@@ -43,12 +41,12 @@ for details.
| `spring.index.ignore`
| Instructs Spring to ignore the components index located in
`META-INF/spring.components`. See <<core.adoc#beans-scanning-index, Generating an Index
of Candidate Components>>.
`META-INF/spring.components`. See xref:core/beans/classpath-scanning.adoc#beans-scanning-index[Generating an Index of Candidate Components]
.
| `spring.jdbc.getParameterType.ignore`
| Instructs Spring to ignore `java.sql.ParameterMetaData.getParameterType` completely.
See the note in <<data-access.adoc#jdbc-batch-list, Batch Operations with a List of Objects>>.
See the note in xref:data-access/jdbc/advanced.adoc#jdbc-batch-list[Batch Operations with a List of Objects].
| `spring.jndi.ignore`
| Instructs Spring to ignore a default JNDI environment, as an optimization for scenarios
@@ -64,17 +62,17 @@ for details.
| `spring.test.constructor.autowire.mode`
| The default _test constructor autowire mode_ to use if `@TestConstructor` is not present
on a test class. See <<testing.adoc#integration-testing-annotations-testconstructor,
Changing the default test constructor autowire mode>>.
on a test class. See xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-testconstructor[Changing the default test constructor autowire mode]
.
| `spring.test.context.cache.maxSize`
| The maximum size of the context cache in the _Spring TestContext Framework_. See
<<testing.adoc#testcontext-ctx-management-caching, Context Caching>>.
xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching].
| `spring.test.enclosing.configuration`
| The default _enclosing configuration inheritance mode_ to use if
`@NestedTestConfiguration` is not present on a test class. See
<<testing.adoc#integration-testing-annotations-nestedtestconfiguration, Changing the
default enclosing configuration inheritance mode>>.
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-nestedtestconfiguration[Changing the default enclosing configuration inheritance mode]
.
|===
@@ -1,5 +1,11 @@
:chomp: default headers packages
// Spring Portfolio
:docs-site: https://docs.spring.io
:docs-spring-boot: {docs-site}/spring-boot/docs/current/reference
:docs-spring-gemfire: {docs-site}/spring-gemfire/docs/current/reference
:docs-spring-security: {docs-site}/spring-security/reference
// spring-asciidoctor-backends Settings
:chomp: default headers packages
:fold: all
// Spring Framework
:docs-spring-framework: {docs-site}/spring-framework/docs/{spring-version}
:api-spring-framework: {docs-spring-framework}/javadoc-api/org/springframework
@@ -7,10 +13,6 @@
:docs-kotlin: {docdir}/../../main/kotlin/org/springframework/docs
:docs-resources: {docdir}/../../main/resources
:spring-framework-main-code: https://github.com/spring-projects/spring-framework/tree/main
// Spring portfolio Links
:docs-spring-boot: {docs-site}/spring-boot/docs/current/reference
:docs-spring-gemfire: {docs-site}/spring-gemfire/docs/current/reference
:docs-spring-security: {docs-site}/spring-security/reference
// Third-party Links
:docs-graalvm: https://www.graalvm.org/22.3/reference-manual
:gh-rsocket: https://github.com/rsocket
@@ -1,7 +1,5 @@
[[spring-core]]
= Core Technologies
include::attributes.adoc[]
include::page-layout.adoc[]
This part of the reference documentation covers all the technologies that are
absolutely integral to the Spring Framework.
@@ -20,24 +18,13 @@ is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically
used for native image deployment using GraalVM.
include::core/core-beans.adoc[leveloffset=+1]
include::core/core-resources.adoc[leveloffset=+1]
include::core/core-validation.adoc[leveloffset=+1]
include::core/core-expressions.adoc[leveloffset=+1]
include::core/core-aop.adoc[leveloffset=+1]
include::core/core-aop-api.adoc[leveloffset=+1]
include::core/core-null-safety.adoc[leveloffset=+1]
include::core/core-databuffer-codec.adoc[leveloffset=+1]
include::core/core-spring-jcl.adoc[leveloffset=+1]
include::core/core-aot.adoc[leveloffset=+1]
include::core/core-appendix.adoc[leveloffset=+1]
@@ -0,0 +1,12 @@
[[aop-api]]
= Spring AOP APIs
:page-section-summary-toc: 1
The previous chapter described the Spring's support for AOP with @AspectJ and schema-based
aspect definitions. In this chapter, we discuss the lower-level Spring AOP APIs. For common
applications, we recommend the use of Spring AOP with AspectJ pointcuts as described in the
previous chapter.
@@ -0,0 +1,592 @@
[[aop-api-advice]]
= Advice API in Spring
Now we can examine how Spring AOP handles advice.
[[aop-api-advice-lifecycle]]
== Advice Lifecycles
Each advice is a Spring bean. An advice instance can be shared across all advised
objects or be unique to each advised object. This corresponds to per-class or
per-instance advice.
Per-class advice is used most often. It is appropriate for generic advice, such as
transaction advisors. These do not depend on the state of the proxied object or add new
state. They merely act on the method and arguments.
Per-instance advice is appropriate for introductions, to support mixins. In this case,
the advice adds state to the proxied object.
You can use a mix of shared and per-instance advice in the same AOP proxy.
[[aop-api-advice-types]]
== Advice Types in Spring
Spring provides several advice types and is extensible to support
arbitrary advice types. This section describes the basic concepts and standard advice types.
[[aop-api-advice-around]]
=== Interception Around Advice
The most fundamental advice type in Spring is interception around advice.
Spring is compliant with the AOP `Alliance` interface for around advice that uses method
interception. Classes that implement `MethodInterceptor` and that implement around advice should also implement the
following interface:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
----
The `MethodInvocation` argument to the `invoke()` method exposes the method being
invoked, the target join point, the AOP proxy, and the arguments to the method. The
`invoke()` method should return the invocation's result: the return value of the join
point.
The following example shows a simple `MethodInterceptor` implementation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class DebugInterceptor : MethodInterceptor {
override fun invoke(invocation: MethodInvocation): Any {
println("Before: invocation=[$invocation]")
val rval = invocation.proceed()
println("Invocation returned")
return rval
}
}
----
======
Note the call to the `proceed()` method of `MethodInvocation`. This proceeds down the
interceptor chain towards the join point. Most interceptors invoke this method and
return its return value. However, a `MethodInterceptor`, like any around advice, can
return a different value or throw an exception rather than invoke the proceed method.
However, you do not want to do this without good reason.
NOTE: `MethodInterceptor` implementations offer interoperability with other AOP Alliance-compliant AOP
implementations. The other advice types discussed in the remainder of this section
implement common AOP concepts but in a Spring-specific way. While there is an advantage
in using the most specific advice type, stick with `MethodInterceptor` around advice if
you are likely to want to run the aspect in another AOP framework. Note that pointcuts
are not currently interoperable between frameworks, and the AOP Alliance does not
currently define pointcut interfaces.
[[aop-api-advice-before]]
=== Before Advice
A simpler advice type is a before advice. This does not need a `MethodInvocation`
object, since it is called only before entering the method.
The main advantage of a before advice is that there is no need to invoke the `proceed()`
method and, therefore, no possibility of inadvertently failing to proceed down the
interceptor chain.
The following listing shows the `MethodBeforeAdvice` interface:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}
----
(Spring's API design would allow for
field before advice, although the usual objects apply to field interception and it is
unlikely for Spring to ever implement it.)
Note that the return type is `void`. Before advice can insert custom behavior before the join
point runs but cannot change the return value. If a before advice throws an
exception, it stops further execution of the interceptor chain. The exception
propagates back up the interceptor chain. If it is unchecked or on the signature of
the invoked method, it is passed directly to the client. Otherwise, it is
wrapped in an unchecked exception by the AOP proxy.
The following example shows a before advice in Spring, which counts all method invocations:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class CountingBeforeAdvice implements MethodBeforeAdvice {
private int count;
public void before(Method m, Object[] args, Object target) throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class CountingBeforeAdvice : MethodBeforeAdvice {
var count: Int = 0
override fun before(m: Method, args: Array<Any>, target: Any?) {
++count
}
}
----
======
TIP: Before advice can be used with any pointcut.
[[aop-api-advice-throws]]
=== Throws Advice
Throws advice is invoked after the return of the join point if the join point threw
an exception. Spring offers typed throws advice. Note that this means that the
`org.springframework.aop.ThrowsAdvice` interface does not contain any methods. It is a
tag interface identifying that the given object implements one or more typed throws
advice methods. These should be in the following form:
[source,java,indent=0,subs="verbatim,quotes"]
----
afterThrowing([Method, args, target], subclassOfThrowable)
----
Only the last argument is required. The method signatures may have either one or four
arguments, depending on whether the advice method is interested in the method and
arguments. The next two listing show classes that are examples of throws advice.
The following advice is invoked if a `RemoteException` is thrown (including from subclasses):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class RemoteThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class RemoteThrowsAdvice : ThrowsAdvice {
fun afterThrowing(ex: RemoteException) {
// Do something with remote exception
}
}
----
======
Unlike the preceding
advice, the next example declares four arguments, so that it has access to the invoked method, method
arguments, and target object. The following advice is invoked if a `ServletException` is thrown:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
// Do something with all arguments
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class ServletThrowsAdviceWithArguments : ThrowsAdvice {
fun afterThrowing(m: Method, args: Array<Any>, target: Any, ex: ServletException) {
// Do something with all arguments
}
}
----
======
The final example illustrates how these two methods could be used in a single class
that handles both `RemoteException` and `ServletException`. Any number of throws advice
methods can be combined in a single class. The following listing shows the final example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public static class CombinedThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
// Do something with all arguments
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class CombinedThrowsAdvice : ThrowsAdvice {
fun afterThrowing(ex: RemoteException) {
// Do something with remote exception
}
fun afterThrowing(m: Method, args: Array<Any>, target: Any, ex: ServletException) {
// Do something with all arguments
}
}
----
======
NOTE: If a throws-advice method throws an exception itself, it overrides the
original exception (that is, it changes the exception thrown to the user). The overriding
exception is typically a RuntimeException, which is compatible with any method
signature. However, if a throws-advice method throws a checked exception, it must
match the declared exceptions of the target method and is, hence, to some degree
coupled to specific target method signatures. _Do not throw an undeclared checked
exception that is incompatible with the target method's signature!_
TIP: Throws advice can be used with any pointcut.
[[aop-api-advice-after-returning]]
=== After Returning Advice
An after returning advice in Spring must implement the
`org.springframework.aop.AfterReturningAdvice` interface, which the following listing shows:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable;
}
----
An after returning advice has access to the return value (which it cannot modify),
the invoked method, the method's arguments, and the target.
The following after returning advice counts all successful method invocations that have
not thrown exceptions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
private int count;
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class CountingAfterReturningAdvice : AfterReturningAdvice {
var count: Int = 0
private set
override fun afterReturning(returnValue: Any?, m: Method, args: Array<Any>, target: Any?) {
++count
}
}
----
======
This advice does not change the execution path. If it throws an exception, it is
thrown up the interceptor chain instead of the return value.
TIP: After returning advice can be used with any pointcut.
[[aop-api-advice-introduction]]
=== Introduction Advice
Spring treats introduction advice as a special kind of interception advice.
Introduction requires an `IntroductionAdvisor` and an `IntroductionInterceptor` that
implement the following interface:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface IntroductionInterceptor extends MethodInterceptor {
boolean implementsInterface(Class intf);
}
----
The `invoke()` method inherited from the AOP Alliance `MethodInterceptor` interface must
implement the introduction. That is, if the invoked method is on an introduced
interface, the introduction interceptor is responsible for handling the method call -- it
cannot invoke `proceed()`.
Introduction advice cannot be used with any pointcut, as it applies only at the class,
rather than the method, level. You can only use introduction advice with the
`IntroductionAdvisor`, which has the following methods:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
public interface IntroductionInfo {
Class<?>[] getInterfaces();
}
----
There is no `MethodMatcher` and, hence, no `Pointcut` associated with introduction
advice. Only class filtering is logical.
The `getInterfaces()` method returns the interfaces introduced by this advisor.
The `validateInterfaces()` method is used internally to see whether or not the
introduced interfaces can be implemented by the configured `IntroductionInterceptor`.
Consider an example from the Spring test suite and suppose we want to
introduce the following interface to one or more objects:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public interface Lockable {
void lock();
void unlock();
boolean locked();
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
interface Lockable {
fun lock()
fun unlock()
fun locked(): Boolean
}
----
======
This illustrates a mixin. We want to be able to cast advised objects to `Lockable`,
whatever their type and call lock and unlock methods. If we call the `lock()` method, we
want all setter methods to throw a `LockedException`. Thus, we can add an aspect that
provides the ability to make objects immutable without them having any knowledge of it:
a good example of AOP.
First, we need an `IntroductionInterceptor` that does the heavy lifting. In this
case, we extend the `org.springframework.aop.support.DelegatingIntroductionInterceptor`
convenience class. We could implement `IntroductionInterceptor` directly, but using
`DelegatingIntroductionInterceptor` is best for most cases.
The `DelegatingIntroductionInterceptor` is designed to delegate an introduction to an
actual implementation of the introduced interfaces, concealing the use of interception
to do so. You can set the delegate to any object using a constructor argument. The
default delegate (when the no-argument constructor is used) is `this`. Thus, in the next example,
the delegate is the `LockMixin` subclass of `DelegatingIntroductionInterceptor`.
Given a delegate (by default, itself), a `DelegatingIntroductionInterceptor` instance
looks for all interfaces implemented by the delegate (other than
`IntroductionInterceptor`) and supports introductions against any of them.
Subclasses such as `LockMixin` can call the `suppressInterface(Class intf)`
method to suppress interfaces that should not be exposed. However, no matter how many
interfaces an `IntroductionInterceptor` is prepared to support, the
`IntroductionAdvisor` used controls which interfaces are actually exposed. An
introduced interface conceals any implementation of the same interface by the target.
Thus, `LockMixin` extends `DelegatingIntroductionInterceptor` and implements `Lockable`
itself. The superclass automatically picks up that `Lockable` can be supported for
introduction, so we do not need to specify that. We could introduce any number of
interfaces in this way.
Note the use of the `locked` instance variable. This effectively adds additional state
to that held in the target object.
The following example shows the example `LockMixin` class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
private boolean locked;
public void lock() {
this.locked = true;
}
public void unlock() {
this.locked = false;
}
public boolean locked() {
return this.locked;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {
throw new LockedException();
}
return super.invoke(invocation);
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class LockMixin : DelegatingIntroductionInterceptor(), Lockable {
private var locked: Boolean = false
fun lock() {
this.locked = true
}
fun unlock() {
this.locked = false
}
fun locked(): Boolean {
return this.locked
}
override fun invoke(invocation: MethodInvocation): Any? {
if (locked() && invocation.method.name.indexOf("set") == 0) {
throw LockedException()
}
return super.invoke(invocation)
}
}
----
======
Often, you need not override the `invoke()` method. The
`DelegatingIntroductionInterceptor` implementation (which calls the `delegate` method if
the method is introduced, otherwise proceeds towards the join point) usually
suffices. In the present case, we need to add a check: no setter method can be invoked
if in locked mode.
The required introduction only needs to hold a distinct
`LockMixin` instance and specify the introduced interfaces (in this case, only
`Lockable`). A more complex example might take a reference to the introduction
interceptor (which would be defined as a prototype). In this case, there is no
configuration relevant for a `LockMixin`, so we create it by using `new`.
The following example shows our `LockMixinAdvisor` class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
public LockMixinAdvisor() {
super(new LockMixin(), Lockable.class);
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class LockMixinAdvisor : DefaultIntroductionAdvisor(LockMixin(), Lockable::class.java)
----
======
We can apply this advisor very simply, because it requires no configuration. (However, it
is impossible to use an `IntroductionInterceptor` without an
`IntroductionAdvisor`.) As usual with introductions, the advisor must be per-instance,
as it is stateful. We need a different instance of `LockMixinAdvisor`, and hence
`LockMixin`, for each advised object. The advisor comprises part of the advised object's
state.
We can apply this advisor programmatically by using the `Advised.addAdvisor()` method or
(the recommended way) in XML configuration, as any other advisor. All proxy creation
choices discussed below, including "`auto proxy creators,`" correctly handle introductions
and stateful mixins.
@@ -0,0 +1,148 @@
[[aop-api-advised]]
= Manipulating Advised Objects
However you create AOP proxies, you can manipulate them BY using the
`org.springframework.aop.framework.Advised` interface. Any AOP proxy can be cast to this
interface, no matter which other interfaces it implements. This interface includes the
following methods:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
Advisor[] getAdvisors();
void addAdvice(Advice advice) throws AopConfigException;
void addAdvice(int pos, Advice advice) throws AopConfigException;
void addAdvisor(Advisor advisor) throws AopConfigException;
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
int indexOf(Advisor advisor);
boolean removeAdvisor(Advisor advisor) throws AopConfigException;
void removeAdvisor(int index) throws AopConfigException;
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
boolean isFrozen();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
fun getAdvisors(): Array<Advisor>
@Throws(AopConfigException::class)
fun addAdvice(advice: Advice)
@Throws(AopConfigException::class)
fun addAdvice(pos: Int, advice: Advice)
@Throws(AopConfigException::class)
fun addAdvisor(advisor: Advisor)
@Throws(AopConfigException::class)
fun addAdvisor(pos: Int, advisor: Advisor)
fun indexOf(advisor: Advisor): Int
@Throws(AopConfigException::class)
fun removeAdvisor(advisor: Advisor): Boolean
@Throws(AopConfigException::class)
fun removeAdvisor(index: Int)
@Throws(AopConfigException::class)
fun replaceAdvisor(a: Advisor, b: Advisor): Boolean
fun isFrozen(): Boolean
----
======
The `getAdvisors()` method returns an `Advisor` for every advisor, interceptor, or
other advice type that has been added to the factory. If you added an `Advisor`, the
returned advisor at this index is the object that you added. If you added an
interceptor or other advice type, Spring wrapped this in an advisor with a
pointcut that always returns `true`. Thus, if you added a `MethodInterceptor`, the advisor
returned for this index is a `DefaultPointcutAdvisor` that returns your
`MethodInterceptor` and a pointcut that matches all classes and methods.
The `addAdvisor()` methods can be used to add any `Advisor`. Usually, the advisor holding
pointcut and advice is the generic `DefaultPointcutAdvisor`, which you can use with
any advice or pointcut (but not for introductions).
By default, it is possible to add or remove advisors or interceptors even once a proxy
has been created. The only restriction is that it is impossible to add or remove an
introduction advisor, as existing proxies from the factory do not show the interface
change. (You can obtain a new proxy from the factory to avoid this problem.)
The following example shows casting an AOP proxy to the `Advised` interface and examining and
manipulating its advice:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(new DebugInterceptor());
// Add selective advice using a pointcut
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val advised = myObject as Advised
val advisors = advised.advisors
val oldAdvisorCount = advisors.size
println("$oldAdvisorCount advisors")
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(DebugInterceptor())
// Add selective advice using a pointcut
advised.addAdvisor(DefaultPointcutAdvisor(mySpecialPointcut, myAdvice))
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.advisors.size)
----
======
NOTE: It is questionable whether it is advisable (no pun intended) to modify advice on a
business object in production, although there are, no doubt, legitimate usage cases.
However, it can be very useful in development (for example, in tests). We have sometimes
found it very useful to be able to add test code in the form of an interceptor or other
advice, getting inside a method invocation that we want to test. (For example, the advice can
get inside a transaction created for that method, perhaps to run SQL to check that
a database was correctly updated, before marking the transaction for roll back.)
Depending on how you created the proxy, you can usually set a `frozen` flag. In that
case, the `Advised` `isFrozen()` method returns `true`, and any attempts to modify
advice through addition or removal results in an `AopConfigException`. The ability
to freeze the state of an advised object is useful in some cases (for example, to
prevent calling code removing a security interceptor).
@@ -0,0 +1,20 @@
[[aop-api-advisor]]
= The Advisor API in Spring
:page-section-summary-toc: 1
In Spring, an Advisor is an aspect that contains only a single advice object associated
with a pointcut expression.
Apart from the special case of introductions, any advisor can be used with any advice.
`org.springframework.aop.support.DefaultPointcutAdvisor` is the most commonly used
advisor class. It can be used with a `MethodInterceptor`, `BeforeAdvice`, or
`ThrowsAdvice`.
It is possible to mix advisor and advice types in Spring in the same AOP proxy. For
example, you could use an interception around advice, throws advice, and before advice in
one proxy configuration. Spring automatically creates the necessary interceptor
chain.
@@ -0,0 +1,131 @@
[[aop-autoproxy]]
= Using the "auto-proxy" facility
So far, we have considered explicit creation of AOP proxies by using a `ProxyFactoryBean` or
similar factory bean.
Spring also lets us use "`auto-proxy`" bean definitions, which can automatically
proxy selected bean definitions. This is built on Spring's "`bean post processor`"
infrastructure, which enables modification of any bean definition as the container loads.
In this model, you set up some special bean definitions in your XML bean definition file
to configure the auto-proxy infrastructure. This lets you declare the targets
eligible for auto-proxying. You need not use `ProxyFactoryBean`.
There are two ways to do this:
* By using an auto-proxy creator that refers to specific beans in the current context.
* A special case of auto-proxy creation that deserves to be considered separately:
auto-proxy creation driven by source-level metadata attributes.
[[aop-autoproxy-choices]]
== Auto-proxy Bean Definitions
This section covers the auto-proxy creators provided by the
`org.springframework.aop.framework.autoproxy` package.
[[aop-api-autoproxy]]
=== `BeanNameAutoProxyCreator`
The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically creates
AOP proxies for beans with names that match literal values or wildcards. The following
example shows how to create a `BeanNameAutoProxyCreator` bean:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="jdk*,onlyJdk"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
----
As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list
of interceptors, to allow correct behavior for prototype advisors. Named "`interceptors`"
can be advisors or any advice type.
As with auto-proxying in general, the main point of using `BeanNameAutoProxyCreator` is
to apply the same configuration consistently to multiple objects, with minimal volume of
configuration. It is a popular choice for applying declarative transactions to multiple
objects.
Bean definitions whose names match, such as `jdkMyBean` and `onlyJdk` in the preceding
example, are plain old bean definitions with the target class. An AOP proxy is
automatically created by the `BeanNameAutoProxyCreator`. The same advice is applied
to all matching beans. Note that, if advisors are used (rather than the interceptor in
the preceding example), the pointcuts may apply differently to different beans.
[[aop-api-autoproxy-default]]
=== `DefaultAdvisorAutoProxyCreator`
A more general and extremely powerful auto-proxy creator is
`DefaultAdvisorAutoProxyCreator`. This automagically applies eligible advisors in the
current context, without the need to include specific bean names in the auto-proxy
advisor's bean definition. It offers the same merit of consistent configuration and
avoidance of duplication as `BeanNameAutoProxyCreator`.
Using this mechanism involves:
* Specifying a `DefaultAdvisorAutoProxyCreator` bean definition.
* Specifying any number of advisors in the same or related contexts. Note that these
must be advisors, not interceptors or other advice. This is necessary,
because there must be a pointcut to evaluate, to check the eligibility of each advice
to candidate bean definitions.
The `DefaultAdvisorAutoProxyCreator` automatically evaluates the pointcut contained
in each advisor, to see what (if any) advice it should apply to each business object
(such as `businessObject1` and `businessObject2` in the example).
This means that any number of advisors can be applied automatically to each business
object. If no pointcut in any of the advisors matches any method in a business object,
the object is not proxied. As bean definitions are added for new business objects,
they are automatically proxied if necessary.
Auto-proxying in general has the advantage of making it impossible for callers or
dependencies to obtain an un-advised object. Calling `getBean("businessObject1")` on this
`ApplicationContext` returns an AOP proxy, not the target business object. (The "`inner
bean`" idiom shown earlier also offers this benefit.)
The following example creates a `DefaultAdvisorAutoProxyCreator` bean and the other
elements discussed in this section:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
----
The `DefaultAdvisorAutoProxyCreator` is very useful if you want to apply the same advice
consistently to many business objects. Once the infrastructure definitions are in place,
you can add new business objects without including specific proxy configuration.
You can also easily drop in additional aspects (for example, tracing or
performance monitoring aspects) with minimal change to configuration.
The `DefaultAdvisorAutoProxyCreator` offers support for filtering (by using a naming
convention so that only certain advisors are evaluated, which allows the use of multiple,
differently configured, AdvisorAutoProxyCreators in the same factory) and ordering.
Advisors can implement the `org.springframework.core.Ordered` interface to ensure
correct ordering if this is an issue. The `TransactionAttributeSourceAdvisor` used in the
preceding example has a configurable order value. The default setting is unordered.
@@ -0,0 +1,71 @@
[[aop-concise-proxy]]
= Concise Proxy Definitions
Especially when defining transactional proxies, you may end up with many similar proxy
definitions. The use of parent and child bean definitions, along with inner bean
definitions, can result in much cleaner and more concise proxy definitions.
First, we create a parent, template, bean definition for the proxy, as follows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
----
This is never instantiated itself, so it can actually be incomplete. Then, each proxy
that needs to be created is a child bean definition, which wraps the target of the
proxy as an inner bean definition, since the target is never used on its own anyway.
The following example shows such a child bean:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="myService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl">
</bean>
</property>
</bean>
----
You can override properties from the parent template. In the following example,
we override the transaction propagation settings:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="mySpecialService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MySpecialServiceImpl">
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="store*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
----
Note that in the parent bean example, we explicitly marked the parent bean definition as
being abstract by setting the `abstract` attribute to `true`, as described
xref:core/beans/child-bean-definitions.adoc[previously], so that it may not actually ever be
instantiated. Application contexts (but not simple bean factories), by default,
pre-instantiate all singletons. Therefore, it is important (at least for singleton beans)
that, if you have a (parent) bean definition that you intend to use only as a template,
and this definition specifies a class, you must make sure to set the `abstract`
attribute to `true`. Otherwise, the application context actually tries to
pre-instantiate it.
@@ -0,0 +1,16 @@
[[aop-extensibility]]
= Defining New Advice Types
:page-section-summary-toc: 1
Spring AOP is designed to be extensible. While the interception implementation strategy
is presently used internally, it is possible to support arbitrary advice types in
addition to the interception around advice, before, throws advice, and
after returning advice.
The `org.springframework.aop.framework.adapter` package is an SPI package that lets
support for new custom advice types be added without changing the core framework.
The only constraint on a custom `Advice` type is that it must implement the
`org.aopalliance.aop.Advice` marker interface.
See the {api-spring-framework}/aop/framework/adapter/package-summary.html[`org.springframework.aop.framework.adapter`]
javadoc for further information.
@@ -0,0 +1,329 @@
[[aop-pfb]]
= Using the `ProxyFactoryBean` to Create AOP Proxies
If you use the Spring IoC container (an `ApplicationContext` or `BeanFactory`) for your
business objects (and you should be!), you want to use one of Spring's AOP
`FactoryBean` implementations. (Remember that a factory bean introduces a layer of indirection, letting
it create objects of a different type.)
NOTE: The Spring AOP support also uses factory beans under the covers.
The basic way to create an AOP proxy in Spring is to use the
`org.springframework.aop.framework.ProxyFactoryBean`. This gives complete control over
the pointcuts, any advice that applies, and their ordering. However, there are simpler
options that are preferable if you do not need such control.
[[aop-pfb-1]]
== Basics
The `ProxyFactoryBean`, like other Spring `FactoryBean` implementations, introduces a
level of indirection. If you define a `ProxyFactoryBean` named `foo`, objects that
reference `foo` do not see the `ProxyFactoryBean` instance itself but an object
created by the implementation of the `getObject()` method in the `ProxyFactoryBean` . This
method creates an AOP proxy that wraps a target object.
One of the most important benefits of using a `ProxyFactoryBean` or another IoC-aware
class to create AOP proxies is that advice and pointcuts can also be
managed by IoC. This is a powerful feature, enabling certain approaches that are hard to
achieve with other AOP frameworks. For example, an advice may itself reference
application objects (besides the target, which should be available in any AOP
framework), benefiting from all the pluggability provided by Dependency Injection.
[[aop-pfb-2]]
== JavaBean Properties
In common with most `FactoryBean` implementations provided with Spring, the
`ProxyFactoryBean` class is itself a JavaBean. Its properties are used to:
* Specify the target you want to proxy.
* Specify whether to use CGLIB (described later and see also xref:core/aop-api/pfb.adoc#aop-pfb-proxy-types[JDK- and CGLIB-based proxies]).
Some key properties are inherited from `org.springframework.aop.framework.ProxyConfig`
(the superclass for all AOP proxy factories in Spring). These key properties include
the following:
* `proxyTargetClass`: `true` if the target class is to be proxied, rather than the
target class's interfaces. If this property value is set to `true`, then CGLIB proxies
are created (but see also xref:core/aop-api/pfb.adoc#aop-pfb-proxy-types[JDK- and CGLIB-based proxies]).
* `optimize`: Controls whether or not aggressive optimizations are applied to proxies
created through CGLIB. You should not blithely use this setting unless you fully
understand how the relevant AOP proxy handles optimization. This is currently used
only for CGLIB proxies. It has no effect with JDK dynamic proxies.
* `frozen`: If a proxy configuration is `frozen`, changes to the configuration are
no longer allowed. This is useful both as a slight optimization and for those cases
when you do not want callers to be able to manipulate the proxy (through the `Advised`
interface) after the proxy has been created. The default value of this property is
`false`, so changes (such as adding additional advice) are allowed.
* `exposeProxy`: Determines whether or not the current proxy should be exposed in a
`ThreadLocal` so that it can be accessed by the target. If a target needs to obtain
the proxy and the `exposeProxy` property is set to `true`, the target can use the
`AopContext.currentProxy()` method.
Other properties specific to `ProxyFactoryBean` include the following:
* `proxyInterfaces`: An array of `String` interface names. If this is not supplied, a CGLIB
proxy for the target class is used (but see also xref:core/aop-api/pfb.adoc#aop-pfb-proxy-types[JDK- and CGLIB-based proxies]).
* `interceptorNames`: A `String` array of `Advisor`, interceptor, or other advice names to
apply. Ordering is significant, on a first come-first served basis. That is to say
that the first interceptor in the list is the first to be able to intercept the
invocation.
+
The names are bean names in the current factory, including bean names from ancestor
factories. You cannot mention bean references here, since doing so results in the
`ProxyFactoryBean` ignoring the singleton setting of the advice.
+
You can append an interceptor name with an asterisk (`*`). Doing so results in the
application of all advisor beans with names that start with the part before the asterisk
to be applied. You can find an example of using this feature in xref:core/aop-api/pfb.adoc#aop-global-advisors[Using "`Global`" Advisors].
* singleton: Whether or not the factory should return a single object, no matter how
often the `getObject()` method is called. Several `FactoryBean` implementations offer
such a method. The default value is `true`. If you want to use stateful advice - for
example, for stateful mixins - use prototype advice along with a singleton value of
`false`.
[[aop-pfb-proxy-types]]
== JDK- and CGLIB-based proxies
This section serves as the definitive documentation on how the `ProxyFactoryBean`
chooses to create either a JDK-based proxy or a CGLIB-based proxy for a particular target
object (which is to be proxied).
NOTE: The behavior of the `ProxyFactoryBean` with regard to creating JDK- or CGLIB-based
proxies changed between versions 1.2.x and 2.0 of Spring. The `ProxyFactoryBean` now
exhibits similar semantics with regard to auto-detecting interfaces as those of the
`TransactionProxyFactoryBean` class.
If the class of a target object that is to be proxied (hereafter simply referred to as
the target class) does not implement any interfaces, a CGLIB-based proxy is
created. This is the easiest scenario, because JDK proxies are interface-based, and no
interfaces means JDK proxying is not even possible. You can plug in the target bean
and specify the list of interceptors by setting the `interceptorNames` property. Note that a
CGLIB-based proxy is created even if the `proxyTargetClass` property of the
`ProxyFactoryBean` has been set to `false`. (Doing so makes no sense and is best
removed from the bean definition, because it is, at best, redundant, and, at worst
confusing.)
If the target class implements one (or more) interfaces, the type of proxy that is
created depends on the configuration of the `ProxyFactoryBean`.
If the `proxyTargetClass` property of the `ProxyFactoryBean` has been set to `true`,
a CGLIB-based proxy is created. This makes sense and is in keeping with the
principle of least surprise. Even if the `proxyInterfaces` property of the
`ProxyFactoryBean` has been set to one or more fully qualified interface names, the fact
that the `proxyTargetClass` property is set to `true` causes CGLIB-based
proxying to be in effect.
If the `proxyInterfaces` property of the `ProxyFactoryBean` has been set to one or more
fully qualified interface names, a JDK-based proxy is created. The created
proxy implements all of the interfaces that were specified in the `proxyInterfaces`
property. If the target class happens to implement a whole lot more interfaces than
those specified in the `proxyInterfaces` property, that is all well and good, but those
additional interfaces are not implemented by the returned proxy.
If the `proxyInterfaces` property of the `ProxyFactoryBean` has not been set, but
the target class does implement one (or more) interfaces, the
`ProxyFactoryBean` auto-detects the fact that the target class does actually
implement at least one interface, and a JDK-based proxy is created. The interfaces
that are actually proxied are all of the interfaces that the target class
implements. In effect, this is the same as supplying a list of each and every
interface that the target class implements to the `proxyInterfaces` property. However,
it is significantly less work and less prone to typographical errors.
[[aop-api-proxying-intf]]
== Proxying Interfaces
Consider a simple example of `ProxyFactoryBean` in action. This example involves:
* A target bean that is proxied. This is the `personTarget` bean definition in
the example.
* An `Advisor` and an `Interceptor` used to provide advice.
* An AOP proxy bean definition to specify the target object (the `personTarget` bean),
the interfaces to proxy, and the advice to apply.
The following listing shows the example:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="personTarget" class="com.mycompany.PersonImpl">
<property name="name" value="Tony"/>
<property name="age" value="51"/>
</bean>
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.mycompany.Person"/>
<property name="target" ref="personTarget"/>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
----
Note that the `interceptorNames` property takes a list of `String`, which holds the bean names of the
interceptors or advisors in the current factory. You can use advisors, interceptors, before, after
returning, and throws advice objects. The ordering of advisors is significant.
NOTE: You might be wondering why the list does not hold bean references. The reason for this is
that, if the singleton property of the `ProxyFactoryBean` is set to `false`, it must be able to
return independent proxy instances. If any of the advisors is itself a prototype, an
independent instance would need to be returned, so it is necessary to be able to obtain
an instance of the prototype from the factory. Holding a reference is not sufficient.
The `person` bean definition shown earlier can be used in place of a `Person` implementation, as
follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
Person person = (Person) factory.getBean("person");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val person = factory.getBean("person") as Person;
----
======
Other beans in the same IoC context can express a strongly typed dependency on it, as
with an ordinary Java object. The following example shows how to do so:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="personUser" class="com.mycompany.PersonUser">
<property name="person"><ref bean="person"/></property>
</bean>
----
The `PersonUser` class in this example exposes a property of type `Person`. As far as
it is concerned, the AOP proxy can be used transparently in place of a "`real`" person
implementation. However, its class would be a dynamic proxy class. It would be possible
to cast it to the `Advised` interface (discussed later).
You can conceal the distinction between target and proxy by using an anonymous
inner bean. Only the `ProxyFactoryBean` definition is different. The
advice is included only for completeness. The following example shows how to use an
anonymous inner bean:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.mycompany.Person"/>
<!-- Use inner bean, not local reference to target -->
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name" value="Tony"/>
<property name="age" value="51"/>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
----
Using an anonymous inner bean has the advantage that there is only one object of type `Person`. This is useful if we want
to prevent users of the application context from obtaining a reference to the un-advised
object or need to avoid any ambiguity with Spring IoC autowiring. There is also,
arguably, an advantage in that the `ProxyFactoryBean` definition is self-contained.
However, there are times when being able to obtain the un-advised target from the
factory might actually be an advantage (for example, in certain test scenarios).
[[aop-api-proxying-class]]
== Proxying Classes
What if you need to proxy a class, rather than one or more interfaces?
Imagine that in our earlier example, there was no `Person` interface. We needed to advise
a class called `Person` that did not implement any business interface. In this case, you
can configure Spring to use CGLIB proxying rather than dynamic proxies. To do so, set the
`proxyTargetClass` property on the `ProxyFactoryBean` shown earlier to `true`. While it is best to
program to interfaces rather than classes, the ability to advise classes that do not
implement interfaces can be useful when working with legacy code. (In general, Spring
is not prescriptive. While it makes it easy to apply good practices, it avoids forcing a
particular approach.)
If you want to, you can force the use of CGLIB in any case, even if you do have
interfaces.
CGLIB proxying works by generating a subclass of the target class at runtime. Spring
configures this generated subclass to delegate method calls to the original target. The
subclass is used to implement the Decorator pattern, weaving in the advice.
CGLIB proxying should generally be transparent to users. However, there are some issues
to consider:
* `final` classes cannot be proxied, because they cannot be extended.
* `final` methods cannot be advised, because they cannot be overridden.
* `private` methods cannot be advised, because they cannot be overridden.
NOTE: There is no need to add CGLIB to your classpath. CGLIB is repackaged and included
in the `spring-core` JAR. In other words, CGLIB-based AOP works "out of the box", as do
JDK dynamic proxies.
There is little performance difference between CGLIB proxies and dynamic proxies.
Performance should not be a decisive consideration in this case.
[[aop-global-advisors]]
== Using "`Global`" Advisors
By appending an asterisk to an interceptor name, all advisors with bean names that match
the part before the asterisk are added to the advisor chain. This can come in handy
if you need to add a standard set of "`global`" advisors. The following example defines
two global advisors:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<property name="interceptorNames">
<list>
<value>global*</value>
</list>
</property>
</bean>
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
----
@@ -0,0 +1,256 @@
[[aop-api-pointcuts]]
= Pointcut API in Spring
This section describes how Spring handles the crucial pointcut concept.
[[aop-api-concepts]]
== Concepts
Spring's pointcut model enables pointcut reuse independent of advice types. You can
target different advice with the same pointcut.
The `org.springframework.aop.Pointcut` interface is the central interface, used to
target advice to particular classes and methods. The complete interface follows:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
----
Splitting the `Pointcut` interface into two parts allows reuse of class and method
matching parts and fine-grained composition operations (such as performing a "`union`"
with another method matcher).
The `ClassFilter` interface is used to restrict the pointcut to a given set of target
classes. If the `matches()` method always returns true, all target classes are
matched. The following listing shows the `ClassFilter` interface definition:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface ClassFilter {
boolean matches(Class clazz);
}
----
The `MethodMatcher` interface is normally more important. The complete interface follows:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface MethodMatcher {
boolean matches(Method m, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method m, Class<?> targetClass, Object... args);
}
----
The `matches(Method, Class)` method is used to test whether this pointcut ever
matches a given method on a target class. This evaluation can be performed when an AOP
proxy is created to avoid the need for a test on every method invocation. If the
two-argument `matches` method returns `true` for a given method, and the `isRuntime()`
method for the MethodMatcher returns `true`, the three-argument matches method is
invoked on every method invocation. This lets a pointcut look at the arguments passed
to the method invocation immediately before the target advice starts.
Most `MethodMatcher` implementations are static, meaning that their `isRuntime()` method
returns `false`. In this case, the three-argument `matches` method is never invoked.
TIP: If possible, try to make pointcuts static, allowing the AOP framework to cache the
results of pointcut evaluation when an AOP proxy is created.
[[aop-api-pointcut-ops]]
== Operations on Pointcuts
Spring supports operations (notably, union and intersection) on pointcuts.
Union means the methods that either pointcut matches.
Intersection means the methods that both pointcuts match.
Union is usually more useful.
You can compose pointcuts by using the static methods in the
`org.springframework.aop.support.Pointcuts` class or by using the
`ComposablePointcut` class in the same package. However, using AspectJ pointcut
expressions is usually a simpler approach.
[[aop-api-pointcuts-aspectj]]
== AspectJ Expression Pointcuts
Since 2.0, the most important type of pointcut used by Spring is
`org.springframework.aop.aspectj.AspectJExpressionPointcut`. This is a pointcut that
uses an AspectJ-supplied library to parse an AspectJ pointcut expression string.
See the xref:core/aop.adoc[previous chapter] for a discussion of supported AspectJ pointcut primitives.
[[aop-api-pointcuts-impls]]
== Convenience Pointcut Implementations
Spring provides several convenient pointcut implementations. You can use some of them
directly; others are intended to be subclassed in application-specific pointcuts.
[[aop-api-pointcuts-static]]
=== Static Pointcuts
Static pointcuts are based on the method and the target class and cannot take into account
the method's arguments. Static pointcuts suffice -- and are best -- for most usages.
Spring can evaluate a static pointcut only once, when a method is first invoked.
After that, there is no need to evaluate the pointcut again with each method invocation.
The rest of this section describes some of the static pointcut implementations that are
included with Spring.
[[aop-api-pointcuts-regex]]
==== Regular Expression Pointcuts
One obvious way to specify static pointcuts is regular expressions. Several AOP
frameworks besides Spring make this possible.
`org.springframework.aop.support.JdkRegexpMethodPointcut` is a generic regular
expression pointcut that uses the regular expression support in the JDK.
With the `JdkRegexpMethodPointcut` class, you can provide a list of pattern strings.
If any of these is a match, the pointcut evaluates to `true`. (As a consequence,
the resulting pointcut is effectively the union of the specified patterns.)
The following example shows how to use `JdkRegexpMethodPointcut`:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="settersAndAbsquatulatePointcut"
class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
----
Spring provides a convenience class named `RegexpMethodPointcutAdvisor`, which lets us
also reference an `Advice` (remember that an `Advice` can be an interceptor, before advice,
throws advice, and others). Behind the scenes, Spring uses a `JdkRegexpMethodPointcut`.
Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both
pointcut and advice, as the following example shows:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="settersAndAbsquatulateAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="beanNameOfAopAllianceInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
----
You can use `RegexpMethodPointcutAdvisor` with any `Advice` type.
[[aop-api-pointcuts-attribute-driven]]
==== Attribute-driven Pointcuts
An important type of static pointcut is a metadata-driven pointcut. This uses the
values of metadata attributes (typically, source-level metadata).
[[aop-api-pointcuts-dynamic]]
=== Dynamic pointcuts
Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account
method arguments as well as static information. This means that they must be
evaluated with every method invocation and that the result cannot be cached, as arguments will
vary.
The main example is the `control flow` pointcut.
[[aop-api-pointcuts-cflow]]
==== Control Flow Pointcuts
Spring control flow pointcuts are conceptually similar to AspectJ `cflow` pointcuts,
although less powerful. (There is currently no way to specify that a pointcut runs
below a join point matched by another pointcut.) A control flow pointcut matches the
current call stack. For example, it might fire if the join point was invoked by a method
in the `com.mycompany.web` package or by the `SomeCaller` class. Control flow pointcuts
are specified by using the `org.springframework.aop.support.ControlFlowPointcut` class.
NOTE: Control flow pointcuts are significantly more expensive to evaluate at runtime than even
other dynamic pointcuts. In Java 1.4, the cost is about five times that of other dynamic
pointcuts.
[[aop-api-pointcuts-superclasses]]
== Pointcut Superclasses
Spring provides useful pointcut superclasses to help you to implement your own pointcuts.
Because static pointcuts are most useful, you should probably subclass
`StaticMethodMatcherPointcut`. This requires implementing only one
abstract method (although you can override other methods to customize behavior). The
following example shows how to subclass `StaticMethodMatcherPointcut`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
class TestStaticPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method m, Class targetClass) {
// return true if custom criteria match
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class TestStaticPointcut : StaticMethodMatcherPointcut() {
override fun matches(method: Method, targetClass: Class<*>): Boolean {
// return true if custom criteria match
}
}
----
======
There are also superclasses for dynamic pointcuts.
You can use custom pointcuts with any advice type.
[[aop-api-pointcuts-custom]]
== Custom Pointcuts
Because pointcuts in Spring AOP are Java classes rather than language features (as in
AspectJ), you can declare custom pointcuts, whether static or dynamic. Custom
pointcuts in Spring can be arbitrarily complex. However, we recommend using the AspectJ pointcut
expression language, if you can.
NOTE: Later versions of Spring may offer support for "`semantic pointcuts`" as offered by JAC --
for example, "`all methods that change instance variables in the target object.`"
@@ -0,0 +1,54 @@
[[aop-prog]]
= Creating AOP Proxies Programmatically with the `ProxyFactory`
It is easy to create AOP proxies programmatically with Spring. This lets you use
Spring AOP without dependency on Spring IoC.
The interfaces implemented by the target object are
automatically proxied. The following listing shows creation of a proxy for a target object, with one
interceptor and one advisor:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val factory = ProxyFactory(myBusinessInterfaceImpl)
factory.addAdvice(myMethodInterceptor)
factory.addAdvisor(myAdvisor)
val tb = factory.proxy as MyBusinessInterface
----
======
The first step is to construct an object of type
`org.springframework.aop.framework.ProxyFactory`. You can create this with a target
object, as in the preceding example, or specify the interfaces to be proxied in an alternate
constructor.
You can add advice (with interceptors as a specialized kind of advice), advisors, or both
and manipulate them for the life of the `ProxyFactory`. If you add an
`IntroductionInterceptionAroundAdvisor`, you can cause the proxy to implement additional
interfaces.
There are also convenience methods on `ProxyFactory` (inherited from `AdvisedSupport`)
that let you add other advice types, such as before and throws advice.
`AdvisedSupport` is the superclass of both `ProxyFactory` and `ProxyFactoryBean`.
TIP: Integrating AOP proxy creation with the IoC framework is best practice in most
applications. We recommend that you externalize configuration from Java code with AOP,
as you should in general.
@@ -0,0 +1,232 @@
[[aop-targetsource]]
= Using `TargetSource` Implementations
Spring offers the concept of a `TargetSource`, expressed in the
`org.springframework.aop.TargetSource` interface. This interface is responsible for
returning the "`target object`" that implements the join point. The `TargetSource`
implementation is asked for a target instance each time the AOP proxy handles a method
invocation.
Developers who use Spring AOP do not normally need to work directly with `TargetSource` implementations, but
this provides a powerful means of supporting pooling, hot swappable, and other
sophisticated targets. For example, a pooling `TargetSource` can return a different target
instance for each invocation, by using a pool to manage instances.
If you do not specify a `TargetSource`, a default implementation is used to wrap a
local object. The same target is returned for each invocation (as you would expect).
The rest of this section describes the standard target sources provided with Spring and how you can use them.
TIP: When using a custom target source, your target will usually need to be a prototype
rather than a singleton bean definition. This allows Spring to create a new target
instance when required.
[[aop-ts-swap]]
== Hot-swappable Target Sources
The `org.springframework.aop.target.HotSwappableTargetSource` exists to let the target
of an AOP proxy be switched while letting callers keep their references to it.
Changing the target source's target takes effect immediately. The
`HotSwappableTargetSource` is thread-safe.
You can change the target by using the `swap()` method on HotSwappableTargetSource, as the follow example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
val oldTarget = swapper.swap(newTarget)
----
======
The following example shows the required XML definitions:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="initialTarget" class="mycompany.OldTarget"/>
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="initialTarget"/>
</bean>
<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="swapper"/>
</bean>
----
The preceding `swap()` call changes the target of the swappable bean. Clients that hold a
reference to that bean are unaware of the change but immediately start hitting
the new target.
Although this example does not add any advice (it is not necessary to add advice to
use a `TargetSource`), any `TargetSource` can be used in conjunction with
arbitrary advice.
[[aop-ts-pool]]
== Pooling Target Sources
Using a pooling target source provides a similar programming model to stateless session
EJBs, in which a pool of identical instances is maintained, with method invocations
going to free objects in the pool.
A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can
be applied to any POJO. As with Spring in general, this service can be applied in a
non-invasive way.
Spring provides support for Commons Pool 2.2, which provides a
fairly efficient pooling implementation. You need the `commons-pool` Jar on your
application's classpath to use this feature. You can also subclass
`org.springframework.aop.target.AbstractPoolingTargetSource` to support any other
pooling API.
NOTE: Commons Pool 1.5+ is also supported but is deprecated as of Spring Framework 4.2.
The following listing shows an example configuration:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject"
scope="prototype">
... properties omitted
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPool2TargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
<property name="maxSize" value="25"/>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="poolTargetSource"/>
<property name="interceptorNames" value="myInterceptor"/>
</bean>
----
Note that the target object (`businessObjectTarget` in the preceding example) must be a
prototype. This lets the `PoolingTargetSource` implementation create new instances
of the target to grow the pool as necessary. See the {api-spring-framework}/aop/target/AbstractPoolingTargetSource.html[javadoc of
`AbstractPoolingTargetSource`] and the concrete subclass you wish to use for information
about its properties. `maxSize` is the most basic and is always guaranteed to be present.
In this case, `myInterceptor` is the name of an interceptor that would need to be
defined in the same IoC context. However, you need not specify interceptors to
use pooling. If you want only pooling and no other advice, do not set the
`interceptorNames` property at all.
You can configure Spring to be able to cast any pooled object to the
`org.springframework.aop.target.PoolingConfig` interface, which exposes information
about the configuration and current size of the pool through an introduction. You
need to define an advisor similar to the following:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="poolTargetSource"/>
<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>
----
This advisor is obtained by calling a convenience method on the
`AbstractPoolingTargetSource` class, hence the use of `MethodInvokingFactoryBean`. This
advisor's name (`poolConfigAdvisor`, here) must be in the list of interceptors names in
the `ProxyFactoryBean` that exposes the pooled object.
The cast is defined as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
System.out.println("Max pool size is " + conf.getMaxSize());
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val conf = beanFactory.getBean("businessObject") as PoolingConfig
println("Max pool size is " + conf.maxSize)
----
======
NOTE: Pooling stateless service objects is not usually necessary. We do not believe it should
be the default choice, as most stateless objects are naturally thread-safe, and instance
pooling is problematic if resources are cached.
Simpler pooling is available by using auto-proxying. You can set the `TargetSource` implementations
used by any auto-proxy creator.
[[aop-ts-prototype]]
== Prototype Target Sources
Setting up a "`prototype`" target source is similar to setting up a pooling `TargetSource`. In this
case, a new instance of the target is created on every method invocation. Although
the cost of creating a new object is not high in a modern JVM, the cost of wiring up the
new object (satisfying its IoC dependencies) may be more expensive. Thus, you should not
use this approach without very good reason.
To do this, you could modify the `poolTargetSource` definition shown earlier as follows
(we also changed the name, for clarity):
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName" ref="businessObjectTarget"/>
</bean>
----
The only property is the name of the target bean. Inheritance is used in the
`TargetSource` implementations to ensure consistent naming. As with the pooling target
source, the target bean must be a prototype bean definition.
[[aop-ts-threadlocal]]
== `ThreadLocal` Target Sources
`ThreadLocal` target sources are useful if you need an object to be created for each
incoming request (per thread that is). The concept of a `ThreadLocal` provides a JDK-wide
facility to transparently store a resource alongside a thread. Setting up a
`ThreadLocalTargetSource` is pretty much the same as was explained for the other types
of target source, as the following example shows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
</bean>
----
NOTE: `ThreadLocal` instances come with serious issues (potentially resulting in memory leaks) when
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
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.
@@ -0,0 +1,38 @@
[[aop]]
= Aspect Oriented Programming with Spring
Aspect-oriented Programming (AOP) complements Object-oriented Programming (OOP) by
providing another way of thinking about program structure. The key unit of modularity
in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects
enable the modularization of concerns (such as transaction management) that cut across
multiple types and objects. (Such concerns are often termed "crosscutting" concerns
in AOP literature.)
One of the key components of Spring is the AOP framework. While the Spring IoC
container does not depend on AOP (meaning you do not need to use AOP if you don't want
to), AOP complements Spring IoC to provide a very capable middleware solution.
.Spring AOP with AspectJ pointcuts
****
Spring provides simple and powerful ways of writing custom aspects by using either a
xref:core/aop/schema.adoc[schema-based approach] or the xref:core/aop/ataspectj.adoc[@AspectJ annotation style].
Both of these styles offer fully typed advice and use of the AspectJ pointcut language
while still using Spring AOP for weaving.
This chapter discusses the schema- and @AspectJ-based AOP support.
The lower-level AOP support is discussed in xref:core/aop-api.adoc[the following chapter].
****
AOP is used in the Spring Framework to:
* Provide declarative enterprise services. The most important such service is
xref:data-access/transaction/declarative.adoc[declarative transaction management].
* Let users implement custom aspects, complementing their use of OOP with AOP.
NOTE: If you are interested only in generic declarative services or other pre-packaged
declarative middleware services such as pooling, you do not need to work directly with
Spring AOP, and can skip most of this chapter.
@@ -0,0 +1,59 @@
[[aop-aspectj-programmatic]]
= Programmatic Creation of @AspectJ Proxies
In addition to declaring aspects in your configuration by using either `<aop:config>`
or `<aop:aspectj-autoproxy>`, it is also possible to programmatically create proxies
that advise target objects. For the full details of Spring's AOP API, see the
xref:core/aop-api.adoc[next chapter]. Here, we want to focus on the ability to automatically
create proxies by using @AspectJ aspects.
You can use the `org.springframework.aop.aspectj.annotation.AspectJProxyFactory` class
to create a proxy for a target object that is advised by one or more @AspectJ aspects.
The basic usage for this class is very simple, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied
// must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
// create a factory that can generate a proxy for the given target object
val factory = AspectJProxyFactory(targetObject)
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager::class.java)
// you can also add existing aspect instances, the type of the object supplied
// must be an @AspectJ aspect
factory.addAspect(usageTracker)
// now get the proxy object...
val proxy = factory.getProxy<Any>()
----
======
See the {api-spring-framework}/aop/aspectj/annotation/AspectJProxyFactory.html[javadoc] for more information.
@@ -0,0 +1,16 @@
[[aop-ataspectj]]
= @AspectJ support
:page-section-summary-toc: 1
@AspectJ refers to a style of declaring aspects as regular Java classes annotated with
annotations. The @AspectJ style was introduced by the
https://www.eclipse.org/aspectj[AspectJ project] as part of the AspectJ 5 release. Spring
interprets the same annotations as AspectJ 5, using a library supplied by AspectJ
for pointcut parsing and matching. The AOP runtime is still pure Spring AOP, though, and
there is no dependency on the AspectJ compiler or weaver.
NOTE: Using the AspectJ compiler and weaver enables use of the full AspectJ language and
is discussed in xref:core/aop/using-aspectj.adoc[Using AspectJ with Spring Applications].
@@ -0,0 +1,946 @@
[[aop-advice]]
= Declaring Advice
Advice is associated with a pointcut expression and runs before, after, or around method
executions matched by the pointcut. The pointcut expression may be either an _inline
pointcut_ or a reference to a xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[_named pointcut_].
[[aop-advice-before]]
== Before Advice
You can declare before advice in an aspect by using the `@Before` annotation.
The following example uses an inline pointcut expression.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("execution(* com.xyz.dao.*.*(..))")
fun doAccessCheck() {
// ...
}
}
----
======
If we use a xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[named pointcut], we can rewrite the preceding example
as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("com.xyz.CommonPointcuts.dataAccessOperation()")
fun doAccessCheck() {
// ...
}
}
----
======
[[aop-advice-after-returning]]
== After Returning Advice
After returning advice runs when a matched method execution returns normally.
You can declare it by using the `@AfterReturning` annotation.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("execution(* com.xyz.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning("execution(* com.xyz.dao.*.*(..))")
fun doAccessCheck() {
// ...
}
}
----
======
NOTE: You can have multiple advice declarations (and other members as well),
all inside the same aspect. We show only a single advice declaration in these
examples to focus the effect of each one.
Sometimes, you need access in the advice body to the actual value that was returned.
You can use the form of `@AfterReturning` that binds the return value to get that
access, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="execution(* com.xyz.dao.*.*(..))",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning(
pointcut = "execution(* com.xyz.dao.*.*(..))",
returning = "retVal")
fun doAccessCheck(retVal: Any?) {
// ...
}
}
----
======
The name used in the `returning` attribute must correspond to the name of a parameter
in the advice method. When a method execution returns, the return value is passed to
the advice method as the corresponding argument value. A `returning` clause also
restricts matching to only those method executions that return a value of the
specified type (in this case, `Object`, which matches any return value).
Please note that it is not possible to return a totally different reference when
using after returning advice.
[[aop-advice-after-throwing]]
== After Throwing Advice
After throwing advice runs when a matched method execution exits by throwing an
exception. You can declare it by using the `@AfterThrowing` annotation, as the
following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("execution(* com.xyz.dao.*.*(..))")
public void doRecoveryActions() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing("execution(* com.xyz.dao.*.*(..))")
fun doRecoveryActions() {
// ...
}
}
----
======
Often, you want the advice to run only when exceptions of a given type are thrown,
and you also often need access to the thrown exception in the advice body. You can
use the `throwing` attribute to both restrict matching (if desired -- use `Throwable`
as the exception type otherwise) and bind the thrown exception to an advice parameter.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="execution(* com.xyz.dao.*.*(..))",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing(
pointcut = "execution(* com.xyz.dao.*.*(..))",
throwing = "ex")
fun doRecoveryActions(ex: DataAccessException) {
// ...
}
}
----
======
The name used in the `throwing` attribute must correspond to the name of a parameter in
the advice method. When a method execution exits by throwing an exception, the exception
is passed to the advice method as the corresponding argument value. A `throwing` clause
also restricts matching to only those method executions that throw an exception of the
specified type (`DataAccessException`, in this case).
[NOTE]
====
Note that `@AfterThrowing` does not indicate a general exception handling callback.
Specifically, an `@AfterThrowing` advice method is only supposed to receive exceptions
from the join point (user-declared target method) itself but not from an accompanying
`@After`/`@AfterReturning` method.
====
[[aop-advice-after-finally]]
== After (Finally) Advice
After (finally) advice runs when a matched method execution exits. It is declared by
using the `@After` annotation. After advice must be prepared to handle both normal and
exception return conditions. It is typically used for releasing resources and similar
purposes. The following example shows how to use after finally advice:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("execution(* com.xyz.dao.*.*(..))")
public void doReleaseLock() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.After
@Aspect
class AfterFinallyExample {
@After("execution(* com.xyz.dao.*.*(..))")
fun doReleaseLock() {
// ...
}
}
----
======
[NOTE]
====
Note that `@After` advice in AspectJ is defined as "after finally advice", analogous
to a finally block in a try-catch statement. It will be invoked for any outcome,
normal return or exception thrown from the join point (user-declared target method),
in contrast to `@AfterReturning` which only applies to successful normal returns.
====
[[aop-ataspectj-around-advice]]
== Around Advice
The last kind of advice is _around_ advice. Around advice runs "around" a matched
method's execution. It has the opportunity to do work both before and after the method
runs and to determine when, how, and even if the method actually gets to run at all.
Around advice is often used if you need to share state before and after a method
execution in a thread-safe manner for example, starting and stopping a timer.
[TIP]
====
Always use the least powerful form of advice that meets your requirements.
For example, do not use _around_ advice if _before_ advice is sufficient for your needs.
====
Around advice is declared by annotating a method with the `@Around` annotation. The
method should declare `Object` as its return type, and the first parameter of the method
must be of type `ProceedingJoinPoint`. Within the body of the advice method, you must
invoke `proceed()` on the `ProceedingJoinPoint` in order for the underlying method to
run. Invoking `proceed()` without arguments will result in the caller's original
arguments being supplied to the underlying method when it is invoked. For advanced use
cases, there is an overloaded variant of the `proceed()` method which accepts an array of
arguments (`Object[]`). The values in the array will be used as the arguments to the
underlying method when it is invoked.
[NOTE]
====
The behavior of `proceed` when called with an `Object[]` is a little different than the
behavior of `proceed` for around advice compiled by the AspectJ compiler. For around
advice written using the traditional AspectJ language, the number of arguments passed to
`proceed` must match the number of arguments passed to the around advice (not the number
of arguments taken by the underlying join point), and the value passed to proceed in a
given argument position supplants the original value at the join point for the entity the
value was bound to (do not worry if this does not make sense right now).
The approach taken by Spring is simpler and a better match to its proxy-based,
execution-only semantics. You only need to be aware of this difference if you compile
`@AspectJ` aspects written for Spring and use `proceed` with arguments with the AspectJ
compiler and weaver. There is a way to write such aspects that is 100% compatible across
both Spring AOP and AspectJ, and this is discussed in the
xref:core/aop/ataspectj/advice.adoc#aop-ataspectj-advice-proceeding-with-the-call[following section on advice parameters].
====
The value returned by the around advice is the return value seen by the caller of the
method. For example, a simple caching aspect could return a value from a cache if it has
one or invoke `proceed()` (and return that value) if it does not. Note that `proceed`
may be invoked once, many times, or not at all within the body of the around advice. All
of these are legal.
WARNING: If you declare the return type of your around advice method as `void`, `null`
will always be returned to the caller, effectively ignoring the result of any invocation
of `proceed()`. It is therefore recommended that an around advice method declare a return
type of `Object`. The advice method should typically return the value returned from an
invocation of `proceed()`, even if the underlying method has a `void` return type.
However, the advice may optionally return a cached value, a wrapped value, or some other
value depending on the use case.
The following example shows how to use around advice:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("execution(* com.xyz..service.*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.ProceedingJoinPoint
@Aspect
class AroundExample {
@Around("execution(* com.xyz..service.*.*(..))")
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any? {
// start stopwatch
val retVal = pjp.proceed()
// stop stopwatch
return retVal
}
}
----
======
[[aop-ataspectj-advice-params]]
== Advice Parameters
Spring offers fully typed advice, meaning that you declare the parameters you need in the
advice signature (as we saw earlier for the returning and throwing examples) rather than
work with `Object[]` arrays all the time. We see how to make argument and other contextual
values available to the advice body later in this section. First, we take a look at how to
write generic advice that can find out about the method the advice is currently advising.
[[aop-ataspectj-advice-params-the-joinpoint]]
=== Access to the Current `JoinPoint`
Any advice method may declare, as its first parameter, a parameter of type
`org.aspectj.lang.JoinPoint`. Note that around advice is required to declare a first
parameter of type `ProceedingJoinPoint`, which is a subclass of `JoinPoint`.
The `JoinPoint` interface provides a number of useful methods:
* `getArgs()`: Returns the method arguments.
* `getThis()`: Returns the proxy object.
* `getTarget()`: Returns the target object.
* `getSignature()`: Returns a description of the method that is being advised.
* `toString()`: Prints a useful description of the method being advised.
See the https://www.eclipse.org/aspectj/doc/released/runtime-api/org/aspectj/lang/JoinPoint.html[javadoc] for more detail.
[[aop-ataspectj-advice-params-passing]]
=== Passing Parameters to Advice
We have already seen how to bind the returned value or exception value (using after
returning and after throwing advice). To make argument values available to the advice
body, you can use the binding form of `args`. If you use a parameter name in place of a
type name in an `args` expression, the value of the corresponding argument is passed as
the parameter value when the advice is invoked. An example should make this clearer.
Suppose you want to advise the execution of DAO operations that take an `Account`
object as the first parameter, and you need access to the account in the advice body.
You could write the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
public void validateAccount(Account account) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
fun validateAccount(account: Account) {
// ...
}
----
======
The `args(account,..)` part of the pointcut expression serves two purposes. First, it
restricts matching to only those method executions where the method takes at least one
parameter, and the argument passed to that parameter is an instance of `Account`.
Second, it makes the actual `Account` object available to the advice through the `account`
parameter.
Another way of writing this is to declare a pointcut that "provides" the `Account`
object value when it matches a join point, and then refer to the named pointcut
from the advice. This would look as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private fun accountDataAccessOperation(account: Account) {
}
@Before("accountDataAccessOperation(account)")
fun validateAccount(account: Account) {
// ...
}
----
======
See the AspectJ programming guide for more details.
The proxy object (`this`), target object (`target`), and annotations (`@within`,
`@target`, `@annotation`, and `@args`) can all be bound in a similar fashion. The next
set of examples shows how to match the execution of methods annotated with an
`@Auditable` annotation and extract the audit code:
The following shows the definition of the `@Auditable` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Auditable(val value: AuditCode)
----
======
The following shows the advice that matches the execution of `@Auditable` methods:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
fun audit(auditable: Auditable) {
val code = auditable.value()
// ...
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
======
[[aop-ataspectj-advice-params-generics]]
=== Advice Parameters and Generics
Spring AOP can handle generics used in class declarations and method parameters. Suppose
you have a generic type like the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public interface Sample<T> {
void sampleGenericMethod(T param);
void sampleGenericCollectionMethod(Collection<T> param);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
interface Sample<T> {
fun sampleGenericMethod(param: T)
fun sampleGenericCollectionMethod(param: Collection<T>)
}
----
======
You can restrict interception of method types to certain parameter types by
tying the advice parameter to the parameter type for which you want to intercept the method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
// Advice implementation
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
fun beforeSampleMethod(param: MyType) {
// Advice implementation
}
----
======
This approach does not work for generic collections. So you cannot define a
pointcut as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
// Advice implementation
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
fun beforeSampleMethod(param: Collection<MyType>) {
// Advice implementation
}
----
======
To make this work, we would have to inspect every element of the collection, which is not
reasonable, as we also cannot decide how to treat `null` values in general. To achieve
something similar to this, you have to type the parameter to `Collection<?>` and manually
check the type of the elements.
[[aop-ataspectj-advice-params-names]]
=== Determining Argument Names
Parameter binding in advice invocations relies on matching the names used in pointcut
expressions to the parameter names declared in advice and pointcut method signatures.
NOTE: This section uses the terms _argument_ and _parameter_ interchangeably, since
AspectJ APIs refer to parameter names as argument names.
Spring AOP uses the following `ParameterNameDiscoverer` implementations to determine
parameter names. Each discoverer will be given a chance to discover parameter names, and
the first successful discoverer wins. If none of the registered discoverers is capable
of determining parameter names, an exception will be thrown.
`AspectJAnnotationParameterNameDiscoverer` :: Uses parameter names that have been explicitly
specified by the user via the `argNames` attribute in the corresponding advice or
pointcut annotation. See xref:core/aop/ataspectj/advice.adoc#aop-ataspectj-advice-params-names-explicit[Explicit Argument Names] for details.
`KotlinReflectionParameterNameDiscoverer` :: Uses Kotlin reflection APIs to determine
parameter names. This discoverer is only used if such APIs are present on the classpath.
`StandardReflectionParameterNameDiscoverer` :: Uses the standard `java.lang.reflect.Parameter`
API to determine parameter names. Requires that code be compiled with the `-parameters`
flag for `javac`. Recommended approach on Java 8+.
`LocalVariableTableParameterNameDiscoverer` :: Analyzes the local variable table available
in the byte code of the advice class to determine parameter names from debug information.
Requires that code be compiled with debug symbols (`-g:vars` at a minimum). Deprecated
as of Spring Framework 6.0 for removal in Spring Framework 6.1 in favor of compiling
code with `-parameters`. Not supported in a GraalVM native image.
`AspectJAdviceParameterNameDiscoverer` :: Deduces parameter names from the pointcut
expression, `returning`, and `throwing` clauses. See the
{api-spring-framework}/aop/aspectj/AspectJAdviceParameterNameDiscoverer.html[javadoc]
for details on the algorithm used.
[[aop-ataspectj-advice-params-names-explicit]]
=== Explicit Argument Names
@AspectJ advice and pointcut annotations have an optional `argNames` attribute that you
can use to specify the argument names of the annotated method.
[TIP]
====
If an @AspectJ aspect has been compiled by the AspectJ compiler (`ajc`) even without
debug information, you do not need to add the `argNames` attribute, since the compiler
retains the needed information.
Similarly, if an @AspectJ aspect has been compiled with `javac` using the `-parameters`
flag, you do not need to add the `argNames` attribute, since the compiler retains the
needed information.
====
The following example shows how to use the `argNames` attribute:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
argNames = "bean,auditable") // <2>
public void audit(Object bean, Auditable auditable) {
AuditCode code = auditable.value();
// ... use code and bean
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
argNames = "bean,auditable") // <2>
fun audit(bean: Any, auditable: Auditable) {
val code = auditable.value()
// ... use code and bean
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names.
======
If the first parameter is of type `JoinPoint`, `ProceedingJoinPoint`, or
`JoinPoint.StaticPart`, you can omit the name of the parameter from the value of the
`argNames` attribute. For example, if you modify the preceding advice to receive the join
point object, the `argNames` attribute does not need to include it:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
argNames = "bean,auditable") // <2>
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
AuditCode code = auditable.value();
// ... use code, bean, and jp
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
argNames = "bean,auditable") // <2>
fun audit(jp: JoinPoint, bean: Any, auditable: Auditable) {
val code = auditable.value()
// ... use code, bean, and jp
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names.
======
The special treatment given to the first parameter of type `JoinPoint`,
`ProceedingJoinPoint`, or `JoinPoint.StaticPart` is particularly convenient for advice
methods that do not collect any other join point context. In such situations, you may
omit the `argNames` attribute. For example, the following advice does not need to declare
the `argNames` attribute:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
public void audit(JoinPoint jp) {
// ... use jp
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
fun audit(jp: JoinPoint) {
// ... use jp
}
----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
======
[[aop-ataspectj-advice-proceeding-with-the-call]]
=== Proceeding with Arguments
We remarked earlier that we would describe how to write a `proceed` call with
arguments that works consistently across Spring AOP and AspectJ. The solution is
to ensure that the advice signature binds each of the method parameters in order.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
"args(accountHolderNamePattern)") // <1>
public Object preProcessQueryPattern(ProceedingJoinPoint pjp,
String accountHolderNamePattern) throws Throwable {
String newPattern = preProcess(accountHolderNamePattern);
return pjp.proceed(new Object[] {newPattern});
}
----
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
"args(accountHolderNamePattern)") // <1>
fun preProcessQueryPattern(pjp: ProceedingJoinPoint,
accountHolderNamePattern: String): Any? {
val newPattern = preProcess(accountHolderNamePattern)
return pjp.proceed(arrayOf<Any>(newPattern))
}
----
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
======
In many cases, you do this binding anyway (as in the preceding example).
[[aop-ataspectj-advice-ordering]]
== Advice Ordering
What happens when multiple pieces of advice all want to run at the same join point?
Spring AOP follows the same precedence rules as AspectJ to determine the order of advice
execution. The highest precedence advice runs first "on the way in" (so, given two pieces
of before advice, the one with highest precedence runs first). "On the way out" from a
join point, the highest precedence advice runs last (so, given two pieces of after
advice, the one with the highest precedence will run second).
When two pieces of advice defined in different aspects both need to run at the same
join point, unless you specify otherwise, the order of execution is undefined. You can
control the order of execution by specifying precedence. This is done in the normal
Spring way by either implementing the `org.springframework.core.Ordered` interface in
the aspect class or annotating it with the `@Order` annotation. Given two aspects, the
aspect returning the lower value from `Ordered.getOrder()` (or the annotation value) has
the higher precedence.
[NOTE]
====
Each of the distinct advice types of a particular aspect is conceptually meant to apply
to the join point directly. As a consequence, an `@AfterThrowing` advice method is not
supposed to receive an exception from an accompanying `@After`/`@AfterReturning` method.
As of Spring Framework 5.2.7, advice methods defined in the same `@Aspect` class that
need to run at the same join point are assigned precedence based on their advice type in
the following order, from highest to lowest precedence: `@Around`, `@Before`, `@After`,
`@AfterReturning`, `@AfterThrowing`. Note, however, that an `@After` advice method will
effectively be invoked after any `@AfterReturning` or `@AfterThrowing` advice methods
in the same aspect, following AspectJ's "after finally advice" semantics for `@After`.
When two pieces of the same type of advice (for example, two `@After` advice methods)
defined in the same `@Aspect` class both need to run at the same join point, the ordering
is undefined (since there is no way to retrieve the source code declaration order through
reflection for javac-compiled classes). Consider collapsing such advice methods into one
advice method per join point in each `@Aspect` class or refactor the pieces of advice into
separate `@Aspect` classes that you can order at the aspect level via `Ordered` or `@Order`.
====
@@ -0,0 +1,61 @@
[[aop-aspectj-support]]
= Enabling @AspectJ Support
To use @AspectJ aspects in a Spring configuration, you need to enable Spring support for
configuring Spring AOP based on @AspectJ aspects and auto-proxying beans based on
whether or not they are advised by those aspects. By auto-proxying, we mean that, if Spring
determines that a bean is advised by one or more aspects, it automatically generates
a proxy for that bean to intercept method invocations and ensures that advice is run
as needed.
The @AspectJ support can be enabled with XML- or Java-style configuration. In either
case, you also need to ensure that AspectJ's `aspectjweaver.jar` library is on the
classpath of your application (version 1.9 or later). This library is available in the
`lib` directory of an AspectJ distribution or from the Maven Central repository.
[[aop-enable-aspectj-java]]
== Enabling @AspectJ Support with Java Configuration
To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy`
annotation, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Configuration
@EnableAspectJAutoProxy
class AppConfig
----
======
[[aop-enable-aspectj-xml]]
== Enabling @AspectJ Support with XML Configuration
To enable @AspectJ support with XML-based configuration, use the `aop:aspectj-autoproxy`
element, as the following example shows:
[source,xml,indent=0,subs="verbatim"]
----
<aop:aspectj-autoproxy/>
----
This assumes that you use schema support as described in
xref:core/appendix/xsd-schemas.adoc[XML Schema-based configuration].
See xref:core/appendix/xsd-schemas.adoc#aop[the AOP schema] for how to
import the tags in the `aop` namespace.
@@ -0,0 +1,68 @@
[[aop-at-aspectj]]
= Declaring an Aspect
With @AspectJ support enabled, any bean defined in your application context with a
class that is an @AspectJ aspect (has the `@Aspect` annotation) is automatically
detected by Spring and used to configure Spring AOP. The next two examples show the
minimal steps required for a not-very-useful aspect.
The first of the two examples shows a regular bean definition in the application context
that points to a bean class that is annotated with `@Aspect`:
[source,xml,indent=0,subs="verbatim"]
----
<bean id="myAspect" class="com.xyz.NotVeryUsefulAspect">
<!-- configure properties of the aspect here -->
</bean>
----
The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is
annotated with `@Aspect`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
----
package com.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
----
package com.xyz
import org.aspectj.lang.annotation.Aspect
@Aspect
class NotVeryUsefulAspect
----
======
Aspects (classes annotated with `@Aspect`) can have methods and fields, the same as any
other class. They can also contain pointcut, advice, and introduction (inter-type)
declarations.
.Autodetecting aspects through component scanning
NOTE: You can register aspect classes as regular beans in your Spring XML configuration,
via `@Bean` methods in `@Configuration` classes, or have Spring autodetect them through
classpath scanning -- the same as any other Spring-managed bean. However, note that the
`@Aspect` annotation is not sufficient for autodetection in the classpath. For that
purpose, you need to add a separate `@Component` annotation (or, alternatively, a custom
stereotype annotation that qualifies, as per the rules of Spring's component scanner).
.Advising aspects with other aspects?
NOTE: In Spring AOP, aspects themselves cannot be the targets of advice from other
aspects. The `@Aspect` annotation on a class marks it as an aspect and, hence, excludes
it from auto-proxying.
@@ -0,0 +1,183 @@
[[aop-ataspectj-example]]
= An AOP Example
Now that you have seen how all the constituent parts work, we can put them together to do
something useful.
The execution of business services can sometimes fail due to concurrency issues (for
example, a deadlock loser). If the operation is retried, it is likely to succeed
on the next try. For business services where it is appropriate to retry in such
conditions (idempotent operations that do not need to go back to the user for conflict
resolution), we want to transparently retry the operation to avoid the client seeing a
`PessimisticLockingFailureException`. This is a requirement that clearly cuts across
multiple services in the service layer and, hence, is ideal for implementing through an
aspect.
Because we want to retry the operation, we need to use around advice so that we can
call `proceed` multiple times. The following listing shows the basic aspect implementation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Aspect
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
@Around("com.xyz.CommonPointcuts.businessService()") // <1>
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
} while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
----
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Aspect
class ConcurrentOperationExecutor : Ordered {
private val DEFAULT_MAX_RETRIES = 2
private var maxRetries = DEFAULT_MAX_RETRIES
private var order = 1
fun setMaxRetries(maxRetries: Int) {
this.maxRetries = maxRetries
}
override fun getOrder(): Int {
return this.order
}
fun setOrder(order: Int) {
this.order = order
}
@Around("com.xyz.CommonPointcuts.businessService()") // <1>
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any? {
var numAttempts = 0
var lockFailureException: PessimisticLockingFailureException
do {
numAttempts++
try {
return pjp.proceed()
} catch (ex: PessimisticLockingFailureException) {
lockFailureException = ex
}
} while (numAttempts <= this.maxRetries)
throw lockFailureException
}
}
----
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
======
Note that the aspect implements the `Ordered` interface so that we can set the precedence of
the aspect higher than the transaction advice (we want a fresh transaction each time we
retry). The `maxRetries` and `order` properties are both configured by Spring. The
main action happens in the `doConcurrentOperation` around advice. Notice that, for the
moment, we apply the retry logic to each `businessService`. We try to proceed,
and if we fail with a `PessimisticLockingFailureException`, we try again, unless
we have exhausted all of our retry attempts.
The corresponding Spring configuration follows:
[source,xml,indent=0,subs="verbatim"]
----
<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor"
class="com.xyz.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
----
To refine the aspect so that it retries only idempotent operations, we might define the following
`Idempotent` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Retention(RetentionPolicy.RUNTIME)
// marker annotation
public @interface Idempotent {
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Retention(AnnotationRetention.RUNTIME)
// marker annotation
annotation class Idempotent
----
======
We can then use the annotation to annotate the implementation of service operations. The change
to the aspect to retry only idempotent operations involves refining the pointcut
expression so that only `@Idempotent` operations match, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any? {
// ...
}
----
======
@@ -0,0 +1,65 @@
[[aop-instantiation-models]]
= Aspect Instantiation Models
NOTE: This is an advanced topic. If you are just starting out with AOP, you can safely skip
it until later.
By default, there is a single instance of each aspect within the application
context. AspectJ calls this the singleton instantiation model. It is possible to define
aspects with alternate lifecycles. Spring supports AspectJ's `perthis`, `pertarget`, and
`pertypewithin` instantiation models; `percflow` and `percflowbelow` are not currently
supported.
You can declare a `perthis` aspect by specifying a `perthis` clause in the `@Aspect`
annotation. Consider the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
public class MyAspect {
private int someState;
@Before("execution(* com.xyz..service.*.*(..))")
public void recordServiceUsage() {
// ...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
class MyAspect {
private val someState: Int = 0
@Before("execution(* com.xyz..service.*.*(..))")
fun recordServiceUsage() {
// ...
}
}
----
======
In the preceding example, the effect of the `perthis` clause is that one aspect instance
is created for each unique service object that performs a business service (each unique
object bound to `this` at join points matched by the pointcut expression). The aspect
instance is created the first time that a method is invoked on the service object. The
aspect goes out of scope when the service object goes out of scope. Before the aspect
instance is created, none of the advice within it runs. As soon as the aspect instance
has been created, the advice declared within it runs at matched join points, but only
when the service object is the one with which this aspect is associated. See the AspectJ
Programming Guide for more information on `per` clauses.
The `pertarget` instantiation model works in exactly the same way as `perthis`, but it
creates one aspect instance for each unique target object at matched join points.
@@ -0,0 +1,79 @@
[[aop-introductions]]
= Introductions
Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare
that advised objects implement a given interface, and to provide an implementation of
that interface on behalf of those objects.
You can make an introduction by using the `@DeclareParents` annotation. This annotation
is used to declare that matching types have a new parent (hence the name). For example,
given an interface named `UsageTracked` and an implementation of that interface named
`DefaultUsageTracked`, the following aspect declares that all implementors of service
interfaces also implement the `UsageTracked` interface (e.g. for statistics via JMX):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Aspect
public class UsageTracking {
@DeclareParents(value="com.xyz.service.*+", defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;
@Before("execution(* com.xyz..service.*.*(..)) && this(usageTracked)")
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Aspect
class UsageTracking {
companion object {
@DeclareParents(value = "com.xyz.service.*+",
defaultImpl = DefaultUsageTracked::class)
lateinit var mixin: UsageTracked
}
@Before("execution(* com.xyz..service.*.*(..)) && this(usageTracked)")
fun recordUsage(usageTracked: UsageTracked) {
usageTracked.incrementUseCount()
}
}
----
======
The interface to be implemented is determined by the type of the annotated field. The
`value` attribute of the `@DeclareParents` annotation is an AspectJ type pattern. Any
bean of a matching type implements the `UsageTracked` interface. Note that, in the
before advice of the preceding example, service beans can be directly used as
implementations of the `UsageTracked` interface. If accessing a bean programmatically,
you would write the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
val usageTracked = context.getBean("myService", UsageTracked.class)
----
======
@@ -0,0 +1,586 @@
[[aop-pointcuts]]
= Declaring a Pointcut
Pointcuts determine join points of interest and thus enable us to control
when advice runs. Spring AOP only supports method execution join points for Spring
beans, so you can think of a pointcut as matching the execution of methods on Spring
beans. A pointcut declaration has two parts: a signature comprising a name and any
parameters and a pointcut expression that determines exactly which method
executions we are interested in. In the @AspectJ annotation-style of AOP, a pointcut
signature is provided by a regular method definition, and the pointcut expression is
indicated by using the `@Pointcut` annotation (the method serving as the pointcut signature
must have a `void` return type).
An example may help make this distinction between a pointcut signature and a pointcut
expression clear. The following example defines a pointcut named `anyOldTransfer` that
matches the execution of any method named `transfer`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Pointcut("execution(* transfer(..))") // the pointcut expression
private fun anyOldTransfer() {} // the pointcut signature
----
======
The pointcut expression that forms the value of the `@Pointcut` annotation is a regular
AspectJ pointcut expression. For a full discussion of AspectJ's pointcut language, see
the https://www.eclipse.org/aspectj/doc/released/progguide/index.html[AspectJ
Programming Guide] (and, for extensions, the
https://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html[AspectJ 5
Developer's Notebook]) or one of the books on AspectJ (such as _Eclipse AspectJ_, by Colyer
et al., or _AspectJ in Action_, by Ramnivas Laddad).
[[aop-pointcuts-designators]]
== Supported Pointcut Designators
Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut
expressions:
* `execution`: For matching method execution join points. This is the primary
pointcut designator to use when working with Spring AOP.
* `within`: Limits matching to join points within certain types (the execution
of a method declared within a matching type when using Spring AOP).
* `this`: Limits matching to join points (the execution of methods when using Spring
AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
* `target`: Limits matching to join points (the execution of methods when using
Spring AOP) where the target object (application object being proxied) is an instance
of the given type.
* `args`: Limits matching to join points (the execution of methods when using Spring
AOP) where the arguments are instances of the given types.
* `@target`: Limits matching to join points (the execution of methods when using
Spring AOP) where the class of the executing object has an annotation of the given type.
* `@args`: Limits matching to join points (the execution of methods when using Spring
AOP) where the runtime type of the actual arguments passed have annotations of the
given types.
* `@within`: Limits matching to join points within types that have the given
annotation (the execution of methods declared in types with the given annotation when
using Spring AOP).
* `@annotation`: Limits matching to join points where the subject of the join point
(the method being run in Spring AOP) has the given annotation.
.Other pointcut types
****
The full AspectJ pointcut language supports additional pointcut designators that are not
supported in Spring: `call`, `get`, `set`, `preinitialization`,
`staticinitialization`, `initialization`, `handler`, `adviceexecution`, `withincode`, `cflow`,
`cflowbelow`, `if`, `@this`, and `@withincode`. Use of these pointcut designators in pointcut
expressions interpreted by Spring AOP results in an `IllegalArgumentException` being
thrown.
The set of pointcut designators supported by Spring AOP may be extended in future
releases to support more of the AspectJ pointcut designators.
****
Because Spring AOP limits matching to only method execution join points, the preceding discussion
of the pointcut designators gives a narrower definition than you can find in the
AspectJ programming guide. In addition, AspectJ itself has type-based semantics and, at
an execution join point, both `this` and `target` refer to the same object: the
object executing the method. Spring AOP is a proxy-based system and differentiates
between the proxy object itself (which is bound to `this`) and the target object behind the
proxy (which is bound to `target`).
[NOTE]
====
Due to the proxy-based nature of Spring's AOP framework, calls within the target object
are, by definition, not intercepted. For JDK proxies, only public interface method
calls on the proxy can be intercepted. With CGLIB, public and protected method calls on
the proxy are intercepted (and even package-visible methods, if necessary). However,
common interactions through proxies should always be designed through public signatures.
Note that pointcut definitions are generally matched against any intercepted method.
If a pointcut is strictly meant to be public-only, even in a CGLIB proxy scenario with
potential non-public interactions through proxies, it needs to be defined accordingly.
If your interception needs include method calls or even constructors within the target
class, consider the use of Spring-driven xref:core/aop/using-aspectj.adoc#aop-aj-ltw[native AspectJ weaving] instead
of Spring's proxy-based AOP framework. This constitutes a different mode of AOP usage
with different characteristics, so be sure to make yourself familiar with weaving
before making a decision.
====
Spring AOP also supports an additional PCD named `bean`. This PCD lets you limit
the matching of join points to a particular named Spring bean or to a set of named
Spring beans (when using wildcards). The `bean` PCD has the following form:
[source,indent=0,subs="verbatim"]
----
bean(idOrNameOfBean)
----
The `idOrNameOfBean` token can be the name of any Spring bean. Limited wildcard
support that uses the `*` character is provided, so, if you establish some naming
conventions for your Spring beans, you can write a `bean` PCD expression
to select them. As is the case with other pointcut designators, the `bean` PCD can
be used with the `&&` (and), `||` (or), and `!` (negation) operators, too.
[NOTE]
====
The `bean` PCD is supported only in Spring AOP and not in
native AspectJ weaving. It is a Spring-specific extension to the standard PCDs that
AspectJ defines and is, therefore, not available for aspects declared in the `@Aspect` model.
The `bean` PCD operates at the instance level (building on the Spring bean name
concept) rather than at the type level only (to which weaving-based AOP is limited).
Instance-based pointcut designators are a special capability of Spring's
proxy-based AOP framework and its close integration with the Spring bean factory, where
it is natural and straightforward to identify specific beans by name.
====
[[aop-pointcuts-combining]]
== Combining Pointcut Expressions
You can combine pointcut expressions by using `&&,` `||` and `!`. You can also refer to
pointcut expressions by name. The following example shows three pointcut expressions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
----
package com.xyz;
public class Pointcuts {
@Pointcut("execution(public * *(..))")
public void publicMethod() {} // <1>
@Pointcut("within(com.xyz.trading..*)")
public void inTrading() {} // <2>
@Pointcut("publicMethod() && inTrading()")
public void tradingOperation() {} // <3>
}
----
<1> `publicMethod` matches if a method execution join point represents the execution
of any public method.
<2> `inTrading` matches if a method execution is in the trading module.
<3> `tradingOperation` matches if a method execution represents any public method in the
trading module.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
----
package com.xyz
class Pointcuts {
@Pointcut("execution(public * *(..))")
fun publicMethod() {} // <1>
@Pointcut("within(com.xyz.trading..*)")
fun inTrading() {} // <2>
@Pointcut("publicMethod() && inTrading()")
fun tradingOperation() {} // <3>
}
----
<1> `publicMethod` matches if a method execution join point represents the execution
of any public method.
<2> `inTrading` matches if a method execution is in the trading module.
<3> `tradingOperation` matches if a method execution represents any public method in the
trading module.
======
It is a best practice to build more complex pointcut expressions out of smaller _named
pointcuts_, as shown above. When referring to pointcuts by name, normal Java visibility
rules apply (you can see `private` pointcuts in the same type, `protected` pointcuts in
the hierarchy, `public` pointcuts anywhere, and so on). Visibility does not affect
pointcut matching.
[[aop-common-pointcuts]]
== Sharing Named Pointcut Definitions
When working with enterprise applications, developers often have the need to refer to
modules of the application and particular sets of operations from within several aspects.
We recommend defining a dedicated class that captures commonly used _named pointcut_
expressions for this purpose. Such a class typically resembles the following
`CommonPointcuts` example (though what you name the class is up to you):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
----
package com.xyz;
import org.aspectj.lang.annotation.Pointcut;
public class CommonPointcuts {
/**
* A join point is in the web layer if the method is defined
* in a type in the com.xyz.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.web..*)")
public void inWebLayer() {}
/**
* A join point is in the service layer if the method is defined
* in a type in the com.xyz.service package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.service..*)")
public void inServiceLayer() {}
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.dao..*)")
public void inDataAccessLayer() {}
/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz..service.*.*(..))")
public void businessService() {}
/**
* A data access operation is the execution of any method defined on a
* DAO interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.dao.*.*(..))")
public void dataAccessOperation() {}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
----
package com.xyz
import org.aspectj.lang.annotation.Pointcut
class CommonPointcuts {
/**
* A join point is in the web layer if the method is defined
* in a type in the com.xyz.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.web..*)")
fun inWebLayer() {}
/**
* A join point is in the service layer if the method is defined
* in a type in the com.xyz.service package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.service..*)")
fun inServiceLayer() {}
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.dao..*)")
fun inDataAccessLayer() {}
/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz..service.*.*(..))")
fun businessService() {}
/**
* A data access operation is the execution of any method defined on a
* DAO interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.dao.*.*(..))")
fun dataAccessOperation() {}
}
----
======
You can refer to the pointcuts defined in such a class anywhere you need a pointcut
expression by referencing the fully-qualified name of the class combined with the
`@Pointcut` method's name. For example, to make the service layer transactional, you
could write the following which references the
`com.xyz.CommonPointcuts.businessService()` _named pointcut_:
[source,xml,indent=0,subs="verbatim"]
----
<aop:config>
<aop:advisor
pointcut="com.xyz.CommonPointcuts.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
----
The `<aop:config>` and `<aop:advisor>` elements are discussed in xref:core/aop/schema.adoc[Schema-based AOP Support]. The
transaction elements are discussed in xref:data-access/transaction.adoc[Transaction Management].
[[aop-pointcuts-examples]]
== Examples
Spring AOP users are likely to use the `execution` pointcut designator the most often.
The format of an execution expression follows:
[literal,indent=0,subs="verbatim"]
----
execution(modifiers-pattern?
ret-type-pattern
declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
----
All parts except the returning type pattern (`ret-type-pattern` in the preceding snippet),
the name pattern, and the parameters pattern are optional. The returning type pattern determines
what the return type of the method must be in order for a join point to be matched.
`{asterisk}` is most frequently used as the returning type pattern. It matches any return
type. A fully-qualified type name matches only when the method returns the given
type. The name pattern matches the method name. You can use the `{asterisk}` wildcard as all or
part of a name pattern. If you specify a declaring type pattern,
include a trailing `.` to join it to the name pattern component.
The parameters pattern is slightly more complex: `()` matches a
method that takes no parameters, whereas `(..)` matches any number (zero or more) of parameters.
The `({asterisk})` pattern matches a method that takes one parameter of any type.
`(*,String)` matches a method that takes two parameters. The first can be of any type, while the
second must be a `String`. Consult the
https://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html[Language
Semantics] section of the AspectJ Programming Guide for more information.
The following examples show some common pointcut expressions:
* The execution of any public method:
+
[literal,indent=0,subs="verbatim"]
----
execution(public * *(..))
----
* The execution of any method with a name that begins with `set`:
+
[literal,indent=0,subs="verbatim"]
----
execution(* set*(..))
----
* The execution of any method defined by the `AccountService` interface:
+
[literal,indent=0,subs="verbatim"]
----
execution(* com.xyz.service.AccountService.*(..))
----
* The execution of any method defined in the `service` package:
+
[literal,indent=0,subs="verbatim"]
----
execution(* com.xyz.service.*.*(..))
----
* The execution of any method defined in the service package or one of its sub-packages:
+
[literal,indent=0,subs="verbatim"]
----
execution(* com.xyz.service..*.*(..))
----
* Any join point (method execution only in Spring AOP) within the service package:
+
[literal,indent=0,subs="verbatim"]
----
within(com.xyz.service.*)
----
* Any join point (method execution only in Spring AOP) within the service package or one of its
sub-packages:
+
[literal,indent=0,subs="verbatim"]
----
within(com.xyz.service..*)
----
* Any join point (method execution only in Spring AOP) where the proxy implements the
`AccountService` interface:
+
[literal,indent=0,subs="verbatim"]
----
this(com.xyz.service.AccountService)
----
+
NOTE: `this` is more commonly used in a binding form. See the section on xref:core/aop/ataspectj/advice.adoc[Declaring Advice]
for how to make the proxy object available in the advice body.
* Any join point (method execution only in Spring AOP) where the target object
implements the `AccountService` interface:
+
[literal,indent=0,subs="verbatim"]
----
target(com.xyz.service.AccountService)
----
+
NOTE: `target` is more commonly used in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section
for how to make the target object available in the advice body.
* Any join point (method execution only in Spring AOP) that takes a single parameter
and where the argument passed at runtime is `Serializable`:
+
[literal,indent=0,subs="verbatim"]
----
args(java.io.Serializable)
----
+
NOTE: `args` is more commonly used in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section
for how to make the method arguments available in the advice body.
+
Note that the pointcut given in this example is different from `execution(*
*(java.io.Serializable))`. The args version matches if the argument passed at runtime is
`Serializable`, and the execution version matches if the method signature declares a single
parameter of type `Serializable`.
* Any join point (method execution only in Spring AOP) where the target object has a
`@Transactional` annotation:
+
[literal,indent=0,subs="verbatim"]
----
@target(org.springframework.transaction.annotation.Transactional)
----
+
NOTE: You can also use `@target` in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section for
how to make the annotation object available in the advice body.
* Any join point (method execution only in Spring AOP) where the declared type of the
target object has an `@Transactional` annotation:
+
[literal,indent=0,subs="verbatim"]
----
@within(org.springframework.transaction.annotation.Transactional)
----
+
NOTE: You can also use `@within` in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section for
how to make the annotation object available in the advice body.
* Any join point (method execution only in Spring AOP) where the executing method has an
`@Transactional` annotation:
+
[literal,indent=0,subs="verbatim"]
----
@annotation(org.springframework.transaction.annotation.Transactional)
----
+
NOTE: You can also use `@annotation` in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section
for how to make the annotation object available in the advice body.
* Any join point (method execution only in Spring AOP) which takes a single parameter,
and where the runtime type of the argument passed has the `@Classified` annotation:
+
[literal,indent=0,subs="verbatim"]
----
@args(com.xyz.security.Classified)
----
+
NOTE: You can also use `@args` in a binding form. See the xref:core/aop/ataspectj/advice.adoc[Declaring Advice] section
how to make the annotation object(s) available in the advice body.
* Any join point (method execution only in Spring AOP) on a Spring bean named
`tradeService`:
+
[literal,indent=0,subs="verbatim"]
----
bean(tradeService)
----
* Any join point (method execution only in Spring AOP) on Spring beans having names that
match the wildcard expression `*Service`:
+
[literal,indent=0,subs="verbatim"]
----
bean(*Service)
----
[[writing-good-pointcuts]]
== Writing Good Pointcuts
During compilation, AspectJ processes pointcuts in order to optimize matching
performance. Examining code and determining if each join point matches (statically or
dynamically) a given pointcut is a costly process. (A dynamic match means the match
cannot be fully determined from static analysis and that a test is placed in the code to
determine if there is an actual match when the code is running). On first encountering a
pointcut declaration, AspectJ rewrites it into an optimal form for the matching
process. What does this mean? Basically, pointcuts are rewritten in DNF (Disjunctive
Normal Form) and the components of the pointcut are sorted such that those components
that are cheaper to evaluate are checked first. This means you do not have to worry
about understanding the performance of various pointcut designators and may supply them
in any order in a pointcut declaration.
However, AspectJ can work only with what it is told. For optimal performance of
matching, you should think about what you are trying to achieve and narrow the search
space for matches as much as possible in the definition. The existing designators
naturally fall into one of three groups: kinded, scoping, and contextual:
* Kinded designators select a particular kind of join point:
`execution`, `get`, `set`, `call`, and `handler`.
* Scoping designators select a group of join points of interest
(probably of many kinds): `within` and `withincode`
* Contextual designators match (and optionally bind) based on context:
`this`, `target`, and `@annotation`
A well written pointcut should include at least the first two types (kinded and
scoping). You can include the contextual designators to match based on
join point context or bind that context for use in the advice. Supplying only a
kinded designator or only a contextual designator works but could affect weaving
performance (time and memory used), due to extra processing and analysis. Scoping
designators are very fast to match, and using them means AspectJ can very quickly
dismiss groups of join points that should not be further processed. A good
pointcut should always include one if possible.
@@ -0,0 +1,113 @@
[[aop-choosing]]
= Choosing which AOP Declaration Style to Use
Once you have decided that an aspect is the best approach for implementing a given
requirement, how do you decide between using Spring AOP or AspectJ and between the
Aspect language (code) style, the @AspectJ annotation style, or the Spring XML style? These
decisions are influenced by a number of factors including application requirements,
development tools, and team familiarity with AOP.
[[aop-spring-or-aspectj]]
== Spring AOP or Full AspectJ?
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ, as
there is no requirement to introduce the AspectJ compiler / weaver into your development
and build processes. If you only need to advise the execution of operations on Spring
beans, Spring AOP is the right choice. If you need to advise objects not managed by
the Spring container (such as domain objects, typically), you need to use
AspectJ. You also need to use AspectJ if you wish to advise join points other than
simple method executions (for example, field get or set join points and so on).
When you use AspectJ, you have the choice of the AspectJ language syntax (also known as
the "code style") or the @AspectJ annotation style. If aspects play a large
role in your design, and you are able to use the https://www.eclipse.org/ajdt/[AspectJ
Development Tools (AJDT)] plugin for Eclipse, the AspectJ language syntax is the
preferred option. It is cleaner and simpler because the language was purposefully
designed for writing aspects. If you do not use Eclipse or have only a few aspects
that do not play a major role in your application, you may want to consider using
the @AspectJ style, sticking with regular Java compilation in your IDE, and adding
an aspect weaving phase to your build script.
[[aop-ataspectj-or-xml]]
== @AspectJ or XML for Spring AOP?
If you have chosen to use Spring AOP, you have a choice of @AspectJ or XML style.
There are various tradeoffs to consider.
The XML style may be most familiar to existing Spring users, and it is backed by genuine
POJOs. When using AOP as a tool to configure enterprise services, XML can be a good
choice (a good test is whether you consider the pointcut expression to be a part of your
configuration that you might want to change independently). With the XML style, it is
arguably clearer from your configuration which aspects are present in the system.
The XML style has two disadvantages. First, it does not fully encapsulate the
implementation of the requirement it addresses in a single place. The DRY principle says
that there should be a single, unambiguous, authoritative representation of any piece of
knowledge within a system. When using the XML style, the knowledge of how a requirement
is implemented is split across the declaration of the backing bean class and the XML in
the configuration file. When you use the @AspectJ style, this information is encapsulated
in a single module: the aspect. Secondly, the XML style is slightly more limited in what
it can express than the @AspectJ style: Only the "singleton" aspect instantiation model
is supported, and it is not possible to combine named pointcuts declared in XML.
For example, in the @AspectJ style you can write something like the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
@Pointcut("execution(* get*())")
public void propertyAccess() {}
@Pointcut("execution(com.xyz.Account+ *(..))")
public void operationReturningAnAccount() {}
@Pointcut("propertyAccess() && operationReturningAnAccount()")
public void accountPropertyAccess() {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
@Pointcut("execution(* get*())")
fun propertyAccess() {}
@Pointcut("execution(com.xyz.Account+ *(..))")
fun operationReturningAnAccount() {}
@Pointcut("propertyAccess() && operationReturningAnAccount()")
fun accountPropertyAccess() {}
----
======
In the XML style you can declare the first two pointcuts:
[source,xml,indent=0,subs="verbatim"]
----
<aop:pointcut id="propertyAccess"
expression="execution(* get*())"/>
<aop:pointcut id="operationReturningAnAccount"
expression="execution(com.xyz.Account+ *(..))"/>
----
The downside of the XML approach is that you cannot define the
`accountPropertyAccess` pointcut by combining these definitions.
The @AspectJ style supports additional instantiation models and richer pointcut
composition. It has the advantage of keeping the aspect as a modular unit. It also has
the advantage that the @AspectJ aspects can be understood (and thus consumed) both by
Spring AOP and by AspectJ. So, if you later decide you need the capabilities of AspectJ
to implement additional requirements, you can easily migrate to a classic AspectJ setup.
In general, the Spring team prefers the @AspectJ style for custom aspects beyond simple
configuration of enterprise services.
@@ -0,0 +1,79 @@
[[aop-introduction-defn]]
= AOP Concepts
Let us begin by defining some central AOP concepts and terminology. These terms are not
Spring-specific. Unfortunately, AOP terminology is not particularly intuitive.
However, it would be even more confusing if Spring used its own terminology.
* Aspect: A modularization of a concern that cuts across multiple classes.
Transaction management is a good example of a crosscutting concern in enterprise Java
applications. In Spring AOP, aspects are implemented by using regular classes
(the xref:core/aop/schema.adoc[schema-based approach]) or regular classes annotated with the
`@Aspect` annotation (the xref:core/aop/ataspectj.adoc[@AspectJ style]).
* Join point: A point during the execution of a program, such as the execution of a
method or the handling of an exception. In Spring AOP, a join point always
represents a method execution.
* Advice: Action taken by an aspect at a particular join point. Different types of
advice include "around", "before", and "after" advice. (Advice types are discussed
later.) Many AOP frameworks, including Spring, model an advice as an interceptor and
maintain a chain of interceptors around the join point.
* Pointcut: A predicate that matches join points. Advice is associated with a
pointcut expression and runs at any join point matched by the pointcut (for example,
the execution of a method with a certain name). The concept of join points as matched
by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut
expression language by default.
* Introduction: Declaring additional methods or fields on behalf of a type. Spring
AOP lets you introduce new interfaces (and a corresponding implementation) to any
advised object. For example, you could use an introduction to make a bean implement an
`IsModified` interface, to simplify caching. (An introduction is known as an
inter-type declaration in the AspectJ community.)
* Target object: An object being advised by one or more aspects. Also referred to as
the "advised object". Since Spring AOP is implemented by using runtime proxies, this
object is always a proxied object.
* AOP proxy: An object created by the AOP framework in order to implement the aspect
contracts (advise method executions and so on). In the Spring Framework, an AOP proxy
is a JDK dynamic proxy or a CGLIB proxy.
* Weaving: linking aspects with other application types or objects to create an
advised object. This can be done at compile time (using the AspectJ compiler, for
example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks,
performs weaving at runtime.
Spring AOP includes the following types of advice:
* Before advice: Advice that runs before a join point but that does not have
the ability to prevent execution flow proceeding to the join point (unless it throws
an exception).
* After returning advice: Advice to be run after a join point completes
normally (for example, if a method returns without throwing an exception).
* After throwing advice: Advice to be run if a method exits by throwing an
exception.
* After (finally) advice: Advice to be run regardless of the means by which a
join point exits (normal or exceptional return).
* Around advice: Advice that surrounds a join point such as a method invocation.
This is the most powerful kind of advice. Around advice can perform custom behavior
before and after the method invocation. It is also responsible for choosing whether to
proceed to the join point or to shortcut the advised method execution by returning its
own return value or throwing an exception.
Around advice is the most general kind of advice. Since Spring AOP, like AspectJ,
provides a full range of advice types, we recommend that you use the least powerful
advice type that can implement the required behavior. For example, if you need only to
update a cache with the return value of a method, you are better off implementing an
after returning advice than an around advice, although an around advice can accomplish
the same thing. Using the most specific advice type provides a simpler programming model
with less potential for errors. For example, you do not need to invoke the `proceed()`
method on the `JoinPoint` used for around advice, and, hence, you cannot fail to invoke it.
All advice parameters are statically typed so that you work with advice parameters of
the appropriate type (e.g. the type of the return value from a method execution) rather
than `Object` arrays.
The concept of join points matched by pointcuts is the key to AOP, which distinguishes
it from older technologies offering only interception. Pointcuts enable advice to be
targeted independently of the object-oriented hierarchy. For example, you can apply an
around advice providing declarative transaction management to a set of methods that span
multiple objects (such as all business operations in the service layer).
@@ -0,0 +1,22 @@
[[aop-introduction-proxies]]
= AOP Proxies
:page-section-summary-toc: 1
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This
enables any interface (or set of interfaces) to be proxied.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than
interfaces. By default, CGLIB is used if a business object does not implement an
interface. As it is good practice to program to interfaces rather than classes, business
classes normally implement one or more business interfaces. It is possible to
xref:core/aop/proxying.adoc[force the use of CGLIB], in those (hopefully rare) cases where you
need to advise a method that is not declared on an interface or where you need to
pass a proxied object to a method as a concrete type.
It is important to grasp the fact that Spring AOP is proxy-based. See
xref:core/aop/proxying.adoc#aop-understanding-aop-proxies[Understanding AOP Proxies] for a thorough examination of exactly what this
implementation detail actually means.
@@ -0,0 +1,61 @@
[[aop-introduction-spring-defn]]
= Spring AOP Capabilities and Goals
Spring AOP is implemented in pure Java. There is no need for a special compilation
process. Spring AOP does not need to control the class loader hierarchy and is thus
suitable for use in a servlet container or application server.
Spring AOP currently supports only method execution join points (advising the execution
of methods on Spring beans). Field interception is not implemented, although support for
field interception could be added without breaking the core Spring AOP APIs. If you need
to advise field access and update join points, consider a language such as AspectJ.
Spring AOP's approach to AOP differs from that of most other AOP frameworks. The aim is
not to provide the most complete AOP implementation (although Spring AOP is quite
capable). Rather, the aim is to provide a close integration between AOP implementation and
Spring IoC, to help solve common problems in enterprise applications.
Thus, for example, the Spring Framework's AOP functionality is normally used in
conjunction with the Spring IoC container. Aspects are configured by using normal bean
definition syntax (although this allows powerful "auto-proxying" capabilities). This is a
crucial difference from other AOP implementations. You cannot do some things
easily or efficiently with Spring AOP, such as advise very fine-grained objects (typically,
domain objects). AspectJ is the best choice in such cases. However, our
experience is that Spring AOP provides an excellent solution to most problems in
enterprise Java applications that are amenable to AOP.
Spring AOP never strives to compete with AspectJ to provide a comprehensive AOP
solution. We believe that both proxy-based frameworks such as Spring AOP and full-blown
frameworks such as AspectJ are valuable and that they are complementary, rather than in
competition. Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable
all uses of AOP within a consistent Spring-based application
architecture. This integration does not affect the Spring AOP API or the AOP Alliance
API. Spring AOP remains backward-compatible. See xref:core/aop-api.adoc[the following chapter]
for a discussion of the Spring AOP APIs.
[NOTE]
====
One of the central tenets of the Spring Framework is that of non-invasiveness. This
is the idea that you should not be forced to introduce framework-specific classes and
interfaces into your business or domain model. However, in some places, the Spring Framework
does give you the option to introduce Spring Framework-specific dependencies into your
codebase. The rationale in giving you such options is because, in certain scenarios, it
might be just plain easier to read or code some specific piece of functionality in such
a way. However, the Spring Framework (almost) always offers you the choice: You have the
freedom to make an informed decision as to which option best suits your particular use
case or scenario.
One such choice that is relevant to this chapter is that of which AOP framework (and
which AOP style) to choose. You have the choice of AspectJ, Spring AOP, or both. You
also have the choice of either the @AspectJ annotation-style approach or the Spring XML
configuration-style approach. The fact that this chapter chooses to introduce the
@AspectJ-style approach first should not be taken as an indication that the Spring team
favors the @AspectJ annotation-style approach over the Spring XML configuration-style.
See xref:core/aop/choosing.adoc[Choosing which AOP Declaration Style to Use] for a more complete discussion of the advantages and disadvantages of
each style.
====
@@ -0,0 +1,12 @@
[[aop-mixing-styles]]
= Mixing Aspect Types
:page-section-summary-toc: 1
It is perfectly possible to mix @AspectJ style aspects by using the auto-proxying support,
schema-defined `<aop:aspect>` aspects, `<aop:advisor>` declared advisors, and even proxies
and interceptors in other styles in the same configuration. All of these are implemented
by using the same underlying support mechanism and can co-exist without any difficulty.
@@ -0,0 +1,281 @@
[[aop-proxying]]
= Proxying Mechanisms
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given
target object. JDK dynamic proxies are built into the JDK, whereas CGLIB is a common
open-source class definition library (repackaged into `spring-core`).
If the target object to be proxied implements at least one interface, a JDK dynamic
proxy is used. All of the interfaces implemented by the target type are proxied.
If the target object does not implement any interfaces, a CGLIB proxy is created.
If you want to force the use of CGLIB proxying (for example, to proxy every method
defined for the target object, not only those implemented by its interfaces),
you can do so. However, you should consider the following issues:
* With CGLIB, `final` methods cannot be advised, as they cannot be overridden in
runtime-generated subclasses.
* As of Spring 4.0, the constructor of your proxied object is NOT called twice anymore,
since the CGLIB proxy instance is created through Objenesis. Only if your JVM does
not allow for constructor bypassing, you might see double invocations and
corresponding debug log entries from Spring's AOP support.
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:
[source,xml,indent=0,subs="verbatim"]
----
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>
----
To force CGLIB proxying when you use the @AspectJ auto-proxy support, set the
`proxy-target-class` attribute of the `<aop:aspectj-autoproxy>` element to `true`,
as follows:
[source,xml,indent=0,subs="verbatim"]
----
<aop:aspectj-autoproxy proxy-target-class="true"/>
----
[NOTE]
====
Multiple `<aop:config/>` sections are collapsed into a single unified auto-proxy creator
at runtime, which applies the _strongest_ proxy settings that any of the
`<aop:config/>` sections (typically from different XML bean definition files) specified.
This also applies to the `<tx:annotation-driven/>` and `<aop:aspectj-autoproxy/>`
elements.
To be clear, using `proxy-target-class="true"` on `<tx:annotation-driven/>`,
`<aop:aspectj-autoproxy/>`, or `<aop:config/>` elements forces the use of CGLIB
proxies _for all three of them_.
====
[[aop-understanding-aop-proxies]]
== Understanding AOP Proxies
Spring AOP is proxy-based. It is vitally important that you grasp the semantics of
what that last statement actually means before you write your own aspects or use any of
the Spring AOP-based aspects supplied with the Spring Framework.
Consider first the scenario where you have a plain-vanilla, un-proxied,
nothing-special-about-it, straight object reference, as the following
code snippet shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public class SimplePojo implements Pojo {
public void foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar();
}
public void bar() {
// some logic...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
class SimplePojo : Pojo {
fun foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar()
}
fun bar() {
// some logic...
}
}
----
======
If you invoke a method on an object reference, the method is invoked directly on
that object reference, as the following image and listing show:
image::aop-proxy-plain-pojo-call.png[]
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public class Main {
public static void main(String[] args) {
Pojo pojo = new SimplePojo();
// this is a direct method call on the 'pojo' reference
pojo.foo();
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
fun main() {
val pojo = SimplePojo()
// this is a direct method call on the 'pojo' reference
pojo.foo()
}
----
======
Things change slightly when the reference that client code has is a proxy. Consider the
following diagram and code snippet:
image::aop-proxy-call.png[]
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
fun main() {
val factory = ProxyFactory(SimplePojo())
factory.addInterface(Pojo::class.java)
factory.addAdvice(RetryAdvice())
val pojo = factory.proxy as Pojo
// this is a method call on the proxy!
pojo.foo()
}
----
======
The key thing to understand here is that the client code inside the `main(..)` method
of the `Main` class has a reference to the proxy. This means that method calls on that
object reference are calls on the proxy. As a result, the proxy can delegate to all of
the interceptors (advice) that are relevant to that particular method call. However,
once the call has finally reached the target object (the `SimplePojo` reference in
this case), any method calls that it may make on itself, such as `this.bar()` or
`this.foo()`, are going to be invoked against the `this` reference, and not the proxy.
This has important implications. It means that self-invocation is not going to result
in the advice associated with a method invocation getting a chance to run.
Okay, so what is to be done about this? The best approach (the term "best" is used
loosely here) is to refactor your code such that the self-invocation does not happen.
This does entail some work on your part, but it is the best, least-invasive approach.
The next approach is absolutely horrendous, and we hesitate to point it out, precisely
because it is so horrendous. You can (painful as it is to us) totally tie the logic
within your class to Spring AOP, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public class SimplePojo implements Pojo {
public void foo() {
// this works, but... gah!
((Pojo) AopContext.currentProxy()).bar();
}
public void bar() {
// some logic...
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
class SimplePojo : Pojo {
fun foo() {
// this works, but... gah!
(AopContext.currentProxy() as Pojo).bar()
}
fun bar() {
// some logic...
}
}
----
======
This totally couples your code to Spring AOP, and it makes the class itself aware of
the fact that it is being used in an AOP context, which flies in the face of AOP. It
also requires some additional configuration when the proxy is being created, as the
following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
----
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
factory.setExposeProxy(true);
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
----
fun main() {
val factory = ProxyFactory(SimplePojo())
factory.addInterface(Pojo::class.java)
factory.addAdvice(RetryAdvice())
factory.isExposeProxy = true
val pojo = factory.proxy as Pojo
// this is a method call on the proxy!
pojo.foo()
}
----
======
Finally, it must be noted that AspectJ does not have this self-invocation issue because
it is not a proxy-based AOP framework.
@@ -0,0 +1,12 @@
[[aop-resources]]
= Further Resources
:page-section-summary-toc: 1
More information on AspectJ can be found on the https://www.eclipse.org/aspectj[AspectJ website].
_Eclipse AspectJ_ by Adrian Colyer et. al. (Addison-Wesley, 2005) provides a
comprehensive introduction and reference for the AspectJ language.
_AspectJ in Action_, Second Edition by Ramnivas Laddad (Manning, 2009) comes highly
recommended. The focus of the book is on AspectJ, but a lot of general AOP themes are
explored (in some depth).

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