Compare commits

...

149 Commits

Author SHA1 Message Date
Spring Builds da19cb342d Release v6.0.7 2023-03-20 09:37:53 +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
592 changed files with 5720 additions and 4374 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ spring-test/test-output/
# Maven artifacts
pom.xml
target/
/target/
# Eclipse artifacts, including WTP generated manifests
bin
+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://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-6.0.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.0.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)
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
+3 -5
View File
@@ -78,7 +78,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.7.0"
toolVersion = "10.9.1"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -127,10 +127,8 @@ configure([rootProject] + javaProjects) { project ->
"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.
//
// 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.
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
// See https://github.com/spring-projects/spring-framework/issues/27497
//
// "https://junit.org/junit5/docs/5.9.2/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
+1 -1
View File
@@ -28,7 +28,7 @@ javadoc {
}
dependencies {
asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.4"
asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.5"
}
/**
@@ -0,0 +1,9 @@
aot=core.aot
aot-basics=core.aot.basics
aot-refresh=core.aot.refresh
aot-bean-factory-initialization-contributions=core.aot.bean-factory-initialization-contributions
aot-bean-registration-contributions=core.aot.bean-registration-contributions
aot-hints=core.aot.hints
aot-hints-import-runtime-hints=core.aot.hints.import-runtime-hints
aot-hints-reflective=core.aot.hints.reflective
aot-hints-register-reflection-for-binding=core.aot.hints.register-reflection-for-binding
@@ -1,6 +1,11 @@
// 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
:docs-site: https://docs.spring.io
// Spring Framework
:docs-spring-framework: {docs-site}/spring-framework/docs/{spring-version}
:api-spring-framework: {docs-spring-framework}/javadoc-api/org/springframework
@@ -8,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
File diff suppressed because it is too large Load Diff
@@ -16,9 +16,9 @@ Applying such optimizations early implies the following restrictions:
* The classpath is fixed and fully defined at build time.
* The beans defined in your application cannot change at runtime, meaning:
** `@Profile`, in particular profile-specific configuration needs to be chosen at build time.
** Environment properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
* Bean definitions with instance suppliers (lambdas or method references) can't be transformed Ahead of Time (see https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] related issue)
* The return type of methods annotated with `@Bean` should be the most specific one in order to allow proper hint inference (typically the concrete class, not an interface).
** `Environment` properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
* Bean definitions with instance suppliers (lambdas or method references) cannot be transformed ahead-of-time (see related https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] issue).
* The return type of methods annotated with `@Bean` should be the most specific type possible (typically the concrete class, not an interface) in order to support proper type inference without invoking the corresponding `@Bean` method at build time.
When these restrictions are in place, it becomes possible to perform ahead-of-time processing at build time and generate additional assets.
A Spring AOT processed application typically generates:
@@ -123,7 +123,7 @@ easy to do in Spring. You do not actually have to do anything or know anything a
the Spring internals (or even about classes such as the `FieldRetrievingFactoryBean`).
The following example enumeration shows how easy injecting an enum value is:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package jakarta.persistence;
@@ -134,7 +134,7 @@ The following example enumeration shows how easy injecting an enum value is:
EXTENDED
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package jakarta.persistence
@@ -148,7 +148,7 @@ The following example enumeration shows how easy injecting an enum value is:
Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package example;
@@ -162,7 +162,7 @@ Now consider the following setter of type `PersistenceContextType` and the corre
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package example
@@ -796,7 +796,7 @@ element results in a single `SimpleDateFormat` bean definition). Spring features
number of convenience classes that support this scenario. In the following example, we
use the `NamespaceHandlerSupport` class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package org.springframework.samples.xml;
@@ -810,7 +810,7 @@ use the `NamespaceHandlerSupport` class:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package org.springframework.samples.xml
@@ -847,7 +847,7 @@ responsible for parsing one distinct top-level XML element defined in the schema
the parser, we' have access to the XML element (and thus to its subelements, too) so that
we can parse our custom XML content, as you can see in the following example:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package org.springframework.samples.xml;
@@ -884,7 +884,7 @@ the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package org.springframework.samples.xml
@@ -1056,7 +1056,7 @@ setter method for the `components` property. This makes it hard (or rather impos
to configure a bean definition for the `Component` class by using setter injection.
The following listing shows the `Component` class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1087,7 +1087,7 @@ The following listing shows the `Component` class:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1114,7 +1114,7 @@ The typical solution to this issue is to create a custom `FactoryBean` that expo
setter property for the `components` property. The following listing shows such a custom
`FactoryBean`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1154,7 +1154,7 @@ setter property for the `components` property. The following listing shows such
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1226,7 +1226,7 @@ listing shows:
Again following <<core.appendix.xsd-custom-introduction, the process described earlier>>,
we then create a custom `NamespaceHandler`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1240,7 +1240,7 @@ we then create a custom `NamespaceHandler`:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1259,7 +1259,7 @@ Next up is the custom `BeanDefinitionParser`. Remember that we are creating
a `BeanDefinition` that describes a `ComponentFactoryBean`. The following
listing shows our custom `BeanDefinitionParser` implementation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1308,7 +1308,7 @@ listing shows our custom `BeanDefinitionParser` implementation:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1403,14 +1403,14 @@ the named JCache for us. We can also modify the existing `BeanDefinition` for th
`'checkingAccountService'` so that it has a dependency on this new
JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
public class JCacheInitializer {
private String name;
private final String name;
public JCacheInitializer(String name) {
this.name = name;
@@ -1421,7 +1421,7 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1453,7 +1453,7 @@ the XSD schema that describes the custom attribute, as follows:
Next, we need to create the associated `NamespaceHandler`, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1469,7 +1469,7 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -1490,7 +1490,7 @@ Next, we need to create the parser. Note that, in this case, because we are goin
an XML attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`.
The following listing shows our `BeanDefinitionDecorator` implementation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo;
@@ -1544,7 +1544,7 @@ The following listing shows our `BeanDefinitionDecorator` implementation:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo
@@ -949,7 +949,7 @@ order in which the constructor arguments are defined in a bean definition is the
in which those arguments are supplied to the appropriate constructor when the bean is
being instantiated. Consider the following class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package x.y;
@@ -961,7 +961,7 @@ being instantiated. Consider the following class:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package x.y
@@ -993,7 +993,7 @@ case with the preceding example). When a simple type is used, such as
`<value>true</value>`, Spring cannot determine the type of the value, and so cannot match
by type without help. Consider the following class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package examples;
@@ -1012,7 +1012,7 @@ by type without help. Consider the following class:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package examples
@@ -1077,7 +1077,7 @@ https://download.oracle.com/javase/8/docs/api/java/beans/ConstructorProperties.h
JDK annotation to explicitly name your constructor arguments. The sample class would
then have to look as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package examples;
@@ -1093,7 +1093,7 @@ then have to look as follows:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package examples
@@ -2276,10 +2276,9 @@ and by <<beans-factory-client,making a `getBean("B")` call to the container>> as
typically new) bean B instance every time bean A needs it. The following example
shows this approach:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
.Java
----
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
@@ -2287,6 +2286,10 @@ shows this approach:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* A class that uses a stateful Command-style class to perform
* some processing.
*/
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
@@ -2310,16 +2313,17 @@ shows this approach:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
.Kotlin
----
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple
// Spring-API imports
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
// A class that uses a stateful Command-style class to perform
// some processing.
class CommandManager : ApplicationContextAware {
private lateinit var applicationContext: ApplicationContext
@@ -2382,7 +2386,7 @@ Spring container dynamically overrides the implementation of the `createCommand(
method. The `CommandManager` class does not have any Spring dependencies, as
the reworked example shows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
.Java
----
package fiona.apple;
@@ -2403,7 +2407,7 @@ the reworked example shows:
protected abstract Command createCommand();
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
.Kotlin
----
package fiona.apple
@@ -4214,7 +4218,7 @@ it is created by the container and prints the resulting string to the system con
The following listing shows the custom `BeanPostProcessor` implementation class definition:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package scripting;
@@ -4234,9 +4238,11 @@ The following listing shows the custom `BeanPostProcessor` implementation class
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package scripting
import org.springframework.beans.factory.config.BeanPostProcessor
class InstantiationTracingBeanPostProcessor : BeanPostProcessor {
@@ -1978,7 +1978,7 @@ The definition of `TemplateParserContext` follows:
This section lists the classes used in the examples throughout this chapter.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Inventor.Java
----
package org.spring.samples.spel.inventor;
@@ -2051,18 +2051,20 @@ This section lists the classes used in the examples throughout this chapter.
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Inventor.kt
----
class Inventor(
var name: String,
var nationality: String,
var inventions: Array<String>? = null,
var birthdate: Date = GregorianCalendar().time,
var placeOfBirth: PlaceOfBirth? = null)
package org.spring.samples.spel.inventor
class Inventor(
var name: String,
var nationality: String,
var inventions: Array<String>? = null,
var birthdate: Date = GregorianCalendar().time,
var placeOfBirth: PlaceOfBirth? = null)
----
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.PlaceOfBirth.java
----
package org.spring.samples.spel.inventor;
@@ -2098,13 +2100,15 @@ class Inventor(
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.PlaceOfBirth.kt
----
package org.spring.samples.spel.inventor
class PlaceOfBirth(var city: String, var country: String? = null) {
----
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Society.java
----
package org.spring.samples.spel.inventor;
@@ -2147,7 +2151,7 @@ class Inventor(
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Society.kt
----
package org.spring.samples.spel.inventor
@@ -640,7 +640,7 @@ support for additional `PropertyEditor` instances to an `ApplicationContext`.
Consider the following example, which defines a user class called `ExoticType` and
another class called `DependsOnExoticType`, which needs `ExoticType` set as a property:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package example;
@@ -663,7 +663,7 @@ another class called `DependsOnExoticType`, which needs `ExoticType` set as a pr
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package example
@@ -689,12 +689,14 @@ string, which a `PropertyEditor` converts into an actual
The `PropertyEditor` implementation could look similar to the following:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
// converts string representation to ExoticType object
package example;
import java.beans.PropertyEditorSupport;
// converts string representation to ExoticType object
public class ExoticTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
@@ -702,14 +704,14 @@ The `PropertyEditor` implementation could look similar to the following:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
// converts string representation to ExoticType object
package example
import java.beans.PropertyEditorSupport
// converts string representation to ExoticType object
class ExoticTypeEditor : PropertyEditorSupport() {
override fun setAsText(text: String) {
@@ -752,7 +754,7 @@ instances for each bean creation attempt.
The following example shows how to create your own `PropertyEditorRegistrar` implementation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package com.foo.editors.spring;
@@ -768,7 +770,7 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package com.foo.editors.spring
@@ -876,7 +878,7 @@ where type conversion is needed.
The SPI to implement type conversion logic is simple and strongly typed, as the following
interface definition shows:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert.converter;
@@ -901,7 +903,7 @@ Several converter implementations are provided in the `core.convert.support` pac
a convenience. These include converters from strings to numbers and other common types.
The following listing shows the `StringToInteger` class, which is a typical `Converter` implementation:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert.support;
@@ -922,7 +924,7 @@ When you need to centralize the conversion logic for an entire class hierarchy
(for example, when converting from `String` to `Enum` objects), you can implement
`ConverterFactory`, as the following example shows:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert.converter;
@@ -938,7 +940,7 @@ where T is a subclass of R.
Consider the `StringToEnumConverterFactory` as an example:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert.support;
@@ -975,7 +977,7 @@ context that you can use when you implement your conversion logic. Such context
type conversion be driven by a field annotation or by generic information declared on a
field signature. The following listing shows the interface definition of `GenericConverter`:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert.converter;
@@ -1039,7 +1041,7 @@ might match only if the target entity type declares a static finder method (for
`ConversionService` defines a unified API for executing type conversion logic at
runtime. Converters are often run behind the following facade interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.core.convert;
@@ -1223,7 +1225,7 @@ provides a unified type conversion API for both SPIs.
The `Formatter` SPI to implement field formatting logic is simple and strongly typed. The
following listing shows the `Formatter` interface definition:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.format;
@@ -1268,7 +1270,7 @@ a `java.text.DateFormat`.
The following `DateFormatter` is an example `Formatter` implementation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package org.springframework.format.datetime;
@@ -1302,7 +1304,7 @@ The following `DateFormatter` is an example `Formatter` implementation:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
class DateFormatter(private val pattern: String) : Formatter<Date> {
@@ -1334,7 +1336,7 @@ Field formatting can be configured by field type or annotation. To bind
an annotation to a `Formatter`, implement `AnnotationFormatterFactory`. The following
listing shows the definition of the `AnnotationFormatterFactory` interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.format;
@@ -1350,15 +1352,14 @@ listing shows the definition of the `AnnotationFormatterFactory` interface:
To create an implementation:
. Parameterize A to be the field `annotationType` with which you wish to associate
. Parameterize `A` to be the field `annotationType` with which you wish to associate
formatting logic -- for example `org.springframework.format.annotation.DateTimeFormat`.
. Have `getFieldTypes()` return the types of fields on which the annotation can be used.
. Have `getPrinter()` return a `Printer` to print the value of an annotated field.
. Have `getParser()` return a `Parser` to parse a `clientValue` for an annotated field.
The following example `AnnotationFormatterFactory` implementation binds the `@NumberFormat`
annotation to a formatter to let a number style or pattern be
specified:
annotation to a formatter to let a number style or pattern be specified:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@@ -1366,10 +1367,12 @@ specified:
public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
private static final Set<Class<?>> FIELD_TYPES = Set.of(Short.class,
Integer.class, Long.class, Float.class, Double.class,
BigDecimal.class, BigInteger.class);
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(asList(new Class<?>[] {
Short.class, Integer.class, Long.class, Float.class,
Double.class, BigDecimal.class, BigInteger.class }));
return FIELD_TYPES;
}
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
@@ -1383,16 +1386,13 @@ specified:
private Formatter<Number> configureFormatterFrom(NumberFormat annotation, Class<?> fieldType) {
if (!annotation.pattern().isEmpty()) {
return new NumberStyleFormatter(annotation.pattern());
} else {
Style style = annotation.style();
if (style == Style.PERCENT) {
return new PercentStyleFormatter();
} else if (style == Style.CURRENCY) {
return new CurrencyStyleFormatter();
} else {
return new NumberStyleFormatter();
}
}
// else
return switch(annotation.style()) {
case Style.PERCENT -> new PercentStyleFormatter();
case Style.CURRENCY -> new CurrencyStyleFormatter();
default -> new NumberStyleFormatter();
};
}
}
----
@@ -1428,7 +1428,7 @@ specified:
}
----
To trigger formatting, you can annotate fields with @NumberFormat, as the following
To trigger formatting, you can annotate fields with `@NumberFormat`, as the following
example shows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
@@ -1490,7 +1490,7 @@ for use with Spring's `DataBinder` and the Spring Expression Language (SpEL).
The following listing shows the `FormatterRegistry` SPI:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.format;
@@ -1526,7 +1526,7 @@ these rules once, and they are applied whenever formatting is needed.
`FormatterRegistrar` is an SPI for registering formatters and converters through the
FormatterRegistry. The following listing shows its interface definition:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.format;
@@ -1578,20 +1578,22 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
public FormattingConversionService conversionService() {
// Use the DefaultFormattingConversionService but do not register defaults
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
DefaultFormattingConversionService conversionService =
new DefaultFormattingConversionService(false);
// Ensure @NumberFormat is still supported
conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
conversionService.addFormatterForFieldAnnotation(
new NumberFormatAnnotationFormatterFactory());
// Register JSR-310 date conversion with a specific global format
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
registrar.registerFormatters(conversionService);
DateTimeFormatterRegistrar dateTimeRegistrar = new DateTimeFormatterRegistrar();
dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
dateTimeRegistrar.registerFormatters(conversionService);
// Register date conversion with a specific global format
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
registrar.registerFormatters(conversionService);
DateFormatterRegistrar dateRegistrar = new DateFormatterRegistrar();
dateRegistrar.setFormatter(new DateFormatter("yyyyMMdd"));
dateRegistrar.registerFormatters(conversionService);
return conversionService;
}
@@ -1612,14 +1614,14 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
addFormatterForFieldAnnotation(NumberFormatAnnotationFormatterFactory())
// Register JSR-310 date conversion with a specific global format
val registrar = DateTimeFormatterRegistrar()
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"))
registrar.registerFormatters(this)
val dateTimeRegistrar = DateTimeFormatterRegistrar()
dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"))
dateTimeRegistrar.registerFormatters(this)
// Register date conversion with a specific global format
val registrar = DateFormatterRegistrar()
registrar.setFormatter(DateFormatter("yyyyMMdd"))
registrar.registerFormatters(this)
val dateRegistrar = DateFormatterRegistrar()
dateRegistrar.setFormatter(DateFormatter("yyyyMMdd"))
dateRegistrar.registerFormatters(this)
}
}
}
@@ -622,7 +622,7 @@ transactions being created and then rolled back in response to the
`UnsupportedOperationException` instance. The following listing shows the `FooService`
interface:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
// the service interface that we want to make transactional
@@ -641,7 +641,7 @@ interface:
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
// the service interface that we want to make transactional
@@ -662,7 +662,7 @@ interface:
The following example shows an implementation of the preceding interface:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package x.y.service;
@@ -690,7 +690,7 @@ The following example shows an implementation of the preceding interface:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package x.y.service
@@ -893,7 +893,7 @@ return type is reactive.
The following listing shows a modified version of the previously used `FooService`, but
this time the code uses reactive types:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
// the reactive service interface that we want to make transactional
@@ -912,7 +912,7 @@ this time the code uses reactive types:
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
// the reactive service interface that we want to make transactional
@@ -933,7 +933,7 @@ this time the code uses reactive types:
The following example shows an implementation of the preceding interface:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package x.y.service;
@@ -961,7 +961,7 @@ The following example shows an implementation of the preceding interface:
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package x.y.service
@@ -2028,7 +2028,7 @@ configuration and AOP in general.
The following code shows the simple profiling aspect discussed earlier:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
.Java
----
package x.y;
@@ -2065,9 +2065,15 @@ The following code shows the simple profiling aspect discussed earlier:
}
}
----
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
.Kotlin
----
package x.y
import org.aspectj.lang.ProceedingJoinPoint
import org.springframework.util.StopWatch
import org.springframework.core.Ordered
class SimpleProfiler : Ordered {
private var order: Int = 0
@@ -582,7 +582,7 @@ a similar contract to the JMS `MessageListener` interface but also gives the mes
method access to the JMS `Session` from which the `Message` was received.
The following listing shows the definition of the `SessionAwareMessageListener` interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.jms.listener;
@@ -31,7 +31,7 @@ The core class in Spring's JMX framework is the `MBeanExporter`. This class is
responsible for taking your Spring beans and registering them with a JMX `MBeanServer`.
For example, consider the following class:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages",chomp="-packages"]
----
package org.springframework.jmx;
@@ -358,7 +358,7 @@ an operation or an attribute.
The following example shows the annotated version of the `JmxTestBean` class that we
used in <<jmx-exporting-mbeanserver>>:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.jmx;
@@ -1067,7 +1067,7 @@ example, consider the scenario where one would like to be informed (through a
`Notification`) each and every time an attribute of a target MBean changes. The following
example writes notifications to the console:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package com.example;
@@ -1317,7 +1317,7 @@ published, and invoke the `sendNotification(Notification)` on the
In the following example, exported instances of the `JmxTestBean` publish a
`NotificationEvent` every time the `add(int, int)` operation is invoked:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.jmx;
@@ -9,6 +9,30 @@ Traces provide a holistic view of an entire system, crossing application boundar
Spring Framework instruments various parts of its own codebase to publish observations if an `ObservationRegistry` is configured.
You can learn more about {docs-spring-boot}/html/actuator.html#actuator.metrics[configuring the observability infrastructure in Spring Boot].
[[integration.observability.list]]
== List of produced Observations
Spring Framework instruments various features for observability.
As outlined <<integration.observability,at the beginning of this section>>, observations can generate timer Metrics and/or Traces depending on the configuration.
.Observations produced by Spring Framework
[%autowidth]
|===
|Observation name |Description
|<<integration.observability.http-client,`"http.client.requests"`>>
|Time spent for HTTP client exchanges
|<<integration.observability.http-server,`"http.server.requests"`>>
|Processing time for HTTP server exchanges at the Framework level
|===
NOTE: Observations are using Micrometer's official naming convention, but Metrics names will be automatically converted
https://micrometer.io/docs/concepts#_naming_meters[to the format preferred by the monitoring system backend]
(Prometheus, Atlas, Graphite, InfluxDB...).
[[integration.observability.concepts]]
== Micrometer Observation concepts
@@ -816,8 +816,7 @@ its properties from the job data mapped to properties of the job instance. So, i
the `ExampleJob` contains a bean property named `timeout`, and the `JobDetail`
has it applied automatically:
[source,java,indent=0]
[subs="verbatim"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package example;
@@ -827,7 +826,7 @@ has it applied automatically:
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailFactoryBean (5)
* with the value from the JobDetailFactoryBean.
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
@@ -33,7 +33,7 @@ implement. Note that this interface is defined in plain Java. Dependent objects
are injected with a reference to the `Messenger` do not know that the underlying
implementation is a Groovy script. The following listing shows the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
@@ -45,7 +45,7 @@ implementation is a Groovy script. The following listing shows the `Messenger` i
The following example defines a class that has a dependency on the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
@@ -65,15 +65,14 @@ The following example defines a class that has a dependency on the `Messenger` i
The following example implements the `Messenger` interface in Groovy:
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
// from the file 'Messenger.groovy'
package org.springframework.scripting.groovy;
package org.springframework.scripting.groovy
// import the Messenger interface (written in Java) that is to be implemented
// Import the Messenger interface (written in Java) that is to be implemented
import org.springframework.scripting.Messenger
// define the implementation in Groovy
// Define the implementation in Groovy in file 'Messenger.groovy'
class GroovyMessenger implements Messenger {
String message
@@ -276,7 +275,7 @@ surrounded by quotation marks. The following listing shows the changes that you
(the developer) should make to the `Messenger.groovy` source file when the
execution of the program is paused:
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting
@@ -331,13 +330,13 @@ feature works:
<lang:groovy id="messenger">
<lang:inline-script>
package org.springframework.scripting.groovy;
package org.springframework.scripting.groovy
import org.springframework.scripting.Messenger
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
String message
}
class GroovyMessenger implements Messenger {
String message
}
</lang:inline-script>
<lang:property name="message" value="I Can Do The Frug" />
@@ -363,13 +362,13 @@ constructors and properties 100% clear, the following mixture of code and config
does not work:
.An approach that cannot work
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
// from the file 'Messenger.groovy'
package org.springframework.scripting.groovy;
package org.springframework.scripting.groovy
import org.springframework.scripting.Messenger
// from the file 'Messenger.groovy'
class GroovyMessenger implements Messenger {
GroovyMessenger() {}
@@ -420,7 +419,7 @@ If you have read this chapter straight from the top, you have already
<<dynamic-language-a-first-example, seen an example>> of a Groovy-dynamic-language-backed
bean. Now consider another example (again using an example from the Spring test suite):
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
@@ -432,11 +431,11 @@ bean. Now consider another example (again using an example from the Spring test
The following example implements the `Calculator` interface in Groovy:
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
// from the file 'calculator.groovy'
package org.springframework.scripting.groovy
// from the file 'calculator.groovy'
class GroovyCalculator implements Calculator {
int add(int x, int y) {
@@ -457,7 +456,7 @@ The following bean definition uses the calculator defined in Groovy:
Finally, the following small application exercises the preceding configuration:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
@@ -596,7 +595,7 @@ Now we can show a fully working example of using a BeanShell-based bean that imp
the `Messenger` interface that was defined earlier in this chapter. We again show the
definition of the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
@@ -676,9 +675,8 @@ beans, you have to enable the "`refreshable beans`" functionality. See
The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented
by using the Groovy dynamic language:
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
// from the file '/WEB-INF/groovy/FortuneController.groovy'
package org.springframework.showcase.fortune.web
import org.springframework.showcase.fortune.service.FortuneService
@@ -689,6 +687,7 @@ by using the Groovy dynamic language:
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
// from the file '/WEB-INF/groovy/FortuneController.groovy'
class FortuneController implements Controller {
@Property FortuneService fortuneService
@@ -251,7 +251,7 @@ By default global configuration enables the following:
* `GET`, `HEAD`, and `POST` methods.
`allowedCredentials` is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information( such as cookies and CSRF tokens) and
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should be used only where appropriate. When it is enabled either `allowOrigins` must be
set to one or more specific domain (but not the special value `"*"`) or alternatively
the `allowOriginPatterns` property may be used to match to a dynamic set of origins.
@@ -2504,7 +2504,7 @@ reactive type, as the following example shows:
----
Note that use of `@ModelAttribute` is optional -- for example, to set its attributes.
By default, any argument that is not a simple value type( as determined by
By default, any argument that is not a simple value type (as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty])
and is not resolved by any other argument resolver is treated as if it were annotated
with `@ModelAttribute`.
+12 -12
View File
@@ -9,17 +9,17 @@ javaPlatform {
dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.14.2"))
api(platform("io.micrometer:micrometer-bom:1.10.4"))
api(platform("io.netty:netty-bom:4.1.89.Final"))
api(platform("io.netty:netty-bom:4.1.90.Final"))
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
api(platform("io.projectreactor:reactor-bom:2022.0.3"))
api(platform("io.projectreactor:reactor-bom:2022.0.5"))
api(platform("io.rsocket:rsocket-bom:1.1.3"))
api(platform("org.apache.groovy:groovy-bom:4.0.8"))
api(platform("org.apache.logging.log4j:log4j-bom:2.19.0"))
api(platform("org.eclipse.jetty:jetty-bom:11.0.13"))
api(platform("org.apache.logging.log4j:log4j-bom:2.20.0"))
api(platform("org.eclipse.jetty:jetty-bom:11.0.14"))
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4"))
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.4.0"))
api(platform("org.junit:junit-bom:5.9.2"))
api(platform("org.mockito:mockito-bom:5.1.1"))
api(platform("org.mockito:mockito-bom:5.2.0"))
constraints {
api("com.fasterxml:aalto-xml:1.3.1")
@@ -55,9 +55,9 @@ dependencies {
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
api("io.reactivex.rxjava3:rxjava:3.1.5")
api("io.smallrye.reactive:mutiny:1.8.0")
api("io.undertow:undertow-core:2.3.3.Final")
api("io.undertow:undertow-servlet:2.3.3.Final")
api("io.undertow:undertow-websockets-jsr:2.3.3.Final")
api("io.undertow:undertow-core:2.3.4.Final")
api("io.undertow:undertow-servlet:2.3.4.Final")
api("io.undertow:undertow-websockets-jsr:2.3.4.Final")
api("io.vavr:vavr:0.10.4")
api("jakarta.activation:jakarta.activation-api:2.0.1")
api("jakarta.annotation:jakarta.annotation-api:2.0.0")
@@ -99,10 +99,10 @@ dependencies {
api("org.apache.httpcomponents.client5:httpclient5:5.2.1")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.1")
api("org.apache.poi:poi-ooxml:5.2.3")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.5")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.5")
api("org.apache.tomcat:tomcat-util:10.1.5")
api("org.apache.tomcat:tomcat-websocket:10.1.5")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.7")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.7")
api("org.apache.tomcat:tomcat-util:10.1.7")
api("org.apache.tomcat:tomcat-websocket:10.1.7")
api("org.aspectj:aspectjrt:1.9.9.1")
api("org.aspectj:aspectjtools:1.9.9.1")
api("org.aspectj:aspectjweaver:1.9.9.1")
+1 -1
View File
@@ -1,4 +1,4 @@
version=6.0.5-SNAPSHOT
version=6.0.7
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m
@@ -248,20 +248,26 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
}
/**
* Set by creator of this advice object if the argument names are known.
* <p>This could be for example because they have been explicitly specified in XML,
* Set by the creator of this advice object if the argument names are known.
* <p>This could be for example because they have been explicitly specified in XML
* or in an advice annotation.
* @param argNames comma delimited list of arg names
* @param argumentNames comma delimited list of argument names
*/
public void setArgumentNames(String argNames) {
String[] tokens = StringUtils.commaDelimitedListToStringArray(argNames);
public void setArgumentNames(String argumentNames) {
String[] tokens = StringUtils.commaDelimitedListToStringArray(argumentNames);
setArgumentNamesFromStringArray(tokens);
}
public void setArgumentNamesFromStringArray(String... args) {
this.argumentNames = new String[args.length];
for (int i = 0; i < args.length; i++) {
this.argumentNames[i] = args[i].strip();
/**
* Set by the creator of this advice object if the argument names are known.
* <p>This could be for example because they have been explicitly specified in XML
* or in an advice annotation.
* @param argumentNames list of argument names
*/
public void setArgumentNamesFromStringArray(String... argumentNames) {
this.argumentNames = new String[argumentNames.length];
for (int i = 0; i < argumentNames.length; i++) {
this.argumentNames[i] = argumentNames[i].strip();
if (!isVariableName(this.argumentNames[i])) {
throw new IllegalArgumentException(
"'argumentNames' property of AbstractAspectJAdvice contains an argument name '" +
@@ -38,6 +38,14 @@ import org.springframework.util.StringUtils;
* for an advice method from the pointcut expression, returning, and throwing clauses.
* If an unambiguous interpretation is not available, it returns {@code null}.
*
* <h3>Algorithm Summary</h3>
* <p>If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* <h3>Algorithm Details</h3>
* <p>This class interprets arguments in the following way:
* <ol>
* <li>If the first parameter of the method is of type {@link JoinPoint}
@@ -65,15 +73,15 @@ import org.springframework.util.StringUtils;
* zero we proceed to the next stage. If {@code a} &gt; 1 then an
* {@code AmbiguousBindingException} is raised. If {@code a} == 1,
* and there are no unbound arguments of type {@code Annotation+},
* then an {@code IllegalArgumentException} is raised. if there is
* then an {@code IllegalArgumentException} is raised. If there is
* exactly one such argument, then the corresponding parameter name is
* assigned the value from the pointcut expression.</li>
* <li>If a returningName has been set, and there are no unbound arguments
* <li>If a {@code returningName} has been set, and there are no unbound arguments
* then an {@code IllegalArgumentException} is raised. If there is
* more than one unbound argument then an
* {@code AmbiguousBindingException} is raised. If there is exactly
* one unbound argument then the corresponding parameter name is assigned
* the value &lt;returningName&gt;.</li>
* the value of the {@code returningName}.</li>
* <li>If there remain unbound arguments, then the pointcut expression is
* examined once more for {@code this}, {@code target}, and
* {@code args} pointcut expressions used in the binding form (binding
@@ -99,20 +107,12 @@ import org.springframework.util.StringUtils;
* <p>The behavior on raising an {@code IllegalArgumentException} or
* {@code AmbiguousBindingException} is configurable to allow this discoverer
* to be used as part of a chain-of-responsibility. By default the condition will
* be logged and the {@code getParameterNames(..)} method will simply return
* be logged and the {@link #getParameterNames(Method)} method will simply return
* {@code null}. If the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property is set to {@code true}, the conditions will be thrown as
* {@code IllegalArgumentException} and {@code AmbiguousBindingException},
* respectively.
*
* <p>Was that perfectly clear? ;)
*
* <p>Short version: If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* @author Adrian Colyer
* @author Juergen Hoeller
* @since 2.0
@@ -197,7 +197,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterReturning} advice binds the return value, the
* returning variable name must be specified.
* {@code returning} variable name must be specified.
* @param returningName the name of the returning variable
*/
public void setReturningName(@Nullable String returningName) {
@@ -206,18 +206,17 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterThrowing} advice binds the thrown value, the
* throwing variable name must be specified.
* {@code throwing} variable name must be specified.
* @param throwingName the name of the throwing variable
*/
public void setThrowingName(@Nullable String throwingName) {
this.throwingName = throwingName;
}
/**
* Deduce the parameter names for an advice method.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
* for this class for details of the algorithm used.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class-level javadoc}
* for this class for details on the algorithm used.
* @param method the target {@link Method}
* @return the parameter names
*/
@@ -309,7 +308,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
/**
* If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as
* If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as
* parameter name and return true, else return false.
*/
private boolean maybeBindThisJoinPoint() {
@@ -348,14 +347,14 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
// Second candidate we've found - ambiguous binding
throw new AmbiguousBindingException("Binding of throwing parameter '" +
this.throwingName + "' is ambiguous: could be bound to argument " +
throwableIndex + " or argument " + i);
throwableIndex + " or " + i);
}
}
}
if (throwableIndex == -1) {
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName
+ "' could not be completed as no available arguments are a subtype of Throwable");
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
"' could not be completed as no available arguments are a subtype of Throwable");
}
else {
bindParameterName(throwableIndex, this.throwingName);
@@ -374,7 +373,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
if (this.returningName != null) {
if (this.numberOfRemainingUnboundArguments > 1) {
throw new AmbiguousBindingException("Binding of returning parameter '" + this.returningName +
"' is ambiguous, there are " + this.numberOfRemainingUnboundArguments + " candidates.");
"' is ambiguous: there are " + this.numberOfRemainingUnboundArguments + " candidates.");
}
// We're all set... find the unbound parameter, and bind it.
@@ -387,7 +386,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/**
* Parse the string pointcut expression looking for:
* &#64;this, &#64;target, &#64;args, &#64;within, &#64;withincode, &#64;annotation.
@@ -431,7 +429,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
int numAnnotationSlots = countNumberOfUnboundAnnotationArguments();
if (numAnnotationSlots > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" potential annotation variable(s), and " +
" potential annotation variable(s) and " +
numAnnotationSlots + " potential argument slots");
}
else if (numAnnotationSlots == 1) {
@@ -452,7 +450,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/*
/**
* If the token starts meets Java identifier conventions, it's in.
*/
@Nullable
@@ -488,7 +486,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
private void maybeBindThisOrTargetOrArgsFromPointcutExpression() {
if (this.numberOfRemainingUnboundArguments > 1) {
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments
+ " unbound args at this(),target(),args() binding stage, with no way to determine between them");
+ " unbound args at this()/target()/args() binding stage, with no way to determine between them");
}
List<String> varNames = new ArrayList<>();
@@ -520,10 +518,9 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate this(), target() or args() variables but only one unbound argument slot");
" candidate this(), target(), or args() variables but only one unbound argument slot");
}
else if (varNames.size() == 1) {
for (int j = 0; j < this.parameterNameBindings.length; j++) {
@@ -596,7 +593,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
// else varNames.size must be 0 and we have nothing to bind.
}
/*
/**
* We've found the start of a binding pointcut at the given index into the
* token array. Now we need to extract the pointcut body and return it.
*/
@@ -649,8 +646,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
private void maybeBindPrimitiveArgsFromPointcutExpression() {
int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();
if (numUnboundPrimitives > 1) {
throw new AmbiguousBindingException("Found '" + numUnboundPrimitives +
"' unbound primitive arguments with no way to distinguish between them.");
throw new AmbiguousBindingException("Found " + numUnboundPrimitives +
" unbound primitive arguments with no way to distinguish between them.");
}
if (numUnboundPrimitives == 1) {
// Look for arg variable and bind it if we find exactly one...
@@ -696,7 +693,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return false;
}
/*
/**
* Return {@code true} if the given argument type is a subclass
* of the given supertype.
*/
@@ -724,7 +721,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return count;
}
/*
/**
* Find the argument index with the given type, and bind the given
* {@code varName} in that position.
*/
@@ -741,22 +738,10 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* Simple struct to hold the extracted text from a pointcut body, together
* Simple record to hold the extracted text from a pointcut body, together
* with the number of tokens consumed in extracting it.
*/
private static class PointcutBody {
private final int numTokensConsumed;
@Nullable
private final String text;
public PointcutBody(int tokens, @Nullable String text) {
this.numTokensConsumed = tokens;
this.text = text;
}
}
private record PointcutBody(int numTokensConsumed, @Nullable String text) {}
/**
* Thrown in response to an ambiguous binding being detected when
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -117,7 +117,7 @@ public class TypePatternClassFilter implements ClassFilter {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
return (this == obj || (obj instanceof TypePatternClassFilter that &&
ObjectUtils.nullSafeEquals(this.typePattern, that.typePattern)));
}
@@ -121,21 +121,21 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
*/
@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
for (Class<?> annotationType : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation annotation = findAnnotation(method, (Class<Annotation>) annotationType);
if (annotation != null) {
return annotation;
}
}
return null;
}
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
private static AspectJAnnotation findAnnotation(Method method, Class<? extends Annotation> annotationType) {
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
if (annotation != null) {
return new AspectJAnnotation(annotation);
}
else {
return null;
@@ -156,9 +156,8 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
/**
* Class modeling an AspectJ annotation, exposing its type enumeration and
* pointcut String.
* @param <A> the annotation type
*/
protected static class AspectJAnnotation<A extends Annotation> {
protected static class AspectJAnnotation {
private static final String[] EXPRESSION_ATTRIBUTES = {"pointcut", "value"};
@@ -171,7 +170,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing //
);
private final A annotation;
private final Annotation annotation;
private final AspectJAnnotationType annotationType;
@@ -179,11 +178,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
private final String argumentNames;
public AspectJAnnotation(A annotation) {
public AspectJAnnotation(Annotation annotation) {
this.annotation = annotation;
this.annotationType = determineAnnotationType(annotation);
try {
this.pointcutExpression = resolveExpression(annotation);
this.pointcutExpression = resolvePointcutExpression(annotation);
Object argNames = AnnotationUtils.getValue(annotation, "argNames");
this.argumentNames = (argNames instanceof String names ? names : "");
}
@@ -192,7 +191,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
}
}
private AspectJAnnotationType determineAnnotationType(A annotation) {
private AspectJAnnotationType determineAnnotationType(Annotation annotation) {
AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
if (type != null) {
return type;
@@ -200,21 +199,21 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
throw new IllegalStateException("Unknown annotation type: " + annotation);
}
private String resolveExpression(A annotation) {
private String resolvePointcutExpression(Annotation annotation) {
for (String attributeName : EXPRESSION_ATTRIBUTES) {
Object val = AnnotationUtils.getValue(annotation, attributeName);
if (val instanceof String str && !str.isEmpty()) {
return str;
}
}
throw new IllegalStateException("Failed to resolve expression in: " + annotation);
throw new IllegalStateException("Failed to resolve pointcut expression in: " + annotation);
}
public AspectJAnnotationType getAnnotationType() {
return this.annotationType;
}
public A getAnnotation() {
public Annotation getAnnotation() {
return this.annotation;
}
@@ -239,19 +238,22 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
*/
private static class AspectJAnnotationParameterNameDiscoverer implements ParameterNameDiscoverer {
private static final String[] EMPTY_ARRAY = new String[0];
@Override
@Nullable
public String[] getParameterNames(Method method) {
if (method.getParameterCount() == 0) {
return new String[0];
return EMPTY_ARRAY;
}
AspectJAnnotation<?> annotation = findAspectJAnnotationOnMethod(method);
AspectJAnnotation annotation = findAspectJAnnotationOnMethod(method);
if (annotation == null) {
return null;
}
StringTokenizer nameTokens = new StringTokenizer(annotation.getArgumentNames(), ",");
if (nameTokens.countTokens() > 0) {
String[] names = new String[nameTokens.countTokens()];
int numTokens = nameTokens.countTokens();
if (numTokens > 0) {
String[] names = new String[numTokens];
for (int i = 0; i < names.length; i++) {
names[i] = nameTokens.nextToken();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -35,7 +35,8 @@ import org.springframework.lang.Nullable;
/**
* Internal implementation of AspectJPointcutAdvisor.
* Note that there will be one instance of this advisor for each target method.
*
* <p>Note that there will be one instance of this advisor for each target method.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -212,7 +213,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
* creation of the advice.
*/
private void determineAdviceType() {
AspectJAnnotation<?> aspectJAnnotation =
AspectJAnnotation aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.aspectJAdviceMethod);
if (aspectJAnnotation == null) {
this.isBeforeAdvice = false;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2023 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.
@@ -23,10 +23,6 @@ import org.springframework.lang.Nullable;
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
* that returns {@link AspectMetadata} associated with AspectJ-annotated classes.
*
* <p>Ideally, AspectInstanceFactory would include this method itself, but because
* AspectMetadata uses Java-5-only {@link org.aspectj.lang.reflect.AjType},
* we need to split out this subinterface.
*
* @author Rod Johnson
* @since 2.0
* @see AspectMetadata
@@ -35,13 +31,13 @@ import org.springframework.lang.Nullable;
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
/**
* Return the AspectJ AspectMetadata for this factory's aspect.
* Get the AspectJ AspectMetadata for this factory's aspect.
* @return the aspect metadata
*/
AspectMetadata getAspectMetadata();
/**
* Return the best possible creation mutex for this factory.
* Get the best possible creation mutex for this factory.
* @return the mutex object (may be {@code null} for no mutex to use)
* @since 4.3
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -87,7 +87,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
AspectJAnnotation ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
@@ -216,7 +216,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AspectJAnnotation aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
@@ -240,7 +240,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AspectJAnnotation aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2023 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.
@@ -21,20 +21,13 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.MethodMatcher;
/**
* Internal framework class, combining a MethodInterceptor instance
* with a MethodMatcher for use as an element in the advisor chain.
* Internal framework record, combining a {@link MethodInterceptor} instance
* with a {@link MethodMatcher} for use as an element in the advisor chain.
*
* @author Rod Johnson
* @author Sam Brannen
* @param interceptor the {@code MethodInterceptor}
* @param matcher the {@code MethodMatcher}
*/
class InterceptorAndDynamicMethodMatcher {
final MethodInterceptor interceptor;
final MethodMatcher methodMatcher;
public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
this.interceptor = interceptor;
this.methodMatcher = methodMatcher;
}
record InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher matcher) {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 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.
@@ -169,8 +169,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
if (dm.matcher().matches(this.method, targetClass, this.arguments)) {
return dm.interceptor().invoke(this);
}
else {
// Dynamic matching failed.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -92,8 +92,7 @@ public class BeanFactoryAdvisorRetrievalHelper {
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (rootCause instanceof BeanCurrentlyInCreationException bce) {
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -58,11 +58,11 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private ConfigurableBeanFactory beanFactory;
/** Internally used DefaultListableBeanFactory instances, keyed by bean name. */
private final Map<String, DefaultListableBeanFactory> internalBeanFactories =
new HashMap<>();
private final Map<String, DefaultListableBeanFactory> internalBeanFactories = new HashMap<>();
@Override
@@ -77,6 +77,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
/**
* Return the BeanFactory that this TargetSourceCreators runs in.
*/
@Nullable
protected final BeanFactory getBeanFactory() {
return this.beanFactory;
}
@@ -0,0 +1,10 @@
/**
* Various {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator}
* implementations for use with Spring's AOP auto-proxying support.
*/
@NonNullApi
@NonNullFields
package org.springframework.aop.framework.autoproxy.target;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -55,8 +55,8 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanType = registeredBean.getBeanType().toClass();
if (beanType.equals(ScopedProxyFactoryBean.class)) {
Class<?> beanClass = registeredBean.getBeanClass();
if (beanClass.equals(ScopedProxyFactoryBean.class)) {
String targetBeanName = getTargetBeanName(registeredBean.getMergedBeanDefinition());
BeanDefinition targetBeanDefinition =
getTargetBeanDefinition(registeredBean.getBeanFactory(), targetBeanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -19,6 +19,7 @@ package org.springframework.aop.support;
import java.io.Serializable;
import org.springframework.aop.ClassFilter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -45,7 +46,7 @@ public class RootClassFilter implements ClassFilter, Serializable {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
return (this == obj || (obj instanceof RootClassFilter that &&
this.clazz.equals(that.clazz)));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -183,7 +183,7 @@ public class AnnotationMatchingPointcut implements Pointcut {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.TargetSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -169,7 +170,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -181,7 +181,7 @@ public class CommonsPool2TargetSource extends AbstractPoolingTargetSource implem
}
/**
* Set whether the call should bock when the pool is exhausted.
* Set whether the call should block when the pool is exhausted.
*/
public void setBlockWhenExhausted(boolean blockWhenExhausted) {
this.blockWhenExhausted = blockWhenExhausted;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 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.
@@ -131,7 +131,7 @@ public final class EmptyTargetSource implements TargetSource, Serializable {
}
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -19,6 +19,7 @@ package org.springframework.aop.target;
import java.io.Serializable;
import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -100,7 +101,7 @@ public class HotSwappableTargetSource implements TargetSource, Serializable {
* objects are equal.
*/
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
return (this == obj || (obj instanceof HotSwappableTargetSource that &&
this.target.equals(that.target)));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2023 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.
@@ -65,7 +65,6 @@ public class LazyInitTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
@Nullable
public synchronized Object getTarget() throws BeansException {
if (this.target == null) {
this.target = getBeanFactory().getBean(getTargetBeanName());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -19,6 +19,7 @@ package org.springframework.aop.target;
import java.io.Serializable;
import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -82,7 +83,7 @@ public class SingletonTargetSource implements TargetSource, Serializable {
* targets or the targets are equal.
*/
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
@@ -0,0 +1,10 @@
/**
* Support for dynamic, refreshable {@link org.springframework.aop.TargetSource}
* implementations for use with Spring AOP.
*/
@NonNullApi
@NonNullFields
package org.springframework.aop.target.dynamic;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -0,0 +1,10 @@
/**
* Various {@link org.springframework.aop.TargetSource} implementations for use
* with Spring AOP.
*/
@NonNullApi
@NonNullFields
package org.springframework.aop.target;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -17,7 +17,6 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
@@ -43,17 +42,17 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void noArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
assertParameterNames(getMethod("noArgs"), "execution(* *(..))");
}
@Test
void joinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
assertParameterNames(getMethod("tjp"), "execution(* *(..))", "thisJoinPoint");
}
@Test
void joinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", "thisJoinPointStaticPart");
}
@Test
@@ -64,18 +63,18 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void oneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
assertParameterNamesExtended(getMethod("oneThrowable"), "foo()", null, "ex", "ex");
}
@Test
void oneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
assertParameterNamesExtended(getMethod("jpAndOneThrowable"), "foo()", null, "ex", "thisJoinPoint", "ex");
}
@Test
void oneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or 2");
}
@Test
@@ -86,13 +85,13 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void returning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
assertParameterNamesExtended(getMethod("oneObject"), "foo()", "obj", null, "obj");
}
@Test
void ambiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
"Binding of returning parameter 'obj' is ambiguous: there are 2 candidates.");
}
@Test
@@ -103,22 +102,22 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void thisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x)", "x");
}
@Test
void thisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x )", "x");
assertParameterNames(getMethod("oneObject"), "this( x)", "x");
assertParameterNames(getMethod("oneObject"), "this (x )", "x");
assertParameterNames(getMethod("oneObject"), "this(x )", "x");
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", "x");
}
@Test
void thisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
}
@Test
@@ -131,22 +130,22 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void targetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x)", "x");
}
@Test
void targetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x )", "x");
assertParameterNames(getMethod("oneObject"), "target( x)", "x");
assertParameterNames(getMethod("oneObject"), "target (x )", "x");
assertParameterNames(getMethod("oneObject"), "target(x )", "x");
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", "x");
}
@Test
void targetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
}
@Test
@@ -159,24 +158,24 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void argsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "args(x)", "x");
}
@Test
void argsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
}
@Test
void ambiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
"Still 2 unbound args at this()/target()/args() binding stage, with no way to determine between them");
}
@Test
void argsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
assertParameterNames(getMethod("onePrimitive"), "args(count)", "count");
}
@Test
@@ -188,37 +187,37 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void thisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
"obj", "count");
}
@Test
void targetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
"obj", "count");
}
@Test
void throwingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
assertParameterNamesExtended(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
"ex", "count");
}
@Test
void allTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
assertParameterNamesExtended(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
"thisJoinPoint", "ex", "x", "foo");
}
@Test
void referenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", "foo");
}
@Test
void referenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", "foo");
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", "foo");
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", "foo");
}
}
@@ -230,38 +229,38 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void atThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", "a");
}
@Test
void atTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", "a");
}
@Test
void atArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", "a");
}
@Test
void atWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", "a");
}
@Test
void atWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", "a");
}
@Test
void atAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", "a");
}
@Test
void ambiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
"Found 2 potential annotation variable(s) and 2 potential argument slots");
}
@Test
@@ -272,15 +271,14 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test
void annotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"});
assertParameterNamesExtended(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", "ex", "foo", "count", "a");
}
@Test
void annotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
"execution(* *(..)) && @annotation(ann)", "thisJoinPoint", "ann");
}
}
@@ -296,33 +294,23 @@ class AspectJAdviceParameterNameDiscovererTests {
throw new AssertionError("Bad test specification, no method '" + name + "' found in test class");
}
private void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
assertParameterNames(method, pointcut, null, null, parameterNames);
private void assertParameterNames(Method method, String pointcut, String... parameterNames) {
assertParameterNamesExtended(method, pointcut, null, null, parameterNames);
}
private void assertParameterNames(
Method method, String pointcut, String returning, String throwing, String[] parameterNames) {
private void assertParameterNamesExtended(
Method method, String pointcut, String returning, String throwing, String... parameterNames) {
assertThat(parameterNames.length).as("bad test specification, must have same number of parameter names as method arguments").isEqualTo(method.getParameterCount());
assertThat(parameterNames)
.as("bad test specification, must have same number of parameter names as method arguments")
.hasSize(method.getParameterCount());
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing);
String[] discoveredNames = discoverer.getParameterNames(method);
String formattedExpectedNames = Arrays.toString(parameterNames);
String formattedActualNames = Arrays.toString(discoveredNames);
assertThat(discoveredNames.length).as("Expecting " + parameterNames.length + " parameter names in return set '" +
formattedExpectedNames + "', but found " + discoveredNames.length +
" '" + formattedActualNames + "'").isEqualTo(parameterNames.length);
for (int i = 0; i < discoveredNames.length; i++) {
assertThat(discoveredNames[i]).as("Parameter names must never be null").isNotNull();
assertThat(discoveredNames[i]).as("Expecting parameter " + i + " to be named '" +
parameterNames[i] + "' but was '" + discoveredNames[i] + "'").isEqualTo(parameterNames[i]);
}
assertThat(discoverer.getParameterNames(method)).isEqualTo(parameterNames);
}
private void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 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.
@@ -38,56 +38,55 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
*/
public class ArgumentBindingTests {
class ArgumentBindingTests {
@Test
public void testBindingInPointcutUsedByAdvice() {
TestBean tb = new TestBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
void bindingInPointcutUsedByAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalArgumentException().isThrownBy(() ->
proxiedTestBean.setName("Supercalifragalisticexpialidocious"));
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
}
@Test
public void testAnnotationArgumentNameBinding() {
TransactionalBean tb = new TransactionalBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
void annotationArgumentNameBinding() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalStateException().isThrownBy(
proxiedTestBean::doInTransaction);
assertThatIllegalStateException()
.isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
}
@Test
public void testParameterNameDiscoverWithReferencePointcut() throws Exception {
void parameterNameDiscoverWithReferencePointcut() throws Exception {
AspectJAdviceParameterNameDiscoverer discoverer =
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
discoverer.setRaiseExceptions(true);
Method methodUsedForParameterTypeDiscovery =
getClass().getMethod("methodWithOneParam", String.class);
String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery);
assertThat(pnames.length).as("one parameter name").isEqualTo(1);
assertThat(pnames[0]).isEqualTo("formal");
Method method = getClass().getDeclaredMethod("methodWithOneParam", String.class);
assertThat(discoverer.getParameterNames(method)).containsExactly("formal");
}
public void methodWithOneParam(String aParam) {
@SuppressWarnings("unused")
private void methodWithOneParam(String aParam) {
}
public interface ITransactionalBean {
interface ITransactionalBean {
@Transactional
void doInTransaction();
}
public static class TransactionalBean implements ITransactionalBean {
static class TransactionalBean implements ITransactionalBean {
@Override
@Transactional
@@ -95,38 +94,35 @@ public class ArgumentBindingTests {
}
}
}
/**
* Mimics Spring's @Transactional annotation without actually introducing the dependency.
*/
@Retention(RetentionPolicy.RUNTIME)
@interface Transactional {
}
/**
* Represents Spring's Transactional annotation without actually introducing the dependency
*/
@Retention(RetentionPolicy.RUNTIME)
@interface Transactional {
}
@Aspect
static class PointcutWithAnnotationArgument {
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transactional)")
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
throw new IllegalStateException("Invoked with @Transactional");
}
@Aspect
class PointcutWithAnnotationArgument {
}
@Aspect
static class NamedPointcutWithArgs {
@Pointcut("execution(* *(..)) && args(s,..)")
public void pointcutWithArgs(String s) {}
@Around("pointcutWithArgs(aString)")
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
throw new IllegalArgumentException(aString);
}
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)")
public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable {
System.out.println("Invoked with transaction " + transaction);
throw new IllegalStateException();
}
}
@Aspect
class NamedPointcutWithArgs {
@Pointcut("execution(* *(..)) && args(s,..)")
public void pointcutWithArgs(String s) {}
@Around("pointcutWithArgs(aString)")
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
System.out.println("got '" + aString + "' at '" + pjp + "'");
throw new IllegalArgumentException(aString);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -21,6 +21,8 @@ import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
/**
* Abstract superclass for counting advices etc.
*
@@ -59,7 +61,7 @@ public class MethodCounter implements Serializable {
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
return (other != null && other.getClass() == this.getClass());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2023 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.
@@ -19,6 +19,8 @@ package org.springframework.aop.testfixture.interceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
/**
* Trivial interceptor that can be introduced in a chain to display it.
*
@@ -45,14 +47,14 @@ public class NopInterceptor implements MethodInterceptor {
@Override
public boolean equals(Object other) {
if (!(other instanceof NopInterceptor)) {
return false;
}
if (this == other) {
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
return this.count == ((NopInterceptor) other).count;
if (!(obj instanceof NopInterceptor that)) {
return false;
}
return this.count == that.count;
}
@Override
@@ -1,9 +1,9 @@
/**
* Support for an HTTP service proxy created from an interface declaration.
* AspectJ-based dependency injection support.
*/
@NonNullApi
@NonNullFields
package org.springframework.web.reactive.service;
package org.springframework.beans.factory.aspectj;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -17,8 +17,8 @@
package org.springframework.cache.aspectj;
/**
* Utility to trick the compiler to throw a valid checked
* exceptions within the interceptor.
* Utility to trick the compiler to throw valid checked exceptions masked as
* runtime exceptions within the interceptor.
*
* @author Stephane Nicoll
*/
@@ -36,4 +36,5 @@ final class AnyThrow {
private static <E extends Throwable> void throwAny(Throwable e) throws E {
throw (E) e;
}
}
@@ -0,0 +1,9 @@
/**
* AspectJ-based caching support.
*/
@NonNullApi
@NonNullFields
package org.springframework.cache.aspectj;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -0,0 +1,11 @@
/**
* AspectJ-based dependency injection support driven by the
* {@link org.springframework.beans.factory.annotation.Configurable @Configurable}
* annotation.
*/
@NonNullApi
@NonNullFields
package org.springframework.context.annotation.aspectj;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -0,0 +1,9 @@
/**
* AspectJ-based scheduling support.
*/
@NonNullApi
@NonNullFields
package org.springframework.scheduling.aspectj;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -0,0 +1,9 @@
/**
* AspectJ-based transaction management support.
*/
@NonNullApi
@NonNullFields
package org.springframework.transaction.aspectj;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 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.
@@ -16,6 +16,7 @@
package org.springframework.cache.config;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -45,16 +46,11 @@ public class TestEntity {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof TestEntity) {
return ObjectUtils.nullSafeEquals(this.id, ((TestEntity) obj).id);
}
return false;
return (obj instanceof TestEntity that && ObjectUtils.nullSafeEquals(this.id, that.id));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -29,6 +29,7 @@ import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -246,7 +247,8 @@ public abstract class BeanUtils {
// A single public constructor
return (Constructor<T>) ctors[0];
}
else if (ctors.length == 0){
else if (ctors.length == 0) {
// No public constructors -> check non-public
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
// A single non-public constructor, e.g. from a non-public record type
@@ -790,11 +792,11 @@ public abstract class BeanUtils {
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -88,8 +88,9 @@ abstract class PropertyDescriptorUtils {
BasicPropertyDescriptor pd = pdMap.get(propertyName);
if (pd != null) {
if (setter) {
if (pd.getWriteMethod() == null ||
pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
Method writeMethod = pd.getWriteMethod();
if (writeMethod == null ||
writeMethod.getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
pd.setWriteMethod(method);
}
else {
@@ -97,8 +98,9 @@ abstract class PropertyDescriptorUtils {
}
}
else {
if (pd.getReadMethod() == null ||
(pd.getReadMethod().getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
Method readMethod = pd.getReadMethod();
if (readMethod == null ||
(readMethod.getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
pd.setReadMethod(method);
}
}
@@ -280,6 +280,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
@Override
@Nullable
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
String beanName = registeredBean.getBeanName();
@@ -323,10 +324,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
checkLookupMethods(beanClass, beanName);
// Pick up subclass with fresh lookup method override from above
if (this.beanFactory instanceof AbstractAutowireCapableBeanFactory aacbf) {
if (this.beanFactory instanceof AbstractAutowireCapableBeanFactory aacBeanFactory) {
RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
if (mbd.getFactoryMethodName() == null && mbd.hasBeanClass()) {
return aacbf.getInstantiationStrategy().getActualBeanClass(mbd, beanName, this.beanFactory);
return aacBeanFactory.getInstantiationStrategy().getActualBeanClass(mbd, beanName, aacBeanFactory);
}
}
return beanClass;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -157,6 +157,7 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
}
@Override
@Nullable
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
beanDefinition.resolveDestroyMethodIfNecessary();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -20,6 +20,7 @@ import java.util.stream.Stream;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -31,7 +32,7 @@ import org.springframework.util.ClassUtils;
class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
if (ClassUtils.isPresent("jakarta.inject.Inject", classLoader)) {
Stream.of("jakarta.inject.Inject", "jakarta.inject.Qualifier").forEach(annotationType ->
hints.reflection().registerType(ClassUtils.resolveClassName(annotationType, classLoader)));
@@ -25,6 +25,7 @@ import java.util.Set;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -240,10 +241,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
}
}
if (targetAnnotation == null) {
BeanFactory beanFactory = getBeanFactory();
// Look for matching annotation on the target class
if (getBeanFactory() != null) {
if (beanFactory != null) {
try {
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
Class<?> beanType = beanFactory.getType(bdHolder.getBeanName());
if (beanType != null) {
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
}
@@ -138,7 +138,7 @@ class BeanDefinitionMethodGenerator {
ClassName topLevelClassName = target.topLevelClassName();
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
.getOrAddForFeatureComponent("BeanDefinitions", topLevelClassName, type -> {
type.addJavadoc("Bean definitions for {@link $T}", topLevelClassName);
type.addJavadoc("Bean definitions for {@link $T}.", topLevelClassName);
type.addModifiers(Modifier.PUBLIC);
});
@@ -159,7 +159,7 @@ class BeanDefinitionMethodGenerator {
private static GeneratedClass createInnerClass(GeneratedClass generatedClass, String name, ClassName target) {
return generatedClass.getOrAdd(name, type -> {
type.addJavadoc("Bean definitions for {@link $T}", target);
type.addJavadoc("Bean definitions for {@link $T}.", target);
type.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
});
}
@@ -186,7 +186,7 @@ class BeanDefinitionMethodGenerator {
this.aotContributions.forEach(aotContribution -> aotContribution.applyTo(generationContext, codeGenerator));
return generatedMethods.add("getBeanDefinition", method -> {
method.addJavadoc("Get the $L definition for '$L'",
method.addJavadoc("Get the $L definition for '$L'.",
(!this.registeredBean.isInnerBean()) ? "bean" : "inner-bean",
getName());
method.addModifiers(modifier, Modifier.STATIC);
@@ -27,9 +27,9 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -97,11 +97,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
private BeanInstanceSupplier(ExecutableLookup lookup,
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
@Nullable String[] shortcuts) {
this.lookup = lookup;
this.generator = generator;
this.shortcuts = shortcuts;
}
/**
* Create a {@link BeanInstanceSupplier} that resolves
* arguments for the specified bean constructor.
@@ -109,9 +111,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
* @param parameterTypes the constructor parameter types
* @return a new {@link BeanInstanceSupplier} instance
*/
public static <T> BeanInstanceSupplier<T> forConstructor(
Class<?>... parameterTypes) {
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null);
@@ -149,11 +149,11 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
* @param generator a {@link ThrowingBiFunction} that uses the
* {@link RegisteredBean} and resolved {@link AutowiredArguments} to
* instantiate the underlying bean
* @return a new {@link BeanInstanceSupplier} instance with the specified
* generator
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
*/
public BeanInstanceSupplier<T> withGenerator(
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
Assert.notNull(generator, "'generator' must not be null");
return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts);
}
@@ -163,11 +163,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
* {@code generator} function to instantiate the underlying bean.
* @param generator a {@link ThrowingFunction} that uses the
* {@link RegisteredBean} to instantiate the underlying bean
* @return a new {@link BeanInstanceSupplier} instance with the specified
* generator
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
*/
public BeanInstanceSupplier<T> withGenerator(
ThrowingFunction<RegisteredBean, T> generator) {
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
Assert.notNull(generator, "'generator' must not be null");
return new BeanInstanceSupplier<>(this.lookup,
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
@@ -176,10 +174,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
/**
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
* {@code generator} supplier to instantiate the underlying bean.
* @param generator a {@link ThrowingSupplier} to instantiate the underlying
* bean
* @return a new {@link BeanInstanceSupplier} instance with the specified
* generator
* @param generator a {@link ThrowingSupplier} to instantiate the underlying bean
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
*/
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
Assert.notNull(generator, "'generator' must not be null");
@@ -282,8 +278,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
if (executable instanceof Method method) {
return new MethodParameter(method, index);
}
throw new IllegalStateException(
"Unsupported executable " + executable.getClass().getName());
throw new IllegalStateException("Unsupported executable: " + executable.getClass().getName());
}
private ConstructorArgumentValues resolveArgumentValues(
@@ -303,9 +298,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
return resolved;
}
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver,
ValueHolder valueHolder) {
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, ValueHolder valueHolder) {
if (valueHolder.isConverted()) {
return valueHolder;
}
@@ -331,8 +324,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
}
try {
try {
return beanFactory.resolveDependency(dependencyDescriptor, beanName,
autowiredBeans, typeConverter);
return beanFactory.resolveDependency(dependencyDescriptor, beanName, autowiredBeans, typeConverter);
}
catch (NoSuchBeanDefinitionException ex) {
if (parameterType.isArray()) {
@@ -348,47 +340,45 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName,
new InjectionPoint(parameter), ex);
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
}
}
@SuppressWarnings("unchecked")
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable,
Object[] arguments) {
try {
if (executable instanceof Constructor<?> constructor) {
return (T) instantiate(constructor, arguments);
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) {
if (executable instanceof Constructor<?> constructor) {
try {
return (T) instantiate(constructor, args);
}
if (executable instanceof Method method) {
return (T) instantiate(beanFactory, method, arguments);
catch (Exception ex) {
throw new BeanInstantiationException(constructor, ex.getMessage(), ex);
}
}
catch (Exception ex) {
throw new BeanCreationException(
"Unable to instantiate bean using " + executable, ex);
if (executable instanceof Method method) {
try {
return (T) instantiate(beanFactory, method, args);
}
catch (Exception ex) {
throw new BeanInstantiationException(method, ex.getMessage(), ex);
}
}
throw new IllegalStateException(
"Unsupported executable " + executable.getClass().getName());
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
}
private Object instantiate(Constructor<?> constructor, Object[] arguments) throws Exception {
private Object instantiate(Constructor<?> constructor, Object[] args) throws Exception {
Class<?> declaringClass = constructor.getDeclaringClass();
if (ClassUtils.isInnerClass(declaringClass)) {
Object enclosingInstance = createInstance(declaringClass.getEnclosingClass());
arguments = ObjectUtils.addObjectToArray(arguments, enclosingInstance, 0);
args = ObjectUtils.addObjectToArray(args, enclosingInstance, 0);
}
ReflectionUtils.makeAccessible(constructor);
return constructor.newInstance(arguments);
return constructor.newInstance(args);
}
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method,
Object[] arguments) {
ReflectionUtils.makeAccessible(method);
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method, Object[] args) throws Exception {
Object target = getFactoryMethodTarget(beanFactory, method);
return ReflectionUtils.invokeMethod(method, target, arguments);
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
@Nullable
@@ -416,13 +406,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
}
/**
* Performs lookup of the {@link Executable}.
*/
static abstract class ExecutableLookup {
abstract Executable get(RegisteredBean registeredBean);
}
@@ -433,12 +423,10 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
private final Class<?>[] parameterTypes;
ConstructorLookup(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
@Override
public Executable get(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
@@ -456,10 +444,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
@Override
public String toString() {
return "Constructor with parameter types [%s]".formatted(
toCommaSeparatedNames(this.parameterTypes));
return "Constructor with parameter types [%s]".formatted(toCommaSeparatedNames(this.parameterTypes));
}
}
@@ -474,23 +460,19 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
private final Class<?>[] parameterTypes;
FactoryMethodLookup(Class<?> declaringClass, String methodName,
Class<?>[] parameterTypes) {
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
this.declaringClass = declaringClass;
this.methodName = methodName;
this.parameterTypes = parameterTypes;
}
@Override
public Executable get(RegisteredBean registeredBean) {
return get();
}
Method get() {
Method method = ReflectionUtils.findMethod(this.declaringClass,
this.methodName, this.parameterTypes);
Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes);
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
return method;
}
@@ -501,7 +483,6 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
this.methodName, toCommaSeparatedNames(this.parameterTypes),
this.declaringClass);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -130,10 +130,10 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* {@link BeanPostProcessor BeanPostProcessors}.
* <p>Note: This is intended for creating a fresh instance, populating annotated
* fields and methods as well as applying all standard bean initialization callbacks.
* Constructor resolution is done via {@link #AUTOWIRE_CONSTRUCTOR}, also influenced
* by {@link SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors}.
* It does <i>not</i> imply traditional by-name or by-type autowiring of properties;
* use {@link #createBean(Class, int, boolean)} for those purposes.
* Constructor resolution is based on Kotlin primary / single public / single non-public,
* with a fallback to the default constructor in ambiguous scenarios, also influenced
* by {@link SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors}
* (e.g. for annotation-driven constructor selection).
* @param beanClass the class of the bean to create
* @return the new bean instance
* @throws BeansException if instantiation or wiring failed
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -188,7 +188,7 @@ public class ConstructorArgumentValues {
* rather than matched multiple times.
* @param value the argument value
*/
public void addGenericArgumentValue(Object value) {
public void addGenericArgumentValue(@Nullable Object value) {
this.genericArgumentValues.add(new ValueHolder(value));
}
@@ -53,6 +53,7 @@ import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -149,8 +150,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
@Nullable
private Binding binding;
@Nullable
private GroovyBeanDefinitionWrapper currentBeanDefinition;
@@ -203,6 +206,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Return a specified binding for Groovy variables, if any.
*/
@Nullable
public Binding getBinding() {
return this.binding;
}
@@ -16,9 +16,9 @@
package org.springframework.beans.factory.groovy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import groovy.lang.GroovyObjectSupport;
@@ -30,6 +30,8 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
@@ -51,58 +53,54 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
private static final String DESTROY_METHOD = "destroyMethod";
private static final String SINGLETON = "singleton";
private static final List<String> dynamicProperties = new ArrayList<>(8);
static {
dynamicProperties.add(PARENT);
dynamicProperties.add(AUTOWIRE);
dynamicProperties.add(CONSTRUCTOR_ARGS);
dynamicProperties.add(FACTORY_BEAN);
dynamicProperties.add(FACTORY_METHOD);
dynamicProperties.add(INIT_METHOD);
dynamicProperties.add(DESTROY_METHOD);
dynamicProperties.add(SINGLETON);
}
private static final Set<String> dynamicProperties = Set.of(PARENT, AUTOWIRE, CONSTRUCTOR_ARGS,
FACTORY_BEAN, FACTORY_METHOD, INIT_METHOD, DESTROY_METHOD, SINGLETON);
@Nullable
private String beanName;
private Class<?> clazz;
@Nullable
private final Class<?> clazz;
private Collection<?> constructorArgs;
@Nullable
private final Collection<?> constructorArgs;
@Nullable
private AbstractBeanDefinition definition;
@Nullable
private BeanWrapper definitionWrapper;
@Nullable
private String parentName;
public GroovyBeanDefinitionWrapper(String beanName) {
this.beanName = beanName;
GroovyBeanDefinitionWrapper(String beanName) {
this(beanName, null);
}
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz) {
this.beanName = beanName;
this.clazz = clazz;
GroovyBeanDefinitionWrapper(@Nullable String beanName, @Nullable Class<?> clazz) {
this(beanName, clazz, null);
}
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz, Collection<?> constructorArgs) {
GroovyBeanDefinitionWrapper(@Nullable String beanName, Class<?> clazz, @Nullable Collection<?> constructorArgs) {
this.beanName = beanName;
this.clazz = clazz;
this.constructorArgs = constructorArgs;
}
@Nullable
public String getBeanName() {
return this.beanName;
}
public void setBeanDefinition(AbstractBeanDefinition definition) {
void setBeanDefinition(AbstractBeanDefinition definition) {
this.definition = definition;
}
public AbstractBeanDefinition getBeanDefinition() {
AbstractBeanDefinition getBeanDefinition() {
if (this.definition == null) {
this.definition = createBeanDefinition();
}
@@ -126,19 +124,17 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
return bd;
}
public void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
this.definition = (AbstractBeanDefinition) holder.getBeanDefinition();
this.beanName = holder.getBeanName();
}
public BeanDefinitionHolder getBeanDefinitionHolder() {
BeanDefinitionHolder getBeanDefinitionHolder() {
return new BeanDefinitionHolder(getBeanDefinition(), getBeanName());
}
public void setParent(Object obj) {
if (obj == null) {
throw new IllegalArgumentException("Parent bean cannot be set to a null runtime bean reference!");
}
void setParent(Object obj) {
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference.");
if (obj instanceof String name) {
this.parentName = name;
}
@@ -152,7 +148,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
getBeanDefinition().setAbstract(false);
}
public GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
if (propertyValue instanceof GroovyBeanDefinitionWrapper wrapper) {
propertyValue = wrapper.getBeanDefinition();
}
@@ -163,6 +159,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
@Override
public Object getProperty(String property) {
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
if (this.definitionWrapper.isReadableProperty(property)) {
return this.definitionWrapper.getPropertyValue(property);
}
@@ -179,6 +176,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
}
else {
AbstractBeanDefinition bd = getBeanDefinition();
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
if (AUTOWIRE.equals(property)) {
if ("byName".equals(newValue)) {
bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.lang.Nullable;
/**
* Used by GroovyBeanDefinitionReader to read a Spring XML namespace expression
@@ -68,6 +69,7 @@ class GroovyDynamicElementReader extends GroovyObjectSupport {
@Override
@Nullable
public Object invokeMethod(String name, Object obj) {
Object[] args = (Object[]) obj;
if (name.equals("doCall")) {
@@ -88,6 +90,7 @@ class GroovyDynamicElementReader extends GroovyObjectSupport {
String myNamespace = this.rootNamespace;
Map<String, String> myNamespaces = this.xmlNamespaces;
@SuppressWarnings("serial")
Closure<Object> callable = new Closure<>(this) {
@Override
public Object call(Object... arguments) {
@@ -1,4 +1,9 @@
/**
* Support package for Groovy-based bean definitions.
*/
@NonNullApi
@NonNullFields
package org.springframework.beans.factory.groovy;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -61,7 +61,6 @@ import org.springframework.beans.factory.config.AutowiredPropertyMarker;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
@@ -315,8 +314,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
@SuppressWarnings("unchecked")
public <T> T createBean(Class<T> beanClass) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setAutowireMode(AUTOWIRE_CONSTRUCTOR);
RootBeanDefinition bd = new CreateFromClassBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
return (T) createBean(beanClass.getName(), bd, null);
@@ -756,13 +754,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (candidate.getTypeParameters().length > 0) {
try {
// Fully resolve parameter names and argument values.
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Class<?>[] paramTypes = candidate.getParameterTypes();
String[] paramNames = null;
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
if (cav.containsNamedArgument()) {
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
@@ -1155,7 +1155,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
return obtainFromSupplier(instanceSupplier, beanName, mbd);
}
if (mbd.getFactoryMethodName() != null) {
@@ -1204,38 +1204,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param supplier the configured supplier
* @param beanName the corresponding bean name
* @return a BeanWrapper for the new instance
* @since 5.0
* @see #getObjectForBeanInstance
*/
protected BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName) {
Object instance = obtainInstanceFromSupplier(supplier, beanName);
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
@Nullable
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
private BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd) {
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
Object instance;
try {
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
return instanceSupplier.get(RegisteredBean.of((ConfigurableListableBeanFactory) this, beanName));
}
if (supplier instanceof ThrowingSupplier<?> throwableSupplier) {
return throwableSupplier.getWithException();
}
return supplier.get();
instance = obtainInstanceFromSupplier(supplier, beanName, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeansException beansException) {
throw beansException;
}
throw new BeanCreationException(beanName,
"Instantiation of supplied bean failed", ex);
throw new BeanCreationException(beanName, "Instantiation of supplied bean failed", ex);
}
finally {
if (outerBean != null) {
@@ -1245,6 +1227,31 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
this.currentlyCreatedBean.remove();
}
}
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
/**
* Obtain a bean instance from the given supplier.
* @param supplier the configured supplier
* @param beanName the corresponding bean name
* @param mbd the bean definition for the bean
* @return the bean instance (possibly {@code null})
* @since 6.0.7
*/
@Nullable
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
throws Exception {
if (supplier instanceof ThrowingSupplier<?> throwingSupplier) {
return throwingSupplier.getWithException();
}
return supplier.get();
}
/**
@@ -1364,6 +1371,17 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
}
if (bw.getWrappedClass().isRecord()) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
}
else {
// Skip property population phase for records since they are immutable.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
@@ -1898,6 +1916,36 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
/**
* {@link RootBeanDefinition} subclass for {@code #createBean} calls with
* flexible selection of a Kotlin primary / single public / single non-public
* constructor candidate in addition to the default constructor.
* @see BeanUtils#getResolvableConstructor(Class)
*/
@SuppressWarnings("serial")
private static class CreateFromClassBeanDefinition extends RootBeanDefinition {
public CreateFromClassBeanDefinition(Class<?> beanClass) {
super(beanClass);
}
public CreateFromClassBeanDefinition(CreateFromClassBeanDefinition original) {
super(original);
}
@Override
@Nullable
public Constructor<?>[] getPreferredConstructors() {
return ConstructorResolver.determinePreferredConstructors(getBeanClass());
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
return new CreateFromClassBeanDefinition(this);
}
}
/**
* Special DependencyDescriptor variant for Spring's good old autowire="byType" mode.
* Always optional; never considering the parameter name for choosing a primary candidate.
@@ -1910,6 +1958,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
@Override
@Nullable
public String getDependencyName() {
return null;
}
@@ -1930,7 +1979,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
public void doWith(Method method) throws IllegalArgumentException {
if (isFactoryBeanMethod(method)) {
ResolvableType returnType = ResolvableType.forMethodReturnType(method);
ResolvableType candidate = returnType.as(FactoryBean.class).getGeneric();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -853,10 +853,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
*/
@Override
public ConstructorArgumentValues getConstructorArgumentValues() {
if (this.constructorArgumentValues == null) {
this.constructorArgumentValues = new ConstructorArgumentValues();
ConstructorArgumentValues cav = this.constructorArgumentValues;
if (cav == null) {
cav = new ConstructorArgumentValues();
this.constructorArgumentValues = cav;
}
return this.constructorArgumentValues;
return cav;
}
/**
@@ -879,10 +881,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
*/
@Override
public MutablePropertyValues getPropertyValues() {
if (this.propertyValues == null) {
this.propertyValues = new MutablePropertyValues();
MutablePropertyValues pvs = this.propertyValues;
if (pvs == null) {
pvs = new MutablePropertyValues();
this.propertyValues = pvs;
}
return this.propertyValues;
return pvs;
}
/**
@@ -1222,6 +1222,54 @@ class ConstructorResolver {
return old;
}
/**
* See {@link BeanUtils#getResolvableConstructor(Class)} for alignment.
* This variant adds a lenient fallback to the default constructor if available, similar to
* {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors}.
*/
@Nullable
static Constructor<?>[] determinePreferredConstructors(Class<?> clazz) {
Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz);
Constructor<?> defaultCtor;
try {
defaultCtor = clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException ex) {
defaultCtor = null;
}
if (primaryCtor != null) {
if (defaultCtor != null && !primaryCtor.equals(defaultCtor)) {
return new Constructor<?>[] {primaryCtor, defaultCtor};
}
else {
return new Constructor<?>[] {primaryCtor};
}
}
Constructor<?>[] ctors = clazz.getConstructors();
if (ctors.length == 1) {
// A single public constructor, potentially in combination with a non-public default constructor
if (defaultCtor != null && !ctors[0].equals(defaultCtor)) {
return new Constructor<?>[] {ctors[0], defaultCtor};
}
else {
return ctors;
}
}
else if (ctors.length == 0) {
// No public constructors -> check non-public
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
// A single non-public constructor, e.g. from a non-public record type
return ctors;
}
}
return null;
}
/**
* Private inner class for holding argument combinations.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -40,6 +40,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import jakarta.inject.Provider;
@@ -937,6 +938,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
}
@Override
@Nullable
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
throws Exception {
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
return instanceSupplier.get(RegisteredBean.of(this, beanName, mbd));
}
return super.obtainInstanceFromSupplier(supplier, beanName, mbd);
}
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
@@ -1720,7 +1732,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (beanInstance != null) {
Integer candidatePriority = getPriority(beanInstance);
if (candidatePriority != null) {
if (highestPriorityBeanName != null) {
if (highestPriority != null) {
if (candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"Multiple beans found with the same priority ('" + highestPriority +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 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.
@@ -340,7 +340,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* (within the entire factory).
* @param beanName the name of the bean
*/
public boolean isSingletonCurrentlyInCreation(String beanName) {
public boolean isSingletonCurrentlyInCreation(@Nullable String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -35,6 +35,7 @@ import org.springframework.util.function.ThrowingSupplier;
* @since 6.0
* @param <T> the type of instance supplied by this supplier
* @see RegisteredBean
* @see org.springframework.beans.factory.aot.BeanInstanceSupplier
*/
@FunctionalInterface
public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
@@ -74,19 +75,17 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
*/
default <V> InstanceSupplier<V> andThen(
ThrowingBiFunction<RegisteredBean, ? super T, ? extends V> after) {
Assert.notNull(after, "'after' function must not be null");
return new InstanceSupplier<>() {
@Override
public V get(RegisteredBean registeredBean) throws Exception {
return after.applyWithException(registeredBean, InstanceSupplier.this.get(registeredBean));
}
@Override
public Method getFactoryMethod() {
return InstanceSupplier.this.getFactoryMethod();
}
};
}
@@ -115,22 +114,21 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
*/
static <T> InstanceSupplier<T> using(@Nullable Method factoryMethod, ThrowingSupplier<T> supplier) {
Assert.notNull(supplier, "Supplier must not be null");
if (supplier instanceof InstanceSupplier<T> instanceSupplier
&& instanceSupplier.getFactoryMethod() == factoryMethod) {
if (supplier instanceof InstanceSupplier<T> instanceSupplier &&
instanceSupplier.getFactoryMethod() == factoryMethod) {
return instanceSupplier;
}
return new InstanceSupplier<>() {
return new InstanceSupplier<>() {
@Override
public T get(RegisteredBean registeredBean) throws Exception {
return supplier.getWithException();
}
@Override
public Method getFactoryMethod() {
return factoryMethod;
}
};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -80,6 +80,18 @@ public final class RegisteredBean {
null);
}
/**
* Create a new {@link RegisteredBean} instance for a regular bean.
* @param beanFactory the source bean factory
* @param beanName the bean name
* @param mbd the pre-determined merged bean definition
* @return a new {@link RegisteredBean} instance
* @since 6.0.7
*/
static RegisteredBean of(ConfigurableListableBeanFactory beanFactory, String beanName, RootBeanDefinition mbd) {
return new RegisteredBean(beanFactory, () -> beanName, false, () -> mbd, null);
}
/**
* Create a new {@link RegisteredBean} instance for an inner-bean.
* @param parent the parent of the inner-bean
@@ -220,45 +232,34 @@ public final class RegisteredBean {
@Nullable
private volatile String resolvedBeanName;
InnerBeanResolver(RegisteredBean parent, @Nullable String innerBeanName,
BeanDefinition innerBeanDefinition) {
Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class,
parent.getBeanFactory());
InnerBeanResolver(RegisteredBean parent, @Nullable String innerBeanName, BeanDefinition innerBeanDefinition) {
Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class, parent.getBeanFactory());
this.parent = parent;
this.innerBeanName = innerBeanName;
this.innerBeanDefinition = innerBeanDefinition;
}
String resolveBeanName() {
String resolvedBeanName = this.resolvedBeanName;
if (resolvedBeanName != null) {
return resolvedBeanName;
}
resolvedBeanName = resolveInnerBean(
(beanName, mergedBeanDefinition) -> beanName);
resolvedBeanName = resolveInnerBean((beanName, mergedBeanDefinition) -> beanName);
this.resolvedBeanName = resolvedBeanName;
return resolvedBeanName;
}
RootBeanDefinition resolveMergedBeanDefinition() {
return resolveInnerBean(
(beanName, mergedBeanDefinition) -> mergedBeanDefinition);
return resolveInnerBean((beanName, mergedBeanDefinition) -> mergedBeanDefinition);
}
private <T> T resolveInnerBean(
BiFunction<String, RootBeanDefinition, T> resolver) {
private <T> T resolveInnerBean(BiFunction<String, RootBeanDefinition, T> resolver) {
// Always use a fresh BeanDefinitionValueResolver in case the parent merged bean definition has changed.
BeanDefinitionValueResolver beanDefinitionValueResolver = new BeanDefinitionValueResolver(
(AbstractAutowireCapableBeanFactory) this.parent.getBeanFactory(),
this.parent.getBeanName(), this.parent.getMergedBeanDefinition());
return beanDefinitionValueResolver.resolveInnerBean(this.innerBeanName,
this.innerBeanDefinition, resolver);
return beanDefinitionValueResolver.resolveInnerBean(this.innerBeanName, this.innerBeanDefinition, resolver);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -163,8 +163,8 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception with message: " +
ex.getTargetException().getMessage();
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory cbf &&
cbf.isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
@@ -127,9 +127,9 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
throw new BeanIsNotAFactoryException(beanName, bean.getClass());
}
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
if (bean instanceof FactoryBean<?> factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
try {
Object exposedObject = ((FactoryBean<?>) bean).getObject();
Object exposedObject = factoryBean.getObject();
if (exposedObject == null) {
throw new BeanCreationException(beanName, "FactoryBean exposed null object");
}
@@ -205,8 +205,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return singleton status of created object.
if (bean instanceof FactoryBean) {
return ((FactoryBean<?>) bean).isSingleton();
if (bean instanceof FactoryBean<?> factoryBean) {
return factoryBean.isSingleton();
}
return true;
}
@@ -215,8 +215,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return prototype status of created object.
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) bean).isPrototype()) ||
(bean instanceof FactoryBean && !((FactoryBean<?>) bean).isSingleton()));
return ((bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isPrototype()) ||
(bean instanceof FactoryBean<?> factoryBean && !factoryBean.isSingleton()));
}
@Override
@@ -246,9 +246,9 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
"Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]");
}
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
if (bean instanceof FactoryBean<?> factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
return ((FactoryBean<?>) bean).getObjectType();
return factoryBean.getObjectType();
}
return bean.getClass();
}
@@ -408,10 +408,10 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
String beanName = entry.getKey();
Object beanInstance = entry.getValue();
// Is bean a FactoryBean?
if (beanInstance instanceof FactoryBean<?> factory && !isFactoryType) {
if (beanInstance instanceof FactoryBean<?> factoryBean && !isFactoryType) {
// Match object created by FactoryBean.
Class<?> objectType = factory.getObjectType();
if ((includeNonSingletons || factory.isSingleton()) &&
Class<?> objectType = factoryBean.getObjectType();
if ((includeNonSingletons || factoryBean.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.put(beanName, getBean(beanName, type));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 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.
@@ -547,7 +547,8 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
* @see DefaultNamespaceHandlerResolver#DefaultNamespaceHandlerResolver(ClassLoader)
*/
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
ResourceLoader resourceLoader = getResourceLoader();
ClassLoader cl = (resourceLoader != null ? resourceLoader.getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
@@ -111,6 +111,7 @@ public class ArgumentConvertingMethodInvoker extends MethodInvoker {
* @see #doFindMatchingMethod
*/
@Override
@Nullable
protected Method findMatchingMethod() {
Method matchingMethod = super.findMatchingMethod();
// Second pass: look for method where arguments can be converted to parameter types.
@@ -18,7 +18,9 @@ package org.springframework.beans.factory;
import java.io.Closeable;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.text.NumberFormat;
import java.text.ParseException;
@@ -74,7 +76,9 @@ import org.springframework.beans.testfixture.beans.NestedTestBean;
import org.springframework.beans.testfixture.beans.SideEffectBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.beans.testfixture.beans.factory.DummyFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.convert.support.DefaultConversionService;
@@ -111,7 +115,21 @@ import static org.mockito.Mockito.verify;
*/
class DefaultListableBeanFactoryTests {
private DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
private final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
{
// No parameter name discovery expected unless named arguments are used
lbf.setParameterNameDiscoverer(new ParameterNameDiscoverer() {
@Override
public String[] getParameterNames(Method method) {
throw new UnsupportedOperationException();
}
@Override
public String[] getParameterNames(Constructor<?> ctor) {
throw new UnsupportedOperationException();
}
});
}
@Test
@@ -431,7 +449,6 @@ class DefaultListableBeanFactoryTests {
@Test
void empty() {
ListableBeanFactory lbf = new DefaultListableBeanFactory();
assertThat(lbf.getBeanDefinitionNames() != null).as("No beans defined --> array != null").isTrue();
assertThat(lbf.getBeanDefinitionNames().length == 0).as("No beans defined after no arg constructor").isTrue();
assertThat(lbf.getBeanDefinitionCount() == 0).as("No beans defined after no arg constructor").isTrue();
@@ -441,6 +458,7 @@ class DefaultListableBeanFactoryTests {
void emptyPropertiesPopulation() {
Properties p = new Properties();
registerBeanDefinitions(p);
assertThat(lbf.getBeanDefinitionCount() == 0).as("No beans defined after ignorable invalid").isTrue();
}
@@ -450,6 +468,7 @@ class DefaultListableBeanFactoryTests {
p.setProperty("foo", "bar");
p.setProperty("qwert", "er");
registerBeanDefinitions(p, "test");
assertThat(lbf.getBeanDefinitionCount() == 0).as("No beans defined after harmless ignorable rubbish").isTrue();
}
@@ -460,8 +479,9 @@ class DefaultListableBeanFactoryTests {
p.setProperty("test.name", "Tony");
p.setProperty("test.age", "48");
int count = registerBeanDefinitions(p);
assertThat(count == 1).as("1 beans registered, not " + count).isTrue();
singleTestBean(lbf);
testPropertiesPopulation(lbf);
}
@Test
@@ -472,8 +492,22 @@ class DefaultListableBeanFactoryTests {
p.setProperty(PREFIX + "test.name", "Tony");
p.setProperty(PREFIX + "test.age", "0x30");
int count = registerBeanDefinitions(p, PREFIX);
assertThat(count == 1).as("1 beans registered, not " + count).isTrue();
singleTestBean(lbf);
testPropertiesPopulation(lbf);
}
private void testPropertiesPopulation(ListableBeanFactory lbf) {
assertThat(lbf.getBeanDefinitionCount() == 1).as("1 beans defined").isTrue();
String[] names = lbf.getBeanDefinitionNames();
assertThat(names != lbf.getBeanDefinitionNames()).isTrue();
assertThat(names.length == 1).as("Array length == 1").isTrue();
assertThat(names[0].equals("test")).as("0th element == test").isTrue();
TestBean tb = (TestBean) lbf.getBean("test");
assertThat(tb != null).as("Test is non null").isTrue();
assertThat("Tony".equals(tb.getName())).as("Test bean name is Tony").isTrue();
assertThat(tb.getAge() == 48).as("Test bean age is 48").isTrue();
}
@Test
@@ -525,6 +559,7 @@ class DefaultListableBeanFactoryTests {
p.setProperty(PREFIX + "kerry.spouse(ref)", "rod");
registerBeanDefinitions(p, PREFIX);
assertThatExceptionOfType(BeansException.class).as("unresolved reference").isThrownBy(() ->
lbf.getBean("kerry"));
}
@@ -650,7 +685,6 @@ class DefaultListableBeanFactoryTests {
assertThat(kerry1 != null).as("Non null").isTrue();
assertThat(kerry1 == kerry2).as("Singletons equal").isTrue();
lbf = new DefaultListableBeanFactory();
p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.(scope)", BeanDefinition.SCOPE_PROTOTYPE);
@@ -661,7 +695,6 @@ class DefaultListableBeanFactoryTests {
assertThat(kerry1 != null).as("Non null").isTrue();
assertThat(kerry1 != kerry2).as("Prototypes NOT equal").isTrue();
lbf = new DefaultListableBeanFactory();
p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.(scope)", "singleton");
@@ -684,8 +717,8 @@ class DefaultListableBeanFactoryTests {
p.setProperty("rod.(singleton)", "false");
p.setProperty("rod.age", "34");
p.setProperty("rod.spouse", "*kerry");
registerBeanDefinitions(p);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.getBean("kerry"))
.satisfies(ex -> assertThat(ex.contains(BeanCurrentlyInCreationException.class)).isTrue());
@@ -706,7 +739,6 @@ class DefaultListableBeanFactoryTests {
assertThat(kerry1).as("Non null").isNotNull();
assertThat(kerry1 == kerry2).as("Singletons equal").isTrue();
lbf = new DefaultListableBeanFactory();
p = new Properties();
p.setProperty("wife.(class)", TestBean.class.getName());
p.setProperty("wife.name", "kerry");
@@ -721,7 +753,6 @@ class DefaultListableBeanFactoryTests {
assertThat(kerry1 != null).as("Non null").isTrue();
assertThat(kerry1 != kerry2).as("Prototypes NOT equal").isTrue();
lbf = new DefaultListableBeanFactory();
p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.(singleton)", "true");
@@ -796,41 +827,17 @@ class DefaultListableBeanFactoryTests {
assertThat(factory.getBean("child")).isInstanceOf(DerivedTestBean.class);
}
@Test
void nameAlreadyBound() {
Properties p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.age", "35");
registerBeanDefinitions(p);
try {
registerBeanDefinitions(p);
}
catch (BeanDefinitionStoreException ex) {
assertThat(ex.getBeanName()).isEqualTo("kerry");
// expected
}
}
private void singleTestBean(ListableBeanFactory lbf) {
assertThat(lbf.getBeanDefinitionCount() == 1).as("1 beans defined").isTrue();
String[] names = lbf.getBeanDefinitionNames();
assertThat(names != lbf.getBeanDefinitionNames()).isTrue();
assertThat(names.length == 1).as("Array length == 1").isTrue();
assertThat(names[0].equals("test")).as("0th element == test").isTrue();
TestBean tb = (TestBean) lbf.getBean("test");
assertThat(tb != null).as("Test is non null").isTrue();
assertThat("Tony".equals(tb.getName())).as("Test bean name is Tony").isTrue();
assertThat(tb.getAge() == 48).as("Test bean age is 48").isTrue();
}
@Test
void aliasCircle() {
lbf.registerAlias("test", "test2");
lbf.registerAlias("test2", "test3");
assertThatIllegalStateException().isThrownBy(() ->
lbf.registerAlias("test3", "test2"));
assertThatIllegalStateException().isThrownBy(() ->
lbf.registerAlias("test3", "test"));
lbf.registerAlias("test", "test3");
}
@@ -840,6 +847,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerAlias("test", "testAlias");
lbf.registerAlias("testAlias", "testAlias2");
lbf.registerAlias("testAlias2", "testAlias3");
Object bean = lbf.getBean("test");
assertThat(lbf.getBean("testAlias")).isSameAs(bean);
assertThat(lbf.getBean("testAlias2")).isSameAs(bean);
@@ -854,6 +862,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerAlias("test", "test2");
lbf.registerAlias("test", "testX");
lbf.registerBeanDefinition("testX", new RootBeanDefinition(TestBean.class));
assertThat(lbf.getBean("test")).isInstanceOf(NestedTestBean.class);
assertThat(lbf.getBean("test2")).isInstanceOf(NestedTestBean.class);
assertThat(lbf.getBean("testX")).isInstanceOf(TestBean.class);
@@ -866,13 +875,15 @@ class DefaultListableBeanFactoryTests {
BeanDefinition newDef = new RootBeanDefinition(NestedTestBean.class);
lbf.registerBeanDefinition("test", oldDef);
lbf.registerAlias("test", "testX");
assertThatExceptionOfType(BeanDefinitionOverrideException.class).isThrownBy(() ->
lbf.registerBeanDefinition("test", newDef))
lbf.registerBeanDefinition("test", newDef))
.satisfies(ex -> {
assertThat(ex.getBeanName()).isEqualTo("test");
assertThat(ex.getBeanDefinition()).isEqualTo(newDef);
assertThat(ex.getExistingDefinition()).isEqualTo(oldDef);
});
assertThatExceptionOfType(BeanDefinitionOverrideException.class).isThrownBy(() ->
lbf.registerBeanDefinition("testX", newDef))
.satisfies(ex -> {
@@ -888,6 +899,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerAlias("test", "testAlias");
lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class));
lbf.registerAlias("test", "testAlias");
assertThat(lbf.getBean("test")).isInstanceOf(NestedTestBean.class);
assertThat(lbf.getBean("testAlias")).isInstanceOf(NestedTestBean.class);
}
@@ -900,6 +912,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(NestedTestBean.class);
bd2.getConstructorArgumentValues().addIndexedArgumentValue(0, "value0");
lbf.registerBeanDefinition("test", bd2);
assertThat(lbf.getBean("test")).isInstanceOf(NestedTestBean.class);
assertThat(lbf.getBean("test", NestedTestBean.class).getCompany()).isEqualTo("value0");
}
@@ -916,6 +929,7 @@ class DefaultListableBeanFactoryTests {
lbf.removeAlias("test2");
lbf.registerBeanDefinition("test", new RootBeanDefinition(NestedTestBean.class));
lbf.registerAlias("test", "test2");
assertThat(lbf.getBean("test")).isInstanceOf(NestedTestBean.class);
assertThat(lbf.getBean("test2")).isInstanceOf(NestedTestBean.class);
}
@@ -955,6 +969,7 @@ class DefaultListableBeanFactoryTests {
p.setProperty("k.name", "kerry");
p.setProperty("k.spouse", "*r");
registerBeanDefinitions(p);
TestBean k = (TestBean) lbf.getBean("k");
TestBean r = (TestBean) lbf.getBean("r");
assertThat(k.getSpouse() == r).isTrue();
@@ -967,6 +982,7 @@ class DefaultListableBeanFactoryTests {
p.setProperty("r.(class)", TestBean.class.getName());
p.setProperty("r.name", "*" + name);
registerBeanDefinitions(p);
TestBean r = (TestBean) lbf.getBean("r");
assertThat(r.getName().equals(name)).isTrue();
}
@@ -982,6 +998,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("testBean", bd);
TestBean testBean = (TestBean) lbf.getBean("testBean");
assertThat(testBean.getMyFloat() == 1.1f).isTrue();
}
@@ -999,11 +1016,13 @@ class DefaultListableBeanFactoryTests {
}
});
lbf.setConversionService(conversionService);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1,1");
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("testBean", bd);
TestBean testBean = (TestBean) lbf.getBean("testBean");
assertThat(testBean.getMyFloat() == 1.1f).isTrue();
}
@@ -1020,6 +1039,7 @@ class DefaultListableBeanFactoryTests {
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("testBean", bd);
lbf.registerSingleton("myFloat", "1,1");
TestBean testBean = (TestBean) lbf.getBean("testBean");
assertThat(testBean.getMyFloat() == 1.1f).isTrue();
}
@@ -1034,6 +1054,7 @@ class DefaultListableBeanFactoryTests {
cav.addIndexedArgumentValue(0, "myName");
cav.addIndexedArgumentValue(1, "myAge");
lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, cav, pvs));
TestBean testBean = (TestBean) lbf.getBean("testBean");
assertThat(testBean.getName()).isEqualTo("myName");
assertThat(testBean.getAge()).isEqualTo(5);
@@ -1051,6 +1072,7 @@ class DefaultListableBeanFactoryTests {
cav.addIndexedArgumentValue(1, "myAge");
lbf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class, cav, pvs));
lbf.registerSingleton("myFloat", "1,1");
TestBean testBean = (TestBean) lbf.getBean("testBean");
assertThat(testBean.getName()).isEqualTo("myName");
assertThat(testBean.getAge()).isEqualTo(5);
@@ -1167,6 +1189,7 @@ class DefaultListableBeanFactoryTests {
bd1.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("testBean", bd1);
assertThat(lbf.getBean("testBean")).isInstanceOf(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(NestedTestBean.class);
bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("testBean", bd2);
@@ -1181,8 +1204,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getResourceArray()[0]).isEqualTo(new UrlResource("http://localhost:8080"));
assertThat(ab.getResourceArray()[1]).isEqualTo(new UrlResource("http://localhost:9090"));
}
@@ -1192,8 +1215,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getResourceArray()).isNull();
}
@@ -1205,8 +1228,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getIntegerArray()[0]).isEqualTo(4);
assertThat(ab.getIntegerArray()[1]).isEqualTo(5);
}
@@ -1216,8 +1239,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getIntegerArray()).isNull();
}
@@ -1231,8 +1254,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getIntegerArray()[0]).isEqualTo(4);
assertThat(ab.getIntegerArray()[1]).isEqualTo(5);
assertThat(ab.getResourceArray()[0]).isEqualTo(new UrlResource("http://localhost:8080"));
@@ -1247,8 +1270,8 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("arrayBean", rbd);
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean");
assertThat(ab.getIntegerArray()).isNull();
assertThat(ab.getResourceArray()).isNull();
}
@@ -1265,6 +1288,7 @@ class DefaultListableBeanFactoryTests {
pvs.add("locations", new String[]{"#{foo}"});
rbd.setPropertyValues(pvs);
lbf.registerBeanDefinition("myProperties", rbd);
Properties properties = (Properties) lbf.getBean("myProperties");
assertThat(properties.getProperty("foo")).isEqualTo("bar");
}
@@ -1287,6 +1311,7 @@ class DefaultListableBeanFactoryTests {
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("rod", bd);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(1);
// Depends on age, name and spouse (TestBean)
Object registered = lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(1);
@@ -1303,6 +1328,7 @@ class DefaultListableBeanFactoryTests {
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("rod", bd);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(1);
Object registered = lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(1);
ConstructorDependency kerry = (ConstructorDependency) registered;
@@ -1316,6 +1342,8 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("rod", bd);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("rod2", bd2);
lbf.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(ConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false))
.withMessageContaining("rod")
@@ -1329,6 +1357,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("rod", bd);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(1);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(UnsatisfiedConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true));
@@ -1340,6 +1369,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("spouse", bd);
ConstructorDependenciesBean bean = (ConstructorDependenciesBean)
lbf.autowire(ConstructorDependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
Object spouse = lbf.getBean("spouse");
assertThat(bean.getSpouse1() == spouse).isTrue();
assertThat(BeanFactoryUtils.beanOfType(lbf, TestBean.class) == spouse).isTrue();
@@ -1351,6 +1381,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("spouse", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
TestBean spouse = (TestBean) lbf.getBean("spouse");
assertThat(bean.getSpouse()).isEqualTo(spouse);
assertThat(BeanFactoryUtils.beanOfType(lbf, TestBean.class) == spouse).isTrue();
@@ -1360,6 +1391,7 @@ class DefaultListableBeanFactoryTests {
void autowireBeanByNameWithDependencyCheck() {
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true));
}
@@ -1370,6 +1402,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("spous", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
assertThat(bean.getSpouse()).isNull();
}
@@ -1381,6 +1414,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn("tb1");
lbf.registerBeanDefinition("tb2", bd2);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.preInstantiateSingletons())
.withMessageContaining("Circular")
@@ -1399,6 +1433,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
bd3.setDependsOn("tb1");
lbf.registerBeanDefinition("tb3", bd3);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
lbf::preInstantiateSingletons)
.withMessageContaining("Circular")
@@ -1408,30 +1443,31 @@ class DefaultListableBeanFactoryTests {
@Test
void getBeanByTypeWithNoneFound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class));
}
@Test
void getBeanByTypeWithLateRegistration() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class));
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@Test
void getBeanByTypeWithLateRegistrationAgainstFrozen() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.freezeConfiguration();
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class));
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@@ -1441,7 +1477,8 @@ class DefaultListableBeanFactoryTests {
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
parent.registerBeanDefinition("bd1", bd1);
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parent);
lbf.setParentBeanFactory(parent);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@@ -1452,6 +1489,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class));
}
@@ -1464,6 +1502,7 @@ class DefaultListableBeanFactoryTests {
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd2");
assertThat(lbf.containsSingleton("bd1")).isFalse();
@@ -1472,12 +1511,12 @@ class DefaultListableBeanFactoryTests {
@Test
@SuppressWarnings("rawtypes")
void getFactoryBeanByTypeWithPrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(NullTestBeanFactoryBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(NullTestBeanFactoryBean.class);
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
NullTestBeanFactoryBean factoryBeanByType = lbf.getBean(NullTestBeanFactoryBean.class);
NullTestBeanFactoryBean bd1FactoryBean = (NullTestBeanFactoryBean)lbf.getBean("&bd1");
NullTestBeanFactoryBean bd2FactoryBean = (NullTestBeanFactoryBean)lbf.getBean("&bd2");
@@ -1496,6 +1535,7 @@ class DefaultListableBeanFactoryTests {
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class))
.withMessageContaining("more than one 'primary'");
@@ -1511,6 +1551,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("bd2", bd2);
lbf.registerBeanDefinition("bd3", bd3);
lbf.preInstantiateSingletons();
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@@ -1527,6 +1568,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("bd3", bd3);
lbf.registerBeanDefinition("bd4", bd4);
lbf.preInstantiateSingletons();
TestBean bean = lbf.getBean(TestBeanRecipient.class).testBean;
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@@ -1538,6 +1580,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(HighPriorityTestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(TestBean.class))
.withMessageContaining("Multiple beans found with the same priority")
@@ -1551,6 +1594,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(NullTestBeanFactoryBean.class);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd1");
}
@@ -1563,6 +1607,7 @@ class DefaultListableBeanFactoryTests {
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName()).isEqualTo("bd2");
}
@@ -1620,7 +1665,7 @@ class DefaultListableBeanFactoryTests {
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
parent.registerBeanDefinition("bd1", bd1);
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parent);
lbf.setParentBeanFactory(parent);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class);
assertThat(bean.beanName).isEqualTo("bd1");
@@ -1652,6 +1697,7 @@ class DefaultListableBeanFactoryTests {
bd2.getConstructorArgumentValues().addGenericArgumentValue("43");
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
lbf.getBean(ConstructorDependency.class));
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() ->
@@ -1769,9 +1815,9 @@ class DefaultListableBeanFactoryTests {
@SuppressWarnings("rawtypes")
void beanProviderSerialization() throws Exception {
lbf.setSerializationId("test");
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
ObjectProvider deserialized = SerializationTestUtils.serializeAndDeserialize(provider);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(
deserialized::getObject);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
@@ -1814,6 +1860,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("test", bd);
DependenciesBean bean = (DependenciesBean)
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
TestBean test = (TestBean) lbf.getBean("test");
assertThat(bean.getSpouse()).isEqualTo(test);
}
@@ -1828,8 +1875,10 @@ class DefaultListableBeanFactoryTests {
void autowireBeanWithFactoryBeanByType() {
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
lbf.registerBeanDefinition("factoryBean", bd);
LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean");
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean);
@@ -1837,16 +1886,17 @@ class DefaultListableBeanFactoryTests {
@Test
void autowireBeanWithFactoryBeanByTypeWithPrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(LazyInitFactory.class);
RootBeanDefinition bd2 = new RootBeanDefinition(LazyInitFactory.class);
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
LazyInitFactory bd1FactoryBean = (LazyInitFactory) lbf.getBean("&bd1");
LazyInitFactory bd2FactoryBean = (LazyInitFactory) lbf.getBean("&bd2");
assertThat(bd1FactoryBean).isNotNull();
assertThat(bd2FactoryBean).isNotNull();
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
assertThat(bean.getFactoryBean()).isNotEqualTo(bd1FactoryBean);
@@ -1915,6 +1965,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
lbf.registerBeanDefinition("factoryBean", bd);
LazyInitFactory factoryBean = (LazyInitFactory) lbf.getBean("&factoryBean");
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
assertThatExceptionOfType(TypeMismatchException.class).isThrownBy(() ->
lbf.autowire(FactoryBeanDependentBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true));
@@ -1926,6 +1977,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withMessageContaining("test")
@@ -1966,6 +2018,7 @@ class DefaultListableBeanFactoryTests {
bd2.setPrimary(true);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class);
@@ -1991,6 +2044,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(HighPriorityTestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true))
.withCauseExactlyInstanceOf(NoUniqueBeanDefinitionException.class)
@@ -2030,6 +2084,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("spouse", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
TestBean spouse = (TestBean) lbf.getBean("spouse");
assertThat(spouse).isEqualTo(existingBean.getSpouse());
assertThat(BeanFactoryUtils.beanOfType(lbf, TestBean.class)).isSameAs(spouse);
@@ -2040,6 +2095,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("spous", bd);
DependenciesBean existingBean = new DependenciesBean();
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true));
}
@@ -2050,6 +2106,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("spous", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
assertThat(existingBean.getSpouse()).isNull();
}
@@ -2059,6 +2116,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("test", bd);
DependenciesBean existingBean = new DependenciesBean();
lbf.autowireBeanProperties(existingBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
TestBean test = (TestBean) lbf.getBean("test");
assertThat(test).isEqualTo(existingBean.getSpouse());
}
@@ -2126,6 +2184,23 @@ class DefaultListableBeanFactoryTests {
assertThat(tb.wasDestroyed()).isTrue();
}
@Test
void createBeanWithNonDefaultConstructor() {
lbf.registerBeanDefinition("otherTestBean", new RootBeanDefinition(TestBean.class));
TestBeanRecipient tb = lbf.createBean(TestBeanRecipient.class);
assertThat(lbf.containsSingleton("otherTestBean")).isTrue();
assertThat(tb.testBean).isEqualTo(lbf.getBean("otherTestBean"));
lbf.destroyBean(tb);
}
@Test
void createBeanWithPreferredDefaultConstructor() {
lbf.registerBeanDefinition("otherTestBean", new RootBeanDefinition(TestBean.class));
TestBean tb = lbf.createBean(TestBean.class);
assertThat(lbf.containsSingleton("otherTestBean")).isFalse();
lbf.destroyBean(tb);
}
@Test
void configureBean() {
MutablePropertyValues pvs = new MutablePropertyValues();
@@ -2133,6 +2208,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.setPropertyValues(pvs);
lbf.registerBeanDefinition("test", bd);
TestBean tb = new TestBean();
assertThat(tb.getAge()).isEqualTo(0);
lbf.configureBean(tb, "test");
@@ -2150,6 +2226,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class);
tbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_NAME);
lbf.registerBeanDefinition("test", tbd);
TestBean tb = new TestBean();
lbf.configureBean(tb, "test");
assertThat(tb.getBeanFactory()).isSameAs(lbf);
@@ -2167,6 +2244,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("bean" + i, bd);
}
lbf.preInstantiateSingletons();
for (int i = 0; i < 1000; i++) {
TestBean bean = (TestBean) lbf.getBean("bean" + i);
TestBean otherBean = (TestBean) lbf.getBean("bean" + (i < 99 ? i + 1 : 0));
@@ -2179,6 +2257,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@@ -2187,6 +2266,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@@ -2195,6 +2275,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> lbf.getBeansOfType(String.class));
}
@@ -2222,12 +2303,14 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyWithClassResolution.class);
bd.getConstructorArgumentValues().addGenericArgumentValue("java.lang.Strin");
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@Test
void beanDefinitionWithInterface() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(ITestBean.class));
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.getBean("test"))
.withMessageContaining("interface")
@@ -2237,6 +2320,7 @@ class DefaultListableBeanFactoryTests {
@Test
void beanDefinitionWithAbstractClass() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(AbstractBeanFactory.class));
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
lbf.getBean("test"))
.withMessageContaining("abstract")
@@ -2280,6 +2364,7 @@ class DefaultListableBeanFactoryTests {
void lazyInitFactory() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(LazyInitFactory.class));
lbf.preInstantiateSingletons();
LazyInitFactory factory = (LazyInitFactory) lbf.getBean("&test");
assertThat(factory.initialized).isFalse();
}
@@ -2288,6 +2373,7 @@ class DefaultListableBeanFactoryTests {
void smartInitFactory() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(EagerInitFactory.class));
lbf.preInstantiateSingletons();
EagerInitFactory factory = (EagerInitFactory) lbf.getBean("&test");
assertThat(factory.initialized).isTrue();
}
@@ -2298,6 +2384,7 @@ class DefaultListableBeanFactoryTests {
stringDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
stringDef.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue("value"));
lbf.registerBeanDefinition("string", stringDef);
String val1 = lbf.getBean("string", String.class);
String val2 = lbf.getBean("string", String.class);
assertThat(val1).isEqualTo("value");
@@ -2312,9 +2399,11 @@ class DefaultListableBeanFactoryTests {
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.getConstructorArgumentValues().addGenericArgumentValue(list);
lbf.registerBeanDefinition("test", bd);
DerivedTestBean tb = (DerivedTestBean) lbf.getBean("test");
assertThat(tb.getName()).isEqualTo("myName");
assertThat(tb.getBeanName()).isEqualTo("myBeanName");
DerivedTestBean tb2 = (DerivedTestBean) lbf.getBean("test");
assertThat(tb != tb2).isTrue();
assertThat(tb2.getName()).isEqualTo("myName");
@@ -2329,9 +2418,11 @@ class DefaultListableBeanFactoryTests {
bd.setFactoryMethodName("create");
bd.getConstructorArgumentValues().addGenericArgumentValue(list);
lbf.registerBeanDefinition("test", bd);
DerivedTestBean tb = (DerivedTestBean) lbf.getBean("test");
assertThat(tb.getName()).isEqualTo("myName");
assertThat(tb.getBeanName()).isEqualTo("myBeanName");
DerivedTestBean tb2 = (DerivedTestBean) lbf.getBean("test");
assertThat(tb != tb2).isTrue();
assertThat(tb2.getName()).isEqualTo("myName");
@@ -2344,6 +2435,7 @@ class DefaultListableBeanFactoryTests {
bd.setInitMethodNames("init1", "init2");
bd.setDestroyMethodNames("destroy2", "destroy1");
lbf.registerBeanDefinition("test", bd);
BeanWithInitAndDestroyMethods bean = lbf.getBean("test", BeanWithInitAndDestroyMethods.class);
assertThat(bean.initMethods).containsExactly("init", "init1", "init2");
assertThat(bean.destroyMethods).isEmpty();
@@ -2361,6 +2453,7 @@ class DefaultListableBeanFactoryTests {
return new TestBean();
}
});
BeanWithDisposableBean.closed = false;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
@@ -2377,6 +2470,7 @@ class DefaultListableBeanFactoryTests {
return new TestBean();
}
});
BeanWithDisposableBean.closed = false;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
@@ -2394,6 +2488,7 @@ class DefaultListableBeanFactoryTests {
return new TestBean();
}
});
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
@@ -2598,6 +2693,7 @@ class DefaultListableBeanFactoryTests {
}
});
lbf.preInstantiateSingletons();
TestBean tb = (TestBean) lbf.getBean("test");
assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField);
if (!skipPropertyPopulation) {
@@ -2641,6 +2737,7 @@ class DefaultListableBeanFactoryTests {
bd.setFactoryMethodName("of");
bd.getConstructorArgumentValues().addGenericArgumentValue("CONTENT");
lbf.registerBeanDefinition("optionalBean", bd);
assertThat((Optional<?>) lbf.getBean(Optional.class)).isEqualTo(Optional.of("CONTENT"));
}
@@ -2649,6 +2746,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(Optional.class);
bd.setFactoryMethodName("empty");
lbf.registerBeanDefinition("optionalBean", bd);
assertThat((Optional<?>) lbf.getBean(Optional.class)).isSameAs(Optional.empty());
}
@@ -2657,18 +2755,21 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(NonPublicEnumHolder.class);
bd.getConstructorArgumentValues().addGenericArgumentValue("VALUE_1");
lbf.registerBeanDefinition("holderBean", bd);
NonPublicEnumHolder holder = (NonPublicEnumHolder) lbf.getBean("holderBean");
assertThat(holder.getNonPublicEnum()).isEqualTo(NonPublicEnum.VALUE_1);
}
@SuppressWarnings("deprecation")
private int registerBeanDefinitions(Properties p) {
return (new org.springframework.beans.factory.support.PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p);
return registerBeanDefinitions(p, null);
}
@SuppressWarnings("deprecation")
private int registerBeanDefinitions(Properties p, String prefix) {
private int registerBeanDefinitions(Properties p, @Nullable String prefix) {
for (String beanName : lbf.getBeanDefinitionNames()) {
lbf.removeBeanDefinition(beanName);
}
return (new org.springframework.beans.factory.support.PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, prefix);
}
@@ -2720,7 +2821,7 @@ class DefaultListableBeanFactoryTests {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -27,10 +27,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AbstractAutowireCapableBeanFactory} instance supplier
* support.
* Tests for {@link AbstractAutowireCapableBeanFactory} instance supplier support.
*
* @author Phillip Webb
* @author Juergen Hoeller
*/
public class BeanFactorySupplierTests {
@@ -44,13 +44,38 @@ public class BeanFactorySupplierTests {
}
@Test
void getBeanWhenUsingInstanceSupplier() {
void getBeanWithInnerBeanUsingRegularSupplier() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setInstanceSupplier(InstanceSupplier
.of(registeredBean -> "I am bean " + registeredBean.getBeanName()));
beanDefinition.setInstanceSupplier(() -> "I am supplied");
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
beanFactory.registerBeanDefinition("test", outerBean);
assertThat(beanFactory.getBean("test")).asString().startsWith("I am supplied");
}
@Test
void getBeanWhenUsingInstanceSupplier() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean ->
"I am bean " + registeredBean.getBeanName() + " of " + registeredBean.getBeanClass()));
beanFactory.registerBeanDefinition("test", beanDefinition);
assertThat(beanFactory.getBean("test")).isEqualTo("I am bean test");
assertThat(beanFactory.getBean("test")).isEqualTo("I am bean test of class java.lang.String");
}
@Test
void getBeanWithInnerBeanUsingInstanceSupplier() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean ->
"I am bean " + registeredBean.getBeanName() + " of " + registeredBean.getBeanClass()));
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
beanFactory.registerBeanDefinition("test", outerBean);
assertThat(beanFactory.getBean("test")).asString()
.startsWith("I am bean (inner bean)")
.endsWith(" of class java.lang.String");
}
@Test
@@ -62,6 +87,17 @@ public class BeanFactorySupplierTests {
assertThat(beanFactory.getBean("test")).isEqualTo("I am supplied");
}
@Test
void getBeanWithInnerBeanUsingThrowableSupplier() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setInstanceSupplier(ThrowingSupplier.of(() -> "I am supplied"));
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
beanFactory.registerBeanDefinition("test", outerBean);
assertThat(beanFactory.getBean("test")).asString().startsWith("I am supplied");
}
@Test
void getBeanWhenUsingThrowableSupplierThatThrowsCheckedException() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 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.
@@ -22,6 +22,7 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
@@ -194,7 +195,7 @@ public class PagedListHolderTests {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -16,6 +16,8 @@
package org.springframework.beans.testfixture.beans;
import org.springframework.lang.Nullable;
/**
* Simple nested test bean used for testing bean factories, AOP framework etc.
*
@@ -43,7 +45,7 @@ public class NestedTestBean implements INestedTestBean {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof NestedTestBean ntb)) {
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2006 the original author or authors.
* Copyright 2002-2023 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.
@@ -16,6 +16,8 @@
package org.springframework.beans.testfixture.beans;
import org.springframework.lang.Nullable;
/**
* @author Rob Harrop
* @since 2.0
@@ -38,7 +40,7 @@ public class Pet {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2023 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.
@@ -18,6 +18,7 @@ package org.springframework.beans.testfixture.beans;
import java.io.Serializable;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -63,7 +64,7 @@ public class SerializablePerson implements Person, Serializable {
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (!(other instanceof SerializablePerson p)) {
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -30,6 +30,7 @@ import java.util.Set;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -464,7 +465,7 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 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.
@@ -133,8 +133,8 @@ public class CandidateComponentsIndexer implements Processor {
List<TypeElement> list = new ArrayList<>();
for (Element element : elements) {
if ((element.getKind().isClass() || element.getKind() == ElementKind.INTERFACE) &&
element.getModifiers().contains(Modifier.STATIC) && element instanceof TypeElement) {
list.add((TypeElement) element);
element.getModifiers().contains(Modifier.STATIC) && element instanceof TypeElement te) {
list.add(te);
}
}
return list;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@@ -73,8 +73,8 @@ class TypeHelper {
}
private String getQualifiedName(Element element) {
if (element instanceof QualifiedNameable) {
return ((QualifiedNameable) element).getQualifiedName().toString();
if (element instanceof QualifiedNameable qualifiedNameable) {
return qualifiedNameable.getQualifiedName().toString();
}
return element.toString();
}
@@ -0,0 +1,4 @@
/**
* Core package for Spring Framework's scanned component index.
*/
package org.springframework.context.index.processor;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 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.
@@ -93,8 +93,8 @@ public class CaffeineCache extends AbstractValueAdaptingCache {
@Override
@Nullable
protected Object lookup(Object key) {
if (this.cache instanceof LoadingCache) {
return ((LoadingCache<Object, Object>) this.cache).get(key);
if (this.cache instanceof LoadingCache<Object, Object> loadingCache) {
return loadingCache.get(key);
}
return this.cache.getIfPresent(key);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 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.
@@ -51,6 +51,7 @@ import org.springframework.util.ObjectUtils;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Sam Brannen
* @author Brian Clozel
* @since 4.3
* @see CaffeineCache
*/
@@ -188,8 +189,13 @@ public class CaffeineCacheManager implements CacheManager {
@Override
@Nullable
public Cache getCache(String name) {
return this.cacheMap.computeIfAbsent(name, cacheName ->
this.dynamic ? createCaffeineCache(cacheName) : null);
if (this.dynamic) {
Cache cache = this.cacheMap.get(name);
return (cache != null) ? cache : this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
}
else {
return this.cacheMap.get(name);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 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.
@@ -48,8 +48,8 @@ public abstract class AbstractJCacheConfiguration extends AbstractCachingConfigu
protected void useCachingConfigurer(CachingConfigurerSupplier cachingConfigurerSupplier) {
super.useCachingConfigurer(cachingConfigurerSupplier);
this.exceptionCacheResolver = cachingConfigurerSupplier.adapt(config -> {
if (config instanceof JCacheConfigurer) {
return ((JCacheConfigurer) config).exceptionCacheResolver();
if (config instanceof JCacheConfigurer jcacheConfigurer) {
return jcacheConfigurer.exceptionCacheResolver();
}
return null;
});
@@ -1,10 +1,10 @@
/**
* Support package for declarative JSR-107 caching configuration. Used
* by the regular Spring's caching configuration when it detects the
* JSR-107 API and Spring's JCache implementation.
* Support package for declarative JSR-107 caching configuration. Used by Spring's
* caching configuration when it detects the JSR-107 API and Spring's JCache
* implementation.
*
* <p>Provide an extension of the {@code CachingConfigurer} that exposes
* the exception cache resolver to use, see {@code JCacheConfigurer}.
* <p>Provides an extension of the {@code CachingConfigurer} that exposes
* the exception cache resolver to use (see {@code JCacheConfigurer}).
*/
@NonNullApi
@NonNullFields
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -42,8 +42,8 @@ class DefaultCacheKeyInvocationContext<A extends Annotation> extends DefaultCach
public DefaultCacheKeyInvocationContext(AbstractJCacheKeyOperation<A> operation, Object target, Object[] args) {
super(operation, target, args);
this.keyParameters = operation.getKeyParameters(args);
if (operation instanceof CachePutOperation) {
this.valueParameter = ((CachePutOperation) operation).getValueParameter(args);
if (operation instanceof CachePutOperation cachePutOperation) {
this.valueParameter = cachePutOperation.getValueParameter(args);
}
else {
this.valueParameter = null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
@@ -71,11 +71,11 @@ public class AdaptableJobFactory implements JobFactory {
* @see DelegatingJob
*/
protected Job adaptJob(Object jobObject) throws Exception {
if (jobObject instanceof Job) {
return (Job) jobObject;
if (jobObject instanceof Job job) {
return job;
}
else if (jobObject instanceof Runnable) {
return new DelegatingJob((Runnable) jobObject);
else if (jobObject instanceof Runnable runnable) {
return new DelegatingJob(runnable);
}
else {
throw new IllegalArgumentException(

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