Compare commits

...

150 Commits

Author SHA1 Message Date
Spring Builds fcfb16839f Release v5.3.21 2022-06-15 08:13:57 +00:00
Stephane Nicoll c75da7ba10 Upgrade to Reactor 2020.0.20
Closes gh-28612
2022-06-14 19:27:03 +02:00
Sam Brannen eeac150030 Polish contribution
See gh-28616
2022-06-14 16:42:51 +02:00
Fabian Gonzalez 0ce9516aef Avoid eager instantiation of non-singleton FactoryBean in getBeanNamesForType
Closes gh-28616
2022-06-14 16:42:31 +02:00
Sam Brannen e47cc44947 Polish DefaultListableBeanFactoryTests 2022-06-14 16:38:11 +02:00
Juergen Hoeller 57db73dcb8 Upgrade to Tomcat 9.0.64, Jackson 2.12.7, Apache Johnzon 1.2.18, OpenPDF 1.3.28, H2 2.1.212, Mockito 4.6.1, HtmlUnit 2.62, Checkstyle 10.3 2022-06-14 15:10:17 +02:00
Juergen Hoeller d7be1e0dab Polishing 2022-06-14 15:09:39 +02:00
Juergen Hoeller 30c873b4b5 Move NestedServletExceptionTests to spring-web module
See gh-25162
2022-06-14 15:09:21 +02:00
Juergen Hoeller e72b0a04cd Document limitations for MessageProducer/Consumer caching with WebLogic JMS
Closes gh-28500
2022-06-14 15:09:10 +02:00
Juergen Hoeller f8b41c1ad2 Consistent support for setContextClass in CGLIB beans package
Closes gh-28530
2022-06-14 15:08:44 +02:00
rstoyanchev 8c777111fa Revise commit #52d068 with corrected test
Update test detecting RouterFunction beans in parent contexts to use
different bean names and avoid shadowing. Changed the fix accordingly
given that BeanProvider does detect beans in parent contexts.

See gh-28595
2022-06-14 10:07:56 +01:00
rstoyanchev d28d603081 Polishing
See gh-28595
2022-06-14 09:35:17 +01:00
rstoyanchev 52d0681ca1 WebMvc respects RouterFunction beans ordering
Closes gh-28595
2022-06-14 09:20:19 +01:00
Sam Brannen 97854d9fec Refactor ObjectToObjectConverter to use Executable instead of Member 2022-06-13 18:01:54 +02:00
Sam Brannen 73f3860bb7 Polish Javadoc for ObjectToObjectConverter 2022-06-13 18:01:05 +02:00
Sam Brannen 452f1b877c Consider return type of static methods in ObjectToObjectConverter
Prior to this commit, ObjectToObjectConverter considered the return
type of non-static `to[targetType.simpleName]()` methods but did not
consider the return type of static `valueOf(sourceType)`,
`of(sourceType)`, and `from(sourceType)` methods.

This led to scenarios in which `canConvert()` returned `true`, but a
subsequent `convert()` invocation resulted in a
ConverterNotFoundException, which violates the contract of the
converter.

This commit addresses this issue by taking into account the return type
of a static valueOf/of/from factory method when determining if the
ObjectToObjectConverter supports a particular conversion. Whereas the
existing check in `determineToMethod()` ensures that the method return
type is assignable to the `targetType`, the new check in
`determineFactoryMethod()` leniently ensures that the method return
type and `targetType` are "related" (i.e., reside in the same type
hierarchy).

Closes gh-28609
2022-06-13 17:20:18 +02:00
Arjen Poutsma c278d8c656 Do not ignore charset in Jaxb2XmlDecoder
This commit makes sure that the charset, if defined in the mimetype, is
used when decoding XML to JAXB2 objects.

Closes gh-28599
2022-06-13 13:47:31 +02:00
Stephane Nicoll e3b288716d Upgrade to Reactor 2020.0.20
Closes gh-28612
2022-06-13 11:39:15 +02:00
Arjen Poutsma 27738cc20f Fix code samples for nested router functions
Closes gh-28603
2022-06-10 13:36:33 +02:00
Sam Brannen babff8e635 Fix Kotlin example for dependency injection with static factory method
Closes gh-28589
2022-06-09 13:16:19 +02:00
Sam Brannen 290cc73d3d Fix Kotlin example for @Required
Since @Required can only be declared on a method, this commit moves the
@Required declaration from the field to the "set" method.

Closes gh-28590
2022-06-09 13:13:43 +02:00
Stephane Nicoll 8a30bc2993 Upgrade Java 18 version in CI image 2022-06-09 08:14:54 +02:00
Stephane Nicoll aa8be28a01 Upgrade Java 17 version in CI image 2022-06-09 08:14:30 +02:00
Stephane Nicoll f43b28e7ba Upgrade Java 11 version in CI image 2022-06-09 08:14:05 +02:00
Stephane Nicoll 1476867ee7 Upgrade Java 18 version in CI image 2022-06-09 08:13:36 +02:00
Stephane Nicoll 4d9dc61f5d Polish 2022-06-09 08:13:12 +02:00
Stephane Nicoll 7eebc48a6e Upgrade Ubuntu version in CI image 2022-06-09 08:11:36 +02:00
Sam Brannen 8478e8e70a Polish contribution
This commit:

- fixes Checkstyle violations
- improves Javadoc
- adds missing @since tags
- renames getCurrentQueueSize() to getQueueSize()
- avoids NullPointerExceptions in getQueueSize()
- introduces tests for queue size and queue capacity

Closes gh-28583
2022-06-08 16:39:10 +02:00
Rémy e386bdb82c Expose ThreadPoolTaskExecutor queue size and capacity for metrics
We use Grafana to monitor our app via Spring's JMX exporter, and we
think it could be interesting to have at least the current queue size
for this purpose since the queue size directly affects the app memory
load. Having the queue capacity seems also interesting to set up
triggers whose values are calculated based on the maximum capacity of
the queue.

This commit introduces new getCurrentQueueSize() and getQueueCapacity()
methods in ThreadPoolTaskExecutor.

See gh-28583
2022-06-08 16:39:00 +02:00
Arjen Poutsma 4912c3c455 Updated sdkmanrc 2022-06-08 12:13:21 +02:00
rstoyanchev 8fcc7ab9d1 CompositeLog respects log level changes at runtime
Closes gh-28477
2022-06-08 10:07:52 +01:00
rstoyanchev 7c47b470ff MockMvc allows HttpMethod input for multipart request
Closes gh-28545
2022-06-08 10:07:52 +01:00
Sam Brannen 479ef3f3fd Update documentation regarding nested test class support
Closes gh-28579
2022-06-08 09:52:42 +02:00
Sam Brannen be1b7da12f Add entries for "Sam Brannen" to .mailmap 2022-06-07 14:27:42 +02:00
Phillip Webb 89360b18f4 Update '.mailmap` to consistently use @vmware.com emails
(cherry picked from commit 83063a7269)
2022-06-07 14:14:10 +02:00
Stephane Nicoll 209fe5f452 Merge pull request #28572 from gorisanson
* pr/28572:
  Polish contribution
  Update reference docs to use PropertySourcesPlaceholderConfigurer

Closes gh-28572
2022-06-07 08:30:52 +02:00
Stephane Nicoll e18a118f8b Polish contribution
See gh-28572
2022-06-07 08:29:28 +02:00
Lee, Kyutae 77aac7768d Update reference docs to use PropertySourcesPlaceholderConfigurer
See gh-28572
2022-06-07 08:22:53 +02:00
Sam Brannen e2767371b5 Lazily initialize DataSize.PATTERN
To avoid unnecessary eager initialization of DataSize.PATTERN, this
commit initializes it lazily in the first invocation of DataSize.parse
by moving PATTERN to a private static nested class.

Closes gh-28560
2022-06-03 13:30:45 +02:00
Sam Brannen aab9da0366 Polish LocaleResolver support 2022-06-03 13:10:55 +02:00
Sam Brannen cda1e5507c Polishing 2022-06-01 16:28:05 +02:00
Balázs Póka 1d5ffaf30a Always construct new exception on error in DefaultWebClient
Always construct new exception on error, otherwise memory leak may
occur due to repeated use of singleton exception.

Closes gh-28550
2022-06-01 16:07:41 +02:00
Arjen Poutsma c55606ed08 Recognize Kotlin coroutines in isAsyncVoidReturnType
This commit makes sure that Kotlin coroutines are correctly identified
by InvocableHandlerMethod::isAsyncVoidReturnType.

Closes gh-26829
2022-06-01 15:13:30 +02:00
Sam Brannen aa8802a81d Avoid new AssertJ deprecations 2022-05-31 16:13:31 +02:00
Sam Brannen 1beb7068f6 Use new AssertJ exception assertions 2022-05-31 14:08:28 +02:00
Sam Brannen 9d324e59a0 Upgrade to AssertJ 3.23.0 2022-05-31 12:55:43 +02:00
Sam Brannen 8547f8601d Polish LocaleResolver tests 2022-05-31 11:55:30 +02:00
Stephane Nicoll 40cb81470b Merge pull request #28542 from eltociear
* pr/28542:
  Fix typo in webflux.adoc

Closes gh-28542
2022-05-31 10:01:30 +02:00
Ikko Ashimine 6e3b3c5419 Fix typo in webflux.adoc
See gh-28542
2022-05-31 10:01:13 +02:00
Sam Brannen a221835558 Throw IllegalStateException for invalid port in HierarchicalUriComponents
Prior to this commit, getPort() in HierarchicalUriComponents threw a
NumberFormatException for an invalid port supplied as a String, which
was inconsistent with exception handling elsewhere in the class as well
as within the same method.

This commit introduces a try-catch block in getPort() to consistently
throw IllegalStateExceptions for ports that cannot be parsed.

Closes gh-28521
2022-05-25 11:29:12 +02:00
Sam Brannen aa06a09dee Polishing 2022-05-25 11:29:12 +02:00
hsteinmueller bde0931e51 Fix Javadoc for DatabaseClient
The documentation for DatabaseClient had misplaced double quotes in the
example on how to map a select statement to a row.

Closes gh-28520
2022-05-24 17:15:44 +02:00
Sam Brannen 7b95c928d1 Fix Javadoc for ResourcePatternResolver 2022-05-23 20:32:01 +02:00
Sam Brannen 53f88d455f Fix Javadoc for AbstractFileResolvingResource.isFile(URI) 2022-05-23 20:32:01 +02:00
Sam Brannen 53a506f6bb Polishing 2022-05-23 20:22:37 +02:00
rstoyanchev f95bf96ec9 Correct path encoding/decoding in PathResourceResolver
Decoding is required for non-UrlResource when the HandlerMapping is
not expected to decode the path. Encoding is the opposite.

This commit ensures correct determination of whether the HandlerMapping
is expected to have decoded the path or not that in turn depends on
whether PathPattern or PathMatcher is in use.

Closes gh-27791
2022-05-23 11:03:42 +01:00
rstoyanchev 66a5742df3 Polishing 2022-05-23 10:07:03 +01:00
Sam Brannen 59c7bb1f86 Use Arrays.toString instead of Arrays.asList when generating Strings 2022-05-17 15:36:31 +02:00
Sam Brannen a1c3efbb5f Polish ManagedList[Tests] and ManagedSet[Tests] 2022-05-17 15:36:31 +02:00
Sam Brannen 6efe3aee34 Polishing 2022-05-16 11:20:20 +02:00
Sam Brannen f2fe7f335c Improve nullReturningBeanPostProcessor() test
See gh-28459
2022-05-14 18:30:39 +02:00
Sam Brannen 48c797e429 Fix Kotlin example for static factory method
Closes gh-28399
2022-05-11 17:33:31 +02:00
Sam Brannen be782a2197 Polish ref docs regarding the BeanFactory API
See gh-28403
2022-05-11 17:16:40 +02:00
Sam Brannen 8098e45bad Sync gradle.properties between 5.3.x and main 2022-05-11 16:30:44 +02:00
Sam Brannen 06679a5583 Fix tests in DispatcherServletTests
See gh-28424
2022-05-11 16:00:26 +02:00
Sam Brannen 745eb1a881 Polish DispatcherServletTests 2022-05-11 15:59:47 +02:00
Spring Builds 10c55ff912 Next development version (v5.3.21-SNAPSHOT) 2022-05-11 07:08:24 +00:00
Juergen Hoeller 83186b689f Refine CachedIntrospectionResults property introspection
Closes gh-28445
2022-05-11 08:32:06 +02:00
rstoyanchev dc2947c52d Ignore invalid connect frame
Closes gh-28443
2022-05-11 07:22:22 +01:00
Arjen Poutsma e4ec376075 Disabling Undertow server in CoroutinesIntegrationTests 2022-05-10 15:55:00 +02:00
Juergen Hoeller c81e11d537 Polishing 2022-05-10 13:07:00 +02:00
Juergen Hoeller de6180b093 Upgrade to Reactor 2020.0.19
Includes Netty 4.1.77 and RxJava 3.1.4.

Closes gh-28437
2022-05-10 13:05:56 +02:00
Sam Brannen 1c10cdd1e8 Update copyright dates
See gh-28433
2022-05-10 11:33:32 +02:00
evgeny.bovykin 941b92cbed Make inner classes static when feasible
A static nested class does not keep an implicit reference to its
enclosing instance.

This prevents a common cause of memory leaks and uses less memory per
instance of the class.

Closes gh-28433
2022-05-10 11:32:37 +02:00
Sam Brannen e26d8839b3 Stop referring to features as Java 6/7 features where unnecessary 2022-05-09 19:09:06 +02:00
Sam Brannen a1c7380398 Add test for value attribute in @ModelAttribute in WebFlux
This complements the previous commit which tested only the `name`
attribute.

See gh-28423
2022-05-09 15:22:22 +02:00
Sam Brannen 7dd622bdb2 Support name attribute in @ModelAttribute in WebFlux
Prior to this commit, the `name` attribute in @ModelAttribute was not
supported when using WebFlux. This is because MethodParameter was used
instead of SynthesizingMethodParameter when retrieving the
@ModelAttribute annotation. In other words, @AliasFor was not honored
because the annotation was not synthesized. Consequently, only the
`value` attribute was supported in WebFlux when specifying a custom name
via @ModelAttribute.

This commit fixes this by using SynthesizingMethodParameter to retrieve
the @ModelAttribute annotation.

Closes gh-28423
2022-05-07 17:16:26 +02:00
Sam Brannen 64c96c579d Polish contribution
See gh-28422
2022-05-07 16:18:47 +02:00
Carlos Bouzón García 39e3876301 Fix BindingResult error when ModelAttribute has custom name in WebFlux
Closes gh-28422
2022-05-07 16:18:04 +02:00
Juergen Hoeller f771603789 Polishing 2022-05-05 18:04:54 +02:00
Juergen Hoeller e441832e99 Accept WritableResource as required dependency type as well
Closes gh-15284
2022-05-05 18:04:13 +02:00
Juergen Hoeller f963fc5f98 Check that nullable annotations are from org.springframework.lang
Closes gh-28410
2022-05-05 18:02:27 +02:00
Juergen Hoeller b55eee1b0d Upgrade to ASM 9.3
Closes gh-28390
2022-05-05 18:01:53 +02:00
Juergen Hoeller 28742171fd Upgrade to Netty 4.1.76, Mockito 4.5.1, HtmlUnit 2.61 2022-05-05 18:01:31 +02:00
Lee, Kyutae 7a75b94556 Fix typo in reference docs regarding RequestMappingHandlerAdapter
Closes gh-28370
2022-05-05 16:31:40 +02:00
Sam Brannen ab71ff93bb Polish package-info for org.springframework.util
See gh-28411
2022-05-05 16:22:52 +02:00
neals cf30327740 Remove Log4J configurer from package-info.java in spring-core
Closes gh-28411
2022-05-05 16:16:49 +02:00
neals e22a038725 Remove Log4J initialization from package-info.java
Closes gh-28420
2022-05-05 16:10:59 +02:00
Brian Clozel 7aedb9ee33 Build CI image using oci-build-task resource 2022-05-03 15:50:29 +02:00
Brian Clozel 5b1719cd77 Upgrade CI to concourse-release-scripts 0.3.4 2022-05-03 15:09:23 +02:00
Brian Clozel c056b81753 Upgrade JDK and Ubuntu versions in CI image 2022-05-03 15:08:14 +02:00
Brian Clozel dbdd67ec62 Remove outdated docker-image resource from CI
The docker-image resource is now replaced by the registry-image
resource.
2022-05-03 15:05:58 +02:00
Sam Brannen 4fcfa5b991 Update and simplify ArrayConstructorTests 2022-05-03 14:27:48 +02:00
Sam Brannen ed06a6de26 Convert SimpleFormController example to @Controller in reference manual
This change is necessary since the SimpleFormController class no longer
exists.
2022-05-03 12:03:04 +02:00
Sam Brannen afa799b4f0 Suppress warning in test 2022-05-03 11:46:47 +02:00
rstoyanchev f0d149b330 Polishing contribution
Closes gh-27830
2022-04-28 11:26:50 +01:00
binchoo caaf83b8e6 Add tests for binding to a Part field
See gh-27830
2022-04-28 10:45:09 +01:00
rstoyanchev b30f4d7bb7 Exposes all root causes to ExceptionHandler methods
Closes gh-28155
2022-04-28 04:04:57 +01:00
Arjen Poutsma b6b03f38d7 Updated .sdkmanrc 2022-04-26 11:54:02 +02:00
Stephane Nicoll 46b0d7dc03 Merge pull request #28369 from izeye
* pr/28369:
  Add Javadoc since for GraphQL constants

Closes gh-28369
2022-04-24 10:05:28 +02:00
izeye fcf64798b5 Add Javadoc since for GraphQL constants
See gh-28369
2022-04-24 09:58:50 +02:00
Stephane Nicoll 94ed07d9cb Merge pull request #28372 from zhangmingqi09
* pr/28372:
  Update copyright year of changed file
  Fix github issue reference in RequestMappingHandlerMapping

Closes gh-28372
2022-04-24 09:57:02 +02:00
Stephane Nicoll b81c62d064 Update copyright year of changed file
See gh-28372
2022-04-24 09:56:39 +02:00
zhangmingqi09 ca1a11acac Fix github issue reference in RequestMappingHandlerMapping
See gh-28372
2022-04-24 09:55:20 +02:00
Stephane Nicoll c261d40610 Merge pull request #28340 from koenpunt
* pr/28340:
  Update copyright year of changed file
  Fix method reference in Kotlin documentation

Closes gh-28340
2022-04-14 14:11:28 +02:00
Stephane Nicoll 3017955eff Update copyright year of changed file
See gh-28340
2022-04-14 14:09:54 +02:00
Koen Punt 22c82ff206 Fix method reference in Kotlin documentation
See gh-28340
2022-04-14 14:09:02 +02:00
Jerome Prinet f54952481b Update Gradle Enterprise plugin to 3.9
Closes gh-28338
2022-04-14 11:04:22 +02:00
Spring Builds 9e733b09e2 Next development version (v5.3.20-SNAPSHOT) 2022-04-13 09:24:33 +00:00
Sam Brannen a7cf19cec5 Improve documentation and matching algorithm in data binders 2022-04-13 09:55:40 +02:00
Juergen Hoeller 0cf7f7bd89 Polishing 2022-04-13 00:24:23 +02:00
Juergen Hoeller 949c3d450c Align plain accessor check 2022-04-13 00:24:06 +02:00
Arjen Poutsma 3b4ae7b028 TomcatHttpHandlerAdapter continues after 0 bytes
This commit makes sure that TomcatServerHttpRequest::readFromInputStream
follows the same contract as the method it overrides, and returns
AbstractListenerReadPublisher.EMPTY_BUFFER when 0 bytes are read.

See gh-28241
2022-04-12 16:52:13 +02:00
Stephane Nicoll 8b39698553 Upgrade to Reactor 2020.0.18
Closes gh-28329
2022-04-12 15:53:10 +02:00
Sam Brannen 6fad00ed22 Ensure dynamic proxy with AOP introduction includes lambda interfaces
Closes gh-28209
2022-04-09 09:57:43 +02:00
Sam Brannen 5f6d8df34b Introduce isLambdaClass() as a public utility in ClassUtils
This commit extracts isLambda() from AopProxyUtils and makes it
publicly available as ClassUtils.isLambdaClass().

This is a prerequisite for gh-28209.
2022-04-09 09:57:43 +02:00
Juergen Hoeller 35de7e19ee Introduce initializer callback for Bean Validation Configuration
Closes gh-27956
2022-04-08 14:39:36 +02:00
Juergen Hoeller 10e979e58b Polishing 2022-04-08 14:37:41 +02:00
Juergen Hoeller 4143b445d6 Polishing 2022-04-08 13:04:14 +02:00
Juergen Hoeller eefdd2c768 Avoid return value reference in potentially cached MethodParameter instance
Closes gh-28232
2022-04-08 13:03:13 +02:00
Juergen Hoeller 9f91168396 Restore ability to configure setClassLoader methods
Closes gh-28269
2022-04-08 13:02:53 +02:00
Juergen Hoeller 7aed6279a2 Consistent fallback in case of fast-class generation failure
Closes gh-28138
2022-04-08 13:02:36 +02:00
Juergen Hoeller c3fe112fd7 Consistent use of getLocalAddr() without DNS lookups in request adapters
Closes gh-28280
2022-04-08 13:00:50 +02:00
Juergen Hoeller 90103b0ae9 Consistent support for direct column matches in DataClassRowMapper
Closes gh-28243
2022-04-08 13:00:31 +02:00
Juergen Hoeller 0cf15c0fdd Upgrade to Tomcat 9.0.62, Jetty 9.4.46, Jetty Reactive HttpClient 1.1.11, Undertow 2.2.17, R2DBC Arabba-SR13, RSocket 1.1.2, OpenPDF 1.3.27, HtmlUnit 2.60, Checkstyle 10.1 2022-04-08 13:00:20 +02:00
Stephane Nicoll 4e9af3e277 Upgrade Java 18 in CI image 2022-04-07 08:52:43 +02:00
Stephane Nicoll 01fd489b47 Upgrade Ubuntu version in CI images 2022-04-07 08:51:48 +02:00
Brian Clozel 270b167e08 Upgrade registry-image-resource in CI pipeline to 1.5.0
See spring-projects/spring-boot#30408
2022-04-04 19:01:03 +02:00
GatinMI b158110801 Fix debug log for no matching acceptableTypes 2022-04-04 18:29:01 +02:00
Brian Clozel 17f7a24118 Add application/graphql+json mime and media types
Closes gh-28271
2022-04-01 19:24:55 +02:00
rstoyanchev d518a7d8c8 AbstractListenerReadPublisher continues after 0 bytes
If we read 0 bytes, e.g. chunked encoding markup read but not the
actual data within it, don't stop reading since the server may or
may not consider it necessary to call onDataAvailable again.
Instead, we keep on reading, and although isReady likely returns
false on the next iteration, it eliminates ambiguity and ensures
the server will call onDataAvailable when more data arrives.

Closes gh-28241
2022-04-01 17:38:03 +01:00
rstoyanchev 24cd3c1f4c Revert "Disable flaky integration tests for now"
This reverts commit 1627f57f1f in
preparation for fixing the root cause
2022-04-01 16:07:05 +01:00
Spring Builds 2a8c369cff Next development version (v5.3.19-SNAPSHOT) 2022-03-31 09:04:49 +00:00
Brian Clozel 002546b3e4 Refine PropertyDescriptor filtering
Restrict property paths under `Class` and properties of types
`ClassLoader` or `ProtectionDomain`.
2022-03-31 10:21:30 +02:00
Stephane Nicoll 1627f57f1f Disable flaky integration tests for now 2022-03-31 09:46:36 +02:00
Sam Brannen 3811cd4c0a Introduce warnings in documentation of SerializationUtils
Closes gh-28246
2022-03-29 15:22:30 +02:00
Sam Brannen d927e37364 Add "Testing ORM entity lifecycle callbacks" note to Testing chapter
Closes gh-28228
2022-03-27 17:46:06 +02:00
Sam Brannen 1d302bf384 Introduce tests for gh-28228 2022-03-27 16:29:45 +02:00
Stephane Nicoll 4b150fd451 Update copyright date in reference manual
Closes gh-28237
2022-03-27 09:59:12 +02:00
Stephane Nicoll 3a6016d356 Merge pull request #28238 from izeye
* pr/28238:
  Update copyright year of EvaluationTests

Closes gh-28238
2022-03-27 09:56:45 +02:00
izeye 135506f672 Update copyright year of EvaluationTests
See gh-28238
2022-03-27 09:55:58 +02:00
Juergen Hoeller cb36ca31f6 Upgrade to ASM master 2022-03-25 18:07:12 +01:00
Juergen Hoeller edd66d96dd Fix accidental use of deprecated setFlushMode method
Closes gh-28234
2022-03-25 18:06:39 +01:00
Juergen Hoeller 35610a535d Expose cancel(mayInterruptIfRunning) variant in ScheduledTask
Closes gh-28233
2022-03-25 18:06:31 +01:00
Yanming Zhou acf2955b96 Ban jetbrains annotations imports
Closes gh-28226
2022-03-24 13:31:36 +01:00
Sam Brannen 8fc744f4f4 Improve Javadoc for BeanExpressionResolver 2022-03-21 16:57:27 +01:00
Sam Brannen 9a5891e6e6 Explicitly close ApplicationContexts and clean up warnings in tests
This commit also ensures that various test methods actually test
something now.
2022-03-20 12:34:56 +01:00
Sam Brannen 64b64d9ba0 Stop referring to features as "Java 5" features
With a Java 8 baseline in place for quite some time now, it no longer
makes sense to refer to features such as annotations as "Java 5
annotations".

This commit also removes old `Tiger*Tests` classes, thereby avoiding
duplicate execution of various tests.
2022-03-18 16:32:30 +01:00
Sam Brannen 1419172fbd Polish Javadoc for JMX support 2022-03-18 15:25:35 +01:00
Spring Builds 420e0ba25f Next development version (v5.3.18-SNAPSHOT) 2022-03-17 10:51:02 +00:00
428 changed files with 7618 additions and 4706 deletions
+32 -22
View File
@@ -1,23 +1,33 @@
Juergen Hoeller <jhoeller@pivotal.io> jhoeller <jhoeller@vmware.com>
<jhoeller@pivotal.io> <jhoeller@vmware.com>
<jhoeller@pivotal.io> <jhoeller@gopivotal.com>
<rstoyanchev@pivotal.io> <rstoyanchev@vmware.com>
<rstoyanchev@pivotal.io> <rstoyanchev@gopivotal.com>
<pwebb@pivotal.io> <pwebb@vmware.com>
<pwebb@pivotal.io> <pwebb@gopivotal.com>
<cbeams@pivotal.io> <cbeams@vmware.com>
<cbeams@pivotal.io> <cbeams@gopivotal.com>
<cbeams@pivotal.io> <cbeams@gmail.com>
<apoutsma@pivotal.io> <apoutsma@vmware.com>
<apoutsma@pivotal.io> <apoutsma@gopivotal.com>
<apoutsma@pivotal.io> <poutsma@mac.com>
<ogierke@pivotal.io> <ogierke@vmware.com>
<ogierke@pivotal.io> <ogierke@gopivotal.com>
<dsyer@pivotal.io> <dsyer@vmware.com>
<dsyer@pivotal.io> <dsyer@gopivotal.com>
<dsyer@pivotal.io> <david_syer@hotmail.com>
<aclement@pivotal.io> <aclement@vmware.com>
<aclement@pivotal.io> <aclement@gopivotal.com>
<aclement@pivotal.io> <andrew.clement@gmail.com>
Juergen Hoeller <jhoeller@vmware.com>
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@pivotal.io>
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@gopivotal.com>
Rossen Stoyanchev <rstoyanchev@vmware.com>
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@pivotal.io>
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@gopivotal.com>
Phillip Webb <pwebb@vmware.com>
Phillip Webb <pwebb@vmware.com> <pwebb@pivotal.io>
Phillip Webb <pwebb@vmware.com> <pwebb@gopivotal.com>
Chris Beams <cbeams@vmware.com>
Chris Beams <cbeams@vmware.com> <cbeams@pivotal.io>
Chris Beams <cbeams@vmware.com> <cbeams@gopivotal.com>
Arjen Poutsma <apoutsma@vmware.com>
Arjen Poutsma <apoutsma@vmware.com> <apoutsma@pivotal.io>
Arjen Poutsma <apoutsma@vmware.com> <apoutsma@gopivotal.com>
Arjen Poutsma <apoutsma@vmware.com> <poutsma@mac.com>
Oliver Drotbohm <odrotbohm@vmware.com>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@vmware.com>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@pivotal.io>
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@gopivotal.com>
Dave Syer <dsyer@vmware.com>
Dave Syer <dsyer@vmware.com> <dsyer@pivotal.io>
Dave Syer <dsyer@vmware.com> <dsyer@gopivotal.com>
Dave Syer <dsyer@vmware.com> <david_syer@hotmail.com>
Andy Clement <aclement@vmware.com>
Andy Clement <aclement@vmware.com> <aclement@pivotal.io>
Andy Clement <aclement@vmware.com> <aclement@gopivotal.com>
Andy Clement <aclement@vmware.com> <andrew.clement@gmail.com>
Sam Brannen <sbrannen@vmware.com>
Sam Brannen <sbrannen@vmware.com> <sbrannen@pivotal.io>
Sam Brannen <sbrannen@vmware.com> <sam@sambrannen.com>
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
Nick Williams <nicholas@nicholaswilliams.net>
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=8.0.322-librca
java=8.0.333-librca
+19 -19
View File
@@ -27,12 +27,12 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.6"
mavenBom "io.netty:netty-bom:4.1.75.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.17"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR12"
mavenBom "io.rsocket:rsocket-bom:1.1.1"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.45.v20220203"
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
mavenBom "io.netty:netty-bom:4.1.77.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.20"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.2"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.46.v20220331"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.32"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.2"
@@ -67,7 +67,7 @@ configure(allprojects) { project ->
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.reactivex.rxjava3:rxjava:3.1.3"
dependency "io.reactivex.rxjava3:rxjava:3.1.4"
dependency "io.smallrye.reactive:mutiny:1.4.0"
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
@@ -83,7 +83,7 @@ configure(allprojects) { project ->
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
dependency "org.apache.johnzon:johnzon-jsonb:1.2.16"
dependency "org.apache.johnzon:johnzon-jsonb:1.2.18"
dependency("org.codehaus.jettison:jettison:1.3.8") {
exclude group: "stax", name: "stax-api"
}
@@ -94,9 +94,9 @@ configure(allprojects) { project ->
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.30"
dependency "com.h2database:h2:2.1.210"
dependency "com.h2database:h2:2.1.212"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
dependency "com.github.librepdf:openpdf:1.3.26"
dependency "com.github.librepdf:openpdf:1.3.28"
dependency "com.rometools:rome:1.18.0"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.4"
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
dependency "org.webjars:webjars-locator-core:0.48"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.60') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.64') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.60') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.64') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.16.Final') {
dependencySet(group: 'io.undertow', version: '2.2.17.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -150,7 +150,7 @@ configure(allprojects) { project ->
}
}
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.10"
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.11"
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.3'
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
@@ -191,14 +191,14 @@ configure(allprojects) { project ->
dependency "org.junit.support:testng-engine:1.0.1"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.22.0"
dependency "org.assertj:assertj-core:3.23.0"
dependencySet(group: 'org.xmlunit', version: '2.9.0') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '4.4.0') {
dependencySet(group: 'org.mockito', version: '4.6.1') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
@@ -206,10 +206,10 @@ configure(allprojects) { project ->
}
dependency "io.mockk:mockk:1.12.1"
dependency("net.sourceforge.htmlunit:htmlunit:2.59.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.62.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.59.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.62.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "9.3"
toolVersion = "10.3"
configDirectory.set(rootProject.file("src/checkstyle"))
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:focal-20220302
FROM ubuntu:focal-20220531
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
+9 -9
View File
@@ -3,18 +3,18 @@ set -e
case "$1" in
java8)
echo "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u322-b06/OpenJDK8U-jdk_x64_linux_hotspot_8u322b06.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/8u333+2/bellsoft-jdk8u333+2-linux-amd64.tar.gz"
;;
java11)
echo "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.14.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.14.1_1.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/11.0.15.1+2/bellsoft-jdk11.0.15.1+2-linux-amd64.tar.gz"
;;
java17)
echo "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.2%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.2_8.tar.gz"
;;
java18)
echo "https://github.com/adoptium/temurin18-binaries/releases/download/jdk18-2022-02-12-08-06-beta/OpenJDK18-jdk_x64_linux_hotspot_2022-02-12-08-06.tar.gz"
;;
*)
java17)
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.3.1+2/bellsoft-jdk17.0.3.1+2-linux-amd64.tar.gz"
;;
java18)
echo "https://github.com/bell-sw/Liberica/releases/download/18.0.1.1+2/bellsoft-jdk18.0.1.1+2-linux-amd64.tar.gz"
;;
*)
echo $"Unknown java version"
exit 1
esac
-2
View File
@@ -14,8 +14,6 @@ rm -rf /var/lib/apt/lists/*
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
###########################################################
# JAVA
###########################################################
+4
View File
@@ -1,5 +1,6 @@
github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
sonatype-staging-profile: "org.springframework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "5.3.x"
@@ -7,4 +8,7 @@ milestone: "5.3.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
registry-mirror-host: docker.repo.spring.io
registry-mirror-username: ((artifactory-username))
registry-mirror-password: ((artifactory-password))
task-timeout: 1h00m
+23 -10
View File
@@ -12,7 +12,7 @@ anchors:
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
SONATYPE_STAGING_PROFILE: ((sonatype-staging-profile))
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
@@ -24,6 +24,10 @@ anchors:
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
registry-mirror-vars: &registry-mirror-vars
registry-mirror-host: ((registry-mirror-host))
registry-mirror-username: ((registry-mirror-username))
registry-mirror-password: ((registry-mirror-password))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
@@ -41,6 +45,11 @@ anchors:
GITHUB_TOKEN: ((github-ci-release-token))
resource_types:
- name: registry-image
type: registry-image
source:
repository: concourse/registry-image-resource
tag: 1.5.0
- name: artifactory-resource
type: registry-image
source:
@@ -87,7 +96,7 @@ resources:
branch: ((branch))
paths: ["ci/images/*"]
- name: ci-image
type: docker-image
type: registry-image
icon: docker
source:
<<: *docker-resource-source
@@ -157,13 +166,20 @@ resources:
jobs:
- name: build-ci-images
plan:
- get: ci-images-git-repo
trigger: true
- in_parallel:
- get: git-repo
- get: ci-images-git-repo
trigger: true
- task: build-ci-image
privileged: true
file: git-repo/ci/tasks/build-ci-image.yml
output_mapping:
image: ci-image
vars:
ci-image-name: ci-image
<<: *registry-mirror-vars
- put: ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
image: ci-image/image.tar
- name: build
serial: true
public: true
@@ -340,7 +356,6 @@ jobs:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: M
@@ -385,7 +400,6 @@ jobs:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RC
@@ -430,7 +444,6 @@ jobs:
download_artifacts: true
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RELEASE
+2 -2
View File
@@ -6,11 +6,11 @@ CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /opt/concourse-release-scripts.jar \
java -jar /concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
java -jar /concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; }
echo "Sync complete"
echo $version > version/version
+31
View File
@@ -0,0 +1,31 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: concourse/oci-build-task
tag: 0.9.1
registry_mirror:
host: ((registry-mirror-host))
username: ((registry-mirror-username))
password: ((registry-mirror-password))
inputs:
- name: ci-images-git-repo
outputs:
- name: image
caches:
- path: ci-image-cache
params:
CONTEXT: ci-images-git-repo/ci/images
DOCKERFILE: ci-images-git-repo/ci/images/ci-image/Dockerfile
DOCKER_HUB_AUTH: ((docker-hub-auth))
run:
path: /bin/sh
args:
- "-c"
- |
mkdir -p /root/.docker
cat > /root/.docker/config.json <<EOF
{ "auths": { "https://index.docker.io/v1/": { "auth": "$DOCKER_HUB_AUTH" }}}
EOF
build
+6 -1
View File
@@ -1,5 +1,10 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: springio/concourse-release-scripts
tag: '0.3.4'
inputs:
- name: git-repo
- name: artifactory-repo
@@ -13,6 +18,6 @@ params:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE_ID:
SONATYPE_STAGING_PROFILE:
run:
path: git-repo/ci/scripts/promote-version.sh
+3 -3
View File
@@ -1,5 +1,5 @@
version=5.3.17-SNAPSHOT
org.gradle.jvmargs=-Xmx1536M
version=5.3.21
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
kotlin.stdlib.default.dependency=false
kotlin.stdlib.default.dependency=false
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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,7 +28,7 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatException;
/**
* Integration tests for advice invocation order for advice configured via the
@@ -52,7 +52,7 @@ class AopNamespaceHandlerAdviceOrderIntegrationTests {
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing");
}
}
@@ -69,7 +69,7 @@ class AopNamespaceHandlerAdviceOrderIntegrationTests {
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after returning", "after");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after throwing", "after");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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 org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatException;
/**
* Integration tests for advice invocation order for advice configured via
@@ -65,8 +65,7 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> echo.echo(new Exception()));
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
}
}
@@ -95,8 +94,7 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> echo.echo(new Exception()));
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -34,7 +34,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Repository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatException;
/**
* Integration tests for the @EnableCaching annotation.
@@ -62,8 +62,7 @@ class EnableCachingIntegrationTests {
// this test is a bit fragile, but gets the job done, proving that an
// attempt was made to look up the AJ aspect. It's due to classpath issues
// in .integration-tests that it's not found.
assertThatExceptionOfType(Exception.class).isThrownBy(
ctx::refresh)
assertThatException().isThrownBy(ctx::refresh)
.withMessageContaining("AspectJCachingConfiguration");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -45,7 +45,7 @@ import org.springframework.transaction.interceptor.BeanFactoryTransactionAttribu
import org.springframework.transaction.testfixture.CallCountingTransactionManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatException;
/**
* Integration tests for the @EnableTransactionManagement annotation.
@@ -98,7 +98,7 @@ class EnableTransactionManagementIntegrationTests {
// this test is a bit fragile, but gets the job done, proving that an
// attempt was made to look up the AJ aspect. It's due to classpath issues
// in .integration-tests that it's not found.
assertThatExceptionOfType(Exception.class)
assertThatException()
.isThrownBy(ctx::refresh)
.withMessageContaining("AspectJJtaTransactionManagementConfiguration");
}
+1 -1
View File
@@ -7,7 +7,7 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.8.1"
id "com.gradle.enterprise" version "3.9"
id "io.spring.ge.conventions" version "0.0.9"
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -378,7 +378,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
logger.debug("Failed to evaluate join point for arguments " + Arrays.toString(args) +
" - falling back to non-match", ex);
}
return false;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
/**
* AspectJ-based proxy factory, allowing for programmatic building
* of proxies which include AspectJ aspects (code style as well
* Java 5 annotation style).
* annotation style).
*
* @author Rob Harrop
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -60,8 +60,8 @@ public class AspectMetadata implements Serializable {
private final Class<?> aspectClass;
/**
* AspectJ reflection information (AspectJ 5 / Java 5 specific).
* Re-resolved on deserialization since it isn't serializable itself.
* AspectJ reflection information.
* <p>Re-resolved on deserialization since it isn't serializable itself.
*/
private transient AjType<?> ajType;
@@ -134,7 +134,7 @@ public abstract class AopProxyUtils {
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
else if (Proxy.isProxyClass(targetClass) || isLambda(targetClass)) {
else if (Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
@@ -245,18 +245,4 @@ public abstract class AopProxyUtils {
return arguments;
}
/**
* Determine if the supplied {@link Class} is a JVM-generated implementation
* class for a lambda expression or method reference.
* <p>This method makes a best-effort attempt at determining this, based on
* checks that work on modern, main stream JVMs.
* @param clazz the class to check
* @return {@code true} if the class is a lambda implementation class
* @since 5.3.16
*/
static boolean isLambda(Class<?> clazz) {
return (clazz.isSynthetic() && (clazz.getSuperclass() == Object.class) &&
(clazz.getInterfaces().length > 0) && clazz.getName().contains("$$Lambda"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -375,6 +375,22 @@ class CglibAopProxy implements AopProxy, Serializable {
return false;
}
/**
* Invoke the given method with a CGLIB MethodProxy if possible, falling back
* to a plain reflection invocation in case of a fast-class generation failure.
*/
@Nullable
private static Object invokeMethod(@Nullable Object target, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
try {
return methodProxy.invoke(target, args);
}
catch (CodeGenerationException ex) {
CglibMethodInvocation.logFastClassGenerationFailure(method);
return AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
}
/**
* Process a return value. Wraps a return of {@code this} if necessary to be the
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
@@ -425,7 +441,7 @@ class CglibAopProxy implements AopProxy, Serializable {
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object retVal = methodProxy.invoke(this.target, args);
Object retVal = invokeMethod(this.target, method, args, methodProxy);
return processReturnType(proxy, this.target, method, retVal);
}
}
@@ -450,7 +466,7 @@ class CglibAopProxy implements AopProxy, Serializable {
Object oldProxy = null;
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(this.target, args);
Object retVal = invokeMethod(this.target, method, args, methodProxy);
return processReturnType(proxy, this.target, method, retVal);
}
finally {
@@ -478,7 +494,7 @@ class CglibAopProxy implements AopProxy, Serializable {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object target = this.targetSource.getTarget();
try {
Object retVal = methodProxy.invoke(target, args);
Object retVal = invokeMethod(target, method, args, methodProxy);
return processReturnType(proxy, target, method, retVal);
}
finally {
@@ -508,7 +524,7 @@ class CglibAopProxy implements AopProxy, Serializable {
Object target = this.targetSource.getTarget();
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(target, args);
Object retVal = invokeMethod(target, method, args, methodProxy);
return processReturnType(proxy, target, method, retVal);
}
finally {
@@ -685,13 +701,7 @@ class CglibAopProxy implements AopProxy, Serializable {
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
try {
retVal = methodProxy.invoke(target, argsToUse);
}
catch (CodeGenerationException ex) {
CglibMethodInvocation.logFastClassGenerationFailure(method);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
// We need to create a method invocation...
@@ -21,6 +21,7 @@ import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;
import org.springframework.core.NativeDetector;
import org.springframework.util.ClassUtils;
/**
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
@@ -60,7 +61,7 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || AopProxyUtils.isLambda(targetClass)) {
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -424,7 +424,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
"- cannot resolve interceptor names " + Arrays.toString(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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,6 +50,7 @@ import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostP
import org.springframework.core.SmartClassLoader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -85,6 +86,7 @@ import org.springframework.util.StringUtils;
* @author Juergen Hoeller
* @author Rod Johnson
* @author Rob Harrop
* @author Sam Brannen
* @since 13.10.2003
* @see #setInterceptorNames
* @see #getAdvicesAndAdvisorsForBean
@@ -442,8 +444,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -183,8 +183,8 @@ public abstract class AopUtils {
* may be {@code DefaultFoo}. In this case, the method may be
* {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
* <p><b>NOTE:</b> In contrast to {@link org.springframework.util.ClassUtils#getMostSpecificMethod},
* this method resolves Java 5 bridge methods in order to retrieve attributes
* from the <i>original</i> method definition.
* this method resolves bridge methods in order to retrieve attributes from
* the <i>original</i> method definition.
* @param method the method to be invoked, which may come from an interface
* @param targetClass the target class for the current invocation.
* May be {@code null} or may not even implement the method.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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,8 +24,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple ClassFilter that looks for a specific Java 5 annotation
* being present on a class.
* Simple ClassFilter that looks for a specific annotation being present on a class.
*
* @author Juergen Hoeller
* @since 2.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,9 +26,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple Pointcut that looks for a specific Java 5 annotation
* being present on a {@link #forClassAnnotation class} or
* {@link #forMethodAnnotation method}.
* Simple {@link Pointcut} that looks for a specific annotation being present on a
* {@linkplain #forClassAnnotation class} or {@linkplain #forMethodAnnotation method}.
*
* @author Juergen Hoeller
* @author Sam Brannen
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,9 +27,10 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple MethodMatcher that looks for a specific Java 5 annotation
* being present on a method (checking both the method on the invoked
* interface, if any, and the corresponding method on the target class).
* Simple {@link org.springframework.aop.MethodMatcher MethodMatcher} that looks
* for a specific annotation being present on a method (checking both the method
* on the invoked interface, if any, and the corresponding method on the target
* class).
*
* @author Juergen Hoeller
* @author Sam Brannen
@@ -1,44 +0,0 @@
/*
* Copyright 2002-2018 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.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.Test;
/**
* Additional parameter name discover tests that need Java 5.
* Yes this will re-run the tests from the superclass, but that
* doesn't matter in the grand scheme of things...
*
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectJAdviceParameterNameDiscoverAnnotationTests extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAnnotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@interface MyAnnotation {}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,11 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
@@ -27,200 +30,265 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Unit tests for the {@link AspectJAdviceParameterNameDiscoverer} class.
*
* <p>See also {@link TigerAspectJAdviceParameterNameDiscovererTests} for tests relating to annotations.
* Unit tests for {@link AspectJAdviceParameterNameDiscoverer}.
*
* @author Adrian Colyer
* @author Chris Beams
* @author Sam Brannen
*/
public class AspectJAdviceParameterNameDiscovererTests {
class AspectJAdviceParameterNameDiscovererTests {
@Test
public void testNoArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
@Nested
class StandardTests {
@Test
void noArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
}
@Test
void joinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
}
@Test
void joinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
}
@Test
void twoJoinPoints() {
assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void oneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
}
@Test
void oneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
}
@Test
void oneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
}
@Test
void throwableNoCandidates() {
assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void returning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
}
@Test
void ambiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
}
@Test
void returningNoCandidates() {
assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void thisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
}
@Test
void thisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
}
@Test
void thisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void thisBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "this(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void targetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
}
@Test
void targetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
}
@Test
void targetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void targetBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "target(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void argsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
}
@Test
void argsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void ambiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
}
@Test
void argsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
}
@Test
void argsOnePrimitiveOneObject() {
assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class,
"Found 2 candidate variable names but only one candidate binding slot when matching primitive args");
}
@Test
void thisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
}
@Test
void targetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
}
@Test
void throwingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
}
@Test
void allTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
}
@Test
void referenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
}
@Test
void referenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
}
}
@Test
public void testJoinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
}
/**
* Tests just the annotation binding part of {@link AspectJAdviceParameterNameDiscoverer}.
*/
@Nested
class AnnotationTests {
@Test
public void testJoinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
}
@Test
void atThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
}
@Test
public void testTwoJoinPoints() {
assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void atTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
}
@Test
public void testOneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
}
@Test
void atArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
}
@Test
public void testOneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
}
@Test
void atWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
}
@Test
public void testOneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
}
@Test
void atWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
}
@Test
public void testThrowableNoCandidates() {
assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void atAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
}
@Test
public void testReturning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
}
@Test
void ambiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
}
@Test
public void testAmbiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
}
@Test
void ambiguousAnnotationOneVar() {
assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class,
"Found 2 candidate annotation binding variables but only one potential argument binding slot");
}
@Test
public void testReturningNoCandidates() {
assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void annotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"});
}
@Test
public void testThisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
}
@Test
void annotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
}
@Test
public void testThisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
}
@Test
public void testThisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testThisBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "this(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testTargetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
}
@Test
public void testTargetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
}
@Test
public void testTargetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testTargetBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "target(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testArgsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
}
@Test
public void testArgsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testAmbiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
}
@Test
public void testArgsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
}
@Test
public void testArgsOnePrimitiveOneObject() {
assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class,
"Found 2 candidate variable names but only one candidate binding slot when matching primitive args");
}
@Test
public void testThisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
}
@Test
public void testTargetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
}
@Test
public void testThrowingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
}
@Test
public void testAllTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
}
@Test
public void testReferenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
}
@Test
public void testReferenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
}
protected Method getMethod(String name) {
private Method getMethod(String name) {
// Assumes no overloading of test methods...
Method[] candidates = getClass().getMethods();
for (Method candidate : candidates) {
for (Method candidate : getClass().getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
@@ -228,11 +296,11 @@ public class AspectJAdviceParameterNameDiscovererTests {
throw new AssertionError("Bad test specification, no method '" + name + "' found in test class");
}
protected void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
private void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
assertParameterNames(method, pointcut, null, null, parameterNames);
}
protected void assertParameterNames(
private void assertParameterNames(
Method method, String pointcut, String returning, String throwing, String[] parameterNames) {
assertThat(parameterNames.length).as("bad test specification, must have same number of parameter names as method arguments").isEqualTo(method.getParameterCount());
@@ -243,8 +311,8 @@ public class AspectJAdviceParameterNameDiscovererTests {
discoverer.setThrowingName(throwing);
String[] discoveredNames = discoverer.getParameterNames(method);
String formattedExpectedNames = format(parameterNames);
String formattedActualNames = format(discoveredNames);
String formattedExpectedNames = Arrays.toString(parameterNames);
String formattedActualNames = Arrays.toString(discoveredNames);
assertThat(discoveredNames.length).as("Expecting " + parameterNames.length + " parameter names in return set '" +
formattedExpectedNames + "', but found " + discoveredNames.length +
@@ -257,37 +325,23 @@ public class AspectJAdviceParameterNameDiscovererTests {
}
}
protected void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
private void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
assertException(method, pointcut, null, null, exceptionType, message);
}
protected void assertException(Method method, String pointcut, String returning,
private void assertException(Method method, String pointcut, String returning,
String throwing, Class<? extends Throwable> exceptionType, String message) {
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing);
assertThatExceptionOfType(exceptionType).isThrownBy(() ->
discoverer.getParameterNames(method))
assertThatExceptionOfType(exceptionType)
.isThrownBy(() -> discoverer.getParameterNames(method))
.withMessageContaining(message);
}
private static String format(String[] names) {
StringBuilder sb = new StringBuilder();
sb.append('(');
for (int i = 0; i < names.length; i++) {
sb.append(names[i]);
if ((i + 1) < names.length) {
sb.append(',');
}
}
sb.append(')');
return sb.toString();
}
// Methods to discover parameter names for
public void noArgs() {
@@ -329,4 +383,14 @@ public class AspectJAdviceParameterNameDiscovererTests {
public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) {
}
public void oneAnnotation(MyAnnotation ann) {}
public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {}
public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@interface MyAnnotation {}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,9 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -25,6 +28,8 @@ import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.annotation.EmptySpringAnnotation;
import test.annotation.transaction.Tx;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
@@ -56,12 +61,19 @@ public class AspectJExpressionPointcutTests {
private Method setSomeNumber;
private final Map<String, Method> methodsOnHasGeneric = new HashMap<>();
@BeforeEach
public void setUp() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
setAge = TestBean.class.getMethod("setAge", int.class);
setSomeNumber = TestBean.class.getMethod("setSomeNumber", Number.class);
// Assumes no overloading
for (Method method : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(method.getName(), method);
}
}
@@ -299,6 +311,279 @@ public class AspectJExpressionPointcutTests {
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
// TODO this will currently map, would be nice for optimization
//assertTrue(ajexp.matches(HasGeneric.class));
//assertFalse(ajexp.matches(TestBean.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(ajexp.matches(takesGenericList, HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchVarargs() throws Exception {
@SuppressWarnings("unused")
class MyTemplate {
public int queryForInt(String sql, Object... params) {
return 0;
}
}
String expression = "execution(int *.*(String, Object...))";
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
assertThat(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class)).isTrue();
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(jdbcVarArgs.matches(takesGenericList, HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithAtWithin() throws Exception {
String expression = "@within(test.annotation.transaction.Tx)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithoutBinding() throws Exception {
String expression = "within(@test.annotation.transaction.Tx *)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws Exception {
String expression = "within(@(test.annotation..*) *)";
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), TestBean.class)).isFalse();
assertThat(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isTrue();
expression = "within(@(test.annotation.transaction..*) *)";
AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws Exception {
String expression = "within(@(test.annotation.transaction.*) *)";
testMatchAnnotationOnClass(expression);
}
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws Exception {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(BeanB.class.getMethod("setName", String.class), BeanB.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
return ajexp;
}
@Test
public void testAnnotationOnMethodWithFQN() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnCglibProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(true);
BeanA proxy = (BeanA) factory.getProxy();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnDynamicProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(false);
IBeanA proxy = (IBeanA) factory.getProxy();
assertThat(ajexp.matches(IBeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnMethodWithWildcard() throws Exception {
String expression = "execution(@(test.annotation..*) * *(..))";
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
anySpringMethodAnnotation.setExpression(expression);
assertThat(anySpringMethodAnnotation.matches(getAge, TestBean.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithFQN() throws Exception {
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
// True because it maybeMatches with potential argument subtypes
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class, new TestBean(), new BeanA())).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithWildcards() throws Exception {
String expression = "execution(* *(*, @(test..*) *))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isFalse();
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
}
public void setEnemies(List<TestBean> enemies) {
}
public void setPartners(List<?> partners) {
}
public void setPhoneNumbers(List<String> numbers) {
}
}
public static class ProcessesSpringAnnotatedParameters {
public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) {
}
public void takesNoAnnotatedParameters(TestBean tb, BeanA tb3) {
}
}
@Tx
public static class HasTransactionalAnnotation {
public void foo() {
}
public Object bar(String foo) {
throw new UnsupportedOperationException();
}
}
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
interface IBeanA {
@Tx
int getAge();
}
static class BeanA implements IBeanA {
@SuppressWarnings("unused")
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Tx
@Override
public int getAge() {
return age;
}
}
@Tx
static class BeanB {
@SuppressWarnings("unused")
private String name;
public void setName(String name) {
this.name = name;
}
}
}
@@ -1,89 +0,0 @@
/*
* Copyright 2002-2017 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.aspectj;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
/**
* Tests just the annotation binding part of {@link AspectJAdviceParameterNameDiscoverer};
* see supertype for remaining tests.
*
* @author Adrian Colyer
* @author Chris Beams
*/
public class TigerAspectJAdviceParameterNameDiscovererTests extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAtThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
}
@Test
public void testAtTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
}
@Test
public void testAtArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
}
@Test
public void testAtWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
}
@Test
public void testAtWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
}
@Test
public void testAtAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
}
@Test
public void testAmbiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
}
@Test
public void testAmbiguousAnnotationOneVar() {
assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class,
"Found 2 candidate annotation binding variables but only one potential argument binding slot");
}
@Test
public void testAnnotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"});
}
public void oneAnnotation(MyAnnotation ann) {}
public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {}
public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {}
@interface MyAnnotation {}
}
@@ -1,330 +0,0 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.annotation.EmptySpringAnnotation;
import test.annotation.transaction.Tx;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.testfixture.beans.TestBean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Java 5 specific {@link AspectJExpressionPointcutTests}.
*
* @author Rod Johnson
* @author Chris Beams
*/
public class TigerAspectJExpressionPointcutTests {
private Method getAge;
private final Map<String, Method> methodsOnHasGeneric = new HashMap<>();
@BeforeEach
public void setup() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
// Assumes no overloading
for (Method method : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(method.getName(), method);
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
// TODO this will currently map, would be nice for optimization
//assertTrue(ajexp.matches(HasGeneric.class));
//assertFalse(ajexp.matches(TestBean.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(ajexp.matches(takesGenericList, HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchVarargs() throws Exception {
@SuppressWarnings("unused")
class MyTemplate {
public int queryForInt(String sql, Object... params) {
return 0;
}
}
String expression = "execution(int *.*(String, Object...))";
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
assertThat(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class)).isTrue();
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(jdbcVarArgs.matches(takesGenericList, HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithAtWithin() throws Exception {
String expression = "@within(test.annotation.transaction.Tx)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithoutBinding() throws Exception {
String expression = "within(@test.annotation.transaction.Tx *)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws Exception {
String expression = "within(@(test.annotation..*) *)";
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), TestBean.class)).isFalse();
assertThat(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isTrue();
expression = "within(@(test.annotation.transaction..*) *)";
AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws Exception {
String expression = "within(@(test.annotation.transaction.*) *)";
testMatchAnnotationOnClass(expression);
}
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws Exception {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(BeanB.class.getMethod("setName", String.class), BeanB.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
return ajexp;
}
@Test
public void testAnnotationOnMethodWithFQN() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnCglibProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(true);
BeanA proxy = (BeanA) factory.getProxy();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnDynamicProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(false);
IBeanA proxy = (IBeanA) factory.getProxy();
assertThat(ajexp.matches(IBeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnMethodWithWildcard() throws Exception {
String expression = "execution(@(test.annotation..*) * *(..))";
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
anySpringMethodAnnotation.setExpression(expression);
assertThat(anySpringMethodAnnotation.matches(getAge, TestBean.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithFQN() throws Exception {
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
// True because it maybeMatches with potential argument subtypes
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class, new TestBean(), new BeanA())).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithWildcards() throws Exception {
String expression = "execution(* *(*, @(test..*) *))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isFalse();
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
}
public void setEnemies(List<TestBean> enemies) {
}
public void setPartners(List<?> partners) {
}
public void setPhoneNumbers(List<String> numbers) {
}
}
public static class ProcessesSpringAnnotatedParameters {
public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) {
}
public void takesNoAnnotatedParameters(TestBean tb, BeanA tb3) {
}
}
@Tx
public static class HasTransactionalAnnotation {
public void foo() {
}
public Object bar(String foo) {
throw new UnsupportedOperationException();
}
}
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
interface IBeanA {
@Tx
int getAge();
}
static class BeanA implements IBeanA {
@SuppressWarnings("unused")
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Tx
@Override
public int getAge() {
return age;
}
}
@Tx
static class BeanB {
@SuppressWarnings("unused")
private String name;
public void setName(String name) {
this.name = name;
}
}
}
@@ -19,7 +19,6 @@ package org.springframework.aop.framework;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
@@ -134,61 +133,4 @@ public class AopProxyUtilsTests {
AopProxyUtils.proxiedUserInterfaces(proxy));
}
@Test
void isLambda() {
assertIsLambda(AopProxyUtilsTests.staticLambdaExpression);
assertIsLambda(AopProxyUtilsTests::staticStringFactory);
assertIsLambda(this.instanceLambdaExpression);
assertIsLambda(this::instanceStringFactory);
}
@Test
void isNotLambda() {
assertIsNotLambda(new EnigmaSupplier());
assertIsNotLambda(new Supplier<String>() {
@Override
public String get() {
return "anonymous inner class";
}
});
assertIsNotLambda(new Fake$$LambdaSupplier());
}
private static void assertIsLambda(Supplier<String> supplier) {
assertThat(AopProxyUtils.isLambda(supplier.getClass())).isTrue();
}
private static void assertIsNotLambda(Supplier<String> supplier) {
assertThat(AopProxyUtils.isLambda(supplier.getClass())).isFalse();
}
private static final Supplier<String> staticLambdaExpression = () -> "static lambda expression";
private final Supplier<String> instanceLambdaExpression = () -> "instance lambda expressions";
private static String staticStringFactory() {
return "static string factory";
}
private String instanceStringFactory() {
return "instance string factory";
}
private static class EnigmaSupplier implements Supplier<String> {
@Override
public String get() {
return "enigma";
}
}
private static class Fake$$LambdaSupplier implements Supplier<String> {
@Override
public String get() {
return "fake lambda";
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -44,7 +44,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.testfixture.TimeStamped;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
/**
* Also tests AdvisedSupport and ProxyCreatorSupport superclasses.
@@ -277,7 +277,7 @@ public class ProxyFactoryTests {
assertThat(config.getAdvisors().length == oldCount).isTrue();
assertThatExceptionOfType(RuntimeException.class)
assertThatRuntimeException()
.as("Existing object won't implement this interface any more")
.isThrownBy(ts::getTimeStamp); // Existing reference will fail
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.aop.testfixture.advice.MyThrowsHandler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
@@ -63,9 +64,7 @@ public class ThrowsAdviceInterceptorTests {
Exception ex = new Exception();
MethodInvocation mi = mock(MethodInvocation.class);
given(mi.proceed()).willThrow(ex);
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
ti.invoke(mi))
.isSameAs(ex);
assertThatException().isThrownBy(() -> ti.invoke(mi)).isSameAs(ex);
assertThat(th.getCalls()).isEqualTo(0);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.transaction.testfixture.CallCountingTransactionManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
/**
* @author Rod Johnson
@@ -104,44 +106,44 @@ public class TransactionAspectTests {
@Test
public void defaultCommitOnAnnotatedClass() throws Throwable {
Exception ex = new Exception();
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), false))
assertThatException()
.isThrownBy(() -> testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), false))
.isSameAs(ex);
}
@Test
public void defaultRollbackOnAnnotatedClass() throws Throwable {
RuntimeException ex = new RuntimeException();
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), true))
assertThatRuntimeException()
.isThrownBy(() -> testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), true))
.isSameAs(ex);
}
@Test
public void defaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
Exception ex = new Exception();
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
testRollback(() -> new SubclassOfClassWithTransactionalAnnotation().echo(ex), false))
assertThatException()
.isThrownBy(() -> testRollback(() -> new SubclassOfClassWithTransactionalAnnotation().echo(ex), false))
.isSameAs(ex);
}
@Test
public void defaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
Exception ex = new Exception();
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
testRollback(() -> new SubclassOfClassWithTransactionalMethodAnnotation().echo(ex), false))
assertThatException()
.isThrownBy(() -> testRollback(() -> new SubclassOfClassWithTransactionalMethodAnnotation().echo(ex), false))
.isSameAs(ex);
}
@Test
public void noCommitOnImplementationOfAnnotatedInterface() throws Throwable {
final Exception ex = new Exception();
Exception ex = new Exception();
testNotTransactional(() -> new ImplementsAnnotatedInterface().echo(ex), ex);
}
@Test
public void noRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
final Exception rollbackProvokingException = new RuntimeException();
Exception rollbackProvokingException = new RuntimeException();
testNotTransactional(() -> new ImplementsAnnotatedInterface().echo(rollbackProvokingException),
rollbackProvokingException);
}
@@ -165,8 +167,9 @@ public class TransactionAspectTests {
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
txManager.clear();
assertThat(txManager.begun).isEqualTo(0);
assertThatExceptionOfType(Throwable.class).isThrownBy(
toc::performTransactionalOperation).isSameAs(expected);
assertThatExceptionOfType(Throwable.class)
.isThrownBy(toc::performTransactionalOperation)
.isSameAs(expected);
assertThat(txManager.begun).isEqualTo(0);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -286,9 +288,17 @@ public final class CachedIntrospectionResults {
// This call is slow so we do it once.
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
if (Class.class == beanClass && !("name".equals(pd.getName()) ||
(pd.getName().endsWith("Name") && String.class == pd.getPropertyType()))) {
// Only allow all name variants of Class properties
continue;
}
if (URL.class == beanClass && "content".equals(pd.getName())) {
// Only allow URL attribute introspection, not content resolution
continue;
}
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
if (logger.isTraceEnabled()) {
@@ -337,6 +347,10 @@ public final class CachedIntrospectionResults {
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
// against a declared read method, so we prefer read method descriptors here.
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
this.propertyDescriptors.put(pd.getName(), pd);
Method readMethod = pd.getReadMethod();
if (readMethod != null) {
@@ -354,7 +368,7 @@ public final class CachedIntrospectionResults {
for (Method method : beanClass.getMethods()) {
if (!this.propertyDescriptors.containsKey(method.getName()) &&
!readMethodNames.contains((method.getName())) && isPlainAccessor(method)) {
!readMethodNames.contains(method.getName()) && isPlainAccessor(method)) {
this.propertyDescriptors.put(method.getName(),
new GenericTypeAwarePropertyDescriptor(beanClass, method.getName(), method, null, null));
readMethodNames.add(method.getName());
@@ -363,8 +377,10 @@ public final class CachedIntrospectionResults {
}
private boolean isPlainAccessor(Method method) {
if (method.getParameterCount() > 0 || method.getReturnType() == void.class ||
method.getDeclaringClass() == Object.class || Modifier.isStatic(method.getModifiers())) {
if (Modifier.isStatic(method.getModifiers()) ||
method.getDeclaringClass() == Object.class || method.getDeclaringClass() == Class.class ||
method.getParameterCount() > 0 || method.getReturnType() == void.class ||
isInvalidReadOnlyPropertyType(method.getReturnType())) {
return false;
}
try {
@@ -377,6 +393,12 @@ public final class CachedIntrospectionResults {
}
}
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
ClassLoader.class.isAssignableFrom(returnType) ||
ProtectionDomain.class.isAssignableFrom(returnType)));
}
BeanInfo getBeanInfo() {
return this.beanInfo;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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,8 +23,9 @@ import org.springframework.lang.Nullable;
/**
* Common interface for classes that can access named properties
* (such as bean properties of an object or fields in an object)
* Serves as base interface for {@link BeanWrapper}.
* (such as bean properties of an object or fields in an object).
*
* <p>Serves as base interface for {@link BeanWrapper}.
*
* @author Juergen Hoeller
* @since 1.1
@@ -1,5 +1,5 @@
/**
* Support package for beans-style handling of Java 5 annotations.
* Support package for beans-style handling of annotations.
*/
@NonNullApi
@NonNullFields
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -44,7 +44,7 @@ import org.springframework.util.Assert;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
* that enforces required JavaBean properties to have been configured.
* Required bean properties are detected through a Java 5 annotation:
* Required bean properties are detected through an annotation:
* by default, Spring's {@link Required} annotation.
*
* <p>The motivation for the existence of this BeanPostProcessor is to allow
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
/**
* Strategy interface for resolving a value through evaluating it
* as an expression, if applicable.
* Strategy interface for resolving a value by evaluating it as an expression,
* if applicable.
*
* <p>A raw {@link org.springframework.beans.factory.BeanFactory} does not
* contain a default implementation of this strategy. However,
@@ -36,12 +36,13 @@ public interface BeanExpressionResolver {
/**
* Evaluate the given value as an expression, if applicable;
* return the value as-is otherwise.
* @param value the value to check
* @param evalContext the evaluation context
* @param value the value to evaluate as an expression
* @param beanExpressionContext the bean expression context to use when
* evaluating the expression
* @return the resolved value (potentially the given value as-is)
* @throws BeansException if evaluation failed
*/
@Nullable
Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException;
Object evaluate(@Nullable String value, BeanExpressionContext beanExpressionContext) throws BeansException;
}
@@ -1,5 +1,5 @@
/**
* Support package for the Java 6 ServiceLoader facility.
* Support package for the Java {@link java.util.ServiceLoader} facility.
*/
@NonNullApi
@NonNullFields
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -985,7 +985,7 @@ class ConstructorResolver {
/**
* Delegate for checking Java 6's {@link ConstructorProperties} annotation.
* Delegate for checking Java's {@link ConstructorProperties} annotation.
*/
private static class ConstructorPropertiesChecker {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -585,7 +585,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
}
if (matchFound) {
@@ -17,7 +17,7 @@
package org.springframework.beans.factory.support;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.BeanMetadataElement;
@@ -31,6 +31,8 @@ import org.springframework.lang.Nullable;
* @author Rod Johnson
* @author Rob Harrop
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Sam Brannen
* @since 27.05.2003
* @param <E> the element type
*/
@@ -55,16 +57,16 @@ public class ManagedList<E> extends ArrayList<E> implements Mergeable, BeanMetad
/**
* Return a new instance containing an arbitrary number of elements.
* Create a new instance containing an arbitrary number of elements.
* @param elements the elements to be contained in the list
* @param <E> the {@code List}'s element type
* @return a {@code List} containing the specified elements
* @return a {@code ManagedList} containing the specified elements
* @since 5.3.16
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static <E> ManagedList<E> of(E... elements) {
ManagedList<E> list = new ManagedList<>();
list.addAll(Arrays.asList(elements));
Collections.addAll(list, elements);
return list;
}
@@ -16,7 +16,7 @@
package org.springframework.beans.factory.support;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -30,6 +30,8 @@ import org.springframework.lang.Nullable;
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Stephane Nicoll
* @author Sam Brannen
* @since 21.01.2004
* @param <E> the element type
*/
@@ -54,16 +56,16 @@ public class ManagedSet<E> extends LinkedHashSet<E> implements Mergeable, BeanMe
/**
* Return a new instance containing an arbitrary number of elements.
* Create a new instance containing an arbitrary number of elements.
* @param elements the elements to be contained in the set
* @param <E> the {@code Set}'s element type
* @return a {@code Set} containing the specified elements
* @return a {@code ManagedSet} containing the specified elements
* @since 5.3.16
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static <E> ManagedSet<E> of(E... elements) {
ManagedSet<E> set = new ManagedSet<>();
set.addAll(Arrays.asList(elements));
Collections.addAll(set, elements);
return set;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2022 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.
@@ -43,6 +43,7 @@ import org.springframework.core.io.ContextResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.WritableResource;
import org.springframework.core.io.support.ResourceArrayPropertyEditor;
import org.springframework.core.io.support.ResourcePatternResolver;
@@ -102,6 +103,7 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
doRegisterEditor(registry, Resource.class, baseEditor);
doRegisterEditor(registry, ContextResource.class, baseEditor);
doRegisterEditor(registry, WritableResource.class, baseEditor);
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@@ -39,7 +39,7 @@ inline fun <reified T : Any> ListableBeanFactory.getBeansOfType(includeNonSingle
/**
* Extension for [ListableBeanFactory.getBeanNamesForAnnotation] providing a
* `getBeansOfType<Foo>()` variant.
* `getBeanNamesForAnnotation<Foo>()` variant.
*
* @author Sebastien Deleuze
* @since 5.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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,6 +23,9 @@ import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.UrlResource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -105,7 +108,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
.satisfies(ex -> assertThat(ex.getPossibleMatches()).containsExactly("age"));
}
@Test // Can't be shared; there is no such thing as a read-only field
@Test // Can't be shared; there is no such thing as a read-only field
void setReadOnlyMapProperty() {
TypedReadOnlyMap map = new TypedReadOnlyMap(Collections.singletonMap("key", new TestBean()));
TypedReadOnlyMapClient target = new TypedReadOnlyMapClient();
@@ -151,18 +154,58 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
@Test
void propertyDescriptors() {
void propertyDescriptors() throws Exception {
TestBean target = new TestBean();
target.setSpouse(new TestBean());
BeanWrapper accessor = createAccessor(target);
accessor.setPropertyValue("name", "a");
accessor.setPropertyValue("spouse.name", "b");
assertThat(target.getName()).isEqualTo("a");
assertThat(target.getSpouse().getName()).isEqualTo("b");
assertThat(accessor.getPropertyValue("name")).isEqualTo("a");
assertThat(accessor.getPropertyValue("spouse.name")).isEqualTo("b");
assertThat(accessor.getPropertyDescriptor("name").getPropertyType()).isEqualTo(String.class);
assertThat(accessor.getPropertyDescriptor("spouse.name").getPropertyType()).isEqualTo(String.class);
assertThat(accessor.isReadableProperty("class.package")).isFalse();
assertThat(accessor.isReadableProperty("class.module")).isFalse();
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
assertThat(accessor.isReadableProperty("class.name")).isTrue();
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
assertThat(accessor.getPropertyValue("class.name")).isEqualTo(TestBean.class.getName());
assertThat(accessor.getPropertyValue("class.simpleName")).isEqualTo(TestBean.class.getSimpleName());
assertThat(accessor.getPropertyDescriptor("class.name").getPropertyType()).isEqualTo(String.class);
assertThat(accessor.getPropertyDescriptor("class.simpleName").getPropertyType()).isEqualTo(String.class);
accessor = createAccessor(new DefaultResourceLoader());
assertThat(accessor.isReadableProperty("class.package")).isFalse();
assertThat(accessor.isReadableProperty("class.module")).isFalse();
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
assertThat(accessor.isReadableProperty("class.name")).isTrue();
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
accessor.setPropertyValue("classLoader", ocl);
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
accessor = createAccessor(new UrlResource("https://spring.io"));
assertThat(accessor.isReadableProperty("class.package")).isFalse();
assertThat(accessor.isReadableProperty("class.module")).isFalse();
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
assertThat(accessor.isReadableProperty("class.name")).isTrue();
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
assertThat(accessor.isReadableProperty("URL.protocol")).isTrue();
assertThat(accessor.isReadableProperty("URL.host")).isTrue();
assertThat(accessor.isReadableProperty("URL.port")).isTrue();
assertThat(accessor.isReadableProperty("URL.file")).isTrue();
assertThat(accessor.isReadableProperty("URL.content")).isFalse();
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
assertThat(accessor.isReadableProperty("filename")).isTrue();
assertThat(accessor.isReadableProperty("description")).isTrue();
}
@Test
@@ -26,7 +26,6 @@ import java.security.Principal;
import java.security.PrivilegedAction;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -95,6 +94,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -178,10 +178,8 @@ class DefaultListableBeanFactoryTests {
registerBeanDefinitions(p);
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(0);
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
assertThat(beanNames).hasSize(0);
assertBeanNamesForType(TestBean.class, false, false);
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
@@ -212,10 +210,8 @@ class DefaultListableBeanFactoryTests {
registerBeanDefinitions(p);
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(0);
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
assertThat(beanNames).hasSize(0);
assertBeanNamesForType(TestBean.class, false, false);
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
@@ -245,10 +241,8 @@ class DefaultListableBeanFactoryTests {
registerBeanDefinitions(p);
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(0);
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
assertThat(beanNames).hasSize(0);
assertBeanNamesForType(TestBean.class, false, false);
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
@@ -278,10 +272,8 @@ class DefaultListableBeanFactoryTests {
registerBeanDefinitions(p);
lbf.preInstantiateSingletons();
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(1);
assertThat(beanNames[0]).isEqualTo("x1");
assertThat(DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isFalse();
assertBeanNamesForType(TestBean.class, true, false, "x1");
assertThat(lbf.containsSingleton("x1")).isTrue();
assertThat(lbf.containsBean("x1")).isTrue();
assertThat(lbf.containsBean("&x1")).isTrue();
@@ -316,14 +308,10 @@ class DefaultListableBeanFactoryTests {
assertThat(lbf.isTypeMatch("&x2", Object.class)).isTrue();
assertThat(lbf.getType("x2")).isEqualTo(TestBean.class);
assertThat(lbf.getType("&x2")).isEqualTo(DummyFactory.class);
assertThat(lbf.getAliases("x1").length).isEqualTo(1);
assertThat(lbf.getAliases("x1")[0]).isEqualTo("x2");
assertThat(lbf.getAliases("&x1").length).isEqualTo(1);
assertThat(lbf.getAliases("&x1")[0]).isEqualTo("&x2");
assertThat(lbf.getAliases("x2").length).isEqualTo(1);
assertThat(lbf.getAliases("x2")[0]).isEqualTo("x1");
assertThat(lbf.getAliases("&x2").length).isEqualTo(1);
assertThat(lbf.getAliases("&x2")[0]).isEqualTo("&x1");
assertThat(lbf.getAliases("x1")).containsExactly("x2");
assertThat(lbf.getAliases("&x1")).containsExactly("&x2");
assertThat(lbf.getAliases("x2")).containsExactly("x1");
assertThat(lbf.getAliases("&x2")).containsExactly("&x1");
}
@Test
@@ -333,9 +321,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("x1", rbd);
TestBeanFactory.initialized = false;
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(1);
assertThat(beanNames[0]).isEqualTo("x1");
assertBeanNamesForType(TestBean.class, true, false, "x1");
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
assertThat(lbf.containsBean("&x1")).isFalse();
@@ -358,9 +344,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("x1", rbd);
TestBeanFactory.initialized = false;
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(1);
assertThat(beanNames[0]).isEqualTo("x1");
assertBeanNamesForType(TestBean.class, true, false, "x1");
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
assertThat(lbf.containsBean("&x1")).isFalse();
@@ -385,9 +369,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("x1", rbd);
TestBeanFactory.initialized = false;
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(1);
assertThat(beanNames[0]).isEqualTo("x1");
assertBeanNamesForType(TestBean.class, true, false, "x1");
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
assertThat(lbf.containsBean("&x1")).isFalse();
@@ -413,9 +395,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("x1", rbd);
TestBeanFactory.initialized = false;
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
assertThat(beanNames).hasSize(1);
assertThat(beanNames[0]).isEqualTo("x1");
assertBeanNamesForType(TestBean.class, true, false, "x1");
assertThat(lbf.containsSingleton("x1")).isFalse();
assertThat(lbf.containsBean("x1")).isTrue();
assertThat(lbf.containsBean("&x1")).isFalse();
@@ -448,14 +428,10 @@ class DefaultListableBeanFactoryTests {
assertThat(lbf.isTypeMatch("&x2", Object.class)).isFalse();
assertThat(lbf.getType("x2")).isEqualTo(TestBean.class);
assertThat(lbf.getType("&x2")).isNull();
assertThat(lbf.getAliases("x1").length).isEqualTo(1);
assertThat(lbf.getAliases("x1")[0]).isEqualTo("x2");
assertThat(lbf.getAliases("&x1").length).isEqualTo(1);
assertThat(lbf.getAliases("&x1")[0]).isEqualTo("&x2");
assertThat(lbf.getAliases("x2").length).isEqualTo(1);
assertThat(lbf.getAliases("x2")[0]).isEqualTo("x1");
assertThat(lbf.getAliases("&x2").length).isEqualTo(1);
assertThat(lbf.getAliases("&x2")[0]).isEqualTo("&x1");
assertThat(lbf.getAliases("x1")).containsExactly("x2");
assertThat(lbf.getAliases("&x1")).containsExactly("&x2");
assertThat(lbf.getAliases("x2")).containsExactly("x1");
assertThat(lbf.getAliases("&x2")).containsExactly("&x1");
}
@Test
@@ -619,8 +595,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerSingleton("string", "A");
TestBean self = (TestBean) lbf.getBean("self");
assertThat(self.getStringArray()).hasSize(1);
assertThat(self.getStringArray()).contains("A");
assertThat(self.getStringArray()).containsExactly("A");
}
@Test
@@ -633,8 +608,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerSingleton("string", "A");
TestBean self = (TestBean) lbf.getBean("self");
assertThat(self.getStringArray()).hasSize(1);
assertThat(self.getStringArray()).contains("A");
assertThat(self.getStringArray()).containsExactly("A");
}
@Test
@@ -666,8 +640,7 @@ class DefaultListableBeanFactoryTests {
.withCauseInstanceOf(NotWritablePropertyException.class)
.satisfies(ex -> {
NotWritablePropertyException cause = (NotWritablePropertyException) ex.getCause();
assertThat(cause.getPossibleMatches()).hasSize(1);
assertThat(cause.getPossibleMatches()[0]).isEqualTo("age");
assertThat(cause.getPossibleMatches()).containsExactly("age");
});
}
@@ -685,7 +658,7 @@ class DefaultListableBeanFactoryTests {
lbf = new DefaultListableBeanFactory();
p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.(scope)", "prototype");
p.setProperty("kerry.(scope)", BeanDefinition.SCOPE_PROTOTYPE);
p.setProperty("kerry.age", "35");
registerBeanDefinitions(p);
kerry1 = (TestBean) lbf.getBean("kerry");
@@ -1145,7 +1118,7 @@ class DefaultListableBeanFactoryTests {
assertThat(lbf.containsBean("singletonObject")).isTrue();
assertThat(lbf.isSingleton("singletonObject")).isTrue();
assertThat(lbf.getType("singletonObject")).isEqualTo(TestBean.class);
assertThat(lbf.getAliases("singletonObject").length).isEqualTo(0);
assertThat(lbf.getAliases("singletonObject")).isEmpty();
DependenciesBean test = (DependenciesBean) lbf.getBean("test");
assertThat(lbf.getBean("singletonObject")).isEqualTo(singletonObject);
assertThat(test.getSpouse()).isEqualTo(singletonObject);
@@ -1791,12 +1764,12 @@ class DefaultListableBeanFactoryTests {
assertThat(bean.beanName).isEqualTo("bd1");
assertThat(bean.spouseAge).isEqualTo(42);
assertThat(lbf.getBeanNamesForType(ConstructorDependency.class).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length).isEqualTo(0);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true).length).isEqualTo(0);
assertThat(lbf.getBeanNamesForType(ConstructorDependency.class)).hasSize(1);
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class)).hasSize(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class))).hasSize(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class))).isEmpty();
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true)).hasSize(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true)).isEmpty();
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
@@ -1861,46 +1834,45 @@ class DefaultListableBeanFactoryTests {
@Test
void getBeanNamesForTypeBeforeFactoryBeanCreation() {
FactoryBeanThatShouldntBeCalled.instantiated = false;
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
assertThat(lbf.containsSingleton("factoryBean")).isFalse();
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isFalse();
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
assertBeanNamesForType(Runnable.class, false, false, "&factoryBean");
assertBeanNamesForType(Callable.class, false, false, "&factoryBean");
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false, "&factoryBean");
assertBeanNamesForType(FactoryBean.class, false, false, "&factoryBean");
}
@Test
void getBeanNamesForTypeAfterFactoryBeanCreation() {
FactoryBeanThatShouldntBeCalled.instantiated = false;
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
lbf.getBean("&factoryBean");
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isTrue();
assertThat(lbf.containsSingleton("factoryBean")).isTrue();
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
assertBeanNamesForType(Runnable.class, false, false, "&factoryBean");
assertBeanNamesForType(Callable.class, false, false, "&factoryBean");
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false, "&factoryBean");
assertBeanNamesForType(FactoryBean.class, false, false, "&factoryBean");
}
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
@Test // gh-28616
void getBeanNamesForTypeWithPrototypeScopedFactoryBean() {
FactoryBeanThatShouldntBeCalled.instantiated = false;
RootBeanDefinition beanDefinition = new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("factoryBean", beanDefinition);
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isFalse();
assertThat(lbf.containsSingleton("factoryBean")).isFalse();
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
assertThat(beanNames.length).isEqualTo(1);
assertThat(beanNames[0]).isEqualTo("&factoryBean");
// We should not find any beans of the following types if the FactoryBean itself is prototype-scoped.
assertBeanNamesForType(Runnable.class, false, false);
assertBeanNamesForType(Callable.class, false, false);
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false);
assertBeanNamesForType(FactoryBean.class, false, false);
}
/**
@@ -2165,8 +2137,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
lbf::preInstantiateSingletons);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@Test
@@ -2174,8 +2145,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
lbf::preInstantiateSingletons);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@Test
@@ -2183,8 +2153,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
lbf.getBeansOfType(String.class));
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> lbf.getBeansOfType(String.class));
}
@Test
@@ -2211,8 +2180,7 @@ class DefaultListableBeanFactoryTests {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyWithClassResolution.class);
bd.getConstructorArgumentValues().addGenericArgumentValue("java.lang.Strin");
lbf.registerBeanDefinition("test", bd);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
lbf::preInstantiateSingletons);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
}
@Test
@@ -2236,7 +2204,13 @@ class DefaultListableBeanFactoryTests {
@Test
void prototypeFactoryBeanNotEagerlyCalled() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
lbf.preInstantiateSingletons();
assertThatNoException().isThrownBy(lbf::preInstantiateSingletons);
}
@Test
void prototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() {
lbf.registerBeanDefinition("test", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName(), null, null));
assertThatNoException().isThrownBy(lbf::preInstantiateSingletons);
}
@Test
@@ -2276,13 +2250,6 @@ class DefaultListableBeanFactoryTests {
assertThat(factory.initialized).isTrue();
}
@Test
void prototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() {
lbf.registerBeanDefinition("test",
new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName(), null, null));
lbf.preInstantiateSingletons();
}
@Test
void prototypeStringCreatedRepeatedly() {
RootBeanDefinition stringDef = new RootBeanDefinition(String.class);
@@ -2462,10 +2429,7 @@ class DefaultListableBeanFactoryTests {
lbf.registerBeanDefinition("fmWithArgs", factoryMethodDefinitionWithArgs);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(4);
List<String> tbNames = Arrays.asList(lbf.getBeanNamesForType(TestBean.class));
assertThat(tbNames.contains("fmWithProperties")).isTrue();
assertThat(tbNames.contains("fmWithArgs")).isTrue();
assertThat(tbNames.size()).isEqualTo(2);
assertBeanNamesForType(TestBean.class, true, true, "fmWithProperties", "fmWithArgs");
TestBean tb = (TestBean) lbf.getBean("fmWithProperties");
TestBean second = (TestBean) lbf.getBean("fmWithProperties");
@@ -2669,6 +2633,19 @@ class DefaultListableBeanFactoryTests {
return (new org.springframework.beans.factory.support.PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, prefix);
}
private void assertBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit, String... names) {
if (names.length == 0) {
assertThat(lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit))
.as("bean names for type " + type.getName())
.isEmpty();
}
else {
assertThat(lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit))
.as("bean names for type " + type.getName())
.containsExactly(names);
}
}
public static class NoDependencies {
@@ -2859,6 +2836,12 @@ class DefaultListableBeanFactoryTests {
public static class FactoryBeanThatShouldntBeCalled<T extends Repository<S, ID>, S, ID extends Serializable>
extends RepositoryFactoryBeanSupport<T, S, ID> implements Runnable, Callable<T> {
static boolean instantiated = false;
{
instantiated = true;
}
@Override
public T getObject() {
throw new IllegalStateException();
@@ -25,61 +25,61 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Unit tests for {@link ManagedList}.
*
* @author Rick Evans
* @author Juergen Hoeller
* @author Sam Brannen
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ManagedListTests {
class ManagedListTests {
@Test
public void mergeSunnyDay() {
void mergeSunnyDay() {
ManagedList parent = ManagedList.of("one", "two");
ManagedList child = ManagedList.of("three");
child.setMergeEnabled(true);
List mergedList = child.merge(parent);
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(3);
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two", "three");
}
@Test
public void mergeWithNullParent() {
void mergeWithNullParent() {
ManagedList child = ManagedList.of("one");
child.setMergeEnabled(true);
assertThat(child.merge(null)).isSameAs(child);
}
@Test
public void mergeNotAllowedWhenMergeNotEnabled() {
void mergeNotAllowedWhenMergeNotEnabled() {
ManagedList child = new ManagedList();
assertThatIllegalStateException().isThrownBy(() ->
child.merge(null));
assertThatIllegalStateException().isThrownBy(() -> child.merge(null));
}
@Test
public void mergeWithNonCompatibleParentType() {
void mergeWithIncompatibleParentType() {
ManagedList child = ManagedList.of("one");
child.setMergeEnabled(true);
assertThatIllegalArgumentException().isThrownBy(() ->
child.merge("hello"));
assertThatIllegalArgumentException().isThrownBy(() -> child.merge("hello"));
}
@Test
public void mergeEmptyChild() {
void mergeEmptyChild() {
ManagedList parent = ManagedList.of("one", "two");
ManagedList child = new ManagedList();
child.setMergeEnabled(true);
List mergedList = child.merge(parent);
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(2);
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two");
}
@Test
public void mergeChildValuesOverrideTheParents() {
void mergedChildValuesDoNotOverrideTheParents() {
// doesn't make much sense in the context of a list...
ManagedList parent = ManagedList.of("one", "two");
ManagedList child = ManagedList.of("one");
child.setMergeEnabled(true);
List mergedList = child.merge(parent);
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(3);
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two", "one");
}
}
@@ -25,61 +25,62 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Unit tests for {@link ManagedSet}.
*
* @author Rick Evans
* @author Juergen Hoeller
* @author Sam Brannen
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ManagedSetTests {
class ManagedSetTests {
@Test
public void mergeSunnyDay() {
void mergeSunnyDay() {
ManagedSet parent = ManagedSet.of("one", "two");
ManagedSet child = ManagedSet.of("three");
child.add("three");
child.add("four");
child.setMergeEnabled(true);
Set mergedSet = child.merge(parent);
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(3);
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two", "three", "four");
}
@Test
public void mergeWithNullParent() {
void mergeWithNullParent() {
ManagedSet child = ManagedSet.of("one");
child.setMergeEnabled(true);
assertThat(child.merge(null)).isSameAs(child);
}
@Test
public void mergeNotAllowedWhenMergeNotEnabled() {
assertThatIllegalStateException().isThrownBy(() ->
new ManagedSet().merge(null));
void mergeNotAllowedWhenMergeNotEnabled() {
assertThatIllegalStateException().isThrownBy(() -> new ManagedSet().merge(null));
}
@Test
public void mergeWithNonCompatibleParentType() {
void mergeWithNonCompatibleParentType() {
ManagedSet child = ManagedSet.of("one");
child.setMergeEnabled(true);
assertThatIllegalArgumentException().isThrownBy(() ->
child.merge("hello"));
assertThatIllegalArgumentException().isThrownBy(() -> child.merge("hello"));
}
@Test
public void mergeEmptyChild() {
void mergeEmptyChild() {
ManagedSet parent = ManagedSet.of("one", "two");
ManagedSet child = new ManagedSet();
child.setMergeEnabled(true);
Set mergedSet = child.merge(parent);
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(2);
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two");
}
@Test
public void mergeChildValuesOverrideTheParents() {
void mergeChildValuesOverrideTheParents() {
// asserts that the set contract is not violated during a merge() operation...
ManagedSet parent = ManagedSet.of("one", "two");
ManagedSet child = ManagedSet.of("one");
child.setMergeEnabled(true);
Set mergedSet = child.merge(parent);
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(2);
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two");
}
}
@@ -58,6 +58,7 @@ import org.springframework.core.io.Resource;
import org.springframework.core.testfixture.security.TestPrincipal;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
@@ -303,14 +304,14 @@ public class CallbacksSecurityTests {
Method method = bean.getClass().getMethod("destroy");
method.setAccessible(true);
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
assertThatException().isThrownBy(() ->
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
method.invoke(bean);
return null;
}, acc));
Class<ConstructorBean> cl = ConstructorBean.class;
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
assertThatException().isThrownBy(() ->
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
cl.newInstance(), acc));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,8 +23,7 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatException;
/**
* With Spring 3.1, bean id attributes (and all other id attributes across the
@@ -40,22 +39,23 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#withDuplicateName
* @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#withDuplicateNameInAlias
*/
public class DuplicateBeanIdTests {
class DuplicateBeanIdTests {
@Test
public void duplicateBeanIdsWithinSameNestingLevelRaisesError() {
void duplicateBeanIdsWithinSameNestingLevelRaisesError() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
assertThatExceptionOfType(Exception.class).as("duplicate ids in same nesting level").isThrownBy(() ->
assertThatException().as("duplicate ids in same nesting level").isThrownBy(() ->
reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-sameLevel-context.xml", this.getClass())));
}
@Test
public void duplicateBeanIdsAcrossNestingLevels() {
void duplicateBeanIdsAcrossNestingLevels() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-multiLevel-context.xml", this.getClass()));
TestBean testBean = bf.getBean(TestBean.class); // there should be only one
assertThat(testBean.getName()).isEqualTo("nested");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import javax.lang.model.element.Element;
/**
* Provide the list of stereotypes that match an {@link Element}.
*
* <p>If an element has one or more stereotypes, it is referenced in the index
* of candidate components and each stereotype can be queried individually.
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.contextsupport.testfixture.jcache.JCacheableService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
/**
* @author Stephane Nicoll
@@ -86,8 +86,8 @@ public class JCacheCustomInterceptorTests {
@Test
public void customInterceptorAppliesWithCheckedException() {
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
cs.cacheWithCheckedException("id", true))
assertThatRuntimeException()
.isThrownBy(() -> cs.cacheWithCheckedException("id", true))
.withCauseExactlyInstanceOf(IOException.class);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ import java.util.Set;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.ConstraintViolation;
import javax.validation.Payload;
import javax.validation.Valid;
@@ -43,6 +44,7 @@ import org.hibernate.validator.HibernateValidatorFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.convert.support.DefaultConversionService;
@@ -52,18 +54,18 @@ import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Juergen Hoeller
*/
@SuppressWarnings("resource")
public class ValidatorFactoryTests {
class ValidatorFactoryTests {
@Test
@SuppressWarnings("cast")
public void testSimpleValidation() {
void simpleValidation() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -78,15 +80,15 @@ public class ValidatorFactoryTests {
Validator nativeValidator = validator.unwrap(Validator.class);
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
assertThat(validator.unwrap(HibernateValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
validator.destroy();
}
@Test
@SuppressWarnings("cast")
public void testSimpleValidationWithCustomProvider() {
void simpleValidationWithCustomProvider() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setProviderClass(HibernateValidator.class);
validator.afterPropertiesSet();
@@ -102,14 +104,15 @@ public class ValidatorFactoryTests {
Validator nativeValidator = validator.unwrap(Validator.class);
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
assertThat(validator.unwrap(HibernateValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
validator.destroy();
}
@Test
public void testSimpleValidationWithClassLevel() {
void simpleValidationWithClassLevel() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -122,10 +125,13 @@ public class ValidatorFactoryTests {
ConstraintViolation<?> cv = iterator.next();
assertThat(cv.getPropertyPath().toString()).isEqualTo("");
assertThat(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid).isTrue();
validator.destroy();
}
@Test
public void testSpringValidationFieldType() {
void springValidationFieldType() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -135,11 +141,16 @@ public class ValidatorFactoryTests {
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(person, "person");
validator.validate(person, errors);
assertThat(errors.getErrorCount()).isEqualTo(1);
assertThat(errors.getFieldError("address").getRejectedValue()).isInstanceOf(ValidAddress.class);
assertThat(errors.getFieldError("address").getRejectedValue())
.as("Field/Value type mismatch")
.isInstanceOf(ValidAddress.class);
validator.destroy();
}
@Test
public void testSpringValidation() {
void springValidation() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -164,10 +175,13 @@ public class ValidatorFactoryTests {
assertThat(errorCodes.contains("NotNull.street")).isTrue();
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
assertThat(errorCodes.contains("NotNull")).isTrue();
validator.destroy();
}
@Test
public void testSpringValidationWithClassLevel() {
void springValidationWithClassLevel() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -182,10 +196,12 @@ public class ValidatorFactoryTests {
assertThat(errorCodes.size()).isEqualTo(2);
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
validator.destroy();
}
@Test
public void testSpringValidationWithAutowiredValidator() {
void springValidationWithAutowiredValidator() {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
LocalValidatorFactoryBean.class);
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
@@ -202,11 +218,14 @@ public class ValidatorFactoryTests {
assertThat(errorCodes.size()).isEqualTo(2);
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
validator.destroy();
ctx.close();
}
@Test
public void testSpringValidationWithErrorInListElement() {
void springValidationWithErrorInListElement() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -221,10 +240,13 @@ public class ValidatorFactoryTests {
assertThat(fieldError.getField()).isEqualTo("address.street");
fieldError = result.getFieldError("addressList[0].street");
assertThat(fieldError.getField()).isEqualTo("addressList[0].street");
validator.destroy();
}
@Test
public void testSpringValidationWithErrorInSetElement() {
void springValidationWithErrorInSetElement() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -239,10 +261,13 @@ public class ValidatorFactoryTests {
assertThat(fieldError.getField()).isEqualTo("address.street");
fieldError = result.getFieldError("addressSet[].street");
assertThat(fieldError.getField()).isEqualTo("addressSet[].street");
validator.destroy();
}
@Test
public void testInnerBeanValidation() {
void innerBeanValidation() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -251,10 +276,13 @@ public class ValidatorFactoryTests {
validator.validate(mainBean, errors);
Object rejected = errors.getFieldValue("inner.value");
assertThat(rejected).isNull();
validator.destroy();
}
@Test
public void testValidationWithOptionalField() {
void validationWithOptionalField() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -263,10 +291,13 @@ public class ValidatorFactoryTests {
validator.validate(mainBean, errors);
Object rejected = errors.getFieldValue("inner.value");
assertThat(rejected).isNull();
validator.destroy();
}
@Test
public void testListValidation() {
void listValidation() {
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
@@ -282,6 +313,34 @@ public class ValidatorFactoryTests {
assertThat(fieldError).isNotNull();
assertThat(fieldError.getRejectedValue()).isEqualTo("X");
assertThat(errors.getFieldValue("list[1]")).isEqualTo("X");
validator.destroy();
}
@Test
void withConstraintValidatorFactory() {
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setConstraintValidatorFactory(cvf);
validator.afterPropertiesSet();
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
validator.destroy();
}
@Test
void withCustomInitializer() {
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
@SuppressWarnings("resource")
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setConfigurationInitializer(configuration -> configuration.constraintValidatorFactory(cvf));
validator.afterPropertiesSet();
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
validator.destroy();
}
@@ -380,8 +439,8 @@ public class ValidatorFactoryTests {
}
boolean valid = (value.name == null || !value.address.street.contains(value.name));
if (!valid && "Phil".equals(value.name)) {
context.buildConstraintViolationWithTemplate(
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
.addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
}
return valid;
}
@@ -417,6 +476,7 @@ public class ValidatorFactoryTests {
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@@ -425,8 +485,8 @@ public class ValidatorFactoryTests {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy=InnerValidator.class)
public static @interface InnerValid {
@Constraint(validatedBy = InnerValidator.class)
public @interface InnerValid {
String message() default "NOT VALID";
@@ -446,7 +506,8 @@ public class ValidatorFactoryTests {
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
if (bean.getValue() == null) {
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
context.buildConstraintViolationWithTemplate("NULL")
.addPropertyNode("value").addConstraintViolation();
return false;
}
return true;
@@ -494,7 +555,8 @@ public class ValidatorFactoryTests {
boolean valid = true;
for (int i = 0; i < list.size(); i++) {
if ("X".equals(list.get(i))) {
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
.addBeanNode().inIterable().atIndex(i).addConstraintViolation();
valid = false;
}
}
@@ -105,7 +105,7 @@ import org.springframework.util.StringValueResolver;
*
* <p>The common annotations supported by this post-processor are available in
* Java 6 (JDK 1.6) as well as in Java EE 5/6 (which provides a standalone jar for
* its common annotations as well, allowing for use in any Java 5 based application).
* its common annotations as well, allowing for use in any based application).
*
* <p>For default usage, resolving resource names as Spring bean names,
* simply define the following in your application context:
@@ -138,7 +138,7 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver {
@Override
@Nullable
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException {
public Object evaluate(@Nullable String value, BeanExpressionContext beanExpressionContext) throws BeansException {
if (!StringUtils.hasLength(value)) {
return value;
}
@@ -148,21 +148,21 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver {
expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext);
this.expressionCache.put(value, expr);
}
StandardEvaluationContext sec = this.evaluationCache.get(evalContext);
StandardEvaluationContext sec = this.evaluationCache.get(beanExpressionContext);
if (sec == null) {
sec = new StandardEvaluationContext(evalContext);
sec = new StandardEvaluationContext(beanExpressionContext);
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor());
sec.addPropertyAccessor(new EnvironmentAccessor());
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
sec.setBeanResolver(new BeanFactoryResolver(beanExpressionContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(beanExpressionContext.getBeanFactory().getBeanClassLoader()));
sec.setTypeConverter(new StandardTypeConverter(() -> {
ConversionService cs = evalContext.getBeanFactory().getConversionService();
ConversionService cs = beanExpressionContext.getBeanFactory().getConversionService();
return (cs != null ? cs : DefaultConversionService.getSharedInstance());
}));
customizeEvaluationContext(sec);
this.evaluationCache.put(evalContext, sec);
this.evaluationCache.put(beanExpressionContext, sec);
}
return expr.getValue(sec);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@@ -37,9 +37,9 @@ public class SimpleLocaleContext implements LocaleContext {
/**
* Create a new SimpleLocaleContext that exposes the specified Locale.
* Every {@link #getLocale()} call will return this Locale.
* @param locale the Locale to expose, or {@code null} for no specific one
* Create a new {@code SimpleLocaleContext} that exposes the specified {@link Locale}.
* <p>Every {@link #getLocale()} call will return this locale.
* @param locale the {@code Locale} to expose, or {@code null} for no specific one
*/
public SimpleLocaleContext(@Nullable Locale locale) {
this.locale = locale;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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.
@@ -143,7 +143,7 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder
this.actualObjectNames = getResolvedObjectNames();
if (this.actualObjectNames != null) {
if (logger.isDebugEnabled()) {
logger.debug("Registering NotificationListener for MBeans " + Arrays.asList(this.actualObjectNames));
logger.debug("Registering NotificationListener for MBeans " + Arrays.toString(this.actualObjectNames));
}
for (ObjectName actualObjectName : this.actualObjectNames) {
this.server.addNotificationListener(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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.
@@ -762,7 +762,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* <p>The default implementation delegates to {@link JmxUtils#isMBean},
* which checks for {@link javax.management.DynamicMBean} classes as well
* as classes with corresponding "*MBean" interface (Standard MBeans)
* or corresponding "*MXBean" interface (Java 6 MXBeans).
* or corresponding "*MXBean" interface (Java MXBeans).
* @param beanClass the bean class to analyze
* @return whether the class qualifies as an MBean
* @see org.springframework.jmx.support.JmxUtils#isMBean(Class)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -46,7 +46,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
* Implementation of the {@code JmxAttributeSource} interface that
* Implementation of the {@link JmxAttributeSource} interface that
* reads annotations and exposes the corresponding attributes.
*
* @author Rob Harrop
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2022 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,7 @@ import org.springframework.jmx.export.naming.MetadataNamingStrategy;
/**
* Convenient subclass of Spring's standard {@link MBeanExporter},
* activating Java 5 annotation usage for JMX exposure of Spring beans:
* activating annotation usage for JMX exposure of Spring beans:
* {@link ManagedResource}, {@link ManagedAttribute}, {@link ManagedOperation}, etc.
*
* <p>Sets a {@link MetadataNamingStrategy} and a {@link MetadataMBeanInfoAssembler}
@@ -27,7 +27,8 @@ import org.springframework.jmx.support.MetricType;
/**
* Method-level annotation that indicates to expose a given bean property as a
* JMX attribute, with added descriptor properties to indicate that it is a metric.
* Only valid when used on a JavaBean getter.
*
* <p>Only valid when used on a JavaBean getter.
*
* @author Jennifer Hickey
* @since 3.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,10 +27,12 @@ import java.lang.annotation.Target;
/**
* Type-level annotation that indicates a JMX notification emitted by a bean.
*
* <p>As of Spring Framework 4.2.4, this annotation is declared as repeatable.
* <p>This annotation is a {@linkplain java.lang.annotation.Repeatable repeatable}
* annotation.
*
* @author Rob Harrop
* @since 2.0
* @see ManagedNotifications
* @see org.springframework.jmx.export.metadata.ManagedNotification
*/
@Target(ElementType.TYPE)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2022 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,8 +24,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Type-level annotation that indicates JMX notifications emitted by a bean,
* containing multiple {@link ManagedNotification ManagedNotifications}.
* Type-level annotation used as a container for one or more
* {@code @ManagedNotification} declarations.
*
* <p>Note, however, that use of the {@code @ManagedNotifications} container
* is completely optional since {@code @ManagedNotification} is a
* {@linkplain java.lang.annotation.Repeatable repeatable} annotation.
*
* @author Rob Harrop
* @since 2.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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,9 +23,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation that indicates to expose a given method as a
* JMX operation, corresponding to the {@code ManagedOperation} attribute.
* Only valid when used on a method that is not a JavaBean getter or setter.
* Method-level annotation that indicates to expose a given method as a JMX operation,
* corresponding to the {@link org.springframework.jmx.export.metadata.ManagedOperation}
* attribute.
*
* <p>Only valid when used on a method that is not a JavaBean getter or setter.
*
* @author Rob Harrop
* @since 1.2
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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,15 +24,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation used to provide metadata about operation parameters,
* corresponding to a {@code ManagedOperationParameter} attribute.
* Used as part of a {@link ManagedOperationParameters} annotation.
* Method-level annotation used to provide metadata about operation parameters, corresponding
* to a {@link org.springframework.jmx.export.metadata.ManagedOperationParameter} attribute.
*
* <p>As of Spring Framework 4.2.4, this annotation is declared as repeatable.
* <p>This annotation is a {@linkplain java.lang.annotation.Repeatable repeatable}
* annotation.
*
* @author Rob Harrop
* @since 1.2
* @see ManagedOperationParameters#value
* @see ManagedOperationParameters
* @see org.springframework.jmx.export.metadata.ManagedOperationParameter
*/
@Target(ElementType.METHOD)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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,8 +23,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation used to provide metadata about operation parameters,
* corresponding to an array of {@code ManagedOperationParameter} attributes.
* Method-level annotation used as a container for one or more
* {@code @ManagedOperationParameter} declarations.
*
* <p>Note, however, that use of the {@code @ManagedOperationParameters} container
* is completely optional since {@code @ManagedOperationParameter} is a
* {@linkplain java.lang.annotation.Repeatable repeatable} annotation.
*
* @author Rob Harrop
* @since 1.2
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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,8 +26,8 @@ import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
* Class-level annotation that indicates to register instances of a class
* with a JMX server, corresponding to the {@code ManagedResource} attribute.
* Class-level annotation that indicates to register instances of a class with a JMX server,
* corresponding to the {@link org.springframework.jmx.export.metadata.ManagedResource} attribute.
*
* <p><b>Note:</b> This annotation is marked as inherited, allowing for generic
* management-aware base classes. In such a scenario, it is recommended to
@@ -1,7 +1,8 @@
/**
* Java 5 annotations for MBean exposure.
* Hooked into Spring's JMX export infrastructure
* via a special JmxAttributeSource implementation.
* Annotations for MBean exposure.
*
* <p>Hooked into Spring's JMX export infrastructure via a special
* {@link org.springframework.jmx.export.metadata.JmxAttributeSource} implementation.
*/
@NonNullApi
@NonNullFields
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import org.springframework.util.StringUtils;
* <p>Uses the {@link JmxAttributeSource} strategy interface, so that
* metadata can be read using any supported implementation. Out of the box,
* {@link org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource}
* introspects a well-defined set of Java 5 annotations that come with Spring.
* introspects a well-defined set of annotations that come with Spring.
*
* @author Rob Harrop
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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.
@@ -255,7 +255,7 @@ public abstract class JmxUtils {
* Determine whether the given bean class qualifies as an MBean as-is.
* <p>This implementation checks for {@link javax.management.DynamicMBean}
* classes as well as classes with corresponding "*MBean" interface
* (Standard MBeans) or corresponding "*MXBean" interface (Java 6 MXBeans).
* (Standard MBeans) or corresponding "*MXBean" interface (Java MXBeans).
* @param clazz the bean class to analyze
* @return whether the class qualifies as an MBean
* @see org.springframework.jmx.export.MBeanExporter#isMBean(Class)
@@ -289,7 +289,7 @@ public abstract class JmxUtils {
}
/**
* Return the Java 6 MXBean interface exists for the given class, if any
* Return the Java MXBean interface for the given class, if any
* (that is, an interface whose name ends with "MXBean" and/or
* carries an appropriate MXBean annotation).
* @param clazz the class to check
@@ -1,5 +1,5 @@
/**
* Java 5 annotation for asynchronous method execution.
* Annotation support for asynchronous method execution.
*/
@NonNullApi
@NonNullFields
@@ -72,6 +72,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* {@link org.springframework.scheduling.concurrent.ConcurrentTaskExecutor} adapter.
*
* @author Juergen Hoeller
* @author Rémy Guihard
* @author Sam Brannen
* @since 2.0
* @see org.springframework.core.task.TaskExecutor
* @see java.util.concurrent.ThreadPoolExecutor
@@ -155,7 +157,7 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
/**
* Set the ThreadPoolExecutor's keep-alive seconds.
* Default is 60.
* <p>Default is 60.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
public void setKeepAliveSeconds(int keepAliveSeconds) {
@@ -178,7 +180,7 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
/**
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
* Default is {@code Integer.MAX_VALUE}.
* <p>Default is {@code Integer.MAX_VALUE}.
* <p>Any positive value will lead to a LinkedBlockingQueue instance;
* any other value will lead to a SynchronousQueue instance.
* @see java.util.concurrent.LinkedBlockingQueue
@@ -188,6 +190,15 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
this.queueCapacity = queueCapacity;
}
/**
* Return the capacity for the ThreadPoolExecutor's BlockingQueue.
* @since 5.3.21
* @see #setQueueCapacity(int)
*/
public int getQueueCapacity() {
return this.queueCapacity;
}
/**
* Specify whether to allow core threads to time out. This enables dynamic
* growing and shrinking even in combination with a non-zero queue (since
@@ -316,6 +327,19 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
return this.threadPoolExecutor.getPoolSize();
}
/**
* Return the current queue size.
* @since 5.3.21
* @see java.util.concurrent.ThreadPoolExecutor#getQueue()
*/
public int getQueueSize() {
if (this.threadPoolExecutor == null) {
// Not initialized yet: assume no queued tasks.
return 0;
}
return this.threadPoolExecutor.getQueue().size();
}
/**
* Return the number of currently active threads.
* @see java.util.concurrent.ThreadPoolExecutor#getActiveCount()
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import org.springframework.lang.Nullable;
* @see ScheduledTaskRegistrar#scheduleCronTask(CronTask)
* @see ScheduledTaskRegistrar#scheduleFixedRateTask(FixedRateTask)
* @see ScheduledTaskRegistrar#scheduleFixedDelayTask(FixedDelayTask)
* @see ScheduledFuture
*/
public final class ScheduledTask {
@@ -54,11 +55,24 @@ public final class ScheduledTask {
/**
* Trigger cancellation of this scheduled task.
* <p>This variant will force interruption of the task if still running.
* @see #cancel(boolean)
*/
public void cancel() {
cancel(true);
}
/**
* Trigger cancellation of this scheduled task.
* @param mayInterruptIfRunning whether to force interruption of the task
* if still running (specify {@code false} to allow the task to complete)
* @since 5.3.18
* @see ScheduledFuture#cancel(boolean)
*/
public void cancel(boolean mayInterruptIfRunning) {
ScheduledFuture<?> future = this.future;
if (future != null) {
future.cancel(true);
future.cancel(mayInterruptIfRunning);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@@ -36,7 +36,7 @@ import org.springframework.util.StringUtils;
/**
* {@link org.springframework.scripting.ScriptFactory} implementation based
* on the JSR-223 script engine abstraction (as included in Java 6+).
* on the JSR-223 script engine abstraction (as included in Java).
* Supports JavaScript, Groovy, JRuby, and other JSR-223 compliant engines.
*
* <p>Typically used in combination with a
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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 org.springframework.lang.Nullable;
/**
* Subclass of {@link ModelMap} that implements the {@link Model} interface.
* Java 5 specific like the {@code Model} interface itself.
*
* <p>This is an implementation class exposed to handler methods by Spring MVC, typically via
* a declaration of the {@link org.springframework.ui.Model} interface. There is no need to
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,9 +22,11 @@ import java.util.Map;
import org.springframework.lang.Nullable;
/**
* Java-5-specific interface that defines a holder for model attributes.
* Primarily designed for adding attributes to the model.
* Allows for accessing the overall model as a {@code java.util.Map}.
* Interface that defines a holder for model attributes.
*
* <p>Primarily designed for adding attributes to the model.
*
* <p>Allows for accessing the overall model as a {@code java.util.Map}.
*
* @author Juergen Hoeller
* @since 2.5.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,18 +51,20 @@ import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
/**
* Binder that allows for setting property values onto a target object,
* including support for validation and binding result analysis.
* The binding process can be customized through specifying allowed fields,
* Binder that allows for setting property values on a target object, including
* support for validation and binding result analysis.
*
* <p>The binding process can be customized by specifying allowed field patterns,
* required fields, custom editors, etc.
*
* <p>Note that there are potential security implications in failing to set an array
* of allowed fields. In the case of HTTP form POST data for example, malicious clients
* can attempt to subvert an application by supplying values for fields or properties
* that do not exist on the form. In some cases this could lead to illegal data being
* set on command objects <i>or their nested objects</i>. For this reason, it is
* <b>highly recommended to specify the {@link #setAllowedFields allowedFields} property</b>
* on the DataBinder.
* <p><strong>WARNING</strong>: Data binding can lead to security issues by exposing
* parts of the object graph that are not meant to be accessed or modified by
* external clients. Therefore the design and use of data binding should be considered
* carefully with regard to security. For more details, please refer to the dedicated
* sections on data binding for
* <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-initbinder-model-design">Spring Web MVC</a> and
* <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-initbinder-model-design">Spring WebFlux</a>
* in the reference manual.
*
* <p>The binding results can be examined via the {@link BindingResult} interface,
* extending the {@link Errors} interface: see the {@link #getBindingResult()} method.
@@ -96,6 +98,7 @@ import org.springframework.util.StringUtils;
* @author Rob Harrop
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @author Sam Brannen
* @see #setAllowedFields
* @see #setRequiredFields
* @see #registerCustomEditor
@@ -418,15 +421,21 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
}
/**
* Register fields that should be allowed for binding. Default is all fields.
* Restrict this for example to avoid unwanted modifications by malicious
* Register field patterns that should be allowed for binding.
* <p>Default is all fields.
* <p>Restrict this for example to avoid unwanted modifications by malicious
* users when binding HTTP request parameters.
* <p>Supports "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
* arbitrary number of pattern parts), as well as direct equality. More
* sophisticated matching can be implemented by overriding the
* {@code isAllowed} method.
* <p>Alternatively, specify a list of <i>disallowed</i> fields.
* @param allowedFields array of field names
* <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
* well as direct equality.
* <p>The default implementation of this method stores allowed field patterns
* in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
* form. Subclasses which override this method must therefore take this into
* account.
* <p>More sophisticated matching can be implemented by overriding the
* {@link #isAllowed} method.
* <p>Alternatively, specify a list of <i>disallowed</i> field patterns.
* @param allowedFields array of allowed field patterns
* @see #setDisallowedFields
* @see #isAllowed(String)
*/
@@ -435,8 +444,9 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
}
/**
* Return the fields that should be allowed for binding.
* @return array of field names
* Return the field patterns that should be allowed for binding.
* @return array of allowed field patterns
* @see #setAllowedFields(String...)
*/
@Nullable
public String[] getAllowedFields() {
@@ -444,25 +454,44 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
}
/**
* Register fields that should <i>not</i> be allowed for binding. Default
* is none. Mark fields as disallowed for example to avoid unwanted
* Register field patterns that should <i>not</i> be allowed for binding.
* <p>Default is none.
* <p>Mark fields as disallowed, for example to avoid unwanted
* modifications by malicious users when binding HTTP request parameters.
* <p>Supports "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
* arbitrary number of pattern parts), as well as direct equality.
* More sophisticated matching can be implemented by overriding the
* {@code isAllowed} method.
* <p>Alternatively, specify a list of <i>allowed</i> fields.
* @param disallowedFields array of field names
* <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
* well as direct equality.
* <p>The default implementation of this method stores disallowed field patterns
* in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
* form. As of Spring Framework 5.2.21, the default implementation also transforms
* disallowed field patterns to {@linkplain String#toLowerCase() lowercase} to
* support case-insensitive pattern matching in {@link #isAllowed}. Subclasses
* which override this method must therefore take both of these transformations
* into account.
* <p>More sophisticated matching can be implemented by overriding the
* {@link #isAllowed} method.
* <p>Alternatively, specify a list of <i>allowed</i> field patterns.
* @param disallowedFields array of disallowed field patterns
* @see #setAllowedFields
* @see #isAllowed(String)
*/
public void setDisallowedFields(@Nullable String... disallowedFields) {
this.disallowedFields = PropertyAccessorUtils.canonicalPropertyNames(disallowedFields);
if (disallowedFields == null) {
this.disallowedFields = null;
}
else {
String[] fieldPatterns = new String[disallowedFields.length];
for (int i = 0; i < fieldPatterns.length; i++) {
fieldPatterns[i] = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]).toLowerCase();
}
this.disallowedFields = fieldPatterns;
}
}
/**
* Return the fields that should <i>not</i> be allowed for binding.
* @return array of field names
* Return the field patterns that should <i>not</i> be allowed for binding.
* @return array of disallowed field patterns
* @see #setDisallowedFields(String...)
*/
@Nullable
public String[] getDisallowedFields() {
@@ -774,16 +803,20 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
}
/**
* Return if the given field is allowed for binding.
* Invoked for each passed-in property value.
* <p>The default implementation checks for "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
* matches (with an arbitrary number of pattern parts), as well as direct equality,
* in the specified lists of allowed fields and disallowed fields. A field matching
* a disallowed pattern will not be accepted even if it also happens to match a
* pattern in the allowed list.
* <p>Can be overridden in subclasses.
* Determine if the given field is allowed for binding.
* <p>Invoked for each passed-in property value.
* <p>Checks for {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
* well as direct equality, in the configured lists of allowed field patterns
* and disallowed field patterns.
* <p>Matching against allowed field patterns is case-sensitive; whereas,
* matching against disallowed field patterns is case-insensitive.
* <p>A field matching a disallowed pattern will not be accepted even if it
* also happens to match a pattern in the allowed list.
* <p>Can be overridden in subclasses, but care must be taken to honor the
* aforementioned contract.
* @param field the field to check
* @return if the field is allowed
* @return {@code true} if the field is allowed
* @see #setAllowedFields
* @see #setDisallowedFields
* @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
@@ -792,7 +825,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
String[] allowed = getAllowedFields();
String[] disallowed = getDisallowedFields();
return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field)));
(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field.toLowerCase())));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Consumer;
import javax.validation.Configuration;
import javax.validation.ConstraintValidatorFactory;
@@ -113,6 +114,9 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
private final Map<String, String> validationPropertyMap = new HashMap<>();
@Nullable
private Consumer<Configuration<?>> configurationInitializer;
@Nullable
private ApplicationContext applicationContext;
@@ -234,6 +238,18 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
return this.validationPropertyMap;
}
/**
* Specify a callback for customizing the Bean Validation {@code Configuration} instance,
* as an alternative to overriding the {@link #postProcessConfiguration(Configuration)}
* method in custom {@code LocalValidatorFactoryBean} subclasses.
* <p>This enables convenient customizations for application purposes. Infrastructure
* extensions may keep overriding the {@link #postProcessConfiguration} template method.
* @since 5.3.19
*/
public void setConfigurationInitializer(Consumer<Configuration<?>> configurationInitializer) {
this.configurationInitializer = configurationInitializer;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
@@ -312,6 +328,9 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
this.validationPropertyMap.forEach(configuration::addProperty);
// Allow for custom post-processing before we actually build the ValidatorFactory.
if (this.configurationInitializer != null) {
this.configurationInitializer.accept(configuration);
}
postProcessConfiguration(configuration);
try {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -37,7 +38,9 @@ import static org.mockito.Mockito.verify;
* @author Rod Johnson
* @author Chris Beams
*/
public class AfterAdviceBindingTests {
class AfterAdviceBindingTests {
private ClassPathXmlApplicationContext ctx;
private AdviceBindingCollaborator mockCollaborator;
@@ -47,9 +50,8 @@ public class AfterAdviceBindingTests {
@BeforeEach
public void setup() throws Exception {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() throws Exception {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
AdviceBindingTestAspect afterAdviceAspect = (AdviceBindingTestAspect) ctx.getBean("testAspect");
testBeanProxy = (ITestBean) ctx.getBean("testBean");
@@ -62,39 +64,44 @@ public class AfterAdviceBindingTests {
afterAdviceAspect.setCollaborator(mockCollaborator);
}
@AfterEach
void tearDown() throws Exception {
this.ctx.close();
}
@Test
public void testOneIntArg() {
void oneIntArg() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntArg(5);
}
@Test
public void testOneObjectArgBindingProxyWithThis() {
void oneObjectArgBindingProxyWithThis() {
testBeanProxy.getAge();
verify(mockCollaborator).oneObjectArg(this.testBeanProxy);
}
@Test
public void testOneObjectArgBindingTarget() {
void oneObjectArgBindingTarget() {
testBeanProxy.getDoctor();
verify(mockCollaborator).oneObjectArg(this.testBeanTarget);
}
@Test
public void testOneIntAndOneObjectArgs() {
void oneIntAndOneObjectArgs() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntAndOneObject(5,this.testBeanProxy);
}
@Test
public void testNeedsJoinPoint() {
void needsJoinPoint() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPoint("getAge");
}
@Test
public void testNeedsJoinPointStaticPart() {
void needsJoinPointStaticPart() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPointStaticPart("getAge");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -39,7 +40,9 @@ import static org.mockito.Mockito.verifyNoInteractions;
* @author Juergen Hoeller
* @author Chris Beams
*/
public class AfterReturningAdviceBindingTests {
class AfterReturningAdviceBindingTests {
private ClassPathXmlApplicationContext ctx;
private AfterReturningAdviceBindingTestAspect afterAdviceAspect;
@@ -51,9 +54,8 @@ public class AfterReturningAdviceBindingTests {
@BeforeEach
public void setup() throws Exception {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() throws Exception {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
afterAdviceAspect = (AfterReturningAdviceBindingTestAspect) ctx.getBean("testAspect");
@@ -67,58 +69,63 @@ public class AfterReturningAdviceBindingTests {
this.testBeanTarget = (TestBean) ((Advised)testBeanProxy).getTargetSource().getTarget();
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testOneIntArg() {
void oneIntArg() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntArg(5);
}
@Test
public void testOneObjectArg() {
void oneObjectArg() {
testBeanProxy.getAge();
verify(mockCollaborator).oneObjectArg(this.testBeanProxy);
}
@Test
public void testOneIntAndOneObjectArgs() {
void oneIntAndOneObjectArgs() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntAndOneObject(5,this.testBeanProxy);
}
@Test
public void testNeedsJoinPoint() {
void needsJoinPoint() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPoint("getAge");
}
@Test
public void testNeedsJoinPointStaticPart() {
void needsJoinPointStaticPart() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPointStaticPart("getAge");
}
@Test
public void testReturningString() {
void returningString() {
testBeanProxy.setName("adrian");
testBeanProxy.getName();
verify(mockCollaborator).oneString("adrian");
}
@Test
public void testReturningObject() {
void returningObject() {
testBeanProxy.returnsThis();
verify(mockCollaborator).oneObjectArg(this.testBeanTarget);
}
@Test
public void testReturningBean() {
void returningBean() {
testBeanProxy.returnsThis();
verify(mockCollaborator).oneTestBeanArg(this.testBeanTarget);
}
@Test
public void testReturningBeanArray() {
void returningBeanArray() {
this.testBeanTarget.setSpouse(new TestBean());
ITestBean[] spouses = this.testBeanTarget.getSpouses();
testBeanProxy.getSpouses();
@@ -126,20 +133,20 @@ public class AfterReturningAdviceBindingTests {
}
@Test
public void testNoInvokeWhenReturningParameterTypeDoesNotMatch() {
void noInvokeWhenReturningParameterTypeDoesNotMatch() {
testBeanProxy.setSpouse(this.testBeanProxy);
testBeanProxy.getSpouse();
verifyNoInteractions(mockCollaborator);
}
@Test
public void testReturningByType() {
void returningByType() {
testBeanProxy.returnsThis();
verify(mockCollaborator).objectMatchNoArgs();
}
@Test
public void testReturningPrimitive() {
void returningPrimitive() {
testBeanProxy.setAge(20);
testBeanProxy.haveBirthday();
verify(mockCollaborator).oneInt(20);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -33,7 +34,9 @@ import static org.mockito.Mockito.verify;
* @author Adrian Colyer
* @author Chris Beams
*/
public class AfterThrowingAdviceBindingTests {
class AfterThrowingAdviceBindingTests {
private ClassPathXmlApplicationContext ctx;
private ITestBean testBean;
@@ -43,9 +46,8 @@ public class AfterThrowingAdviceBindingTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
testBean = (ITestBean) ctx.getBean("testBean");
afterThrowingAdviceAspect = (AfterThrowingAdviceBindingTestAspect) ctx.getBean("testAspect");
@@ -54,16 +56,21 @@ public class AfterThrowingAdviceBindingTests {
afterThrowingAdviceAspect.setCollaborator(mockCollaborator);
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testSimpleAfterThrowing() throws Throwable {
void simpleAfterThrowing() throws Throwable {
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(new Throwable()));
verify(mockCollaborator).noArgs();
}
@Test
public void testAfterThrowingWithBinding() throws Throwable {
void afterThrowingWithBinding() throws Throwable {
Throwable t = new Throwable();
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(t));
@@ -71,7 +78,7 @@ public class AfterThrowingAdviceBindingTests {
}
@Test
public void testAfterThrowingWithNamedTypeRestriction() throws Throwable {
void afterThrowingWithNamedTypeRestriction() throws Throwable {
Throwable t = new Throwable();
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(t));
@@ -81,7 +88,7 @@ public class AfterThrowingAdviceBindingTests {
}
@Test
public void testAfterThrowingWithRuntimeExceptionBinding() throws Throwable {
void afterThrowingWithRuntimeExceptionBinding() throws Throwable {
RuntimeException ex = new RuntimeException();
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(ex));
@@ -89,14 +96,14 @@ public class AfterThrowingAdviceBindingTests {
}
@Test
public void testAfterThrowingWithTypeSpecified() throws Throwable {
void afterThrowingWithTypeSpecified() throws Throwable {
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(new Throwable()));
verify(mockCollaborator).noArgsOnThrowableMatch();
}
@Test
public void testAfterThrowingWithRuntimeTypeSpecified() throws Throwable {
void afterThrowingWithRuntimeTypeSpecified() throws Throwable {
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
this.testBean.exceptional(new RuntimeException()));
verify(mockCollaborator).noArgsOnRuntimeExceptionMatch();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -33,7 +34,9 @@ import org.springframework.lang.Nullable;
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectAndAdvicePrecedenceTests {
class AspectAndAdvicePrecedenceTests {
private ClassPathXmlApplicationContext ctx;
private PrecedenceTestAspect highPrecedenceAspect;
@@ -47,9 +50,8 @@ public class AspectAndAdvicePrecedenceTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
highPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("highPrecedenceAspect");
lowPrecedenceAspect = (PrecedenceTestAspect) ctx.getBean("lowPrecedenceAspect");
highPrecedenceSpringAdvice = (SimpleSpringBeforeAdvice) ctx.getBean("highPrecedenceSpringAdvice");
@@ -57,9 +59,14 @@ public class AspectAndAdvicePrecedenceTests {
testBean = (ITestBean) ctx.getBean("testBean");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testAdviceOrder() {
void testAdviceOrder() {
PrecedenceTestAspect.Collaborator collaborator = new PrecedenceVerifyingCollaborator();
this.highPrecedenceAspect.setCollaborator(collaborator);
this.lowPrecedenceAspect.setCollaborator(collaborator);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.springframework.aop.aspectj;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.ITestBean;
@@ -31,29 +30,22 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Juergen Hoeller
* @author Chris Beams
*/
public class AspectJExpressionPointcutAdvisorTests {
private ITestBean testBean;
private CallCountingInterceptor interceptor;
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
testBean = (ITestBean) ctx.getBean("testBean");
interceptor = (CallCountingInterceptor) ctx.getBean("interceptor");
}
class AspectJExpressionPointcutAdvisorTests {
@Test
public void testPointcutting() {
assertThat(interceptor.getCount()).as("Count should be 0").isEqualTo(0);
void pointcutting() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
ITestBean testBean = ctx.getBean("testBean", ITestBean.class);
CallCountingInterceptor interceptor = ctx.getBean("interceptor", CallCountingInterceptor.class);
assertThat(interceptor.getCount()).as("Count").isEqualTo(0);
testBean.getSpouses();
assertThat(interceptor.getCount()).as("Count should be 1").isEqualTo(1);
assertThat(interceptor.getCount()).as("Count").isEqualTo(1);
testBean.getSpouse();
assertThat(interceptor.getCount()).as("Count should be 1").isEqualTo(1);
assertThat(interceptor.getCount()).as("Count").isEqualTo(1);
ctx.close();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
@@ -35,7 +37,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Juergen Hoeller
* @author Chris Beams
*/
public class BeanNamePointcutAtAspectTests {
class BeanNamePointcutAtAspectTests {
private ClassPathXmlApplicationContext ctx;
private ITestBean testBean1;
@@ -44,19 +48,24 @@ public class BeanNamePointcutAtAspectTests {
private CounterAspect counterAspect;
@org.junit.jupiter.api.BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
@BeforeEach
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
counterAspect = (CounterAspect) ctx.getBean("counterAspect");
testBean1 = (ITestBean) ctx.getBean("testBean1");
testBean3 = (ITestBean) ctx.getBean("testBean3");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testMatchingBeanName() {
void matchingBeanName() {
boolean condition = testBean1 instanceof Advised;
assertThat(condition).as("Expected a proxy").isTrue();
@@ -67,7 +76,7 @@ public class BeanNamePointcutAtAspectTests {
}
@Test
public void testNonMatchingBeanName() {
void nonMatchingBeanName() {
boolean condition = testBean3 instanceof Advised;
assertThat(condition).as("Didn't expect a proxy").isFalse();
@@ -76,7 +85,7 @@ public class BeanNamePointcutAtAspectTests {
}
@Test
public void testProgrammaticProxyCreation() {
void programmaticProxyCreation() {
ITestBean testBean = new TestBean();
AspectJProxyFactory factory = new AspectJProxyFactory();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -37,7 +38,9 @@ import static org.mockito.Mockito.verify;
* @author Rod Johnson
* @author Chris Beams
*/
public class BeforeAdviceBindingTests {
class BeforeAdviceBindingTests {
private ClassPathXmlApplicationContext ctx;
private AdviceBindingCollaborator mockCollaborator;
@@ -47,9 +50,8 @@ public class BeforeAdviceBindingTests {
@BeforeEach
public void setup() throws Exception {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() throws Exception {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
testBeanProxy = (ITestBean) ctx.getBean("testBean");
assertThat(AopUtils.isAopProxy(testBeanProxy)).isTrue();
@@ -63,38 +65,43 @@ public class BeforeAdviceBindingTests {
beforeAdviceAspect.setCollaborator(mockCollaborator);
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testOneIntArg() {
void oneIntArg() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntArg(5);
}
@Test
public void testOneObjectArgBoundToProxyUsingThis() {
void oneObjectArgBoundToProxyUsingThis() {
testBeanProxy.getAge();
verify(mockCollaborator).oneObjectArg(this.testBeanProxy);
}
@Test
public void testOneIntAndOneObjectArgs() {
void oneIntAndOneObjectArgs() {
testBeanProxy.setAge(5);
verify(mockCollaborator).oneIntAndOneObject(5,this.testBeanTarget);
}
@Test
public void testNeedsJoinPoint() {
void needsJoinPoint() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPoint("getAge");
}
@Test
public void testNeedsJoinPointStaticPart() {
void needsJoinPointStaticPart() {
testBeanProxy.getAge();
verify(mockCollaborator).needsJoinPointStaticPart("getAge");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj;
import java.io.Serializable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -31,7 +32,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Adrian Colyer
* @author Chris Beams
*/
public class DeclarationOrderIndependenceTests {
class DeclarationOrderIndependenceTests {
private ClassPathXmlApplicationContext ctx;
private TopsyTurvyAspect aspect;
@@ -39,28 +42,32 @@ public class DeclarationOrderIndependenceTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
aspect = (TopsyTurvyAspect) ctx.getBean("topsyTurvyAspect");
target = (TopsyTurvyTarget) ctx.getBean("topsyTurvyTarget");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testTargetIsSerializable() {
void testTargetIsSerializable() {
boolean condition = this.target instanceof Serializable;
assertThat(condition).as("target bean is serializable").isTrue();
}
@Test
public void testTargetIsBeanNameAware() {
void testTargetIsBeanNameAware() {
boolean condition = this.target instanceof BeanNameAware;
assertThat(condition).as("target bean is bean name aware").isTrue();
}
@Test
public void testBeforeAdviceFiringOk() {
void testBeforeAdviceFiringOk() {
AspectCollaborator collab = new AspectCollaborator();
this.aspect.setCollaborator(collab);
this.target.doSomething();
@@ -68,7 +75,7 @@ public class DeclarationOrderIndependenceTests {
}
@Test
public void testAroundAdviceFiringOk() {
void testAroundAdviceFiringOk() {
AspectCollaborator collab = new AspectCollaborator();
this.aspect.setCollaborator(collab);
this.target.getX();
@@ -76,7 +83,7 @@ public class DeclarationOrderIndependenceTests {
}
@Test
public void testAfterReturningFiringOk() {
void testAfterReturningFiringOk() {
AspectCollaborator collab = new AspectCollaborator();
this.aspect.setCollaborator(collab);
this.target.getX();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -27,31 +28,35 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Ramnivas Laddad
* @author Chris Beams
*/
public class DeclareParentsDelegateRefTests {
class DeclareParentsDelegateRefTests {
protected NoMethodsBean noMethodsBean;
private ClassPathXmlApplicationContext ctx;
protected Counter counter;
private NoMethodsBean noMethodsBean;
private Counter counter;
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
noMethodsBean = (NoMethodsBean) ctx.getBean("noMethodsBean");
counter = (Counter) ctx.getBean("counter");
counter.reset();
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testIntroductionWasMade() {
boolean condition = noMethodsBean instanceof ICounter;
assertThat(condition).as("Introduction must have been made").isTrue();
void introductionWasMade() {
assertThat(noMethodsBean).as("Introduction must have been made").isInstanceOf(ICounter.class);
}
@Test
public void testIntroductionDelegation() {
void introductionDelegation() {
((ICounter)noMethodsBean).increment();
assertThat(counter.getCount()).as("Delegate's counter should be updated").isEqualTo(1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.aop.aspectj;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.mixin.Lockable;
@@ -31,7 +32,9 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Rod Johnson
* @author Chris Beams
*/
public class DeclareParentsTests {
class DeclareParentsTests {
private ClassPathXmlApplicationContext ctx;
private ITestBean testBeanProxy;
@@ -39,20 +42,23 @@ public class DeclareParentsTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
testBeanProxy = (ITestBean) ctx.getBean("testBean");
introductionObject = ctx.getBean("introduction");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testIntroductionWasMade() {
void introductionWasMade() {
assertThat(AopUtils.isAopProxy(testBeanProxy)).isTrue();
assertThat(AopUtils.isAopProxy(introductionObject)).as("Introduction should not be proxied").isFalse();
boolean condition = testBeanProxy instanceof Lockable;
assertThat(condition).as("Introduction must have been made").isTrue();
assertThat(testBeanProxy).as("Introduction must have been made").isInstanceOf(Lockable.class);
}
// TODO if you change type pattern from org.springframework.beans..*
@@ -60,7 +66,7 @@ public class DeclareParentsTests {
// Perhaps generated advisor bean definition could be made to depend
// on the introduction, in which case this would not be a problem.
@Test
public void testLockingWorks() {
void lockingWorks() {
Lockable lockable = (Lockable) testBeanProxy;
assertThat(lockable.locked()).isFalse();
@@ -69,8 +75,7 @@ public class DeclareParentsTests {
testBeanProxy.setName("");
lockable.lock();
assertThatIllegalStateException().as("should be locked").isThrownBy(() ->
testBeanProxy.setName(" "));
assertThatIllegalStateException().as("should be locked").isThrownBy(() -> testBeanProxy.setName(" "));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2022 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,10 +28,11 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
* @author Ramnivas Laddad
* @author Chris Beams
*/
public class ImplicitJPArgumentMatchingTests {
class ImplicitJPArgumentMatchingTests {
@Test
public void testAspect() {
@SuppressWarnings("resource")
void testAspect() {
// nothing to really test; it is enough if we don't get error while creating app context
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for overloaded advice.
@@ -29,32 +29,26 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Adrian Colyer
* @author Chris Beams
*/
public class OverloadedAdviceTests {
class OverloadedAdviceTests {
@Test
public void testExceptionOnConfigParsingWithMismatchedAdviceMethod() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
}
catch (BeanCreationException ex) {
Throwable cause = ex.getRootCause();
boolean condition = cause instanceof IllegalArgumentException;
assertThat(condition).as("Should be IllegalArgumentException").isTrue();
assertThat(cause.getMessage().contains("invalidAbsoluteTypeName")).as("invalidAbsoluteTypeName should be detected by AJ").isTrue();
}
@SuppressWarnings("resource")
void testExceptionOnConfigParsingWithMismatchedAdviceMethod() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass()))
.havingRootCause()
.isInstanceOf(IllegalArgumentException.class)
.as("invalidAbsoluteTypeName should be detected by AJ").withMessageContaining("invalidAbsoluteTypeName");
}
@Test
public void testExceptionOnConfigParsingWithAmbiguousAdviceMethod() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ambiguous.xml", getClass());
}
catch (BeanCreationException ex) {
Throwable cause = ex.getRootCause();
boolean condition = cause instanceof IllegalArgumentException;
assertThat(condition).as("Should be IllegalArgumentException").isTrue();
assertThat(cause.getMessage().contains("Cannot resolve method 'myBeforeAdvice' to a unique method")).as("Cannot resolve method 'myBeforeAdvice' to a unique method").isTrue();
}
@SuppressWarnings("resource")
void testExceptionOnConfigParsingWithAmbiguousAdviceMethod() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ambiguous.xml", getClass()))
.havingRootCause()
.isInstanceOf(IllegalArgumentException.class)
.withMessageContaining("Cannot resolve method 'myBeforeAdvice' to a unique method");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -33,7 +34,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Adrian Colyer
* @author Chris Beams
*/
public class ProceedTests {
class ProceedTests {
private ClassPathXmlApplicationContext ctx;
private SimpleBean testBean;
@@ -43,43 +46,46 @@ public class ProceedTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
testBean = (SimpleBean) ctx.getBean("testBean");
firstTestAspect = (ProceedTestingAspect) ctx.getBean("firstTestAspect");
secondTestAspect = (ProceedTestingAspect) ctx.getBean("secondTestAspect");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testSimpleProceedWithChangedArgs() {
void testSimpleProceedWithChangedArgs() {
this.testBean.setName("abc");
assertThat(this.testBean.getName()).as("Name changed in around advice").isEqualTo("ABC");
}
@Test
public void testGetArgsIsDefensive() {
void testGetArgsIsDefensive() {
this.testBean.setAge(5);
assertThat(this.testBean.getAge()).as("getArgs is defensive").isEqualTo(5);
}
@Test
public void testProceedWithArgsInSameAspect() {
void testProceedWithArgsInSameAspect() {
this.testBean.setMyFloat(1.0F);
assertThat(this.testBean.getMyFloat() > 1.9F).as("value changed in around advice").isTrue();
assertThat(this.firstTestAspect.getLastBeforeFloatValue() > 1.9F).as("changed value visible to next advice in chain").isTrue();
}
@Test
public void testProceedWithArgsAcrossAspects() {
void testProceedWithArgsAcrossAspects() {
this.testBean.setSex("male");
assertThat(this.testBean.getSex()).as("value changed in around advice").isEqualTo("MALE");
assertThat(this.secondTestAspect.getLastBeforeStringValue()).as("changed value visible to next before advice in chain").isEqualTo("MALE");
assertThat(this.secondTestAspect.getLastAroundStringValue()).as("changed value visible to next around advice in chain").isEqualTo("MALE");
}
}
@@ -214,4 +220,3 @@ class ProceedTestingAspect implements Ordered {
return this.lastBeforeFloatValue;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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,53 +16,52 @@
package org.springframework.aop.aspectj;
import org.junit.jupiter.api.BeforeEach;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* See SPR-1682.
*
* @author Adrian Colyer
* @author Chris Beams
* @author Sam Brannen
*/
public class SharedPointcutWithArgsMismatchTests {
class SharedPointcutWithArgsMismatchTests {
private ToBeAdvised toBeAdvised;
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
toBeAdvised = (ToBeAdvised) ctx.getBean("toBeAdvised");
}
private static final List<String> messages = new ArrayList<>();
@Test
public void testMismatchedArgBinding() {
this.toBeAdvised.foo("Hello");
void mismatchedArgBinding() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
ToBeAdvised toBeAdvised = ctx.getBean(ToBeAdvised.class);
toBeAdvised.foo("test");
assertThat(messages).containsExactly("doBefore(String): test", "foo(String): test");
ctx.close();
}
static class ToBeAdvised {
public void foo(String s) {
messages.add("foo(String): " + s);
}
}
static class MyAspect {
public void doBefore(int x) {
messages.add("doBefore(int): " + x);
}
public void doBefore(String x) {
messages.add("doBefore(String): " + x);
}
}
}
class ToBeAdvised {
public void foo(String s) {
System.out.println(s);
}
}
class MyAspect {
public void doBefore(int x) {
System.out.println(x);
}
public void doBefore(String x) {
System.out.println(x);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj;
import java.io.Serializable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -30,7 +31,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Adrian Colyer
* @author Chris Beams
*/
public class SubtypeSensitiveMatchingTests {
class SubtypeSensitiveMatchingTests {
private ClassPathXmlApplicationContext ctx;
private NonSerializableFoo nonSerializableBean;
@@ -40,31 +43,38 @@ public class SubtypeSensitiveMatchingTests {
@BeforeEach
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
void setup() {
this.ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
nonSerializableBean = (NonSerializableFoo) ctx.getBean("testClassA");
serializableBean = (SerializableFoo) ctx.getBean("testClassB");
bar = (Bar) ctx.getBean("testClassC");
}
@AfterEach
void tearDown() {
this.ctx.close();
}
@Test
public void testBeansAreProxiedOnStaticMatch() {
boolean condition = this.serializableBean instanceof Advised;
assertThat(condition).as("bean with serializable type should be proxied").isTrue();
void beansAreProxiedOnStaticMatch() {
assertThat(this.serializableBean)
.as("bean with serializable type should be proxied")
.isInstanceOf(Advised.class);
}
@Test
public void testBeansThatDoNotMatchBasedSolelyOnRuntimeTypeAreNotProxied() {
boolean condition = this.nonSerializableBean instanceof Advised;
assertThat(condition).as("bean with non-serializable type should not be proxied").isFalse();
void beansThatDoNotMatchBasedSolelyOnRuntimeTypeAreNotProxied() {
assertThat(this.nonSerializableBean)
.as("bean with non-serializable type should not be proxied")
.isNotInstanceOf(Advised.class);
}
@Test
public void testBeansThatDoNotMatchBasedOnOtherTestAreProxied() {
boolean condition = this.bar instanceof Advised;
assertThat(condition).as("bean with args check should be proxied").isTrue();
void beansThatDoNotMatchBasedOnOtherTestAreProxied() {
assertThat(this.bar)
.as("bean with args check should be proxied")
.isInstanceOf(Advised.class);
}
}

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