Compare commits

...

207 Commits

Author SHA1 Message Date
Spring Builds b19f98bfd2 Release v6.1.3 2024-01-11 08:59:42 +00:00
rstoyanchev 50fad9ed05 Lenient port handling in HierarchicalUriComponents#toUriString
Closes gh-32003
2024-01-10 20:59:59 +00:00
rstoyanchev 2b4ffe0391 Consistent inclusion of baseUrl in URI_TEMPLATE attribute
Closes gh-31882
2024-01-10 20:39:14 +00:00
rstoyanchev e7eaaaded1 Explicit initialization of shouldValidate flags
Closes gh-32007
2024-01-10 18:13:25 +00:00
Sam Brannen f6e52900a2 Polish SpEL documentation 2024-01-10 17:39:19 +01:00
Sam Brannen 62b5e42769 Fix syntax for disabled selection/projection tests in ParsingTests 2024-01-10 17:39:19 +01:00
Sébastien Deleuze 1631be5660 Provide guidelines in AspectJ documentation to avoid dumps
Closes gh-27650
2024-01-10 17:08:56 +01:00
Juergen Hoeller 9ccc72a9fb Upgrade to spring-javaformat-checkstyle 0.0.41 2024-01-10 17:07:01 +01:00
Sébastien Deleuze 01b2856114 Document Kotlin internal modifier impact on @Bean
Closes gh-31985
2024-01-10 13:41:46 +01:00
rstoyanchev 6dca7b28cc Polishing contribution
Closes gh-31991
2024-01-10 12:17:20 +00:00
Olga MaciaszekSharma 864b1c95cd Document exception handling for RestClient and RestTemplate-backed interface clients. 2024-01-10 12:17:20 +00:00
rstoyanchev 168c60c18a Polishing contribution
Closes gh-31992
2024-01-10 12:17:20 +00:00
Aaron Rosser 1e49334209 Exclude query from URI in WebClient checkpoints
See gh-31992
2024-01-10 12:17:20 +00:00
Juergen Hoeller 79cc0ec4aa Make prepareSynchronization overridable again
Closes gh-32000
2024-01-10 13:07:20 +01:00
Juergen Hoeller fdfa4284de Upgrade to Reactor 2023.0.2 and Micrometer 1.12.2
Includes SLF4J 2.0.11, Tomcat 10.1.18, Apache HttpClient 5.3, POI 5.2.5, OpenPDF 1.3.36

Closes gh-31995
Closes gh-31996
2024-01-10 10:48:12 +01:00
Arjen Poutsma 49d3ec58fc Use timeout for JdkClientHttpRequest response retrieval
This commit ensures that, in JdkClientHttpRequest, the response is
obtained  using a timeout, instead of blocking indefinitely.

Closes gh-31911
2024-01-10 09:53:16 +01:00
Stéphane Nicoll c4405104a8 Polish 2024-01-09 17:31:34 +01:00
Sam Brannen 4b0443090a Polish Javadoc for test annotations 2024-01-09 16:32:22 +01:00
Sam Brannen b1bf1b0c82 Update Spring Properties section of reference manual
This commit documents the following Spring properties in the reference
manual.

- spring.aot.enabled
- spring.cache.reactivestreams.ignore
- spring.classformat.ignore
- spring.context.checkpoint
- spring.context.exit

Closes gh-31987
2024-01-09 14:23:14 +01:00
Sam Brannen 5d45b94e93 Polishing 2024-01-09 14:23:14 +01:00
Sébastien Deleuze 598c972a78 Update ContentRequestMatchers#multipartData Javadoc
This commit updates ContentRequestMatchers#multipartData
Javadoc to mention Tomcat fork of Commons FileUpload library
instead of the original variant.

It also adds a similar note to
ContentRequestMatchers#multipartDataContains.

Closes gh-31988
2024-01-09 14:12:09 +01:00
rstoyanchev 2593b60f2b Do not set exception attribute if response body is set
ResponseEntityExceptionHandler should not set the exception attribute
when there is a response body, and the response is fully handled.

Closes gh-31541
2024-01-09 12:11:23 +00:00
Arjen Poutsma e6f638132c Create case-insensitive copy in RestClientResponseException
Closes gh-31978
2024-01-09 12:11:02 +01:00
Sam Brannen b823c46aae Revise SpEL Evaluation documentation 2024-01-09 12:03:28 +01:00
Juergen Hoeller 4d11307b84 Polishing 2024-01-09 11:55:04 +01:00
Juergen Hoeller 03b6e51225 Evaluate thread-bound MethodInvocation only if it matches current Method
Closes gh-26068
2024-01-09 11:54:05 +01:00
Sam Brannen 785598629a Make max length of SpEL expressions in an ApplicationContext configurable
This commit introduces support for a Spring property named
`spring.context.expression.maxLength`. When set, the value of that
property is used internally in StandardBeanExpressionResolver to
configure the SpelParserConfiguration used when evaluating String
values in bean definitions, @⁠Value, etc.

Closes gh-31952
2024-01-09 11:15:32 +01:00
Arjen Poutsma 3452354a11 Ensure correct capacity in DefaultDataBuffer
Closes gh-31873
2024-01-09 10:33:46 +01:00
Juergen Hoeller bb1cdb6b48 Consistently expose parameter annotations from base classes as well
Closes gh-25788
2024-01-08 21:03:32 +01:00
rstoyanchev 37fa82c578 Lenient rejectedValue lookup in SpringValidatorAdapter
Closes gh-29043
2024-01-08 16:39:53 +00:00
Stéphane Nicoll 1f2d29ee08 Polish 2024-01-08 17:12:33 +01:00
Sébastien Deleuze cffc8835c6 Mention parameter-names in Jackson2ObjectMapperBuilder documentation
Closes gh-31959
2024-01-08 14:59:02 +01:00
Stéphane Nicoll 515c654a46 Merge pull request #31976 from wfouche
* pr/31976:
  Upgrade to gradle-versions-plugin 0.50.0

Closes gh-31976
2024-01-08 13:04:06 +01:00
Werner Fouché aacb7e1604 Upgrade to gradle-versions-plugin 0.50.0
See gh-31976
2024-01-08 13:03:27 +01:00
Stéphane Nicoll c86642dfee Merge pull request #31977 from SuhasBk
* pr/31977:
  Add missing preposition

Closes gh-31977
2024-01-08 13:01:31 +01:00
Suhas Kowligi f4a9b12340 Add missing preposition
See gh-31977
2024-01-08 13:00:13 +01:00
Sébastien Deleuze bd66763f26 Polishing
See gh-28546
2024-01-08 12:27:37 +01:00
Stéphane Nicoll 2d3b02a89d Polish 2024-01-08 11:48:08 +01:00
rstoyanchev 8552e149b5 Improve method validation for container elements
This change moves container element properties from ParameterErrors
to base class ParameterValidationResult, and makes that support
independent of whether violations are nested within a container
element bean or through constraints on container elements, e.g.
`List<@NotBlank String>`.

Closes gh-31887
2024-01-05 16:32:14 +00:00
rstoyanchev e0d6b69195 Update contribution
Closes gh-30300
2024-01-04 14:53:13 +00:00
Yanming Zhou a3532bfccc ResponseStatusException reason as message code for ProblemDetail
See gh-30300
2023-04-06 17:18:27 +08:00
Werner Fouché 6697f01d05 Upgrade to Kotlin 1.9.22
Closes gh-31971
2024-01-08 09:28:16 +01:00
Stéphane Nicoll 01c62f86b3 Polish 2024-01-07 17:33:27 +01:00
Juergen Hoeller 9912a52bb8 Avoid getMostSpecificMethod resolution for non-annotated methods
This is aligned with AutowiredAnnotationBeanPostProcessor now.

Closes gh-31967
2024-01-07 16:33:49 +01:00
Juergen Hoeller 419e34e571 Introduce getMostSpecificMethod variant on BridgeMethodResolver
This is able to resolve the original method even if no bridge method has been generated at the same class hierarchy level (a known difference between the Eclipse compiler and regular javac).

Closes gh-21843
2024-01-07 16:33:06 +01:00
Werner Fouché f0e16bd31b Update SDKMAN config to use 17.0.9-librca
Closes gh-31966
2024-01-07 15:05:19 +01:00
Juergen Hoeller 43107e7eb1 Propagate arguments for dynamic prototype-scoped advice
Closes gh-28407
2024-01-07 00:12:15 +01:00
Juergen Hoeller 81bd6be1c0 Upgrade to Checkstyle 10.12.7 2024-01-06 23:37:45 +01:00
Juergen Hoeller d6c84c43ec Polishing 2024-01-06 23:24:48 +01:00
Juergen Hoeller 70247c4a94 Refine exception handling for type not present versus access exception
Includes TypeVariable bypass for reflection-free annotation retrieval.
Includes info log message for annotation attribute retrieval failure.

Closes gh-27182
2024-01-06 23:02:59 +01:00
Stéphane Nicoll 87b35e7d8e Polish 2024-01-06 09:21:16 +01:00
slovenlyimp a51c22b266 Fix a typo in kotlin.adoc
Closes gh-31958
2024-01-05 20:26:04 +01:00
Sébastien Deleuze 318d460256 Add CORS support for Private Network Access
This commit adds CORS support for Private Network Access
by adding an Access-Control-Allow-Private-Network response
header when the preflight request is sent with an
Access-Control-Request-Private-Network header and that
Private Network Access has been enabled in the CORS
configuration.

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

Closes gh-28546
2024-01-05 20:07:51 +01:00
Stéphane Nicoll d7cfdc633a Polish 2024-01-05 18:42:44 +01:00
Sam Brannen 085af10afd Polishing 2024-01-05 18:16:39 +01:00
Stéphane Nicoll a8273a3009 Resolve property placeholder in RequestMapping if necessary
This commit makes sure to resolve placeholders in request mappings
using the EmbeddedValueResolver of the current WebApplicationContext.

To avoid retrieving the context too often, we check for the presence of
the standard placeholder prefix.

Closes gh-26795
2024-01-05 17:50:54 +01:00
Sam Brannen 580d9f81e2 Polishing 2024-01-05 17:06:32 +01:00
Sam Brannen 79b0d71514 Support the use of @⁠Resource in test classes in AOT mode
Closes gh-31733
2024-01-05 16:31:18 +01:00
Sam Brannen f6b36a689a Introduce processInjection() in CommonAnnotationBeanPostProcessor
To align with the existing processInjection() method in
AutowiredAnnotationBeanPostProcessor, this commit introduces an analogous
method in CommonAnnotationBeanPostProcessor.

Closes gh-31956
2024-01-05 16:05:07 +01:00
Sam Brannen 4b6126c057 Polishing 2024-01-05 15:17:51 +01:00
Fabrice Bibonne a108e701bc Add Javadoc for use of regexp PathPattern
Closes gh-31886
2024-01-05 14:47:45 +01:00
Johnny Lim 0ad561d379 Ensure that Observation is stopped and scope is closed in doReceiveAndExecute()
Closes gh-31798
2024-01-05 14:45:58 +01:00
Brian Clozel 1372265bd9 Undo workaround for SameSite support in WebFlux
This commit implements Cookie support in WebFlux without any workaround
as now all supported servers have the SameSite feature enabled.

Closes gh-31954
2024-01-05 14:44:32 +01:00
Sam Brannen 476ef0c3ca Introduce basic unit test for AutowiredAnnotationBeanPostProcessor.processInjection() 2024-01-05 13:22:29 +01:00
Stéphane Nicoll 534d3229fe Polish 2024-01-05 10:46:00 +01:00
Juergen Hoeller 07097976ef Polishing 2024-01-05 10:08:57 +01:00
Juergen Hoeller fb4fbeab50 Allow CronTrigger to resume from specified timestamp
Includes differentiation between lenient and fixed execution.
Includes default time zone resolution from scheduler-wide Clock.

Closes gh-19475
Closes gh-31948
2024-01-05 10:08:01 +01:00
Stéphane Nicoll b169dc50ad Upgrade CI to Ubuntu Jammy 20231211.1 2024-01-05 09:41:45 +01:00
Stéphane Nicoll 02e32baa80 Merge pull request #31951 from pri88yank
* pr/31951:
  Polish "Fix references to "application/*+xml" in Javadoc"
  Fix references to "application/*+xml" in Javadoc

Closes gh-31951
2024-01-05 06:45:19 +01:00
Stéphane Nicoll 549f6c1e80 Polish "Fix references to "application/*+xml" in Javadoc"
See gh-31951
2024-01-05 06:44:14 +01:00
pri88yank 16b4c25f7d Fix references to "application/*+xml" in Javadoc
See gh-31951
2024-01-05 06:44:02 +01:00
Stéphane Nicoll af2e13e211 Polish 2024-01-05 06:34:09 +01:00
Brian Clozel 7c9307e970 Fix HandlerMappingIntrospector uri matching
Prior to this commit, the `HandlerMappingIntrospector` would comparea
request with a cached request by using `String#matches` on their String
URI. This could lead to `PatternSyntaxException` exceptions at runtime
if the request URI contained pattern characters.

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

Fixes gh-31937
2024-01-04 16:44:00 +01:00
Stéphane Nicoll 4f599b7396 Polish 2024-01-04 14:49:45 +01:00
Stéphane Nicoll 2784f6008e Only log status in ServletRequestHandledEvent
This commit updates the description of RequestHandledEvent to avoid
providing a misleading status as the absence of a failure logs OK which
can be inaccurate.

Closes gh-27595
2024-01-04 11:47:59 +01:00
Stefano Cordio be9ee9112c Upgrade to AssertJ 3.25.1, use AssertJ BOM
Closes gh-31945
2024-01-04 09:55:12 +01:00
Sébastien Deleuze 19a87e968e Update outdated elements in Kotlin reference documentation
Closes gh-31943
2024-01-03 18:39:15 +01:00
Sébastien Deleuze 207b9a14f4 Improve the documentation and discoverability of CoWebFilter
Closes gh-31877
2024-01-03 17:50:22 +01:00
Stéphane Nicoll 05ebca8677 Polish 2024-01-03 17:03:58 +01:00
Brian Clozel f846d9484c Add Javadoc to MockHttpServletResponse
This commit adds Javadoc to the `getContentLength` method of
`MockHttpServletResponse` to reflect that it gets its value from the
HTTP response header.

Closes gh-31833
2024-01-03 15:19:53 +01:00
Dávid Csákvári 50069ef029 Update autowired-qualifiers.adoc 2024-01-03 14:56:51 +01:00
Stéphane Nicoll 777ff3f1a8 Merge pull request #31938 from JuHyun419
* pr/31938:
  Fix typo in NumberFormat javadoc

Closes gh-31938
2024-01-03 14:27:56 +01:00
juhyun 89466cb33c Fix typo in NumberFormat javadoc
See gh-31938
2024-01-03 14:27:00 +01:00
Stéphane Nicoll bf3a478990 Add support for functional registration of application listener
This commit adds a functional style registration of an application
listener for a particular event. Rather than introducing another method
at the ConfigurableApplicationContext interface level, this commit
provides a factory method in GenericApplicationListener.

Closes gh-21411
2024-01-03 13:38:08 +01:00
Stéphane Nicoll efb97cca82 Merge pull request #31932 from janjouketjalsma
* pr/31932:
  Fix Kotlin example for simpler SELECT variant using IN

Closes gh-31932
2024-01-02 18:12:08 +01:00
Jan Jouke Tjalsma b692c0ed03 Fix Kotlin example for simpler SELECT variant using IN
Removed unused code, fixed bind parameter name.

See gh-31932
2024-01-02 18:10:36 +01:00
Sam Brannen 6eed2b0aee Upgrade to "TestNG Engine for the JUnit Platform" version 1.0.5
Thanks to a bug fix in 1.0.5, test methods in TestNG test classes can
finally be package private as was always the case with TestNG itself.

See https://github.com/junit-team/testng-engine/issues/16
2024-01-02 16:46:24 +01:00
Sam Brannen 7876db03c6 Upgrade to TestNG 7.9.0 2024-01-02 16:45:04 +01:00
Sam Brannen ffddbb586e Upgrade to AssertJ 3.25.0 2024-01-02 16:45:04 +01:00
Sam Brannen a3c11fc033 Clean up warnings in tests in Gradle build 2024-01-02 16:44:52 +01:00
Stéphane Nicoll 321de9ab9b Update copyright year to 2024 2024-01-02 16:22:43 +01:00
Brian Clozel ec5f566ba5 Fix Scheduled observation convention for lambdas
Prior to this commit, the `DefaultScheduledTaskObservationConvention`
would fail as it tried to add a `KeyValue` to the observation context
that is `null`. This is rejected by the observation registry and should
be prevented. This happened when registered scheduled methods were
lambdas or part of anonymous classes. Those types do not have a
canonical name and return `null` as a value there.

This commit ensures that for these cases, the default convetion uses a
`"ANONYMOUS"` value as the `"code.namespace"` keyvalue.

Fixes gh-31918
2024-01-02 15:12:26 +01:00
Stéphane Nicoll 2d6b77336b Revert Upgrad to Jetty Reactive Httpclient 4.0.2
Upgrading leads to to WebClientIntegrationTests to fail with Jetty and
the build does not complete properly. This commit reverts the upgrade.

See gh-31931
2024-01-01 11:22:25 +01:00
Stéphane Nicoll 9a1ee48d73 Merge pull request #31930 from izeye
* pr/31930:
  Update copyright year of changed files
  Polish

Closes gh-31930
2024-01-01 11:01:07 +01:00
Stéphane Nicoll e22d1efdc0 Update copyright year of changed files
See gh-31930
2024-01-01 11:00:56 +01:00
Johnny Lim ff8097d37c Polish
See gh-31930
2024-01-01 10:59:35 +01:00
Stéphane Nicoll 7d44a4dcad Polish 2024-01-01 10:56:33 +01:00
Juergen Hoeller fdb454b9a4 Declare JdkDynamicAopProxy's ProxiedInterfacesCache as private
See gh-30499
2023-12-31 13:48:50 +01:00
Juergen Hoeller b4174377c2 Correctly document Propagation.NOT_SUPPORTED in javadoc
See gh-31907
2023-12-31 13:44:09 +01:00
Juergen Hoeller 174eae377f Upgrade to ASM master (including early support for Java 23 bytecode)
Closes gh-31929
2023-12-31 13:29:50 +01:00
Juergen Hoeller 243ec88e95 Upgrade to SLF4J 2.0.10, AspectJ 1.9.21, Groovy 4.0.17, Tomcat 10.1.17, Jetty 12.0.5, Netty 4.1.104, Jackson 2.15.3, Protobuf 3.25.1, OpenPDF 1.3.35 2023-12-30 16:47:50 +01:00
Stéphane Nicoll 9f3fd103ef Polish 2023-12-30 11:17:49 +01:00
Juergen Hoeller 0ad3800f54 Polishing 2023-12-30 11:06:16 +01:00
Juergen Hoeller 473efb6d4f Adapt test to current 5.0+ behavior
See gh-24502
2023-12-30 10:47:52 +01:00
Stéphane Nicoll 153f8895cb Polish 2023-12-29 18:19:26 +01:00
Juergen Hoeller f5b4f7d9e8 Support for SSLContext configuration on StandardWebSocketClient
Closes gh-30680
2023-12-28 23:42:04 +01:00
Juergen Hoeller 989625d2d4 Allow SockJsUrlInfo to be overridden in SockJsClient
Closes gh-25888
2023-12-28 20:56:18 +01:00
Stéphane Nicoll 28e5468162 Merge pull request #31917 from ghkim3221
* pr/31917:
  Polish "Fix usage of WebClientAdapter in reference documentation"
  Fix usage of WebClientAdapter in reference documentation

Closes gh-31917
2023-12-28 13:53:53 +01:00
Stéphane Nicoll b1c0b65666 Polish "Fix usage of WebClientAdapter in reference documentation"
See gh-31917
2023-12-28 13:52:57 +01:00
Gihwan Kim 490aaa1ed8 Fix usage of WebClientAdapter in reference documentation
See gh-31917
2023-12-28 13:51:12 +01:00
Stéphane Nicoll c7d2d6716d Merge pull request #31916 from quaff
* pr/31916:
  Upgrade copyright year of changed files
  Polish "Replace if with switch where feasible"
  Replace if with switch where feasible
  Use Map.computeIfAbsent() where feasible
  Polish "Use Object.equals() where feasible"
  Use Object.equals() where feasible
  Polish "Use diamond operator where feasible"
  Use diamond operator where feasible
  Use auto boxing and unboxing where feasible
  Use enhanced for loop where feasible
  Polish "Use text block where feasible"
  Use text block where feasible
  Polish "Use String.repeat() where feasible"
  Use String.repeat() where feasible
  Polish "Remove unnecessary final modifier"
  Remove unnecessary final modifier

Closes gh-31916
2023-12-28 13:47:08 +01:00
Stéphane Nicoll eefe65d95a Upgrade copyright year of changed files
See gh-31916
2023-12-28 13:36:58 +01:00
Stéphane Nicoll 3c5d46166e Polish "Replace if with switch where feasible"
See gh-31916
2023-12-28 13:33:32 +01:00
Yanming Zhou cfa3aa001f Replace if with switch where feasible
See gh-31916
2023-12-28 13:29:50 +01:00
Yanming Zhou ea5ef098cf Use Map.computeIfAbsent() where feasible
See gh-31916
2023-12-28 13:23:48 +01:00
Stéphane Nicoll adcf236a3d Polish "Use Object.equals() where feasible"
See gh-31916
2023-12-28 13:21:46 +01:00
Yanming Zhou 72a9864788 Use Object.equals() where feasible
See gh-31916
2023-12-28 13:19:03 +01:00
Stéphane Nicoll a6e87b40c7 Polish "Use diamond operator where feasible"
See gh-31916
2023-12-28 13:14:26 +01:00
Yanming Zhou 094479b55f Use diamond operator where feasible
See gh-31916
2023-12-28 13:08:08 +01:00
Yanming Zhou db2c532c07 Use auto boxing and unboxing where feasible
See gh-31916
2023-12-28 13:01:44 +01:00
Yanming Zhou 4a450c6fab Use enhanced for loop where feasible
See gh-31916
2023-12-28 13:01:44 +01:00
Stéphane Nicoll ed1bfb8177 Polish "Use text block where feasible"
See gh-31916
2023-12-28 13:01:44 +01:00
Yanming Zhou a35384fd57 Use text block where feasible
See gh-31916
2023-12-28 13:01:44 +01:00
Stéphane Nicoll 9d31537ae5 Polish "Use String.repeat() where feasible"
See gh-31916
2023-12-28 13:01:44 +01:00
Yanming Zhou dee1b726f9 Use String.repeat() where feasible
See gh-31916
2023-12-28 13:01:44 +01:00
Stéphane Nicoll 7cfff4049d Polish "Remove unnecessary final modifier"
See gh-31916
2023-12-28 13:01:44 +01:00
Yanming Zhou 45080e3724 Remove unnecessary final modifier
final is useless for private and static methods

See gh-31916
2023-12-28 13:01:43 +01:00
Stéphane Nicoll c3b5f5bf90 Merge pull request #31913 from quaff
* pr/31913:
  Update copyright year of changed files
  Cleanup kotlin sources

Closes gh-31913
2023-12-28 11:56:12 +01:00
Stéphane Nicoll 7e5afc8bbb Update copyright year of changed files
See gh-31913
2023-12-28 11:47:17 +01:00
Yanming Zhou 7474af4f09 Cleanup kotlin sources
1. remove unused import
2. remove redundant semicolon
3. remove redundant empty constructor and SAM-constructor
4. remove unnecessary type argument
5. adjust indent

See gh-31913
2023-12-28 11:46:47 +01:00
Stéphane Nicoll 28a7b6103a Merge pull request #31914 from quaff
* pr/31914:
  Add missing @Test
  Fix @Nested class not be executed

Closes gh-31914
2023-12-28 11:40:56 +01:00
Yanming Zhou 3cddb0434d Add missing @Test
See gh-31914
2023-12-28 11:38:03 +01:00
Yanming Zhou 36a72115f9 Fix @Nested class not be executed
See gh-31914
2023-12-28 11:37:47 +01:00
Stéphane Nicoll 3c0b5459be Merge pull request #31912 from izeye
* pr/31912:
  Add Javadoc since to CacheOperationContext.getGeneratedKey()

Closes gh-31912
2023-12-28 11:29:31 +01:00
Johnny Lim 088be2d017 Add Javadoc since to CacheOperationContext.getGeneratedKey()
See gh-31912
2023-12-28 11:25:36 +01:00
Juergen Hoeller a155a6b3e2 Document target method expectations for ReactiveTransactionManager
Closes gh-23277
2023-12-27 23:48:55 +01:00
Juergen Hoeller a338a16b29 Polishing 2023-12-27 23:23:38 +01:00
Juergen Hoeller 7613bdfdf9 Document thread safety and visibility for Spring-managed bean instances
Closes gh-8986
2023-12-27 23:22:35 +01:00
Juergen Hoeller 57f27fa42f Document autowiring of request/session proxies into Spring-managed beans
Closes gh-26201
2023-12-27 23:22:30 +01:00
Juergen Hoeller 55d9d151fb Recommend ResourcePropertySource for distinct PropertySource names
Closes gh-28886
2023-12-27 23:19:27 +01:00
Stéphane Nicoll 70f31dee45 Polish 2023-12-27 13:04:21 +01:00
Stéphane Nicoll 699f93fed7 Use proper SQLServer dialect for Hibernate 6+
This commit fixes the Hibernate dialect lookup for SQLServer as it was
previously using a dialect that has been deprecated. In recent
versions, the standard SQLServerDialect is the one we should be using.

Closes gh-31896
2023-12-26 14:03:20 +01:00
Kai Zander 4c6ca05af5 Fix formatting in scheduling.adoc 2023-12-26 11:36:51 +01:00
Juergen Hoeller 75c7596259 Allow Propagation.NOT_SUPPORTED with @TransactionalEventListener
Closes gh-31907
2023-12-26 10:59:19 +01:00
Juergen Hoeller 17d362fa85 Document limited concurrency with fixed-delay tasks on virtual threads
Closes gh-31900
2023-12-26 10:59:13 +01:00
Juergen Hoeller a428955438 Avoid unnecessary DatabasePopulator init/destroy processing
Closes gh-23405
2023-12-23 13:40:12 +01:00
Brian Clozel 4afac17e58 Reject invalid forwarded requests in ForwardedHeaderFilter
Prior to this commit, the `ForwardedHeaderFilter` and the forwarded
header utils would throw `IllegalArgumentException` and
`IllegalStateException` when request headers are invalid and cannot be
parsed for Forwarded handling.

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

Fixes gh-31842
2023-12-22 17:27:06 +01:00
Sébastien Deleuze 8bd8c4f627 Add support for @Async Kotlin function returning Unit?
Closes gh-31881
2023-12-22 15:33:34 +01:00
Stéphane Nicoll 0390709577 Use proper Oracle dialect for Hibernate 6+
This commit fixes the Hibernate dialect lookup for Oracle as it was
previously using a dialect that has been moved and deprecated to a
separate project. In recent versions, the standard OracleDialect is the
one we should be using.

Closes gh-31892
2023-12-22 15:22:01 +01:00
Stéphane Nicoll 9f2970bc5c Use non deprecated MySQL dialect for Hibernate 6+
This commit fixes the Hibernate dialect lookup for MySQL as it was
previously using a deprecated dialect that has been removed in the most
recent Hibernate version.

Closes gh-31889
2023-12-22 15:03:40 +01:00
Juergen Hoeller 232225b2aa Polishing 2023-12-22 13:06:29 +01:00
Stéphane Nicoll 5caf714ff4 Document CGLIB restriction with methods that are effectively private
Closes gh-28973
2023-12-22 12:39:35 +01:00
Juergen Hoeller cd11219fa7 Declare proxyMetadataCache as volatile and ProxiedInterfacesCache fields as final
See gh-30499
2023-12-22 12:27:03 +01:00
Juergen Hoeller 44c652ec98 Introduce ProxiedInterfacesCache for JdkDynamicAopProxy
Closes gh-30499
2023-12-22 11:55:59 +01:00
Stéphane Nicoll cd8bc2f82a Remove useless empty inheritDoc Javadoc tag 2023-12-22 11:23:11 +01:00
Stéphane Nicoll 12f6330fae Improve code coverage of PropertyPlaceholderHelper
See gh-26268
2023-12-22 11:07:16 +01:00
Juergen Hoeller fc0ea465e1 Clarify expectations for getBean call with provided arguments
Closes gh-24955
2023-12-21 19:32:38 +01:00
rstoyanchev 459338f6fd Unwrap Optional in MethodValidationAdapter
See gh-31746
2023-12-21 17:55:49 +00:00
rstoyanchev f0add920f5 Adjust container types to which methodValidation
After the updates to MethodValidationAdapter in commit d7ce13 related
to method validation on element containers, we also need to adjust
the checks in HandlerMethod when method validation applies.

See gh-31746
2023-12-21 17:50:40 +00:00
rstoyanchev 33c149077a Check constraints on container elements
We now check for constraint annotations on elements of a
container to decide whether to apply method validation.

Closes gh-31870
2023-12-21 17:35:19 +00:00
Baoyi Chen e00a882333 Complete Jetty frame callback when opcode is not PONG
The onWebSocketFrame method should complete callback.
For more details, see https://github.com/jetty/jetty.project/issues/11088.

Closes gh-31869
2023-12-21 17:56:26 +01:00
Sam Brannen 3ed5a90b7c Fix assertions in ReactiveCachingTests 2023-12-21 17:30:56 +01:00
Sam Brannen 3476402a75 Polish switch statements 2023-12-21 17:30:56 +01:00
Juergen Hoeller b04803de99 Polishing 2023-12-21 17:20:29 +01:00
Juergen Hoeller f443cf965a Introduce NoOpTaskScheduler for test setups
Closes gh-28073
2023-12-21 17:20:24 +01:00
Stéphane Nicoll c9292f8e09 Replace Twitter reference to 𝕏 2023-12-21 15:56:20 +01:00
Juergen Hoeller bd65a19d71 Introduce write method fallback step for overloaded setter methods
Closes gh-31872
2023-12-21 14:32:10 +01:00
Sébastien Deleuze 85cb6cc5fb Support Kotlin extensions in web handlers
This commit restores support for Kotlin extensions in
web handlers, and adds support for invoking reflectively
suspending extension functions, as well as the other
features supported as of Spring Framework 6.1 like
value classes and default value for parameters.

Closes gh-31876
2023-12-21 12:16:33 +01:00
Juergen Hoeller 5f8a031c22 Introduce "spring.cache.reactivestreams.ignore" escape hatch
Closes gh-31861
2023-12-21 11:14:33 +01:00
Juergen Hoeller dc564f3ef2 Respect cache hit when empty Mono/Flux response is returned
Closes gh-31868
2023-12-20 22:52:51 +01:00
rstoyanchev d7ce13c763 Revert use of leafBean in MethodValidationAdapter
The goal for #31530 was to support bean validation on Set and other
method parameters that are containers of value(s) for which there is
a registered Jakarta Validation ValueExtractor.

Unfortunately, bean validation does not expose the unwrapped value
for a Path.Node, which we need for a method parameter in order to
create a BindingResult for the specific bean within the container,
and the leafBean that we tried to use is really the node at the
very bottom of the property path (i.e. not what we need).

This change removes the use of beanLeaf, restores the logic as it
was before, adds support for arrays, and a new test class for
scenarios with cascaded violations.

See gh-31746
2023-12-20 17:56:05 +00:00
Stéphane Nicoll 7b9037b054 Merge pull request #31875 from izeye
* pr/31875:
  Polish Javadoc for ClientRequestObservationContext constructors

Closes gh-31875
2023-12-20 17:29:45 +01:00
Johnny Lim 3162afbf16 Polish Javadoc for ClientRequestObservationContext constructors
See gh-31875
2023-12-20 17:26:29 +01:00
Stéphane Nicoll 1bd523f6b6 Polish 2023-12-20 09:52:55 +01:00
Juergen Hoeller 4c0d0ba5b3 Use standard String comparison in PropertyDescriptorComparator
Closes gh-31866
2023-12-20 08:45:53 +01:00
Stéphane Nicoll 212346a86d Polish 2023-12-19 19:48:42 +01:00
Brian Clozel 564803f56a Trigger JDK 22 builds every morning in CI
Closes gh-31459
2023-12-19 18:39:23 +01:00
Brian Clozel df708d16e4 Add missing JDK env variable in CI script 2023-12-19 18:23:22 +01:00
Brian Clozel 848dedb576 Upgrade CI to JDK 22ea28 2023-12-19 18:08:36 +01:00
Brian Clozel 4516e0d413 Ignore XML tests on JDK 22
This is until https://bugs.openjdk.org/browse/JDK-8322216 is resolved.

See gh-31459
2023-12-19 18:06:47 +01:00
Juergen Hoeller a23375c49d Document JDBC driver requirement for KeyHolder-based update methods
Closes gh-31486
2023-12-19 17:53:32 +01:00
Brian Clozel 53b937976d Reject setups with multiple observation conventions
Prior to this commit, the `WebHttpHandlerBuilder` would only configure
a custom observation convention if there is a single convention in the
application context. It would other wise use the default.

This commit aligns with the previous Spring Boot behavior where multiple
conventions setups are rejected as invalid with
`NoUniqueBeanDefinitionException`.

Fixes gh-31864
2023-12-19 17:35:02 +01:00
Sébastien Deleuze 12f01f9b5f Add support for @RequestMapping on Kotlin property accessors
This commit refines InvocableHandlerMethod (both Servlet and
Reactive variants) in order to support annotated property
accessors as they translate into regular Java methods, instead
of throwing a NullPointerException.

Closes gh-31856
2023-12-19 12:29:55 +01:00
Sébastien Deleuze 917978cbc2 Refactor InvocableHandlerMethodKotlinTests
The variant in org.springframework.web.method.support in
order to allow testing with a various classes.

See gh-31856
2023-12-19 12:10:13 +01:00
rstoyanchev 3f5c3b1747 Fix checkstyle violation
See gh-31711
2023-12-18 15:32:18 +00:00
rstoyanchev bec7210b4b Improve check to skip bean validation in DataBinder
DataBinder should skip any jakarta.validation.Validator yielding
to method validation when that is expected. This change improves
the check to skip by unwrapping the validator from in a
SmartValidator before checking if it is for bean validation.

Closes gh-31711
2023-12-18 15:25:18 +00:00
rstoyanchev 0a94dce41d Improve HandlerMethod check when method validation applies
Method validation needs to be used for a container such as a List or
Map, but until now we were only checking for a List container.
Moreover, in gh-31530 we improved method validation to also cover
any Collection.

This change aligns with HandlerMethod check for when method validation
applies with the underlying ability of method validation.
2023-12-18 15:25:18 +00:00
Stéphane Nicoll 9b3afcdac7 Merge pull request #31845 from bohub12
* pr/31845:
  Polish "Replace deprecated usage of project.buildDir"
  Replace deprecated usage of project.buildDir

Closes gh-31845
2023-12-18 16:24:11 +01:00
Stéphane Nicoll 8eb524dc4d Polish "Replace deprecated usage of project.buildDir"
See gh-31845
2023-12-18 16:24:02 +01:00
bohub12 dee8108bbc Replace deprecated usage of project.buildDir
See gh-31845
2023-12-18 16:24:02 +01:00
Juergen Hoeller 045c5dc1b4 Detect Jetty 12 "max length exceeded" message in handleParseFailure
Closes gh-31850
2023-12-18 16:18:27 +01:00
Arjen Poutsma 24f8eac12a Improve ByteBuffer copy method
This commit improves JettyWebSocketHandlerAdapter::copyByteBuffer so
that it allocates a buffer large enough for the remaining bytes
contained in the source, instead of allocating one with the capacity of
the source.

Closes gh-31857
2023-12-18 15:23:27 +01:00
Stéphane Nicoll eaf7a28250 Write runtime hints with deterministic order
This commit updates the JSON writers to use a deterministic order for
arrays. Previously, the order could change with the same content,
breaking caching.

Closes gh-31852
2023-12-18 14:57:13 +01:00
Stéphane Nicoll 7965c1969f Merge pull request #31802 from Drezir
* pr/31802:
  Polish "Use String.repeat instead of explicit cycle"
  Use String.repeat instead of explicit cycle

Closes gh-31802
2023-12-18 14:11:35 +01:00
Stéphane Nicoll d0574197ea Polish "Use String.repeat instead of explicit cycle"
See gh-31802
2023-12-18 14:10:16 +01:00
Adam Ostrožlík 63b2787da6 Use String.repeat instead of explicit cycle
See gh-31802
2023-12-18 13:54:03 +01:00
Arjen Poutsma 1ff683b259 Correctly set capacity of remainder in DefaultDataBuffer::split
This commit ensures that the capacity of the remainder buffer after a
split operation is set directly on the field. Calling capacity(int)
caused a new buffer to be allocated.

Closes gh-31848
2023-12-18 11:45:02 +01:00
Stéphane Nicoll 22bf4df290 Polish 2023-12-16 19:19:33 +01:00
Yaklede b56fc50c27 Update copyright headers in spring-test
Closes gh-31853
2023-12-16 14:23:37 +01:00
Sébastien Deleuze d2aa6a98f2 Polishing
Closes gh-31846
2023-12-15 10:12:15 +01:00
T45K bf0819390f Support Kotlin value classes as suspending function arguments
Similar to gh-31698 but for Coroutines.

See gh-31846
2023-12-15 10:11:59 +01:00
dogglezz 503ccb577c Remove unused imports
Closes gh-31851
2023-12-15 09:35:17 +01:00
Stéphane Nicoll 2f7e650122 Merge pull request #31847 from achhibi
* pr/31847:
  Upgrade copyright year of changed file
  Combine conditions for better readability and simplicity

Closes gh-31847
2023-12-15 07:37:26 +01:00
Stéphane Nicoll 68931a2091 Upgrade copyright year of changed file
See gh-31847
2023-12-15 07:36:50 +01:00
achhibi 7f79ccbec0 Combine conditions for better readability and simplicity 2023-12-14 20:29:09 +01:00
Sébastien Deleuze 43c2e51d6e Document BytecodeProviderImpl substitution related issue
See gh-29549
See gh-31051
2023-12-14 15:37:43 +01:00
Spring Builds 66b8f369dc Next development version (v6.1.3-SNAPSHOT) 2023-12-14 10:42:10 +00:00
1611 changed files with 14608 additions and 11840 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.8.1-librca
java=17.0.9-librca
+1 -1
View File
@@ -31,7 +31,7 @@ Information regarding CI builds can be found in the [Spring Framework Concourse
## Stay in Touch
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on Twitter. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [releases feed](https://spring.io/blog/category/releases).
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on 𝕏. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [releases feed](https://spring.io/blog/category/releases).
## License
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka' version '1.8.20'
id 'org.unbroken-dome.xjc' version '2.0.0' apply false
id 'com.github.ben-manes.versions' version '0.49.0'
id 'com.github.ben-manes.versions' version '0.50.0'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
id 'de.undercouch.download' version '5.4.0'
id 'me.champeau.jmh' version '0.7.2' apply false
+1 -1
View File
@@ -1,2 +1,2 @@
org.gradle.caching=true
javaFormatVersion=0.0.39
javaFormatVersion=0.0.41
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,12 +50,12 @@ public class CheckstyleConventions {
project.getPlugins().apply(CheckstylePlugin.class);
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g"));
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.setToolVersion("10.12.5");
checkstyle.setToolVersion("10.12.7");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
checkstyleDependencies
.add(project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
checkstyleDependencies.add(
project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
});
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:jammy-20231128
FROM ubuntu:jammy-20231211.1
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
+1 -1
View File
@@ -9,7 +9,7 @@ case "$1" in
echo "https://download.bell-sw.com/java/21.0.1+12/bellsoft-jdk21.0.1+12-linux-amd64.tar.gz"
;;
java22)
echo "https://download.java.net/java/early_access/jdk22/27/GPL/openjdk-22-ea+27_linux-x64_bin.tar.gz"
echo "https://download.java.net/java/early_access/jdk22/28/GPL/openjdk-22-ea+28_linux-x64_bin.tar.gz"
;;
*)
echo $"Unknown java version"
+2
View File
@@ -255,6 +255,8 @@ jobs:
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk22-build
params: { state: "pending", commit: "git-repo" }
- do:
+1 -1
View File
@@ -4,6 +4,6 @@ set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21 \
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21,JDK22 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check antora
popd > /dev/null
+2 -2
View File
@@ -28,7 +28,7 @@ javadoc {
header = rootProject.description
use = true
overview = project.relativePath("$rootProject.rootDir/framework-docs/src/docs/api/overview.html")
destinationDir = file("${project.buildDir}/docs/javadoc-api")
destinationDir = file("$project.docsDir/javadoc-api")
splitIndex = true
links(rootProject.ext.javadocLinks)
addBooleanOption('Xdoclint:syntax,reference', true) // only check syntax and reference with doclint
@@ -52,7 +52,7 @@ rootProject.tasks.dokkaHtmlMultiModule.configure {
tasks.named("javadoc")
}
moduleName.set("spring-framework")
outputDirectory.set(project.file("$buildDir/docs/kdoc-api"))
outputDirectory.set(file("$docsDir/kdoc-api"))
includes.from("$rootProject.rootDir/framework-docs/src/docs/api/dokka-overview.md")
}
@@ -19,15 +19,53 @@ of the classpath -- for example, deployed within the application's JAR file.
The following table lists all currently supported Spring properties.
.Supported Spring Properties
[cols="1,1", stripes=odd]
|===
| Name | Description
| `spring.aot.enabled`
| Indicates the application should run with AOT generated artifacts. See
xref:core/aot.adoc[Ahead of Time Optimizations] and
{spring-framework-api}++/aot/AotDetector.html#AOT_ENABLED++[`AotDetector`]
for details.
| `spring.beaninfo.ignore`
| Instructs Spring to use the `Introspector.IGNORE_ALL_BEANINFO` mode when calling the
JavaBeans `Introspector`. See
{spring-framework-api}++/beans/StandardBeanInfoFactory.html#IGNORE_BEANINFO_PROPERTY_NAME++[`CachedIntrospectionResults`]
for details.
| `spring.cache.reactivestreams.ignore`
| Instructs Spring's caching infrastructure to ignore the presence of Reactive Streams,
in particular Reactor's `Mono`/`Flux` in `@Cacheable` method return type declarations. See
{spring-framework-api}++/cache/interceptor/CacheAspectSupport.html#IGNORE_REACTIVESTREAMS_PROPERTY_NAME++[`CacheAspectSupport`]
for details.
| `spring.classformat.ignore`
| Instructs Spring to ignore class format exceptions during classpath scanning, in
particular for unsupported class file versions. See
{spring-framework-api}++/context/annotation/ClassPathScanningCandidateComponentProvider.html#IGNORE_CLASSFORMAT_PROPERTY_NAME++[`ClassPathScanningCandidateComponentProvider`]
for details.
| `spring.context.checkpoint`
| Property that specifies a common context checkpoint. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic
checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#CHECKPOINT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.exit`
| Property for terminating the JVM when the context reaches a specific phase. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic
checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#EXIT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.expression.maxLength`
| The maximum length for
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expressions used in XML bean definitions, `@Value`, etc.
| `spring.expression.compiler.mode`
| The mode to use when compiling expressions for the
xref:core/expressions/evaluation.adoc#expressions-compiler-configuration[Spring Expression Language].
@@ -291,6 +291,8 @@ to consider:
* `final` classes cannot be proxied, because they cannot be extended.
* `final` methods cannot be advised, because they cannot be overridden.
* `private` methods cannot be advised, because they cannot be overridden.
* Methods that are not visible, typically package private methods in a parent class
from a different package, cannot be advised because they are effectively private.
NOTE: There is no need to add CGLIB to your classpath. CGLIB is repackaged and included
in the `spring-core` JAR. In other words, CGLIB-based AOP works "out of the box", as do
@@ -168,7 +168,7 @@ Kotlin::
======
NOTE: Pooling stateless service objects is not usually necessary. We do not believe it should
be the default choice, as most stateless objects are naturally thread safe, and instance
be the default choice, as most stateless objects are naturally thread-safe, and instance
pooling is problematic if resources are cached.
Simpler pooling is available by using auto-proxying. You can set the `TargetSource` implementations
@@ -533,6 +533,11 @@ standard AspectJ. The following example shows the `aop.xml` file:
</aspectj>
----
NOTE: It is recommended to only weave specific classes (typically those in the
application packages, as shown in the `aop.xml` example above) in order
to avoid side effects such as AspectJ dump files and warnings.
This is also a best practice from an efficiency perspective.
Now we can move on to the Spring-specific portion of the configuration. We need
to configure a `LoadTimeWeaver` (explained later). This load-time weaver is the
essential component responsible for weaving the aspect configuration in one or
@@ -714,10 +719,29 @@ Furthermore, the compiled aspect classes need to be available on the classpath.
[[aop-aj-ltw-aop_dot_xml]]
=== 'META-INF/aop.xml'
=== `META-INF/aop.xml`
The AspectJ LTW infrastructure is configured by using one or more `META-INF/aop.xml`
files that are on the Java classpath (either directly or, more typically, in jar files).
For example:
[source,xml,indent=0,subs="verbatim"]
----
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="com.xyz.*"/>
</weaver>
</aspectj>
----
NOTE: It is recommended to only weave specific classes (typically those in the
application packages, as shown in the `aop.xml` example above) in order
to avoid side effects such as AspectJ dump files and warnings.
This is also a best practice from an efficiency perspective.
The structure and contents of this file is detailed in the LTW part of the
{aspectj-docs-devguide}/ltw-configuration.html[AspectJ reference
@@ -155,6 +155,8 @@ If there is no other resolution indicator (such as a qualifier or a primary mark
for a non-unique dependency situation, Spring matches the injection point name
(that is, the field name or parameter name) against the target bean names and chooses the
same-named candidate, if any.
Since version 6.1, this requires the `-parameters` Java compiler flag to be present.
====
That said, if you intend to express annotation-driven injection by name, do not
@@ -592,6 +592,40 @@ Kotlin::
[[beans-factory-thread-safety]]
=== Thread Safety and Visibility
The Spring core container publishes created singleton instances in a thread-safe manner,
guarding access through a singleton lock and guaranteeing visibility in other threads.
As a consequence, application-provided bean classes do not have to be concerned about the
visibility of their initialization state. Regular configuration fields do not have to be
marked as `volatile` as long as they are only mutated during the initialization phase,
providing visibility guarantees similar to `final` even for setter-based configuration
state that is mutable during that initial phase. If such fields get changed after the
bean creation phase and its subsequent initial publication, they need to be declared as
`volatile` or guarded by a common lock whenever accessed.
Note that concurrent access to such configuration state in singleton bean instances,
e.g. for controller instances or repository instances, is perfectly thread-safe after
such safe initial publication from the container side. This includes common singleton
`FactoryBean` instances which are processed within the general singleton lock as well.
For destruction callbacks, the configuration state remains thread-safe but any runtime
state accumulated between initialization and destruction should be kept in thread-safe
structures (or in `volatile` fields for simple cases) as per common Java guidelines.
Deeper `Lifecycle` integration as shown above involves runtime-mutable state such as
a `runnable` field which will have to be declared as `volatile`. While the common
lifecycle callbacks follow a certain order, e.g. a start callback is guaranteed to
only happen after full initialization and a stop callback only after an initial start,
there is a special case with the common stop before destroy arrangement: It is strongly
recommended that the internal state in any such bean also allows for an immediate
destroy callback without a preceding stop since this may happen during an extraordinary
shutdown after a cancelled bootstrap or in case of a stop timeout caused by another bean.
[[beans-factory-aware]]
== `ApplicationContextAware` and `BeanNameAware`
@@ -324,7 +324,6 @@ Kotlin::
[[beans-factory-scopes-application]]
=== Application Scope
@@ -374,7 +373,6 @@ Kotlin::
[[beans-factory-scopes-websocket]]
=== WebSocket Scope
@@ -384,7 +382,6 @@ xref:web/websocket/stomp/scope.adoc[WebSocket scope] for more details.
[[beans-factory-scopes-other-injection]]
=== Scoped Beans as Dependencies
@@ -544,6 +541,19 @@ see xref:core/aop/proxying.adoc[Proxying Mechanisms].
[[beans-factory-scopes-injection]]
=== Injecting Request/Session References Directly
As an alternative to factory scopes, a Spring `WebApplicationContext` also supports
the injection of `HttpServletRequest`, `HttpServletResponse`, `HttpSession`,
`WebRequest` and (if JSF is present) `FacesContext` and `ExternalContext` into
Spring-managed beans, simply through type-based autowiring next to regular injection
points for other beans. Spring generally injects proxies for such request and session
objects which has the advantage of working in singleton beans and serializable beans
as well, similar to scoped proxies for factory-scoped beans.
[[beans-factory-scopes-custom]]
== Custom Scopes
@@ -1,12 +1,12 @@
[[expressions-evaluation]]
= Evaluation
This section introduces the simple use of SpEL interfaces and its expression language.
The complete language reference can be found in
This section introduces programmatic use of SpEL's interfaces and its expression language.
The complete language reference can be found in the
xref:core/expressions/language-ref.adoc[Language Reference].
The following code introduces the SpEL API to evaluate the literal string expression,
`Hello World`.
The following code demonstrates how to use the SpEL API to evaluate the literal string
expression, `Hello World`.
[tabs]
======
@@ -18,7 +18,7 @@ Java::
Expression exp = parser.parseExpression("'Hello World'"); // <1>
String message = (String) exp.getValue();
----
<1> The value of the message variable is `'Hello World'`.
<1> The value of the message variable is `"Hello World"`.
Kotlin::
+
@@ -28,24 +28,24 @@ Kotlin::
val exp = parser.parseExpression("'Hello World'") // <1>
val message = exp.value as String
----
<1> The value of the message variable is `'Hello World'`.
<1> The value of the message variable is `"Hello World"`.
======
The SpEL classes and interfaces you are most likely to use are located in the
`org.springframework.expression` package and its sub-packages, such as `spel.support`.
The `ExpressionParser` interface is responsible for parsing an expression string. In
the preceding example, the expression string is a string literal denoted by the surrounding single
quotation marks. The `Expression` interface is responsible for evaluating the previously defined
expression string. Two exceptions that can be thrown, `ParseException` and
`EvaluationException`, when calling `parser.parseExpression` and `exp.getValue`,
respectively.
The `ExpressionParser` interface is responsible for parsing an expression string. In the
preceding example, the expression string is a string literal denoted by the surrounding
single quotation marks. The `Expression` interface is responsible for evaluating the
defined expression string. The two types of exceptions that can be thrown when calling
`parser.parseExpression(...)` and `exp.getValue(...)` are `ParseException` and
`EvaluationException`, respectively.
SpEL supports a wide range of features, such as calling methods, accessing properties,
SpEL supports a wide range of features such as calling methods, accessing properties,
and calling constructors.
In the following example of method invocation, we call the `concat` method on the string literal:
In the following method invocation example, we call the `concat` method on the string
literal, `Hello World`.
[tabs]
======
@@ -57,7 +57,7 @@ Java::
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
String message = (String) exp.getValue();
----
<1> The value of `message` is now 'Hello World!'.
<1> The value of `message` is now `"Hello World!"`.
Kotlin::
+
@@ -67,10 +67,11 @@ Kotlin::
val exp = parser.parseExpression("'Hello World'.concat('!')") // <1>
val message = exp.value as String
----
<1> The value of `message` is now 'Hello World!'.
<1> The value of `message` is now `"Hello World!"`.
======
The following example of calling a JavaBean property calls the `String` property `Bytes`:
The following example demonstrates how to access the `Bytes` JavaBean property of the
string literal, `Hello World`.
[tabs]
======
@@ -100,10 +101,10 @@ Kotlin::
======
SpEL also supports nested properties by using the standard dot notation (such as
`prop1.prop2.prop3`) and also the corresponding setting of property values.
`prop1.prop2.prop3`) as well as the corresponding setting of property values.
Public fields may also be accessed.
The following example shows how to use dot notation to get the length of a literal:
The following example shows how to use dot notation to get the length of a string literal.
[tabs]
======
@@ -133,7 +134,7 @@ Kotlin::
======
The String's constructor can be called instead of using a string literal, as the following
example shows:
example shows.
[tabs]
======
@@ -145,7 +146,7 @@ Java::
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
String message = exp.getValue(String.class);
----
<1> Construct a new `String` from the literal and make it be upper case.
<1> Construct a new `String` from the literal and convert it to upper case.
Kotlin::
+
@@ -155,10 +156,9 @@ Kotlin::
val exp = parser.parseExpression("new String('hello world').toUpperCase()") // <1>
val message = exp.getValue(String::class.java)
----
<1> Construct a new `String` from the literal and make it be upper case.
<1> Construct a new `String` from the literal and convert it to upper case.
======
Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`.
Using this method removes the need to cast the value of the expression to the desired
result type. An `EvaluationException` is thrown if the value cannot be cast to the
@@ -166,8 +166,8 @@ type `T` or converted by using the registered type converter.
The more common usage of SpEL is to provide an expression string that is evaluated
against a specific object instance (called the root object). The following example shows
how to retrieve the `name` property from an instance of the `Inventor` class or
create a boolean condition:
how to retrieve the `name` property from an instance of the `Inventor` class and how to
reference the `name` property in a boolean expression.
[tabs]
======
@@ -240,7 +240,7 @@ It excludes Java type references, constructors, and bean references. It also req
you to explicitly choose the level of support for properties and methods in expressions.
By default, the `create()` static factory method enables only read access to properties.
You can also obtain a builder to configure the exact level of support needed, targeting
one or some combination of the following:
one or some combination of the following.
* Custom `PropertyAccessor` only (no reflection)
* Data binding properties for read-only access
@@ -252,16 +252,15 @@ one or some combination of the following:
By default, SpEL uses the conversion service available in Spring core
(`org.springframework.core.convert.ConversionService`). This conversion service comes
with many built-in converters for common conversions but is also fully extensible so that
you can add custom conversions between types. Additionally, it is
generics-aware. This means that, when you work with generic types in
expressions, SpEL attempts conversions to maintain type correctness for any objects
it encounters.
with many built-in converters for common conversions, but is also fully extensible so
that you can add custom conversions between types. Additionally, it is generics-aware.
This means that, when you work with generic types in expressions, SpEL attempts
conversions to maintain type correctness for any objects it encounters.
What does this mean in practice? Suppose assignment, using `setValue()`, is being used
to set a `List` property. The type of the property is actually `List<Boolean>`. SpEL
recognizes that the elements of the list need to be converted to `Boolean` before
being placed in it. The following example shows how to do so:
being placed in it. The following example shows how to do so.
[tabs]
======
@@ -325,7 +324,7 @@ constructor before setting the specified value. If the element type does not hav
default constructor, `null` will be added to the array or list. If there is no built-in
or custom converter that knows how to set the value, `null` will remain in the array or
list at the specified index. The following example demonstrates how to automatically grow
the list:
the list.
[tabs]
======
@@ -380,16 +379,25 @@ Kotlin::
----
======
By default, a SpEL expression cannot contain more than 10,000 characters; however, the
`maxExpressionLength` is configurable. If you create a `SpelExpressionParser`
programmatically, you can specify a custom `maxExpressionLength` when creating the
`SpelParserConfiguration` that you provide to the `SpelExpressionParser`. If you wish to
set the `maxExpressionLength` used for parsing SpEL expressions within an
`ApplicationContext` -- for example, in XML bean definitions, `@Value`, etc. -- you can
set a JVM system property or Spring property named `spring.context.expression.maxLength`
to the maximum expression length needed by your application (see
xref:appendix.adoc#appendix-spring-properties[Supported Spring Properties]).
[[expressions-spel-compilation]]
== SpEL Compilation
Spring Framework 4.1 includes a basic expression compiler. Expressions are usually
interpreted, which provides a lot of dynamic flexibility during evaluation but
does not provide optimum performance. For occasional expression usage,
this is fine, but, when used by other components such as Spring Integration,
performance can be very important, and there is no real need for the dynamism.
Spring provides a basic compiler for SpEL expressions. Expressions are usually
interpreted, which provides a lot of dynamic flexibility during evaluation but does not
provide optimum performance. For occasional expression usage, this is fine, but, when
used by other components such as Spring Integration, performance can be very important,
and there is no real need for the dynamism.
The SpEL compiler is intended to address this need. During evaluation, the compiler
generates a Java class that embodies the expression behavior at runtime and uses that
@@ -402,16 +410,17 @@ information can cause trouble later if the types of the various expression eleme
change over time. For this reason, compilation is best suited to expressions whose
type information is not going to change on repeated evaluations.
Consider the following basic expression:
Consider the following basic expression.
[source,java,indent=0,subs="verbatim,quotes"]
----
someArray[0].someProperty.someOtherProperty < 0.1
someArray[0].someProperty.someOtherProperty < 0.1
----
Because the preceding expression involves array access, some property de-referencing,
and numeric operations, the performance gain can be very noticeable. In an example
micro benchmark run of 50000 iterations, it took 75ms to evaluate by using the
interpreter and only 3ms using the compiled version of the expression.
Because the preceding expression involves array access, some property de-referencing, and
numeric operations, the performance gain can be very noticeable. In an example micro
benchmark run of 50,000 iterations, it took 75ms to evaluate by using the interpreter and
only 3ms using the compiled version of the expression.
[[expressions-compiler-configuration]]
@@ -419,33 +428,34 @@ interpreter and only 3ms using the compiled version of the expression.
The compiler is not turned on by default, but you can turn it on in either of two
different ways. You can turn it on by using the parser configuration process
(xref:core/expressions/evaluation.adoc#expressions-parser-configuration[discussed earlier]) or by using a Spring property
when SpEL usage is embedded inside another component. This section discusses both of
these options.
(xref:core/expressions/evaluation.adoc#expressions-parser-configuration[discussed
earlier]) or by using a Spring property when SpEL usage is embedded inside another
component. This section discusses both of these options.
The compiler can operate in one of three modes, which are captured in the
`org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows:
`org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows.
* `OFF` (default): The compiler is switched off.
* `IMMEDIATE`: In immediate mode, the expressions are compiled as soon as possible. This
is typically after the first interpreted evaluation. If the compiled expression fails
(typically due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception.
* `MIXED`: In mixed mode, the expressions silently switch between interpreted and compiled
mode over time. After some number of interpreted runs, they switch to compiled
form and, if something goes wrong with the compiled form (such as a type changing, as
described earlier), the expression automatically switches back to interpreted form
again. Sometime later, it may generate another compiled form and switch to it. Basically,
the exception that the user gets in `IMMEDIATE` mode is instead handled internally.
is typically after the first interpreted evaluation. If the compiled expression fails
(typically due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception.
* `MIXED`: In mixed mode, the expressions silently switch between interpreted and
compiled mode over time. After some number of interpreted runs, they switch to compiled
form and, if something goes wrong with the compiled form (such as a type changing, as
described earlier), the expression automatically switches back to interpreted form
again. Sometime later, it may generate another compiled form and switch to it.
Basically, the exception that the user gets in `IMMEDIATE` mode is instead handled
internally.
`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that
have side effects. If a compiled expression blows up after partially succeeding, it
may have already done something that has affected the state of the system. If this
has happened, the caller may not want it to silently re-run in interpreted mode,
since part of the expression may be running twice.
since part of the expression may be run twice.
After selecting a mode, use the `SpelParserConfiguration` to configure the parser. The
following example shows how to do so:
following example shows how to do so.
[tabs]
======
@@ -482,15 +492,16 @@ Kotlin::
----
======
When you specify the compiler mode, you can also specify a classloader (passing null is allowed).
Compiled expressions are defined in a child classloader created under any that is supplied.
It is important to ensure that, if a classloader is specified, it can see all the types involved in
the expression evaluation process. If you do not specify a classloader, a default classloader is used
(typically the context classloader for the thread that is running during expression evaluation).
When you specify the compiler mode, you can also specify a `ClassLoader` (passing `null`
is allowed). Compiled expressions are defined in a child `ClassLoader` created under any
that is supplied. It is important to ensure that, if a `ClassLoader` is specified, it can
see all the types involved in the expression evaluation process. If you do not specify a
`ClassLoader`, a default `ClassLoader` is used (typically the context `ClassLoader` for
the thread that is running during expression evaluation).
The second way to configure the compiler is for use when SpEL is embedded inside some
other component and it may not be possible to configure it through a configuration
object. In these cases, it is possible to set the `spring.expression.compiler.mode`
object. In such cases, it is possible to set the `spring.expression.compiler.mode`
property via a JVM system property (or via the
xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism) to one of the
`SpelCompilerMode` enum values (`off`, `immediate`, or `mixed`).
@@ -499,18 +510,14 @@ xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism) to
[[expressions-compiler-limitations]]
=== Compiler Limitations
Since Spring Framework 4.1, the basic compilation framework is in place. However, the framework
does not yet support compiling every kind of expression. The initial focus has been on the
common expressions that are likely to be used in performance-critical contexts. The following
kinds of expression cannot be compiled at the moment:
Spring does not support compiling every kind of expression. The primary focus is on
common expressions that are likely to be used in performance-critical contexts. The
following kinds of expressions cannot be compiled.
* Expressions involving assignment
* Expressions relying on the conversion service
* Expressions using custom resolvers or accessors
* Expressions using selection or projection
More types of expressions will be compilable in the future.
Compilation of additional kinds of expressions may be supported in the future.
@@ -4,7 +4,7 @@
Projection lets a collection drive the evaluation of a sub-expression, and the result is
a new collection. The syntax for projection is `.![projectionExpression]`. For example,
suppose we have a list of inventors but want the list of cities where they were born.
Effectively, we want to evaluate 'placeOfBirth.city' for every entry in the inventor
Effectively, we want to evaluate `placeOfBirth.city` for every entry in the inventor
list. The following example uses projection to do so:
[tabs]
@@ -440,12 +440,8 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val tuples: MutableList<Array<Any>> = ArrayList()
tuples.add(arrayOf("John", 35))
tuples.add(arrayOf("Ann", 50))
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
.bind("tuples", arrayOf(35, 50))
.bind("ages", arrayOf(35, 50))
----
======
@@ -38,6 +38,11 @@ within the method.
A reactive transaction managed by `ReactiveTransactionManager` uses the Reactor context
instead of thread-local attributes. As a consequence, all participating data access
operations need to execute within the same Reactor context in the same reactive pipeline.
When configured with a `ReactiveTransactionManager`, all transaction-demarcated methods
are expected to return a reactive pipeline. Void methods or regular return types need
to be associated with a regular `PlatformTransactionManager`, e.g. through the
`transactionManager` attribute of the corresponding `@Transactional` declarations.
====
The following image shows a conceptual view of calling a method on a transactional proxy:
+1 -1
View File
@@ -29,7 +29,7 @@ Brannen, Ramnivas Laddad, Arjen Poutsma, Chris Beams, Tareq Abedrabbo, Andy Clem
Syer, Oliver Gierke, Rossen Stoyanchev, Phillip Webb, Rob Winch, Brian Clozel, Stephane
Nicoll, Sebastien Deleuze, Jay Bryant, Mark Paluch
Copyright © 2002 - 2023 VMware, Inc. All Rights Reserved.
Copyright © 2002 - 2024 VMware, Inc. All Rights Reserved.
Copies of this document may be made for your own use and for distribution to others,
provided that you do not charge any fee for such copies and further provided that each
@@ -85,7 +85,7 @@ email when someone places an order:
// Call the collaborators to persist the order...
// Create a thread safe "copy" of the template message and customize it
// Create a thread-safe "copy" of the template message and customize it
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
msg.setTo(order.getCustomer().getEmailAddress());
msg.setText(
@@ -108,7 +108,7 @@ By default, the following `KeyValues` are created:
|===
|Name | Description
|`code.function` _(required)_|Name of Java `Method` that is scheduled for execution.
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method.
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method, or `"ANONYMOUS"` for anonymous classes.
|`error` _(required)_|Class name of the exception thrown during the execution, or `"none"` if no exception happened.
|`exception` _(deprecated)_|Duplicates the `error` key and might be removed in the future.
|`outcome` _(required)_|Outcome of the method execution. Can be `"SUCCESS"`, `"ERROR"` or `"UNKNOWN"` (if for example the operation was cancelled during execution).
@@ -906,8 +906,8 @@ For `WebClient`:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.forClient(webClient)
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
@@ -1078,11 +1078,34 @@ underlying HTTP client, which operates at a lower level and provides more contro
[[rest-http-interface-exceptions]]
=== Exception Handling
=== Error Handling
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status
codes. To customize this, you can register a response status handler that applies to all
responses performed through the client:
To customize error response handling, you need to configure the underlying HTTP client.
For `RestClient`:
By default, `RestClient` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestClient restClient = RestClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
.build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `RestClient.Builder`.
For `WebClient`:
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -1090,10 +1113,28 @@ responses performed through the client:
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(clientAdapter).build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `WebClient.Builder`.
For `RestTemplate`:
By default, `RestTemplate` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register an error handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and
the `ResponseErrorHandler` hierarchy.
@@ -252,7 +252,9 @@ application server environments, as well -- in particular on Tomcat and Jetty.
As of 6.1, `ThreadPoolTaskScheduler` provides a pause/resume capability and graceful
shutdown through Spring's lifecycle management. There is also a new option called
`SimpleAsyncTaskScheduler` which is aligned with JDK 21's Virtual Threads, using a
single scheduler thread but firing up a new thread for every scheduled task execution.
single scheduler thread but firing up a new thread for every scheduled task execution
(except for fixed-delay tasks which all operate on a single scheduler thread, so for
this virtual-thread-aligned option, fixed rates and cron triggers are recommended).
@@ -477,12 +479,12 @@ the framework to invoke a suspending function as a `Publisher`.
The Spring Framework will obtain a `Publisher` for the annotated method once and will
schedule a `Runnable` in which it subscribes to said `Publisher`. These inner regular
subscriptions occur according to the corresponding `cron`/fixedDelay`/`fixedRate` configuration.
subscriptions occur according to the corresponding `cron`/`fixedDelay`/`fixedRate` configuration.
If the `Publisher` emits `onNext` signal(s), these are ignored and discarded (the same way
return values from synchronous `@Scheduled` methods are ignored).
In the following example, the `Flux` emits `onNext("Hello"), onNext("World")` every 5
In the following example, the `Flux` emits `onNext("Hello")`, `onNext("World")` every 5
seconds, but these values are unused:
[source,java,indent=0,subs="verbatim,quotes"]
@@ -13,7 +13,7 @@ Most of the code samples of the reference documentation are
provided in Kotlin in addition to Java.
The easiest way to build a Spring application with Kotlin is to leverage Spring Boot and
its{spring-boot-docs}/boot-features-kotlin.html[dedicated Kotlin support].
its {spring-boot-docs}/boot-features-kotlin.html[dedicated Kotlin support].
{spring-site-guides}/tutorials/spring-boot-kotlin/[This comprehensive tutorial]
will teach you how to build Spring Boot applications with Kotlin using https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
@@ -107,7 +107,7 @@ NOTE: Spring Boot is based on JavaConfig and
{spring-boot-issues}/8115[does not yet provide specific support for functional bean definition],
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
See {stackoverflow-questions}/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}/spring-fu[Spring Fu incubator].
for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}-experimental/spring-fu[Spring Fu incubator].
@@ -14,8 +14,10 @@ Spring Framework provides support for Coroutines on the following scope:
* Suspending function support in Spring MVC and WebFlux annotated `@Controller`
* Extensions for WebFlux {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.client/index.html[client] and {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/index.html[server] functional API.
* WebFlux.fn {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }] DSL
* WebFlux {spring-framework-api-kdoc}/spring-web/org.springframework.web.server/-co-web-filter/index.html[`CoWebFilter`]
* Suspending function and `Flow` support in RSocket `@MessageMapping` annotated methods
* Extensions for {spring-framework-api-kdoc}/spring-messaging/org.springframework.messaging.rsocket/index.html[`RSocketRequester`]
* Spring AOP
@@ -10,22 +10,21 @@ The easiest way to learn how to build a Spring application with Kotlin is to fol
== `start.spring.io`
The easiest way to start a new Spring Framework project in Kotlin is to create a new Spring
Boot 2 project on https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
Boot project on https://start.spring.io/#!language=kotlin&type=gradle-project-kotlin[start.spring.io].
[[choosing-the-web-flavor]]
== Choosing the Web Flavor
Spring Framework now comes with two different web stacks: xref:web/webmvc.adoc#mvc[Spring MVC] and
Spring Framework comes with two different web stacks: xref:web/webmvc.adoc#mvc[Spring MVC] and
xref:testing/unit.adoc#mock-objects-web-reactive[Spring WebFlux].
Spring WebFlux is recommended if you want to create applications that will deal with latency,
long-lived connections, streaming scenarios or if you want to use the web functional
Kotlin DSL.
long-lived connections or streaming scenarios.
For other use cases, especially if you are using blocking technologies such as JPA, Spring
MVC and its annotation-based programming model is the recommended choice.
MVC is the recommended choice.
@@ -2,15 +2,12 @@
= Requirements
:page-section-summary-toc: 1
Spring Framework supports Kotlin 1.3+ and requires
Spring Framework supports Kotlin 1.7+ and requires
https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`]
(or one of its variants, such as https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`])
and https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`]
to be present on the classpath. They are provided by default if you bootstrap a Kotlin project on
https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
WARNING: Kotlin {kotlin-docs}/inline-classes.html[inline classes] are not yet supported.
NOTE: The {jackson-github-org}/jackson-module-kotlin[Jackson Kotlin module] is required
for serializing or deserializing JSON data for Kotlin classes with Jackson, so make sure to add the
`com.fasterxml.jackson.module:jackson-module-kotlin` dependency to your project if you have such need.
@@ -18,28 +18,9 @@ Kotlin and the Spring Framework:
The following Github projects offer examples that you can learn from and possibly even extend:
* https://github.com/spring-guides/tut-spring-boot-kotlin[tut-spring-boot-kotlin]: Sources of {spring-site}/guides/tutorials/spring-boot-kotlin/[the official Spring + Kotlin tutorial]
* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: Regular Spring Boot and Spring Data JPA project
* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2, WebFlux, and Reactive Spring Data MongoDB
* https://github.com/mixitconf/mixit[mixit]: Spring Boot, WebFlux, and Reactive Spring Data MongoDB
* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: Standalone WebFlux and functional bean definition DSL
* https://github.com/sdeleuze/spring-kotlin-fullstack[spring-kotlin-fullstack]: WebFlux Kotlin fullstack example with Kotlin2js for frontend instead of JavaScript or TypeScript
* https://github.com/spring-petclinic/spring-petclinic-kotlin[spring-petclinic-kotlin]: Kotlin version of the Spring PetClinic Sample Application
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin
* https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples/spring-cloud-gcp-kotlin-app-sample[spring-cloud-gcp-kotlin-app-sample]: Spring Boot with Google Cloud Platform Integrations
[[issues]]
== Issues
The following list categorizes the pending issues related to Spring and Kotlin support:
* Spring Framework
** {spring-framework-issues}/20606[Unable to use WebTestClient with mock server in Kotlin]
** {spring-framework-issues}/20496[Support null-safety at generics, varargs and array elements level]
* Kotlin
** {kotlin-issues}/KT-6380[Parent issue for Spring Framework support]
** {kotlin-issues}/KT-5464[Kotlin requires type inference where Java doesn't]
** {kotlin-issues}/KT-20283[Smart cast regression with open classes]
** {kotlin-issues}/KT-14984[Impossible to pass not all SAM argument as function]
** {kotlin-issues}/KT-15125[Support JSR 223 bindings directly via script variables]
** {kotlin-issues}/KT-6653[Kotlin properties do not override Java-style getters and setters]
@@ -97,6 +97,9 @@ does not require the `kotlin-noarg` plugin if the module uses Spring Data object
[[injecting-dependencies]]
== Injecting Dependencies
[[favor-constructor-injection]]
=== Favor constructor injection
Our recommendation is to try to favor constructor injection with `val` read-only (and
non-nullable when possible) {kotlin-docs}/properties.html[properties],
as the following example shows:
@@ -130,7 +133,41 @@ as the following example shows:
}
----
[[internal-functions-name-mangling]]
=== Internal functions name mangling
Kotlin functions with the `internal` {kotlin-docs}/visibility-modifiers.html#class-members[visibility modifier] have
their names mangled when compiled to JVM bytecode, which has a side effect when injecting dependencies by name.
For example, this Kotlin class:
[source,kotlin,indent=0]
----
@Configuration
class SampleConfiguration {
@Bean
internal fun sampleBean() = SampleBean()
}
----
Translates to this Java representation of the compiled JVM bytecode:
[source,java,indent=0]
----
@Configuration
@Metadata(/* ... */)
public class SampleConfiguration {
@Bean
@NotNull
public SampleBean sampleBean$demo_kotlin_internal_test() {
return new SampleBean();
}
}
----
As a consequence, the related bean name represented as a Kotlin string is `"sampleBean\$demo_kotlin_internal_test"`,
instead of `"sampleBean"` for the regular `public` function use-case. Make sure to use the mangled name when injecting
such bean by name.
[[injecting-configuration-properties]]
== Injecting Configuration Properties
@@ -8,9 +8,9 @@
Spring Framework comes with a Kotlin router DSL available in 3 flavors:
* WebMvc.fn DSL with {spring-framework-api-kdoc}/spring-webmvc/org.springframework.web.servlet.function/router.html[router { }]
* WebFlux.fn <<web-reactive#webflux-fn, Reactive>> DSL with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/router.html[router { }]
* WebFlux.fn <<Coroutines>> DSL with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
* xref:web/webmvc-functional.adoc[WebMvc.fn DSL] with {spring-framework-api-kdoc}/spring-webmvc/org.springframework.web.servlet.function/router.html[router { }]
* xref:web/webflux-functional.adoc[WebFlux.fn Reactive DSL] with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/router.html[router { }]
* xref:languages/kotlin/coroutines.adoc[WebFlux.fn Coroutines DSL] with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
These DSL let you write clean and idiomatic Kotlin code to build a `RouterFunction` instance as the following example shows:
@@ -126,7 +126,7 @@ project for more details.
[[kotlin-multiplatform-serialization]]
== Kotlin multiplatform serialization
As of Spring Framework 5.3, {kotlin-github-org}/kotlinx.serialization[Kotlin multiplatform serialization] is
{kotlin-github-org}/kotlinx.serialization[Kotlin multiplatform serialization] is
supported in Spring MVC, Spring WebFlux and Spring Messaging (RSocket). The builtin support currently targets CBOR, JSON, and ProtoBuf formats.
To enable it, follow {kotlin-github-org}/kotlinx.serialization#setup[those instructions] to add the related dependency and plugin.
@@ -78,8 +78,9 @@ it does the same, but it also compares the computed value against the `If-None-M
request header and, if the two are equal, returns a 304 (NOT_MODIFIED).
This strategy saves network bandwidth but not CPU, as the full response must be computed for each request.
State-changing HTTP methods and other HTTP conditional request headers such as `If-Match` and `If-Unmodified-Since` are outside the scope of this filter.
Other strategies at the controller level can avoid the computation and have a broader support for HTTP conditional requests.
State-changing HTTP methods and other HTTP conditional request headers such as `If-Match` and
`If-Unmodified-Since` are outside the scope of this filter. Other strategies at the controller level
can avoid the computation and have a broader support for HTTP conditional requests.
See xref:web/webmvc/mvc-caching.adoc[HTTP Caching].
This filter has a `writeWeakETag` parameter that configures the filter to write weak ETags
@@ -38,7 +38,7 @@ The next example uses server-side configuration to register a custom authenticat
interceptor. Note that an interceptor needs only to authenticate and set
the user header on the CONNECT `Message`. Spring notes and saves the authenticated
user and associate it with subsequent STOMP messages on the same session. The following
example shows how register a custom authentication interceptor:
example shows how to register a custom authentication interceptor:
[source,java,indent=0,subs="verbatim,quotes"]
----
+23 -23
View File
@@ -7,16 +7,17 @@ javaPlatform {
}
dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.15.2"))
api(platform("io.micrometer:micrometer-bom:1.12.1"))
api(platform("io.netty:netty-bom:4.1.101.Final"))
api(platform("com.fasterxml.jackson:jackson-bom:2.15.3"))
api(platform("io.micrometer:micrometer-bom:1.12.2"))
api(platform("io.netty:netty-bom:4.1.104.Final"))
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
api(platform("io.projectreactor:reactor-bom:2023.0.1"))
api(platform("io.projectreactor:reactor-bom:2023.0.2"))
api(platform("io.rsocket:rsocket-bom:1.1.3"))
api(platform("org.apache.groovy:groovy-bom:4.0.16"))
api(platform("org.apache.groovy:groovy-bom:4.0.17"))
api(platform("org.apache.logging.log4j:log4j-bom:2.21.1"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.4"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.3"))
api(platform("org.assertj:assertj-bom:3.25.1"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.5"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.5"))
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3"))
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.0"))
api(platform("org.junit:junit-bom:5.10.1"))
@@ -26,11 +27,11 @@ dependencies {
api("com.fasterxml:aalto-xml:1.3.2")
api("com.fasterxml.woodstox:woodstox-core:6.5.1")
api("com.github.ben-manes.caffeine:caffeine:3.1.8")
api("com.github.librepdf:openpdf:1.3.33")
api("com.github.librepdf:openpdf:1.3.36")
api("com.google.code.findbugs:findbugs:3.0.1")
api("com.google.code.findbugs:jsr305:3.0.2")
api("com.google.code.gson:gson:2.10.1")
api("com.google.protobuf:protobuf-java-util:3.25.0")
api("com.google.protobuf:protobuf-java-util:3.25.1")
api("com.h2database:h2:2.2.224")
api("com.jayway.jsonpath:json-path:2.8.0")
api("com.rometools:rome:1.19.0")
@@ -99,17 +100,16 @@ dependencies {
api("org.apache.derby:derby:10.16.1.1")
api("org.apache.derby:derbyclient:10.16.1.1")
api("org.apache.derby:derbytools:10.16.1.1")
api("org.apache.httpcomponents.client5:httpclient5:5.2.1")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.3")
api("org.apache.poi:poi-ooxml:5.2.4")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.16")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.16")
api("org.apache.tomcat:tomcat-util:10.1.16")
api("org.apache.tomcat:tomcat-websocket:10.1.16")
api("org.aspectj:aspectjrt:1.9.20.1")
api("org.aspectj:aspectjtools:1.9.20.1")
api("org.aspectj:aspectjweaver:1.9.20.1")
api("org.assertj:assertj-core:3.24.2")
api("org.apache.httpcomponents.client5:httpclient5:5.3")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.4")
api("org.apache.poi:poi-ooxml:5.2.5")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.18")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.18")
api("org.apache.tomcat:tomcat-util:10.1.18")
api("org.apache.tomcat:tomcat-websocket:10.1.18")
api("org.aspectj:aspectjrt:1.9.21")
api("org.aspectj:aspectjtools:1.9.21")
api("org.aspectj:aspectjweaver:1.9.21")
api("org.awaitility:awaitility:4.2.0")
api("org.bouncycastle:bcpkix-jdk18on:1.72")
api("org.codehaus.jettison:jettison:1.5.4")
@@ -131,7 +131,7 @@ dependencies {
api("org.hsqldb:hsqldb:2.7.2")
api("org.javamoney:moneta:1.4.2")
api("org.jruby:jruby:9.4.5.0")
api("org.junit.support:testng-engine:1.0.4")
api("org.junit.support:testng-engine:1.0.5")
api("org.mozilla:rhino:1.7.14")
api("org.ogce:xpp3:1.1.6")
api("org.python:jython-standalone:2.7.3")
@@ -139,8 +139,8 @@ dependencies {
api("org.seleniumhq.selenium:htmlunit-driver:2.70.0")
api("org.seleniumhq.selenium:selenium-java:3.141.59")
api("org.skyscreamer:jsonassert:1.5.1")
api("org.slf4j:slf4j-api:2.0.9")
api("org.testng:testng:7.8.0")
api("org.slf4j:slf4j-api:2.0.11")
api("org.testng:testng:7.9.0")
api("org.webjars:underscorejs:1.8.3")
api("org.webjars:webjars-locator-core:0.55")
api("org.xmlunit:xmlunit-assertj:2.9.1")
+2 -2
View File
@@ -1,10 +1,10 @@
version=6.1.2-SNAPSHOT
version=6.1.3
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m
org.gradle.parallel=true
kotlinVersion=1.9.21
kotlinVersion=1.9.22
kotlin.jvm.target.validation.mode=ignore
kotlin.stdlib.default.dependency=false
@@ -1,3 +1,19 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.autoproxy
import kotlinx.coroutines.delay
@@ -94,12 +110,12 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
open class Echo {
open fun echo(value: String): String {
return value;
return value
}
open suspend fun suspendingEcho(value: String): String {
delay(1)
return value;
return value
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -334,13 +334,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
Object targetObject = null;
Object thisObject = null;
try {
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
targetObject = mi.getThis();
if (!(mi instanceof ProxyMethodInvocation _pmi)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
MethodInvocation curr = ExposeInvocationInterceptor.currentInvocation();
if (curr.getMethod() == method) {
targetObject = curr.getThis();
if (!(curr instanceof ProxyMethodInvocation currPmi)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + curr);
}
pmi = currPmi;
thisObject = pmi.getProxy();
}
pmi = _pmi;
thisObject = pmi.getProxy();
}
catch (IllegalStateException ex) {
// No current invocation...
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -293,7 +293,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
// This can match only on declared pointcut.
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass, args));
}
private boolean isAspectMaterialized() {
@@ -201,9 +201,8 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
List<BeanReference> beanReferences = new ArrayList<>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
for (Element declareParent : declareParents) {
beanDefinitions.add(parseDeclareParents(declareParent, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
@@ -405,24 +404,14 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
*/
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
return switch (elementName) {
case BEFORE -> AspectJMethodBeforeAdvice.class;
case AFTER -> AspectJAfterAdvice.class;
case AFTER_RETURNING_ELEMENT -> AspectJAfterReturningAdvice.class;
case AFTER_THROWING_ELEMENT -> AspectJAfterThrowingAdvice.class;
case AROUND -> AspectJAroundAdvice.class;
default -> throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
};
}
/**
@@ -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.
@@ -42,10 +42,8 @@ class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
boolean proxyTargetClass = true;
if (node instanceof Element ele) {
if (ele.hasAttribute(PROXY_TARGET_CLASS)) {
proxyTargetClass = Boolean.parseBoolean(ele.getAttribute(PROXY_TARGET_CLASS));
}
if (node instanceof Element ele && ele.hasAttribute(PROXY_TARGET_CLASS)) {
proxyTargetClass = Boolean.parseBoolean(ele.getAttribute(PROXY_TARGET_CLASS));
}
// Register the original bean definition as it will be referenced by the scoped proxy
@@ -102,8 +102,23 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
private List<Advisor> advisors = new ArrayList<>();
/**
* List of minimal {@link AdvisorKeyEntry} instances,
* to be assigned to the {@link #advisors} field on reduction.
* @since 6.0.10
* @see #reduceToAdvisorKey
*/
private List<Advisor> advisorKey = this.advisors;
/**
* Optional field for {@link AopProxy} implementations to store metadata in.
* Used by {@link JdkDynamicAopProxy}.
* @since 6.1.3
* @see JdkDynamicAopProxy#JdkDynamicAopProxy(AdvisedSupport)
*/
@Nullable
transient volatile Object proxyMetadataCache;
/**
* No-arg constructor for use as a JavaBean.
@@ -491,6 +506,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
protected void adviceChanged() {
this.methodCache.clear();
this.proxyMetadataCache = null;
}
/**
@@ -551,18 +567,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.methodCache = new ConcurrentHashMap<>(32);
}
@Override
public String toProxyConfigString() {
return toString();
@@ -584,6 +588,19 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.methodCache = new ConcurrentHashMap<>(32);
}
/**
* Simple wrapper class around a Method. Used as the key when
* caching methods, for efficient equals and hashCode comparisons.
@@ -633,7 +650,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* @see #getConfigurationOnlyCopy()
* @see #getAdvisorKey()
*/
private static class AdvisorKeyEntry implements Advisor {
private static final class AdvisorKeyEntry implements Advisor {
private final Class<?> adviceType;
@@ -643,7 +660,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
@Nullable
private final String methodMatcherKey;
public AdvisorKeyEntry(Advisor advisor) {
this.adviceType = advisor.getAdvice().getClass();
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
@@ -16,6 +16,8 @@
package org.springframework.aop.framework;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -71,34 +73,16 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
private static final long serialVersionUID = 5531744639992436476L;
/*
* NOTE: We could avoid the code duplication between this class and the CGLIB
* proxies by refactoring "invoke" into a template method. However, this approach
* adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice
* elegance for performance (we have a good test suite to ensure that the different
* proxies behave the same :-)).
* This way, we can also more easily take advantage of minor optimizations in each class.
*/
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
/** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
/** Config used to configure this proxy. */
private final AdvisedSupport advised;
private final Class<?>[] proxiedInterfaces;
/**
* Is the {@link #equals} method defined on the proxied interfaces?
*/
private boolean equalsDefined;
/**
* Is the {@link #hashCode} method defined on the proxied interfaces?
*/
private boolean hashCodeDefined;
/** Cached in {@link AdvisedSupport#proxyMetadataCache}. */
private transient ProxiedInterfacesCache cache;
/**
@@ -110,8 +94,17 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
this.advised = config;
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
// Initialize ProxiedInterfacesCache if not cached already
ProxiedInterfacesCache cache;
if (config.proxyMetadataCache instanceof ProxiedInterfacesCache proxiedInterfacesCache) {
cache = proxiedInterfacesCache;
}
else {
cache = new ProxiedInterfacesCache(config);
config.proxyMetadataCache = cache;
}
this.cache = cache;
}
@@ -125,13 +118,13 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this);
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.cache.proxiedInterfaces, this);
}
@SuppressWarnings("deprecation")
@Override
public Class<?> getProxyClass(@Nullable ClassLoader classLoader) {
return Proxy.getProxyClass(determineClassLoader(classLoader), this.proxiedInterfaces);
return Proxy.getProxyClass(determineClassLoader(classLoader), this.cache.proxiedInterfaces);
}
/**
@@ -160,28 +153,6 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return classLoader;
}
/**
* Finds any {@link #equals} or {@link #hashCode} method that may be defined
* on the supplied set of interfaces.
* @param proxiedInterfaces the interfaces to introspect
*/
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
/**
* Implementation of {@code InvocationHandler.invoke}.
@@ -198,11 +169,11 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
if (!this.cache.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
else if (!this.cache.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
@@ -324,4 +295,63 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.cache = new ProxiedInterfacesCache(this.advised);
}
/**
* Holder for the complete proxied interfaces and derived metadata,
* to be cached in {@link AdvisedSupport#proxyMetadataCache}.
* @since 6.1.3
*/
private static final class ProxiedInterfacesCache {
final Class<?>[] proxiedInterfaces;
final boolean equalsDefined;
final boolean hashCodeDefined;
ProxiedInterfacesCache(AdvisedSupport config) {
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(config, true);
// Find any {@link #equals} or {@link #hashCode} method that may be defined
// on the supplied set of interfaces.
boolean equalsDefined = false;
boolean hashCodeDefined = false;
for (Class<?> proxiedInterface : this.proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
equalsDefined = true;
if (hashCodeDefined) {
break;
}
}
if (AopUtils.isHashCodeMethod(method)) {
hashCodeDefined = true;
if (equalsDefined) {
break;
}
}
}
if (equalsDefined && hashCodeDefined) {
break;
}
}
this.equalsDefined = equalsDefined;
this.hashCodeDefined = hashCodeDefined;
}
}
}
@@ -58,6 +58,7 @@ import org.springframework.util.function.SingletonSupplier;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author He Bo
* @author Sebastien Deleuze
* @since 3.1.2
*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
@@ -292,7 +293,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
else if (Future.class.isAssignableFrom(returnType)) {
return executor.submit(task);
}
else if (void.class == returnType) {
else if (void.class == returnType || "kotlin.Unit".equals(returnType.getName())) {
executor.submit(task);
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@ import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* AOP Alliance {@code MethodInterceptor} that processes method invocations
@@ -101,10 +100,9 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport imple
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
final Method userMethod = BridgeMethodResolver.getMostSpecificMethod(invocation.getMethod(), targetClass);
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
AsyncTaskExecutor executor = determineAsyncExecutor(userMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
@@ -118,10 +116,10 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport imple
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
handleError(ex.getCause(), userMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userDeclaredMethod, invocation.getArguments());
handleError(ex, userMethod, invocation.getArguments());
}
return null;
};
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -199,12 +199,11 @@ public abstract class AopUtils {
* @return the specific target method, or the original method if the
* {@code targetClass} doesn't implement it or is {@code null}
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
* @see org.springframework.core.BridgeMethodResolver#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
return BridgeMethodResolver.getMostSpecificMethod(method, specificTargetClass);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
/**
* The class against which to match.
* <p>Available for use in subclasses since 6.1.
* @since 6.1
*/
protected final Class<?> clazz;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Unit tests for {@link AspectJAdviceParameterNameDiscoverer}.
* Tests for {@link AspectJAdviceParameterNameDiscoverer}.
*
* @author Adrian Colyer
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
import org.junit.jupiter.api.BeforeEach;
@@ -66,7 +65,7 @@ public class AspectJExpressionPointcutTests {
@BeforeEach
public void setUp() throws NoSuchMethodException {
public void setup() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
setAge = TestBean.class.getMethod("setAge", int.class);
setSomeNumber = TestBean.class.getMethod("setSomeNumber", Number.class);
@@ -247,14 +246,13 @@ public class AspectJExpressionPointcutTests {
@Test
public void testInvalidExpression() {
String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number) && args(Double)";
assertThatIllegalArgumentException().isThrownBy(
getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution
assertThatIllegalArgumentException().isThrownBy(getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution
}
private TestBean getAdvisedProxy(String pointcutExpression, CallCountingInterceptor interceptor) {
TestBean target = new TestBean();
Pointcut pointcut = getPointcut(pointcutExpression);
AspectJExpressionPointcut pointcut = getPointcut(pointcutExpression);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setAdvice(interceptor);
@@ -278,40 +276,31 @@ public class AspectJExpressionPointcutTests {
@Test
public void testWithUnsupportedPointcutPrimitive() {
String expression = "call(int org.springframework.beans.testfixture.beans.TestBean.getAge())";
assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class).isThrownBy(() ->
getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution...
.satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL));
assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class)
.isThrownBy(() -> getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution...
.satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL));
}
@Test
public void testAndSubstitution() {
Pointcut pc = getPointcut("execution(* *(..)) and args(String)");
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String)");
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String)");
String expr = pc.getPointcutExpression().getPointcutExpression();
assertThat(expr).isEqualTo("execution(* *(..)) && args(String)");
}
@Test
public void testMultipleAndSubstitutions() {
Pointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
String expr = pc.getPointcutExpression().getPointcutExpression();
assertThat(expr).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
}
private Pointcut getPointcut(String expression) {
private AspectJExpressionPointcut getPointcut(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return pointcut;
}
public static class OtherIOther implements IOther {
@Override
public void absquatulate() {
// Empty
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
@@ -531,6 +520,15 @@ public class AspectJExpressionPointcutTests {
}
public static class OtherIOther implements IOther {
@Override
public void absquatulate() {
// Empty
}
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Unit tests for the {@link TypePatternClassFilter} class.
* Tests for {@link TypePatternClassFilter}.
*
* @author Rod Johnson
* @author Rick Evans
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,26 +42,38 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*/
class ArgumentBindingTests {
@Test
void bindingInPointcutUsedByAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
}
@Test
void annotationArgumentNameBinding() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalStateException()
.isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
.isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
}
@Test
void bindingInPointcutUsedByAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
}
@Test
void bindingWithDynamicAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(DynamicPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
proxiedTestBean.applyName(1);
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.applyName("enigma"))
.withMessage("enigma");
}
@Test
@@ -94,6 +106,7 @@ class ArgumentBindingTests {
}
}
/**
* Mimics Spring's @Transactional annotation without actually introducing the dependency.
*/
@@ -101,16 +114,17 @@ class ArgumentBindingTests {
@interface Transactional {
}
@Aspect
static class PointcutWithAnnotationArgument {
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transactional)")
@Around("execution(* org.springframework..*.*(..)) && @annotation(transactional)")
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
throw new IllegalStateException("Invoked with @Transactional");
}
}
@Aspect
static class NamedPointcutWithArgs {
@@ -121,7 +135,16 @@ class ArgumentBindingTests {
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
throw new IllegalArgumentException(aString);
}
}
@Aspect("pertarget(execution(* *(..)))")
static class DynamicPointcutWithArgs {
@Around("execution(* *(..)) && args(java.lang.String)")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
throw new IllegalArgumentException(String.valueOf(pjp.getArgs()[0]));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Unit tests for the {@link DebugInterceptor} class.
* Tests for {@link DebugInterceptor}.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Unit tests for the {@link SimpleTraceInterceptor} class.
* Tests for {@link SimpleTraceInterceptor}.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.mockito.Mockito.mock;
/**
* Unit tests for the {@link DefaultScopedObject} class.
* Tests for {@link DefaultScopedObject}.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Unit tests for {@link ScopedProxyUtils}.
* Tests for {@link ScopedProxyUtils}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link ClassFilters}.
* Tests for {@link ClassFilters}.
*
* @author Rod Johnson
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import org.springframework.beans.testfixture.beans.ITestBean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link RootClassFilter}.
* Tests for {@link RootClassFilter}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link AnnotationMatchingPointcut}.
* Tests for {@link AnnotationMatchingPointcut}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -46,7 +46,7 @@ class AopUtilsKotlinTests {
@Suppress("unused")
suspend fun suspendingFunction(value: String): String {
delay(1)
return value;
return value
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
/**
* Unit tests for {@link AnnotationAsyncExecutionAspect}.
* Tests for {@link AnnotationAsyncExecutionAspect}.
*
* @author Ramnivas Laddad
* @author Stephane Nicoll
@@ -221,7 +221,7 @@ public class AnnotationAsyncExecutionAspectTests {
@Async public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
return new AsyncResult<>(5);
}
/**
@@ -256,7 +256,7 @@ public class AnnotationAsyncExecutionAspectTests {
public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
return new AsyncResult<>(5);
}
}
@@ -265,12 +265,12 @@ public class AnnotationAsyncExecutionAspectTests {
@Async
public Future<Thread> defaultWork() {
return new AsyncResult<Thread>(Thread.currentThread());
return new AsyncResult<>(Thread.currentThread());
}
@Async("e1")
public ListenableFuture<Thread> e1Work() {
return new AsyncResult<Thread>(Thread.currentThread());
return new AsyncResult<>(Thread.currentThread());
}
@Async("e1")
@@ -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.
@@ -16,7 +16,7 @@
package org.springframework.beans
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.BenchmarkMode
@@ -30,22 +30,22 @@ import org.openjdk.jmh.annotations.State
@OutputTimeUnit(TimeUnit.NANOSECONDS)
open class KotlinBeanUtilsBenchmark {
private val noArgConstructor = TestClass1::class.java.getDeclaredConstructor()
private val constructor = TestClass2::class.java.getDeclaredConstructor(Int::class.java, String::class.java)
private val noArgConstructor = TestClass1::class.java.getDeclaredConstructor()
private val constructor = TestClass2::class.java.getDeclaredConstructor(Int::class.java, String::class.java)
@Benchmark
fun emptyConstructor(): Any {
@Benchmark
fun emptyConstructor(): Any {
return BeanUtils.instantiateClass(noArgConstructor)
}
}
@Benchmark
fun nonEmptyConstructor(): Any {
@Benchmark
fun nonEmptyConstructor(): Any {
return BeanUtils.instantiateClass(constructor, 1, "str")
}
}
class TestClass1()
class TestClass1
@Suppress("UNUSED_PARAMETER")
class TestClass2(int: Int, string: String)
@Suppress("UNUSED_PARAMETER")
class TestClass2(int: Int, string: String)
}
@@ -461,7 +461,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
if (!ph.setValueFallbackIfPossible(pv.getValue())) {
throw ex;
}
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
@@ -1061,6 +1063,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
public abstract Object getValue() throws Exception;
public abstract void setValue(@Nullable Object value) throws Exception;
public boolean setValueFallbackIfPossible(@Nullable Object value) {
return false;
}
}
@@ -19,6 +19,8 @@ package org.springframework.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
@@ -278,6 +280,22 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
}
@Override
public boolean setValueFallbackIfPossible(@Nullable Object value) {
Method writeMethod = this.pd.getWriteMethodFallback(value != null ? value.getClass() : null);
if (writeMethod != null) {
ReflectionUtils.makeAccessible(writeMethod);
try {
writeMethod.invoke(getWrappedInstance(), value);
return true;
}
catch (Exception ex) {
LogFactory.getLog(BeanPropertyHandler.class).debug("Write method fallback failed", ex);
}
}
return false;
}
}
}
@@ -524,20 +524,7 @@ class ExtendedBeanInfo implements BeanInfo {
@Override
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
String left = desc1.getName();
String right = desc2.getName();
byte[] leftBytes = left.getBytes();
byte[] rightBytes = right.getBytes();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = leftBytes[i] - rightBytes[i];
if (result != 0) {
return result;
}
}
return left.length() - right.length();
return desc1.getName().compareTo(desc2.getName());
}
}
@@ -54,7 +54,9 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
private final Method writeMethod;
@Nullable
private volatile Set<Method> ambiguousWriteMethods;
private Set<Method> ambiguousWriteMethods;
private volatile boolean ambiguousWriteMethodsLogged;
@Nullable
private MethodParameter writeMethodParameter;
@@ -147,16 +149,28 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
public Method getWriteMethodForActualAccess() {
Assert.state(this.writeMethod != null, "No write method available");
Set<Method> ambiguousCandidates = this.ambiguousWriteMethods;
if (ambiguousCandidates != null) {
this.ambiguousWriteMethods = null;
if (this.ambiguousWriteMethods != null && !this.ambiguousWriteMethodsLogged) {
this.ambiguousWriteMethodsLogged = true;
LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).debug("Non-unique JavaBean property '" +
getName() + "' being accessed! Ambiguous write methods found next to actually used [" +
this.writeMethod + "]: " + ambiguousCandidates);
this.writeMethod + "]: " + this.ambiguousWriteMethods);
}
return this.writeMethod;
}
@Nullable
public Method getWriteMethodFallback(@Nullable Class<?> valueType) {
if (this.ambiguousWriteMethods != null) {
for (Method method : this.ambiguousWriteMethods) {
Class<?> paramType = method.getParameterTypes()[0];
if (valueType != null ? paramType.isAssignableFrom(valueType) : !paramType.isPrimitive()) {
return method;
}
}
}
return null;
}
public MethodParameter getWriteMethodParameter() {
Assert.state(this.writeMethodParameter != null, "No write method available");
return this.writeMethodParameter;
@@ -170,6 +170,8 @@ public interface BeanFactory {
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* Note that the provided arguments need to match a specific candidate constructor /
* factory method in the order of declared parameters.
* @param name the name of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
@@ -202,6 +204,8 @@ public interface BeanFactory {
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* Note that the provided arguments need to match a specific candidate constructor /
* factory method in the order of declared parameters.
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -517,9 +517,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
/**
* 'Native' processing method for direct calls with an arbitrary target instance,
* resolving all of its fields and methods which are annotated with one of the
* configured 'autowired' annotation types.
* <em>Native</em> processing method for direct calls with an arbitrary target
* instance, resolving all of its fields and methods which are annotated with
* one of the configured 'autowired' annotation types.
* @param bean the target instance to process
* @throws BeanCreationException if autowiring failed
* @see #setAutowiredAnnotationTypes(Set)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -367,7 +367,7 @@ class BeanDefinitionPropertiesCodeGenerator {
* @param castNecessary whether a cast is necessary
* @param castType the type to cast to
* @param valueCode the code for the value
* @return the existing value or a form of {@code (CastType) valueCode} if a
* @return the existing value or a form of {@code (castType) valueCode} if a
* cast is necessary
*/
private CodeBlock castIfNecessary(boolean castNecessary, Class<?> castType, CodeBlock valueCode) {
@@ -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.
@@ -98,9 +98,7 @@ public final class ParseState {
for (ParseState.Entry entry : this.state) {
if (i > 0) {
sb.append('\n');
for (int j = 0; j < i; j++) {
sb.append('\t');
}
sb.append("\t".repeat(i));
sb.append("-> ");
}
sb.append(entry);
@@ -92,10 +92,10 @@ import org.springframework.util.function.ThrowingSupplier;
* Supports autowiring constructors, properties by name, and properties by type.
*
* <p>The main template method to be implemented by subclasses is
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)},
* used for autowiring by type. In case of a factory which is capable of searching
* its bean definitions, matching beans will typically be implemented through such
* a search. For other factory styles, simplified matching algorithms can be implemented.
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)}, used for
* autowiring. In case of a {@link org.springframework.beans.factory.ListableBeanFactory}
* which is capable of searching its bean definitions, matching beans will typically be
* implemented through such a search. Otherwise, simplified matching can be implemented.
*
* <p>Note that this class does <i>not</i> assume or implement bean definition
* registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
@@ -653,7 +653,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
// eventual type after a before-instantiation shortcut.
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
boolean matchingOnlyFactoryBean = typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class;
boolean matchingOnlyFactoryBean = (typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class);
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Class<?> predicted = bp.predictBeanType(targetType, beanName);
if (predicted != null &&
@@ -581,7 +581,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
*/
@Override
public boolean isLazyInit() {
return (this.lazyInit != null && this.lazyInit.booleanValue());
return (this.lazyInit != null && this.lazyInit);
}
/**
@@ -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.
@@ -59,7 +59,7 @@ public class BeanDefinitionDefaults {
* @return whether to apply lazy-init semantics ({@code false} by default)
*/
public boolean isLazyInit() {
return (this.lazyInit != null && this.lazyInit.booleanValue());
return (this.lazyInit != null && this.lazyInit);
}
/**
@@ -121,11 +121,7 @@ class ConstructorResolver {
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>This corresponds to constructor injection: In this mode, a Spring
* bean factory is able to host components that expect constructor-based
* dependency resolution.
* Also applied if explicit constructor argument values are specified.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param chosenCtors chosen candidate constructors (or {@code null} if none)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -294,7 +294,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setNestedPropertyPolymorphic() throws Exception {
void setNestedPropertyPolymorphic() {
ITestBean target = new TestBean("rod", 31);
ITestBean kerry = new Employee();
@@ -316,7 +316,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setAnotherNestedProperty() throws Exception {
void setAnotherNestedProperty() {
ITestBean target = new TestBean("rod", 31);
ITestBean kerry = new TestBean("kerry", 0);
@@ -386,7 +386,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setAnotherPropertyIntermediatePropertyIsNull() throws Exception {
void setAnotherPropertyIntermediatePropertyIsNull() {
ITestBean target = new TestBean("rod", 31);
AbstractPropertyAccessor accessor = createAccessor(target);
assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() ->
@@ -406,7 +406,6 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
@SuppressWarnings("unchecked")
void setPropertyIntermediateListIsNullWithAutoGrow() {
Foo target = new Foo();
AbstractPropertyAccessor accessor = createAccessor(target);
@@ -553,7 +552,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringPropertyWithCustomEditor() throws Exception {
void setStringPropertyWithCustomEditor() {
TestBean target = new TestBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String.class, "name", new PropertyEditorSupport() {
@@ -724,7 +723,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setPropertiesProperty() throws Exception {
void setPropertiesProperty() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setPropertyValue("name", "ptest");
@@ -742,7 +741,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayProperty() throws Exception {
void setStringArrayProperty() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
@@ -767,7 +766,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithCustomStringEditor() throws Exception {
void setStringArrayPropertyWithCustomStringEditor() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String.class, "stringArray", new PropertyEditorSupport() {
@@ -796,7 +795,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithStringSplitting() throws Exception {
void setStringArrayPropertyWithStringSplitting() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.useConfigValueEditors();
@@ -805,7 +804,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithCustomStringDelimiter() throws Exception {
void setStringArrayPropertyWithCustomStringDelimiter() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String[].class, "stringArray", new StringArrayPropertyEditor("-"));
@@ -814,7 +813,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayWithAutoGrow() throws Exception {
void setStringArrayWithAutoGrow() {
StringArrayBean target = new StringArrayBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setAutoGrowNestedPaths(true);
@@ -888,7 +887,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setIntArrayPropertyWithStringSplitting() throws Exception {
void setIntArrayPropertyWithStringSplitting() {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.useConfigValueEditors();
@@ -943,7 +942,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setPrimitiveArrayPropertyWithAutoGrow() throws Exception {
void setPrimitiveArrayPropertyWithAutoGrow() {
PrimitiveArrayBean target = new PrimitiveArrayBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setAutoGrowNestedPaths(true);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.SoftAssertions.assertSoftly;
/**
* Unit tests for {@link BeanUtils}.
* Tests for {@link BeanUtils}.
*
* @author Juergen Hoeller
* @author Rob Harrop
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class BeanWrapperAutoGrowingTests {
class BeanWrapperAutoGrowingTests {
private final Bean bean = new Bean();
@@ -38,43 +38,43 @@ public class BeanWrapperAutoGrowingTests {
@BeforeEach
public void setup() {
void setup() {
wrapper.setAutoGrowNestedPaths(true);
}
@Test
public void getPropertyValueNullValueInNestedPath() {
void getPropertyValueNullValueInNestedPath() {
assertThat(wrapper.getPropertyValue("nested.prop")).isNull();
}
@Test
public void setPropertyValueNullValueInNestedPath() {
void setPropertyValueNullValueInNestedPath() {
wrapper.setPropertyValue("nested.prop", "test");
assertThat(bean.getNested().getProp()).isEqualTo("test");
}
@Test
public void getPropertyValueNullValueInNestedPathNoDefaultConstructor() {
void getPropertyValueNullValueInNestedPathNoDefaultConstructor() {
assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() ->
wrapper.getPropertyValue("nestedNoConstructor.prop"));
}
@Test
public void getPropertyValueAutoGrowArray() {
void getPropertyValueAutoGrowArray() {
assertNotNull(wrapper.getPropertyValue("array[0]"));
assertThat(bean.getArray()).hasSize(1);
assertThat(bean.getArray()[0]).isInstanceOf(Bean.class);
}
@Test
public void setPropertyValueAutoGrowArray() {
void setPropertyValueAutoGrowArray() {
wrapper.setPropertyValue("array[0].prop", "test");
assertThat(bean.getArray()[0].getProp()).isEqualTo("test");
}
@Test
public void getPropertyValueAutoGrowArrayBySeveralElements() {
void getPropertyValueAutoGrowArrayBySeveralElements() {
assertNotNull(wrapper.getPropertyValue("array[4]"));
assertThat(bean.getArray()).hasSize(5);
assertThat(bean.getArray()[0]).isInstanceOf(Bean.class);
@@ -89,21 +89,21 @@ public class BeanWrapperAutoGrowingTests {
}
@Test
public void getPropertyValueAutoGrow2dArray() {
void getPropertyValueAutoGrow2dArray() {
assertThat(wrapper.getPropertyValue("multiArray[0][0]")).isNotNull();
assertThat(bean.getMultiArray()[0]).hasSize(1);
assertThat(bean.getMultiArray()[0][0]).isInstanceOf(Bean.class);
}
@Test
public void getPropertyValueAutoGrow3dArray() {
void getPropertyValueAutoGrow3dArray() {
assertThat(wrapper.getPropertyValue("threeDimensionalArray[1][2][3]")).isNotNull();
assertThat(bean.getThreeDimensionalArray()[1]).hasNumberOfRows(3);
assertThat(bean.getThreeDimensionalArray()[1][2][3]).isInstanceOf(Bean.class);
}
@Test
public void setPropertyValueAutoGrow2dArray() {
void setPropertyValueAutoGrow2dArray() {
Bean newBean = new Bean();
newBean.setProp("enigma");
wrapper.setPropertyValue("multiArray[2][3]", newBean);
@@ -113,7 +113,7 @@ public class BeanWrapperAutoGrowingTests {
}
@Test
public void setPropertyValueAutoGrow3dArray() {
void setPropertyValueAutoGrow3dArray() {
Bean newBean = new Bean();
newBean.setProp("enigma");
wrapper.setPropertyValue("threeDimensionalArray[2][3][4]", newBean);
@@ -123,20 +123,20 @@ public class BeanWrapperAutoGrowingTests {
}
@Test
public void getPropertyValueAutoGrowList() {
void getPropertyValueAutoGrowList() {
assertNotNull(wrapper.getPropertyValue("list[0]"));
assertThat(bean.getList()).hasSize(1);
assertThat(bean.getList()).element(0).isInstanceOf(Bean.class);
}
@Test
public void setPropertyValueAutoGrowList() {
void setPropertyValueAutoGrowList() {
wrapper.setPropertyValue("list[0].prop", "test");
assertThat(bean.getList().get(0).getProp()).isEqualTo("test");
}
@Test
public void getPropertyValueAutoGrowListBySeveralElements() {
void getPropertyValueAutoGrowListBySeveralElements() {
assertNotNull(wrapper.getPropertyValue("list[4]"));
assertThat(bean.getList()).hasSize(5);
assertThat(bean.getList()).element(0).isInstanceOf(Bean.class);
@@ -151,7 +151,7 @@ public class BeanWrapperAutoGrowingTests {
}
@Test
public void getPropertyValueAutoGrowListFailsAgainstLimit() {
void getPropertyValueAutoGrowListFailsAgainstLimit() {
wrapper.setAutoGrowCollectionLimit(2);
assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() ->
wrapper.getPropertyValue("list[4]"))
@@ -159,26 +159,26 @@ public class BeanWrapperAutoGrowingTests {
}
@Test
public void getPropertyValueAutoGrowMultiDimensionalList() {
void getPropertyValueAutoGrowMultiDimensionalList() {
assertNotNull(wrapper.getPropertyValue("multiList[0][0]"));
assertThat(bean.getMultiList()).element(0).asList().hasSize(1);
assertThat(bean.getMultiList().get(0)).element(0).isInstanceOf(Bean.class);
}
@Test
public void getPropertyValueAutoGrowListNotParameterized() {
void getPropertyValueAutoGrowListNotParameterized() {
assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() ->
wrapper.getPropertyValue("listNotParameterized[0]"));
}
@Test
public void setPropertyValueAutoGrowMap() {
void setPropertyValueAutoGrowMap() {
wrapper.setPropertyValue("map[A]", new Bean());
assertThat(bean.getMap().get("A")).isInstanceOf(Bean.class);
}
@Test
public void setNestedPropertyValueAutoGrowMap() {
void setNestedPropertyValueAutoGrowMap() {
wrapper.setPropertyValue("map[A].nested", new Bean());
assertThat(bean.getMap().get("A").getNested()).isInstanceOf(Bean.class);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,10 +31,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Juergen Hoeller
* @author Chris Beams
*/
public class BeanWrapperEnumTests {
class BeanWrapperEnumTests {
@Test
public void testCustomEnum() {
void testCustomEnum() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", "VALUE_1");
@@ -42,7 +42,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumWithNull() {
void testCustomEnumWithNull() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", null);
@@ -50,7 +50,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumWithEmptyString() {
void testCustomEnumWithEmptyString() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", "");
@@ -58,7 +58,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumArrayWithSingleValue() {
void testCustomEnumArrayWithSingleValue() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", "VALUE_1");
@@ -67,7 +67,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumArrayWithMultipleValues() {
void testCustomEnumArrayWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", new String[] {"VALUE_1", "VALUE_2"});
@@ -77,7 +77,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumArrayWithMultipleValuesAsCsv() {
void testCustomEnumArrayWithMultipleValuesAsCsv() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", "VALUE_1,VALUE_2");
@@ -87,7 +87,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumSetWithSingleValue() {
void testCustomEnumSetWithSingleValue() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", "VALUE_1");
@@ -96,7 +96,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumSetWithMultipleValues() {
void testCustomEnumSetWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", new String[] {"VALUE_1", "VALUE_2"});
@@ -106,7 +106,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumSetWithMultipleValuesAsCsv() {
void testCustomEnumSetWithMultipleValuesAsCsv() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", "VALUE_1,VALUE_2");
@@ -116,7 +116,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testCustomEnumSetWithGetterSetterMismatch() {
void testCustomEnumSetWithGetterSetterMismatch() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSetMismatch", new String[] {"VALUE_1", "VALUE_2"});
@@ -126,7 +126,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testStandardEnumSetWithMultipleValues() {
void testStandardEnumSetWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setConversionService(new DefaultConversionService());
@@ -138,7 +138,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testStandardEnumSetWithAutoGrowing() {
void testStandardEnumSetWithAutoGrowing() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setAutoGrowNestedPaths(true);
@@ -148,7 +148,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testStandardEnumMapWithMultipleValues() {
void testStandardEnumMapWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setConversionService(new DefaultConversionService());
@@ -163,7 +163,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testStandardEnumMapWithAutoGrowing() {
void testStandardEnumMapWithAutoGrowing() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setAutoGrowNestedPaths(true);
@@ -174,7 +174,7 @@ public class BeanWrapperEnumTests {
}
@Test
public void testNonPublicEnum() {
void testNonPublicEnum() {
NonPublicEnumHolder holder = new NonPublicEnumHolder();
BeanWrapper bw = new BeanWrapperImpl(holder);
bw.setPropertyValue("nonPublicEnum", "VALUE_1");
@@ -184,7 +184,7 @@ public class BeanWrapperEnumTests {
enum NonPublicEnum {
VALUE_1, VALUE_2;
VALUE_1, VALUE_2
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -201,7 +201,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("listOfLists[0][0]", 5);
assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5);
assertThat(gb.getListOfLists().get(0)).element(0).isEqualTo(5);
assertThat(gb.getListOfLists()).singleElement().asList().containsExactly(5);
}
@Test
@@ -213,7 +213,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("listOfLists[0][0]", "5");
assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5);
assertThat(gb.getListOfLists().get(0)).element(0).isEqualTo(5);
assertThat(gb.getListOfLists()).singleElement().asList().containsExactly(5);
}
@Test
@@ -298,7 +298,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("mapOfLists[1][0]", 5);
assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).element(0).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).containsExactly(5);
}
@Test
@@ -310,7 +310,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("mapOfLists[1][0]", "5");
assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).element(0).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).containsExactly(5);
}
@Test
@@ -516,8 +516,7 @@ class BeanWrapperGenericsTests {
bw.setPropertyValue("genericProperty", "10");
bw.setPropertyValue("genericListProperty", new String[] {"20", "30"});
assertThat(gb.getGenericProperty()).isEqualTo(10);
assertThat(gb.getGenericListProperty()).element(0).isEqualTo(20);
assertThat(gb.getGenericListProperty()).element(1).isEqualTo(30);
assertThat(gb.getGenericListProperty()).containsExactly(20, 30);
}
@Test
@@ -526,9 +525,9 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("genericProperty", "10");
bw.setPropertyValue("genericListProperty", new String[] {"20", "30"});
assertThat(gb.getGenericProperty()).element(0).isEqualTo(10);
assertThat(gb.getGenericListProperty().get(0)).element(0).isEqualTo(20);
assertThat(gb.getGenericListProperty().get(1)).element(0).isEqualTo(30);
assertThat(gb.getGenericProperty()).containsExactly(10);
assertThat(gb.getGenericListProperty().get(0)).containsExactly(20);
assertThat(gb.getGenericListProperty().get(1)).containsExactly(30);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.beans;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
@@ -172,10 +173,26 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
void setterOverload() {
SetterOverload target = new SetterOverload();
BeanWrapper accessor = createAccessor(target);
accessor.setPropertyValue("object", "a String");
assertThat(target.value).isEqualTo("a String");
assertThat(target.getObject()).isEqualTo("a String");
assertThat(accessor.getPropertyValue("object")).isEqualTo("a String");
accessor.setPropertyValue("object", 1000);
assertThat(target.value).isEqualTo("1000");
assertThat(target.getObject()).isEqualTo("1000");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000");
accessor.setPropertyValue("value", 1000);
assertThat(target.value).isEqualTo("1000i");
assertThat(target.getObject()).isEqualTo("1000i");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000i");
accessor.setPropertyValue("value", Duration.ofSeconds(1000));
assertThat(target.value).isEqualTo("1000s");
assertThat(target.getObject()).isEqualTo("1000s");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000s");
}
@Test
@@ -382,7 +399,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String value;
public void setObject(Integer length) {
this.value = length.toString();
this.value = length + "i";
}
public void setObject(String object) {
@@ -392,6 +409,14 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String getObject() {
return this.value;
}
public void setValue(int length) {
this.value = length + "i";
}
public void setValue(Duration duration) {
this.value = duration.getSeconds() + "s";
}
}
@@ -403,7 +428,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
@Override
public void close() throws Exception {
public void close() {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @author Arjen Poutsma
*/
public class CachedIntrospectionResultsTests {
class CachedIntrospectionResultsTests {
@Test
public void acceptAndClearClassLoader() throws Exception {
void acceptAndClearClassLoader() throws Exception {
BeanWrapper bw = new BeanWrapperImpl(TestBean.class);
assertThat(bw.isWritableProperty("name")).isTrue();
assertThat(bw.isWritableProperty("age")).isTrue();
@@ -56,7 +56,7 @@ public class CachedIntrospectionResultsTests {
}
@Test
public void clearClassLoaderForSystemClassLoader() throws Exception {
void clearClassLoaderForSystemClassLoader() {
BeanUtils.getPropertyDescriptors(ArrayList.class);
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(ArrayList.class)).isTrue();
CachedIntrospectionResults.clearClassLoader(ArrayList.class.getClassLoader());
@@ -64,7 +64,7 @@ public class CachedIntrospectionResultsTests {
}
@Test
public void shouldUseExtendedBeanInfoWhenApplicable() throws NoSuchMethodException, SecurityException {
void shouldUseExtendedBeanInfoWhenApplicable() throws NoSuchMethodException, SecurityException {
// given a class with a non-void returning setter method
@SuppressWarnings("unused")
class C {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ class ConcurrentBeanWrapperTests {
// ByteArrayOutputStream does not throw
// any IOException
}
String value = new String(buffer.toByteArray());
String value = buffer.toString();
BeanWrapperImpl wrapper = new BeanWrapperImpl(bean);
wrapper.setPropertyValue("properties", value);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -558,7 +558,7 @@ class ExtendedBeanInfoTests {
* @see #cornerSpr9702()
*/
@Test
void cornerSpr10111() throws Exception {
void cornerSpr10111() {
assertThatNoException().isThrownBy(() -> new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class)));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,22 +21,22 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link PropertyAccessorUtils}.
* Tests for {@link PropertyAccessorUtils}.
*
* @author Juergen Hoeller
* @author Chris Beams
*/
public class PropertyAccessorUtilsTests {
class PropertyAccessorUtilsTests {
@Test
public void getPropertyName() {
void getPropertyName() {
assertThat(PropertyAccessorUtils.getPropertyName("")).isEmpty();
assertThat(PropertyAccessorUtils.getPropertyName("[user]")).isEmpty();
assertThat(PropertyAccessorUtils.getPropertyName("user")).isEqualTo("user");
}
@Test
public void isNestedOrIndexedProperty() {
void isNestedOrIndexedProperty() {
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty(null)).isFalse();
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty("")).isFalse();
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty("user")).isFalse();
@@ -46,19 +46,19 @@ public class PropertyAccessorUtilsTests {
}
@Test
public void getFirstNestedPropertySeparatorIndex() {
void getFirstNestedPropertySeparatorIndex() {
assertThat(PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex("[user]")).isEqualTo(-1);
assertThat(PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex("user.name")).isEqualTo(4);
}
@Test
public void getLastNestedPropertySeparatorIndex() {
void getLastNestedPropertySeparatorIndex() {
assertThat(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex("[user]")).isEqualTo(-1);
assertThat(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex("user.address.street")).isEqualTo(12);
}
@Test
public void matchesProperty() {
void matchesProperty() {
assertThat(PropertyAccessorUtils.matchesProperty("user", "email")).isFalse();
assertThat(PropertyAccessorUtils.matchesProperty("username", "user")).isFalse();
assertThat(PropertyAccessorUtils.matchesProperty("admin[user]", "user")).isFalse();
@@ -68,7 +68,7 @@ public class PropertyAccessorUtilsTests {
}
@Test
public void canonicalPropertyName() {
void canonicalPropertyName() {
assertThat(PropertyAccessorUtils.canonicalPropertyName(null)).isEmpty();
assertThat(PropertyAccessorUtils.canonicalPropertyName("map")).isEqualTo("map");
assertThat(PropertyAccessorUtils.canonicalPropertyName("map[key1]")).isEqualTo("map[key1]");
@@ -82,7 +82,7 @@ public class PropertyAccessorUtilsTests {
}
@Test
public void canonicalPropertyNames() {
void canonicalPropertyNames() {
assertThat(PropertyAccessorUtils.canonicalPropertyNames(null)).isNull();
String[] original =
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,28 +30,28 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Stephane Nicoll
*/
public class PropertyMatchesTests {
class PropertyMatchesTests {
@Test
public void simpleBeanPropertyTypo() {
void simpleBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).contains("name");
}
@Test
public void complexBeanPropertyTypo() {
void complexBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("desriptn", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
public void unknownBeanProperty() {
void unknownBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("unknown", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
public void severalMatchesBeanProperty() {
void severalMatchesBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).contains("counter1");
assertThat(matches.getPossibleMatches()).contains("counter2");
@@ -59,7 +59,7 @@ public class PropertyMatchesTests {
}
@Test
public void simpleBeanPropertyErrorMessage() {
void simpleBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("naem");
@@ -69,7 +69,7 @@ public class PropertyMatchesTests {
}
@Test
public void complexBeanPropertyErrorMessage() {
void complexBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("counter");
@@ -79,25 +79,25 @@ public class PropertyMatchesTests {
}
@Test
public void simpleFieldPropertyTypo() {
void simpleFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).contains("name");
}
@Test
public void complexFieldPropertyTypo() {
void complexFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("desriptn", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
public void unknownFieldProperty() {
void unknownFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("unknown", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
public void severalMatchesFieldProperty() {
void severalMatchesFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).contains("counter1");
assertThat(matches.getPossibleMatches()).contains("counter2");
@@ -105,7 +105,7 @@ public class PropertyMatchesTests {
}
@Test
public void simpleFieldPropertyErrorMessage() {
void simpleFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("naem");
@@ -115,7 +115,7 @@ public class PropertyMatchesTests {
}
@Test
public void complexFieldPropertyErrorMessage() {
void complexFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("counter");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,10 +30,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @see ExtendedBeanInfoTests
*/
public class SimplePropertyDescriptorTests {
class SimplePropertyDescriptorTests {
@Test
public void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
{
Object pd = new ExtendedBeanInfo.SimplePropertyDescriptor("foo", null, null);
assertThat(pd.toString()).contains(
@@ -71,7 +71,7 @@ public class SimplePropertyDescriptorTests {
}
@Test
public void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
Object pd1 = new ExtendedBeanInfo.SimplePropertyDescriptor("foo", null, null);
assertThat(pd1).isEqualTo(pd1);
@@ -108,7 +108,7 @@ public class SimplePropertyDescriptorTests {
}
@Test
public void indexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
void indexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
Object pd1 = new ExtendedBeanInfo.SimpleIndexedPropertyDescriptor("foo", null, null, null, null);
assertThat(pd1).isEqualTo(pd1);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
* @author Sam Brannen
* @since 04.07.2003
*/
public class BeanFactoryUtilsTests {
class BeanFactoryUtilsTests {
private static final Class<?> CLASS = BeanFactoryUtilsTests.class;
private static final Resource ROOT_CONTEXT = qualifiedResource(CLASS, "root.xml");
@@ -63,7 +63,7 @@ public class BeanFactoryUtilsTests {
@BeforeEach
public void setup() {
void setup() {
// Interesting hierarchical factory to test counts.
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
@@ -81,7 +81,7 @@ public class BeanFactoryUtilsTests {
@Test
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
void testHierarchicalCountBeansWithNonHierarchicalFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("t1", new TestBean());
lbf.addBean("t2", new TestBean());
@@ -92,7 +92,7 @@ public class BeanFactoryUtilsTests {
* Check that override doesn't count as two separate beans.
*/
@Test
public void testHierarchicalCountBeansWithOverride() {
void testHierarchicalCountBeansWithOverride() {
// Leaf count
assertThat(this.listableBeanFactory.getBeanDefinitionCount()).isEqualTo(1);
// Count minus duplicate
@@ -101,14 +101,14 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalNamesWithNoMatch() {
void testHierarchicalNamesWithNoMatch() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertThat(names).isEmpty();
}
@Test
public void testHierarchicalNamesWithMatchOnlyInRoot() {
void testHierarchicalNamesWithMatchOnlyInRoot() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertThat(names).hasSize(1);
@@ -118,7 +118,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testGetBeanNamesForTypeWithOverride() {
void testGetBeanNamesForTypeWithOverride() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
@@ -130,7 +130,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testNoBeansOfType() {
void testNoBeansOfType() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("foo", new Object());
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
@@ -138,7 +138,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testFindsBeansOfTypeWithStaticFactory() {
void testFindsBeansOfTypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean t1 = new TestBean();
TestBean t2 = new TestBean();
@@ -169,7 +169,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testFindsBeansOfTypeWithDefaultFactory() {
void testFindsBeansOfTypeWithDefaultFactory() {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
@@ -232,7 +232,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalResolutionWithOverride() {
void testHierarchicalResolutionWithOverride() {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
@@ -271,14 +271,14 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testHierarchicalNamesForAnnotationWithNoMatch() {
void testHierarchicalNamesForAnnotationWithNoMatch() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
assertThat(names).isEmpty();
}
@Test
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
assertThat(names).hasSize(1);
@@ -288,7 +288,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testGetBeanNamesForAnnotationWithOverride() {
void testGetBeanNamesForAnnotationWithOverride() {
AnnotatedBean annotatedBean = new AnnotatedBean();
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
List<String> names = Arrays.asList(
@@ -299,31 +299,31 @@ public class BeanFactoryUtilsTests {
}
@Test
public void testADependencies() {
void testADependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("a");
assertThat(ObjectUtils.isEmpty(deps)).isTrue();
}
@Test
public void testBDependencies() {
void testBDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("b");
assertThat(Arrays.equals(new String[] { "c" }, deps)).isTrue();
}
@Test
public void testCDependencies() {
void testCDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("c");
assertThat(Arrays.equals(new String[] { "int", "long" }, deps)).isTrue();
}
@Test
public void testIntDependencies() {
void testIntDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("int");
assertThat(Arrays.equals(new String[] { "buffer" }, deps)).isTrue();
}
@Test
public void findAnnotationOnBean() {
void findAnnotationOnBean() {
this.listableBeanFactory.registerSingleton("controllerAdvice", new ControllerAdviceClass());
this.listableBeanFactory.registerSingleton("restControllerAdvice", new RestControllerAdviceClass());
testFindAnnotationOnBean(this.listableBeanFactory);
@@ -350,7 +350,7 @@ public class BeanFactoryUtilsTests {
}
@Test
public void isSingletonAndIsPrototypeWithStaticFactory() {
void isSingletonAndIsPrototypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean bean = new TestBean();
DummyFactory fb1 = new DummyFactory();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1240,7 +1240,7 @@ class DefaultListableBeanFactoryTests {
}
@Test
void arrayPropertyWithOptionalAutowiring() throws MalformedURLException {
void arrayPropertyWithOptionalAutowiring() {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
lbf.registerBeanDefinition("arrayBean", rbd);
@@ -3211,7 +3211,7 @@ class DefaultListableBeanFactoryTests {
extends RepositoryFactoryBeanSupport<T, S, ID> {
@Override
public T getObject() throws Exception {
public T getObject() {
throw new IllegalArgumentException("Should not be called");
}
@@ -3460,7 +3460,7 @@ class DefaultListableBeanFactoryTests {
enum NonPublicEnum {
VALUE_1, VALUE_2;
VALUE_1, VALUE_2
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,42 +32,42 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Chris Beams
*/
public class FactoryBeanLookupTests {
class FactoryBeanLookupTests {
private BeanFactory beanFactory;
@BeforeEach
public void setUp() {
void setUp() {
beanFactory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory).loadBeanDefinitions(
new ClassPathResource("FactoryBeanLookupTests-context.xml", this.getClass()));
}
@Test
public void factoryBeanLookupByNameDereferencing() {
void factoryBeanLookupByNameDereferencing() {
Object fooFactory = beanFactory.getBean("&fooFactory");
assertThat(fooFactory).isInstanceOf(FooFactoryBean.class);
}
@Test
public void factoryBeanLookupByType() {
void factoryBeanLookupByType() {
FooFactoryBean fooFactory = beanFactory.getBean(FooFactoryBean.class);
assertThat(fooFactory).isNotNull();
}
@Test
public void factoryBeanLookupByTypeAndNameDereference() {
void factoryBeanLookupByTypeAndNameDereference() {
FooFactoryBean fooFactory = beanFactory.getBean("&fooFactory", FooFactoryBean.class);
assertThat(fooFactory).isNotNull();
}
@Test
public void factoryBeanObjectLookupByName() {
void factoryBeanObjectLookupByName() {
Object fooFactory = beanFactory.getBean("fooFactory");
assertThat(fooFactory).isInstanceOf(Foo.class);
}
@Test
public void factoryBeanObjectLookupByNameAndType() {
void factoryBeanObjectLookupByNameAndType() {
Foo foo = beanFactory.getBean("fooFactory", Foo.class);
assertThat(foo).isNotNull();
}
@@ -75,7 +75,7 @@ public class FactoryBeanLookupTests {
class FooFactoryBean extends AbstractFactoryBean<Foo> {
@Override
protected Foo createInstance() throws Exception {
protected Foo createInstance() {
return new Foo();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
* @author Juergen Hoeller
* @author Chris Beams
*/
public class FactoryBeanTests {
class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
@@ -48,7 +48,7 @@ public class FactoryBeanTests {
@Test
public void testFactoryBeanReturnsNull() throws Exception {
void testFactoryBeanReturnsNull() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(RETURNS_NULL_CONTEXT);
@@ -56,7 +56,7 @@ public class FactoryBeanTests {
}
@Test
public void testFactoryBeansWithAutowiring() throws Exception {
void testFactoryBeansWithAutowiring() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(WITH_AUTOWIRING_CONTEXT);
@@ -77,7 +77,7 @@ public class FactoryBeanTests {
}
@Test
public void testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure() throws Exception {
void testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(WITH_AUTOWIRING_CONTEXT);
@@ -92,21 +92,21 @@ public class FactoryBeanTests {
}
@Test
public void testAbstractFactoryBeanViaAnnotation() throws Exception {
void testAbstractFactoryBeanViaAnnotation() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansWithAnnotation(Component.class);
}
@Test
public void testAbstractFactoryBeanViaType() throws Exception {
void testAbstractFactoryBeanViaType() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansOfType(AbstractFactoryBean.class);
}
@Test
public void testCircularReferenceWithPostProcessor() {
void testCircularReferenceWithPostProcessor() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(CIRCULAR_CONTEXT);
@@ -284,11 +284,7 @@ public class FactoryBeanTests {
if (bean instanceof FactoryBean) {
return bean;
}
AtomicInteger c = count.get(beanName);
if (c == null) {
c = new AtomicInteger();
count.put(beanName, c);
}
AtomicInteger c = count.computeIfAbsent(beanName, k -> new AtomicInteger());
c.incrementAndGet();
return bean;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,10 +33,10 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.ro
* @author Chris Beams
* @author Juergen Hoeller
*/
public class Spr5475Tests {
class Spr5475Tests {
@Test
public void noArgFactoryMethodInvokedWithOneArg() {
void noArgFactoryMethodInvokedWithOneArg() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
@@ -47,7 +47,7 @@ public class Spr5475Tests {
}
@Test
public void noArgFactoryMethodInvokedWithTwoArgs() {
void noArgFactoryMethodInvokedWithTwoArgs() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
@@ -59,7 +59,7 @@ public class Spr5475Tests {
}
@Test
public void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() {
void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() {
RootBeanDefinition def = new RootBeanDefinition(Foo.class);
def.setFactoryMethodName("noArgFactory");
ConstructorArgumentValues cav = new ConstructorArgumentValues();
@@ -82,7 +82,7 @@ public class Spr5475Tests {
}
@Test
public void singleArgFactoryMethodInvokedWithNoArgs() {
void singleArgFactoryMethodInvokedWithNoArgs() {
// calling a factory method that accepts arguments without any arguments emits an exception unlike cases
// where a no-arg factory method is called with arguments. Adding this test just to document the difference
assertExceptionMessageForMisconfiguredFactoryMethod(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,30 +27,30 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
* @author Rick Evans
* @author Chris Beams
*/
public class AnnotationBeanWiringInfoResolverTests {
class AnnotationBeanWiringInfoResolverTests {
@Test
public void testResolveWiringInfo() throws Exception {
void testResolveWiringInfo() {
assertThatIllegalArgumentException().isThrownBy(() ->
new AnnotationBeanWiringInfoResolver().resolveWiringInfo(null));
}
@Test
public void testResolveWiringInfoWithAnInstanceOfANonAnnotatedClass() {
void testResolveWiringInfoWithAnInstanceOfANonAnnotatedClass() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo("java.lang.String is not @Configurable");
assertThat(info).as("Must be returning null for a non-@Configurable class instance").isNull();
}
@Test
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClass() {
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClass() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new Soap());
assertThat(info).as("Must *not* be returning null for a non-@Configurable class instance").isNotNull();
}
@Test
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitly() {
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitly() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new WirelessSoap());
assertThat(info).as("Must *not* be returning null for an @Configurable class instance even when autowiring is NO").isNotNull();
@@ -59,7 +59,7 @@ public class AnnotationBeanWiringInfoResolverTests {
}
@Test
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitlyAndCustomBeanName() {
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitlyAndCustomBeanName() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new NamedWirelessSoap());
assertThat(info).as("Must *not* be returning null for an @Configurable class instance even when autowiring is NO").isNotNull();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
@@ -83,13 +82,15 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AutowiredAnnotationBeanPostProcessor}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @author Chris Beams
* @author Stephane Nicoll
*/
public class AutowiredAnnotationBeanPostProcessorTests {
class AutowiredAnnotationBeanPostProcessorTests {
private DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@@ -119,6 +120,20 @@ public class AutowiredAnnotationBeanPostProcessorTests {
.withRootCauseInstanceOf(IllegalStateException.class);
}
@Test
void processInjection() {
ResourceInjectionBean bean = new ResourceInjectionBean();
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
bpp.processInjection(bean);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
}
@Test
void resourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class);
@@ -711,15 +726,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansSetter).hasSize(2);
assertThat(bean.nestedTestBeansSetter).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansSetter).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansSetter).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansField).containsExactly(ntb2, ntb1);
}
@Test
@@ -744,15 +753,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansSetter).hasSize(2);
assertThat(bean.nestedTestBeansSetter).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansSetter).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansSetter).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansField).containsExactly(ntb2, ntb1);
}
@Test
@@ -1112,9 +1115,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
}
@Test
@@ -1129,9 +1130,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
}
@Test
@@ -1158,9 +1157,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
}
@Test
@@ -1187,9 +1184,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
}
@Test
@@ -1500,8 +1495,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
SelfInjectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionBean.class);
assertThat(bean.reference).isSameAs(bean2);
assertThat(bean.referenceCollection).hasSize(1);
assertThat(bean.referenceCollection).element(0).isSameAs(bean2);
assertThat(bean.referenceCollection).containsExactly(bean2);
}
@Test
@@ -1986,10 +1980,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2000,10 +1992,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2032,10 +2022,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2046,10 +2034,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2074,10 +2060,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2141,9 +2125,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray).hasSize(1);
assertThat(bean.repositoryArray[0]).isSameAs(repo);
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.repositoryList).containsExactly(repo);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2201,7 +2184,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2230,9 +2212,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray).hasSize(1);
assertThat(bean.repositoryArray[0]).isSameAs(repo);
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.repositoryList).containsExactly(repo);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2270,10 +2251,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2284,10 +2263,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2316,10 +2293,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2330,10 +2305,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2357,10 +2330,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2383,10 +2354,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(gr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(gr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(gr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(gr);
assertThat(bean.stringRepositoryList).containsExactly(gr);
assertThat(bean.integerRepositoryList).containsExactly(gr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("genericRepo")).isSameAs(gr);
@@ -2408,10 +2377,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.stringRepositoryList).containsExactly(ngr);
assertThat(bean.integerRepositoryList).containsExactly(ngr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("simpleRepo")).isSameAs(ngr);
@@ -2436,10 +2403,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(gr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(gr);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(gr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2463,10 +2428,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ngr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2602,7 +2565,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
public void mixedNullableArgMethodInjection(){
void mixedNullableArgMethodInjection(){
bf.registerSingleton("nonNullBean", "Test");
bf.registerBeanDefinition("mixedNullableInjectionBean",
new RootBeanDefinition(MixedNullableInjectionBean.class));
@@ -2612,7 +2575,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
public void mixedOptionalArgMethodInjection(){
void mixedOptionalArgMethodInjection(){
bf.registerSingleton("nonNullBean", "Test");
bf.registerBeanDefinition("mixedOptionalInjectionBean",
new RootBeanDefinition(MixedOptionalInjectionBean.class));
@@ -3463,7 +3426,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class StringFactoryBean implements FactoryBean<String> {
@Override
public String getObject() throws Exception {
public String getObject() {
return "";
}
@@ -3998,7 +3961,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@SuppressWarnings("unchecked")
public <T> T createMock(Class<T> toMock) {
return (T) Proxy.newProxyInstance(AutowiredAnnotationBeanPostProcessorTests.class.getClassLoader(), new Class<?>[] {toMock},
(InvocationHandler) (proxy, method, args) -> {
(proxy, method, args) -> {
throw new UnsupportedOperationException("mocked!");
});
}
@@ -4146,7 +4109,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class MyCallable implements Callable<Thread> {
@Override
public Thread call() throws Exception {
public Thread call() {
return null;
}
}
@@ -4155,7 +4118,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class SecondCallable implements Callable<Thread>{
@Override
public Thread call() throws Exception {
public Thread call() {
return null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,16 +28,16 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource;
/**
* Unit tests for {@link CustomAutowireConfigurer}.
* Tests for {@link CustomAutowireConfigurer}.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
*/
public class CustomAutowireConfigurerTests {
class CustomAutowireConfigurerTests {
@Test
public void testCustomResolver() {
void testCustomResolver() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
qualifiedResource(CustomAutowireConfigurerTests.class, "context.xml"));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessorTests.StringFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
@@ -49,13 +50,13 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Unit tests for {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
* processing the JSR-330 {@link jakarta.inject.Inject} annotation.
* Tests for {@link AutowiredAnnotationBeanPostProcessor} processing
* the JSR-330 {@link jakarta.inject.Inject} annotation.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class InjectAnnotationBeanPostProcessorTests {
class InjectAnnotationBeanPostProcessorTests {
private DefaultListableBeanFactory bf;
@@ -63,7 +64,7 @@ public class InjectAnnotationBeanPostProcessorTests {
@BeforeEach
public void setup() {
void setup() {
bf = new DefaultListableBeanFactory();
bf.registerResolvableDependency(BeanFactory.class, bf);
bpp = new AutowiredAnnotationBeanPostProcessor();
@@ -73,13 +74,13 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@AfterEach
public void close() {
void close() {
bf.destroySingletons();
}
@Test
public void testIncompleteBeanDefinition() {
void testIncompleteBeanDefinition() {
bf.registerBeanDefinition("testBean", new GenericBeanDefinition());
try {
bf.getBean("testBean");
@@ -90,7 +91,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testResourceInjection() {
void testResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -107,7 +108,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testExtendedResourceInjection() {
void testExtendedResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -134,7 +135,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testExtendedResourceInjectionWithOverriding() {
void testExtendedResourceInjectionWithOverriding() {
RootBeanDefinition annotatedBd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
TestBean tb2 = new TestBean();
annotatedBd.getPropertyValues().add("testBean2", tb2);
@@ -154,7 +155,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testConstructorResourceInjection() {
void testConstructorResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -181,7 +182,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testConstructorResourceInjectionWithMultipleCandidatesAsCollection() {
void testConstructorResourceInjectionWithMultipleCandidatesAsCollection() {
bf.registerBeanDefinition("annotatedBean",
new RootBeanDefinition(ConstructorsCollectionResourceInjectionBean.class));
TestBean tb = new TestBean();
@@ -200,7 +201,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() {
void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
@@ -211,7 +212,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testConstructorInjectionWithMap() {
void testConstructorInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -236,7 +237,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testFieldInjectionWithMap() {
void testFieldInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -261,7 +262,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testMethodInjectionWithMap() {
void testMethodInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -282,7 +283,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testMethodInjectionWithMapAndMultipleMatches() {
void testMethodInjectionWithMapAndMultipleMatches() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
@@ -291,7 +292,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testMethodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
void testMethodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
RootBeanDefinition rbd2 = new RootBeanDefinition(TestBean.class);
@@ -307,7 +308,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryInjection() {
void testObjectFactoryInjection() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class));
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
@@ -319,7 +320,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryQualifierInjection() {
void testObjectFactoryQualifierInjection() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class));
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
@@ -330,7 +331,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryFieldInjectionIntoPrototypeBean() {
void testObjectFactoryFieldInjectionIntoPrototypeBean() {
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class);
annotatedBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
@@ -347,7 +348,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryMethodInjectionIntoPrototypeBean() {
void testObjectFactoryMethodInjectionIntoPrototypeBean() {
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryQualifierMethodInjectionBean.class);
annotatedBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
@@ -364,7 +365,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithBeanField() throws Exception {
void testObjectFactoryWithBeanField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -376,7 +377,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithBeanMethod() throws Exception {
void testObjectFactoryWithBeanMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -388,7 +389,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithTypedListField() throws Exception {
void testObjectFactoryWithTypedListField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -400,7 +401,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithTypedListMethod() throws Exception {
void testObjectFactoryWithTypedListMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -412,7 +413,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithTypedMapField() throws Exception {
void testObjectFactoryWithTypedMapField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -424,7 +425,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testObjectFactoryWithTypedMapMethod() throws Exception {
void testObjectFactoryWithTypedMapMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -441,7 +442,7 @@ public class InjectAnnotationBeanPostProcessorTests {
* specifically addressing SPR-4040.
*/
@Test
public void testBeanAutowiredWithFactoryBean() {
void testBeanAutowiredWithFactoryBean() {
bf.registerBeanDefinition("factoryBeanDependentBean", new RootBeanDefinition(FactoryBeanDependentBean.class));
bf.registerSingleton("stringFactoryBean", new StringFactoryBean());
@@ -454,7 +455,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testNullableFieldInjectionWithBeanAvailable() {
void testNullableFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -463,7 +464,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testNullableFieldInjectionWithBeanNotAvailable() {
void testNullableFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableFieldInjectionBean.class));
NullableFieldInjectionBean bean = (NullableFieldInjectionBean) bf.getBean("annotatedBean");
@@ -471,7 +472,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testNullableMethodInjectionWithBeanAvailable() {
void testNullableMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -480,7 +481,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testNullableMethodInjectionWithBeanNotAvailable() {
void testNullableMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableMethodInjectionBean.class));
NullableMethodInjectionBean bean = (NullableMethodInjectionBean) bf.getBean("annotatedBean");
@@ -488,7 +489,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalFieldInjectionWithBeanAvailable() {
void testOptionalFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -498,7 +499,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalFieldInjectionWithBeanNotAvailable() {
void testOptionalFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
OptionalFieldInjectionBean bean = (OptionalFieldInjectionBean) bf.getBean("annotatedBean");
@@ -506,7 +507,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalMethodInjectionWithBeanAvailable() {
void testOptionalMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -516,7 +517,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalMethodInjectionWithBeanNotAvailable() {
void testOptionalMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
OptionalMethodInjectionBean bean = (OptionalMethodInjectionBean) bf.getBean("annotatedBean");
@@ -524,7 +525,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalListFieldInjectionWithBeanAvailable() {
void testOptionalListFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -534,7 +535,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalListFieldInjectionWithBeanNotAvailable() {
void testOptionalListFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListFieldInjectionBean.class));
OptionalListFieldInjectionBean bean = (OptionalListFieldInjectionBean) bf.getBean("annotatedBean");
@@ -542,7 +543,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalListMethodInjectionWithBeanAvailable() {
void testOptionalListMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -552,7 +553,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testOptionalListMethodInjectionWithBeanNotAvailable() {
void testOptionalListMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListMethodInjectionBean.class));
OptionalListMethodInjectionBean bean = (OptionalListMethodInjectionBean) bf.getBean("annotatedBean");
@@ -560,7 +561,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testProviderOfOptionalFieldInjectionWithBeanAvailable() {
void testProviderOfOptionalFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -570,7 +571,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testProviderOfOptionalFieldInjectionWithBeanNotAvailable() {
void testProviderOfOptionalFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalFieldInjectionBean.class));
ProviderOfOptionalFieldInjectionBean bean = (ProviderOfOptionalFieldInjectionBean) bf.getBean("annotatedBean");
@@ -578,7 +579,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testProviderOfOptionalMethodInjectionWithBeanAvailable() {
void testProviderOfOptionalMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -588,7 +589,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testProviderOfOptionalMethodInjectionWithBeanNotAvailable() {
void testProviderOfOptionalMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalMethodInjectionBean.class));
ProviderOfOptionalMethodInjectionBean bean = (ProviderOfOptionalMethodInjectionBean) bf.getBean("annotatedBean");
@@ -596,7 +597,7 @@ public class InjectAnnotationBeanPostProcessorTests {
}
@Test
public void testAnnotatedDefaultConstructor() {
void testAnnotatedDefaultConstructor() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedDefaultConstructorBean.class));
assertThat(bf.getBean("annotatedBean")).isNotNull();
@@ -644,7 +645,6 @@ public class InjectAnnotationBeanPostProcessorTests {
@Override
@Inject
@SuppressWarnings("deprecation")
public void setTestBean2(TestBean testBean2) {
super.setTestBean2(testBean2);
}
@@ -1108,25 +1108,6 @@ public class InjectAnnotationBeanPostProcessorTests {
}
public static class StringFactoryBean implements FactoryBean<String> {
@Override
public String getObject() {
return "";
}
@Override
public Class<String> getObjectType() {
return String.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,13 +31,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Karl Pietrzak
* @author Juergen Hoeller
*/
public class LookupAnnotationTests {
class LookupAnnotationTests {
private DefaultListableBeanFactory beanFactory;
@BeforeEach
public void setup() {
void setup() {
beanFactory = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
aabpp.setBeanFactory(beanFactory);
@@ -51,7 +51,7 @@ public class LookupAnnotationTests {
@Test
public void testWithoutConstructorArg() {
void testWithoutConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
Object expected = bean.get();
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -59,7 +59,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithOverloadedArg() {
void testWithOverloadedArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.get("haha");
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -68,7 +68,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithOneConstructorArg() {
void testWithOneConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.getOneArgument("haha");
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -77,7 +77,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithTwoConstructorArg() {
void testWithTwoConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.getTwoArguments("haha", 72);
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -87,7 +87,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithThreeArgsShouldFail() {
void testWithThreeArgsShouldFail() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
assertThatExceptionOfType(AbstractMethodError.class).as("TestBean has no three arg constructor").isThrownBy(() ->
bean.getThreeArguments("name", 1, 2));
@@ -95,7 +95,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithEarlyInjection() {
void testWithEarlyInjection() {
AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
Object expected = bean.get();
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -115,7 +115,7 @@ public class LookupAnnotationTests {
}
@Test
public void testWithGenericBean() {
void testWithGenericBean() {
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
@@ -126,7 +126,7 @@ public class LookupAnnotationTests {
}
@Test
public void testSingletonWithoutMetadataCaching() {
void testSingletonWithoutMetadataCaching() {
beanFactory.setCacheBeanMetadata(false);
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
@@ -139,7 +139,7 @@ public class LookupAnnotationTests {
}
@Test
public void testPrototypeWithoutMetadataCaching() {
void testPrototypeWithoutMetadataCaching() {
beanFactory.setCacheBeanMetadata(false);
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class, BeanDefinition.SCOPE_PROTOTYPE, null));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,35 +35,35 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Unit tests for {@link ParameterResolutionDelegate}.
* Tests for {@link ParameterResolutionDelegate}.
*
* @author Sam Brannen
* @author Juergen Hoeller
* @author Loïc Ledoyen
*/
public class ParameterResolutionTests {
class ParameterResolutionTests {
@Test
public void isAutowirablePreconditions() {
void isAutowirablePreconditions() {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.isAutowirable(null, 0))
.withMessageContaining("Parameter must not be null");
}
@Test
public void annotatedParametersInMethodAreCandidatesForAutowiring() throws Exception {
void annotatedParametersInMethodAreCandidatesForAutowiring() throws Exception {
Method method = getClass().getDeclaredMethod("autowirableMethod", String.class, String.class, String.class, String.class);
assertAutowirableParameters(method);
}
@Test
public void annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring() throws Exception {
void annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring() throws Exception {
Constructor<?> constructor = AutowirableClass.class.getConstructor(String.class, String.class, String.class, String.class);
assertAutowirableParameters(constructor);
}
@Test
public void annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring() throws Exception {
void annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring() throws Exception {
Class<?> innerClass = AutowirableClass.InnerAutowirableClass.class;
assertThat(ClassUtils.isInnerClass(innerClass)).isTrue();
Constructor<?> constructor = innerClass.getConstructor(AutowirableClass.class, String.class, String.class);
@@ -81,7 +81,7 @@ public class ParameterResolutionTests {
}
@Test
public void nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring() throws Exception {
void nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring() throws Exception {
Constructor<?> notAutowirableConstructor = AutowirableClass.class.getConstructor(String.class);
Parameter[] parameters = notAutowirableConstructor.getParameters();
@@ -92,21 +92,21 @@ public class ParameterResolutionTests {
}
@Test
public void resolveDependencyPreconditionsForParameter() {
void resolveDependencyPreconditionsForParameter() {
assertThatIllegalArgumentException()
.isThrownBy(() -> ParameterResolutionDelegate.resolveDependency(null, 0, null, mock()))
.withMessageContaining("Parameter must not be null");
}
@Test
public void resolveDependencyPreconditionsForContainingClass() throws Exception {
void resolveDependencyPreconditionsForContainingClass() {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.resolveDependency(getParameter(), 0, null, null))
.withMessageContaining("Containing class must not be null");
}
@Test
public void resolveDependencyPreconditionsForBeanFactory() throws Exception {
void resolveDependencyPreconditionsForBeanFactory() {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.resolveDependency(getParameter(), 0, getClass(), null))
.withMessageContaining("AutowireCapableBeanFactory must not be null");
@@ -118,7 +118,7 @@ public class ParameterResolutionTests {
}
@Test
public void resolveDependencyForAnnotatedParametersInTopLevelClassConstructor() throws Exception {
void resolveDependencyForAnnotatedParametersInTopLevelClassConstructor() throws Exception {
Constructor<?> constructor = AutowirableClass.class.getConstructor(String.class, String.class, String.class, String.class);
AutowireCapableBeanFactory beanFactory = mock();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -692,7 +692,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
@Nullable
@Override
public String getObject() throws Exception {
public String getObject() {
return getPrefix() + " " + getName();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@ import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.InjectAnnotationBeanPostProcessorTests.StringFactoryBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.factory.DummyFactory;
import org.springframework.beans.testfixture.beans.factory.StringFactoryBean;
import org.springframework.beans.testfixture.beans.factory.aot.GenericFactoryBean;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationCode;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationsCode;
@@ -275,7 +275,7 @@ class DefaultBeanRegistrationCodeFragmentsTests {
static class PrivilegedTestBeanFactoryBean implements FactoryBean<SimpleBean> {
@Override
public SimpleBean getObject() throws Exception {
public SimpleBean getObject() {
return new SimpleBean();
}

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