Compare commits

...

193 Commits

Author SHA1 Message Date
Spring Builds b02f4a06ca Release v5.3.28 2023-06-15 07:19:13 +00:00
Juergen Hoeller 99ae6e70bb Declare ClassLoader for DeserializingConverter constructor as nullable
Closes gh-30670

(cherry picked from commit b9221656cc)
2023-06-14 22:34:28 +02:00
Juergen Hoeller c2cc55eacc Consider UUID as simple value type with concise toString output
Closes gh-30661

(cherry picked from commit 927d27b121)
2023-06-14 10:47:54 +02:00
Juergen Hoeller 9cff2ace97 Upgrade to Reactor 2020.0.33
Closes gh-30656
2023-06-13 18:40:46 +02:00
Juergen Hoeller 3c2590d339 Document limited isolation level support for concurrent transactions
See gh-29997
2023-06-13 12:57:52 +02:00
Juergen Hoeller 4b55333b0e Document which @Scheduled attributes support SpEL expressions
Closes gh-29290

(cherry picked from commit f8c8873c99)
2023-06-12 13:08:02 +02:00
Juergen Hoeller c27acad616 Specific check for parent of MethodInvocationInfo ClassLoader
See gh-30389
2023-06-12 11:33:54 +02:00
Juergen Hoeller 70be9afdc6 Reuse method cache from original proxy factory (aligned with 6.0.x)
See gh-30616
2023-06-12 11:11:07 +02:00
Juergen Hoeller d4450a8702 Specific check for parent of spring-aop ClassLoader
Closes gh-30389

(cherry picked from commit 0a5aff1b60)
2023-06-12 11:08:37 +02:00
Juergen Hoeller 210e47d65e Polishing 2023-06-08 18:31:31 +02:00
Juergen Hoeller 06411831e8 Consistent ProxyCallbackFilter#equals/hashCode methods
Opaque check in equals instead; no consideration of optimize flag.

Closes gh-30616
2023-06-08 18:31:26 +02:00
Juergen Hoeller 8c7daa807a Polishing 2023-06-07 20:14:41 +02:00
Juergen Hoeller 46d171a8fd Restore creation of plain HashSet/HashMap for direct HashSet/HashMap type
Closes gh-30596

(cherry picked from commit cdc4497664)
2023-06-05 14:03:15 +02:00
Juergen Hoeller 259bd5250d Consistent javadoc references to JdbcTransactionManager 2023-06-05 11:12:38 +02:00
Juergen Hoeller cef046218c Upgrade to Tomcat 9.0.75, Netty 4.1.93, Undertow 2.2.24, EclipseLink 2.7.12 2023-06-04 18:13:00 +02:00
Juergen Hoeller e4bd1344e2 Set and reset shared isolation value within synchronized transaction begin
Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to immediately restore the original value after the current value got picked up for JDBC Connection access inside of EclipseLink. In order to not interfere with concurrent transactions, we need to use synchronization around the transaction begin sequence in such a case.

Closes gh-29997
2023-06-04 18:12:40 +02:00
Juergen Hoeller 9decbf2158 Polishing 2023-06-03 00:01:18 +02:00
Juergen Hoeller 268b7a8931 Revise TargetSource implementations for proper nullability
Includes hashCode optimization in AbstractBeanFactoryBasedTargetSource.
Includes ThreadLocal naming fix in ThreadLocalTargetSource.

Closes gh-30576
Closes gh-30581

(cherry picked from commit c68552556f)
2023-06-02 23:48:41 +02:00
Juergen Hoeller 1240fb6b9a Consistently publish events from CompletableFuture
Closes gh-30578

(cherry picked from commit b738a20233)
2023-06-02 23:36:13 +02:00
Brian Clozel 7dae3afb4b Resolve Asciidoctor extensions from Central
This commit upgrades spring-asciidoctor-extensions-block-switch to 0.6.1
as this version is available on Maven Central.
2023-05-30 09:49:23 +02:00
Stephane Nicoll d9de36b5ee Merge branch 'gh-30555' into 5.3.x
Closes gh-30555
2023-05-30 09:18:41 +02:00
Stephane Nicoll 4e696db922 Update copyright year of changed file
See gh-30554
2023-05-30 09:18:06 +02:00
Stefano Cordio 0adad10595 Fix FileSystemUtils::deleteRecursively Javadoc
See gh-30554
2023-05-30 09:17:54 +02:00
Juergen Hoeller 540d0d9345 Avoid Autowired shortcut resolution for NullBean values
Includes getBean documentation against NullBean values.

Closes gh-30485

(cherry picked from commit 8b8d147480)
2023-05-26 11:16:09 +02:00
Brian Clozel 572bbeeba3 Use spring-doc-resources SNAPSHOT version 2023-05-25 20:04:08 +02:00
Brian Clozel 77cd44dd20 Update CI pipeline 2023-05-25 19:13:58 +02:00
rstoyanchev 65e7b4a279 Add ignore rule for cached-antora-playbook.yml
In case of checking out the 5.3.x branch after 6.0.x or main
2023-05-23 15:14:01 +01:00
Sam Brannen 7d95a24573 Make maximum SpEL expression length configurable
Closes gh-30446
2023-05-10 15:12:36 +02:00
Juergen Hoeller 1dbe0ee6db Respect TaskDecorator configuration on DefaultManagedTaskExecutor
Closes gh-30442
2023-05-08 12:18:53 +02:00
Juergen Hoeller 0211016957 Consistent support for MultiValueMap and common Map implementations
Closes gh-30440
2023-05-08 12:13:44 +02:00
Sam Brannen 08fe123930 Introduce Environment.matchesProfiles() for profile expressions
Environment.acceptsProfiles(String...) was deprecated in 5.1 in
conjunction with gh-17063 which introduced a new
acceptsProfiles(Profiles) method to replace it. The deprecated method
only supports OR semantics; whereas, the new method supports profile
expressions. Thus, the goal was to encourage people to use the more
powerful profile expressions instead of the limited OR support with
profile names.

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

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

See gh-30206
Closes gh-30226
2023-04-25 19:19:22 +02:00
Sam Brannen 219448796f Polish Environment and StandardEnvironmentTests
See gh-30206
See gh-30226
2023-04-25 19:19:03 +02:00
Sam Brannen 0956c144c9 Polish ProfilesParser internals 2023-04-25 18:56:08 +02:00
Sam Brannen 964950a8b9 Reject null and empty SpEL expressions
Prior to gh-30325, supplying a null reference for a SpEL expression was
effectively equivalent to supplying the String "null" as the
expression. Consequently, evaluation of a null reference expression
always evaluated to a null reference. However, that was accidental
rather than by design.

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

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

See gh-30371
Closes gh-30373
2023-04-25 14:31:35 +02:00
Sam Brannen 5afd94f90f Polish SpelParserTests and TemplateExpressionParsingTests 2023-04-25 14:29:01 +02:00
Arjen Poutsma ec5f7644e4 Updated CI image JDK 2023-04-24 13:00:06 +02:00
Arjen Poutsma 0c8ef4c671 Updated sdkmanrc 2023-04-24 12:37:15 +02:00
Spring Builds a851b7309a Next development version (v5.3.28-SNAPSHOT) 2023-04-13 08:57:10 +00:00
Sam Brannen 6bfb94a563 Disable variable assignment in SimpleEvaluationContext
This commit introduces infrastructure to differentiate between
programmatic setting of a variable in an EvaluationContext versus the
assignment of a variable within a SpEL expression using the assignment
operator (=). In addition, this commit disables variable assignment
within expressions when using the SimpleEvaluationContext.

Closes gh-30327
2023-04-13 10:20:06 +02:00
Sam Brannen ebc8265428 Limit SpEL expression length
This commit enforces a limit of the maximum size of a single SpEL
expression.

Closes gh-30329
2023-04-13 10:15:02 +02:00
Sam Brannen 86457464d7 Limit string concatenation in SpEL expressions
This commit introduces support for limiting the maximum length of a
string resulting from the concatenation operator (+) in SpEL
expressions.

Closes gh-30331
2023-04-13 10:14:18 +02:00
Sam Brannen be129dc171 Change max regex length in SpEL expressions to 1000
This commit changes the max regex length in SpEL expressions from 1024
to 1000 in order to consistently use "round" numbers for recently
introduced limits.

See gh-30265
2023-04-13 10:14:15 +02:00
Juergen Hoeller 8bb1b3eb44 Upgrade to Netty 4.1.91 and Checkstyle 10.9.3 2023-04-12 13:53:17 +02:00
Stephane Nicoll 6abd822e77 Upgrade to Reactor 2020.0.31
Closes gh-30315
2023-04-11 17:35:25 +02:00
rstoyanchev 1c43a4c7ab Fix regression in ReactorServerHttpRequest
Instead of a backport for cef916, this change simply undoes the
optimization that led to the regression.

Closes gh-30314
2023-04-11 15:12:54 +01:00
Sam Brannen 423f2215c2 Remove flaky assertion to fix build on JDK 17
Sometime between JDK 8 and JDK 17, the behavior for List::toArray()
changed. Specifically, the type returned for List<String> changed from
String[] to Object[].

This commit therefore removes an assertion against this particular
JDK-specific behavior. The affected test method retains additional
assertions along the same lines but which are not flaky.
2023-04-10 17:34:04 +02:00
Sébastien Deleuze 0bad69d5fb Fix SSE with indenting serializer in WebMvc.fn
This commit ensures that HTTP headers like "text/event-stream"
are correctly forwarded to the converter used in
SseServerResponse for proper pretty print handling.

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

Closes gh-30298
2023-04-06 18:02:36 +02:00
Sam Brannen 19bb4e96f2 Improve Javadoc for ObjectUtils.nullSafeConciseToString() 2023-04-06 17:36:32 +02:00
Sam Brannen 7a2594acda Add tests for corner cases
See gh-30290
See gh-30286
2023-04-05 15:28:45 +02:00
Sam Brannen 91c58af7af Introduce ObjectUtils.nullSafeConciseToString()
ObjectUtils.nullSafeToString(Object) exists for generating a string
representation of various objects in a "null-safe" manner, including
support for object graphs, collections, etc.

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

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

Closes gh-30286
2023-04-05 15:25:59 +02:00
Sam Brannen 0a1aeafe08 Introduce StringUtils.truncate()
StringUtils.truncate() serves as central, consistent way for truncating
strings used in log messages and exception failure messages, for
immediate use in LogFormatUtils and ObjectUtils.

See gh-30286
Closes gh-30290
2023-04-05 15:15:53 +02:00
Simon Baslé 0e69bac7b0 Polish 0cfbf60: fix a test for Java 8 compatibility 2023-04-04 15:25:27 +02:00
Simon Baslé 0cfbf6036c Rename MockMVC matcher methods to prevent regression in user tests
This commit changes the name of two recently introduced methods in the
`MockRestRequestMatchers` class for header and queryParam. These have
been found to cause false negatives in user tests, due to the new
overload taking precedence in some cases.

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

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

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

See gh-30220
See gh-30238
Closes gh-30235
2023-04-04 15:07:41 +02:00
Sébastien Deleuze e931fdc5c2 Make HttpComponentsHeadersAdapter#getFirst nullable
Backport of gh-30267

Closes gh-30269
2023-04-03 09:06:32 +02:00
Sébastien Deleuze 3a1681357c Fix PathVariable reference documentation code snippets
Closes gh-30258
2023-03-31 15:51:45 +02:00
Juergen Hoeller a93382dbbf Propagate HttpStreamResetException itself if cause is null
Closes gh-30245

(cherry picked from commit 8fca258207)
2023-03-30 19:32:29 +02:00
Sébastien Deleuze 79c5ef88f5 Refine generic type management in AbstractMessageWriterResultHandler
This commit updates AbstractMessageWriterResultHandler#writeBody in
order to use the declared bodyParameter instead of
ResolvableType.forInstance(body) when the former has unresolvable
generics.

Closes gh-30215
2023-03-30 18:26:15 +02:00
Juergen Hoeller 0c80e5f9e6 Use JdkDynamicAopProxy class loader instead of JDK bootstrap/platform loader
Closes gh-30115

(cherry picked from commit 7e905e3e00)
2023-03-29 14:07:50 +02:00
Juergen Hoeller 7ad01a94d6 Use MethodInvocationInfo class loader in case of JDK platform loader as well
Closes gh-30210

(cherry picked from commit 491ae1e3be)
2023-03-29 13:56:23 +02:00
Juergen Hoeller 5d6d653cbd Use MethodInvocationInfo class loader in case of core JDK interface type
Closes gh-30210

(cherry picked from commit ce2689eead)
2023-03-28 13:56:02 +02:00
Johnny Lim 9868e888a5 Update versions in Javadoc
Closes gh-30191
2023-03-25 17:17:28 +01:00
ghostg00 6f6eb3d996 Fix example in Javadoc for @EnableWebSocket
The `echoWebSocketHandler()` method is not defined in the
`WebSocketConfigurer` interface and should therefore be annotated with
`@Bean` instead of `@Override`.

Closes gh-30187
2023-03-24 17:55:24 +01:00
Giuseppe a94c50e294 Handle all exceptions for stored proc out param retrieval in SharedEntityManagerCreator
Prior to this commit, the EntityManager was not closed in
SharedEntityManagerCreator.DeferredQueryInvocationHandler's
invoke(Object, Method, Object[]) method if an invocation of
getOutputParameterValue(*) threw an exception other than
IllegalArgumentException, which could lead to a connection leak.

This commit addresses this by catching RuntimeException instead of
IllegalArgumentException.

Closes gh-30164
2023-03-22 15:44:06 +01:00
Kukri b8c1255ee0 Fix anchor in link to "Web on Reactive Stack" chapter
Closes gh-30163
2023-03-22 11:35:12 +01:00
Spring Builds 129062034b Next development version (v5.3.27-SNAPSHOT) 2023-03-20 10:05:15 +00:00
rstoyanchev eafe3afe11 Polishing and minor refactoring in HandlerMappingIntrospector
Closes gh-30128
2023-03-20 08:38:11 +00:00
Sam Brannen 26e0343c16 Improve diagnostics in SpEL for matches operator
Supplying a large regular expression to the `matches` operator in a
SpEL expression can result in errors that are not very helpful to the
user.

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

Closes gh-30145
2023-03-20 00:07:01 +01:00
Sam Brannen 4d5e7207f2 Improve diagnostics in SpEL for repeated text
Attempting to create repeated text in a SpEL expression using the
repeat operator can result in errors that are not very helpful to the
user.

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

Closes gh-30143
2023-03-20 00:06:54 +01:00
Sam Brannen 430fc25aca Increase scope of regex pattern cache for the SpEL matches operator
Prior to this commit, the pattern cache for the SpEL `matches` operator
only applied to expressions such as the following where the same
`matches` operator is invoked multiple times with different input:

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

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

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

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

Closes gh-30141
2023-03-20 00:06:46 +01:00
Sam Brannen 0882ca57d4 Polishing 2023-03-20 00:06:32 +01:00
Sam Brannen 94bbf85c0e Stop printing to System.out in SpEL tests 2023-03-20 00:06:24 +01:00
Juergen Hoeller 2c2ef12f68 Upgrade to Netty 4.1.90 and Checkstyle 10.9.1 2023-03-17 18:10:02 +01:00
Juergen Hoeller 120d512ff6 Polishing (backported from main) 2023-03-17 18:09:46 +01:00
Sam Brannen 3ddf183922 Update copyright headers 2023-03-17 14:51:13 +01:00
rstoyanchev 4c69bfd32f Upgrade to Reactor 2020.0.30
Closes gh-30116
2023-03-16 08:30:16 +00:00
Sam Brannen 41d71e9a7f Revise contribution
See gh-25316
2023-03-15 14:30:53 +01:00
mrcoffee77 36682b7ad2 Ensure methods declared in Object can be invoked on a JDK proxy in SpEL
This commit ensures that methods declared in java.lang.Object (such as
toString() can be invoked on a JDK proxy instance in a SpEL expression.

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

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

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

Fixes gh-30121
2023-03-15 10:45:31 +01:00
rstoyanchev f0da099b12 Prefer request hostName and hostPort in ReactorServerHttpRequest
Backport of 682a4d53 and 9624ea39

Closes gh-29974
2023-03-14 07:02:21 +00:00
Brian Clozel d00fd4c502 Allow runtime compatibility with SnakeYaml 2.0
This commit ensures that SnakeYaml 2.0 is compatible at runtime with
Spring Framework 5.3.x with the `YamlProcessor` support.
The baseline version for SnakeYaml remains the same.

Closes gh-30097
2023-03-10 12:41:03 +01:00
Sébastien Deleuze 44a6d13cc0 Fix minor spacings in webflux docs
Closes gh-30095
2023-03-09 11:56:55 +01:00
Juergen Hoeller 284657355a Upgrade to Log4J 2.20, Tomcat 9.0.73, Jetty 9.4.51, Undertow 2.2.23 2023-03-08 17:44:10 +01:00
Juergen Hoeller 6a81ed3a50 Polishing 2023-03-08 17:43:35 +01:00
Brian Clozel 0a053cfccb Avoid lock contention in CaffeineCacheManager
Prior to this commit, using a dynamic `CaffeineCacheManager` would rely
on `ConcurrentHashMap#computeIfAbsent` for retrieving and creating cache
instances as needed. It turns out that using this method concurrently
can cause lock contention even when all known cache instances are
instantiated.

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

See gh-30066
Fixes gh-30085
2023-03-08 16:27:50 +01:00
Sam Brannen 22bb76d326 Revise documentation for @AspectJ argument name resolution algorithm
Closes gh-30057
2023-03-02 17:22:17 +01:00
Sam Brannen 4dc45d551c Update documentation for @AspectJ argument name resolution algorithm
Closes gh-30057
2023-03-01 17:29:50 +01:00
Sam Brannen e5d05ddfc3 Remove obsolete MetadataAwareAspectInstanceFactory Javadoc
We no longer have any JDK 5 related limitations imposed on us as was
the case when MetadataAwareAspectInstanceFactory was introduced; however,
MetadataAwareAspectInstanceFactory will remain as a specialized
sub-interface of AspectInstanceFactory.
2023-03-01 17:13:55 +01:00
Sam Brannen 44a5f8ec06 Add missing package-info.java file for autoproxy.target package 2023-03-01 17:13:45 +01:00
Sam Brannen 0a8bda40f4 Fix .gitignore pattern for Maven "target" folders
Rationale: changes in org.springframework.aop.framework.autoproxy.target
were previously ignored since the "target" package was ignored by the
previous "eager" pattern for "target" folders.
2023-03-01 17:13:32 +01:00
Radek Kraus 8a879c6fed Protect JMS connection creation against prepareConnection errors
This commit uses a local variable for the creation of a new JMS
Connection so that a rare failure in prepareConnection(...) does not
leave the connection field in a partially initialized state.

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

See gh-29116
Closes gh-30051
2023-02-28 16:35:36 +01:00
Sam Brannen 28d11aaf64 Polish contribution
See gh-30036
2023-02-27 16:47:09 +01:00
1993heqiang 02941127e1 Fix "Configuring a Global Date and Time Format" example
Closes gh-30036
2023-02-27 16:47:03 +01:00
Sam Brannen b1b24458c9 Polishing 2023-02-27 16:46:16 +01:00
Sébastien Deleuze 854b625be2 Add missing @Nullable annotations to LogMessage methods
Closes gh-30009
2023-02-24 17:51:52 +01:00
rstoyanchev a2b7a907ec Prefer local hostAddress in ReactorServerHttpRequest
Closes gh-28601
2023-02-23 16:40:38 +00:00
Brian Clozel 4f0a8911ca Fix CI image resource in pipeline
This commit fixes the CI image resource configuration so that it can be
checked autmatically by the pipeline.
This also updates various resources.
2023-02-23 09:44:09 +01:00
Sam Brannen 40fef7b232 Fix Javadoc for MockRestRequestMatchers 2023-02-22 11:09:03 +01:00
Sam Brannen 423134f64c Revise queryParam() and header() support in MockRestRequestMatchers
See gh-29953
See gh-29964
2023-02-22 11:08:05 +01:00
Sam Brannen 574c10d219 Polishing 2023-02-22 11:08:05 +01:00
Johnny Lim 2b4b947050 Fix Javadoc since for MockRestRequestMatchers queryParam() and header() (#29986)
See gh-29953
See gh-29964
2023-02-22 11:08:05 +01:00
Juergen Hoeller 4993b1090a Polishing 2023-02-22 11:08:05 +01:00
Juergen Hoeller 3adabf391f Consistent ordering of Resource methods (backported from main) 2023-02-15 12:35:41 +01:00
Juergen Hoeller 0026338c00 Consistent @Bean method return type for equivalence with XML example
Closes gh-29970
2023-02-14 16:57:35 +01:00
Juergen Hoeller cdea667e58 Test for request attribute visibility in FreeMarker (backported from main)
See gh-29787
2023-02-14 16:57:22 +01:00
Juergen Hoeller 66b1c0b4b0 Upgrade to Netty 4.1.89 2023-02-14 11:38:32 +01:00
Juergen Hoeller 6e42d36614 ASM upgrade for JDK 20/21 support (backported from main)
Closes gh-29966
2023-02-14 11:38:12 +01:00
Simon Baslé 7f2c93fa1f Allow MockRest to match header/queryParam value list with one Matcher
This commit adds a `header` variant and a `queryParam` variant to the
`MockRestRequestMatchers` API which take a single `Matcher` over the
list of values.

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

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

See gh-29953
Closes gh-29964
2023-02-13 17:53:48 +01:00
Johnny Lim 4c351e811a Polish
See gh-29928
2023-02-09 09:55:19 +01:00
rstoyanchev 5b67dea506 Unwrap session before selecting stats counter
See gh-29375
2023-02-08 18:10:11 +00:00
Sam Brannen b9fe095f60 Clearly document that DataClassRowMapper supports Java records
Closes gh-29814
2023-02-07 19:09:47 +01:00
Sam Brannen 6b17014b5a Polish RowMapper tests 2023-02-07 19:09:32 +01:00
Sam Brannen 878246b09b Avoid confusing terminology in BeanPropertyRowMapper
Prior to this commit, the term "field" was sometimes used to refer to a
database column and sometimes used to refer to a bean property, which
lead to confusion in the Javadoc as well as within the code.

This commit addresses this by avoiding use of the term "field".
2023-02-07 19:07:40 +01:00
Sam Brannen 9067ccab2d Update copyright headers 2023-02-07 16:35:52 +01:00
Manthan Bhatt 4e00aece7a Restrict forwards in MockMvcWebConnection to 100
This change restricts the maximum number of forwards in MockMvcWebConnection to 100,
in case a forward is configured in a way that causes a loop. This is necessary in HtmlUnit
backed tests, unlike in classic MockMvc tests in which the forwards are not actually resolved.

See gh-29557
Closes gh-29866

Co-authored-by: Simon Baslé <sbasle@vmware.com>
2023-02-07 16:24:57 +01:00
Sam Brannen c9841f37b6 Revise Testcontainers examples based on feedback
Closes gh-29940
2023-02-07 15:57:23 +01:00
Johnny Lim 92d513e9fb Add MockMvc.multipart() Kotlin extensions with HttpMethod
See gh-28545
See gh-28631
Closes gh-29941
2023-02-07 15:12:27 +01:00
Sam Brannen 782ee34cb7 Update @DynamicPropertySource examples regarding changes in Testcontainers
Closes gh-29939
2023-02-07 13:38:50 +01:00
Sam Brannen 80c10fad92 Polish RowMapper tests 2023-02-03 18:06:10 +01:00
Sam Brannen 498a0d286f Clarify semantics of primitivesDefaultedForNullValue in BeanPropertyRowMapper
Closes gh-29923
2023-02-03 18:06:10 +01:00
Sam Brannen e9d45d1b49 Polish Javadoc for RowMappers 2023-02-03 18:01:07 +01:00
danu 0851b0f72d Release R2DBC connection when cleanup fails in transaction
When using R2dbcTransactionManager, connection will not be released if
it encounters error while doing `afterCleanup` steps. As `afterCleanup`
can use a database connection when doing `setAutoCommit(true)`, it can
fail under some conditions where the connection is not reliable.

This leads to the Connection not being released.

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

Backport of commit e050c37
See gh-29703
Closes gh-29925

Co-authored-by: Simon Baslé <sbasle@vmware.com>
2023-02-03 17:43:22 +01:00
Brian Clozel 91d991e86c Rely only on Docker Hub for fetching OCI images 2023-02-02 21:47:19 +01:00
Juergen Hoeller 960f6fb936 Add missing warn level check (backported from main) 2023-02-01 18:28:20 +01:00
Juergen Hoeller 4d3d34528e Upgrade to Tomcat 9.0.71, Netty 4.1.87, AssertJ 3.24.2, HtmlUnit 2.70, Checkstyle 10.7 2023-02-01 18:26:00 +01:00
Juergen Hoeller 78ba946266 Clarify postProcessBeanFactory lifecycle state
Closes gh-29064

(cherry picked from commit b8827d8e11)
2023-02-01 18:21:16 +01:00
Juergen Hoeller 42e7318cbb Polishing 2023-01-31 16:48:36 +01:00
Juergen Hoeller 000383fbff Explicit target ClassLoader for interface-based infrastructure proxies
Includes direct JDK Proxy usage instead of ProxyFactory where possible.

Closes gh-29913

(cherry picked from commit 4d6249811e)
2023-01-31 16:48:27 +01:00
Juergen Hoeller 37cbdc2cf4 Lazily load ContextLoader.properties (and lazily fail if not present)
Closes gh-29905

(cherry picked from commit a74b86e812)
2023-01-31 16:21:45 +01:00
Juergen Hoeller 6d95e7f9d9 Declare no-op close() method in order to avoid container-triggered shutdown call
Closes gh-29892

(cherry picked from commit 7c9dca3d2e)
2023-01-31 16:21:39 +01:00
rstoyanchev 45a7917a36 Backport of cf9fc69d6b
Closes gh-29911
2023-01-31 11:55:32 +00:00
rstoyanchev 25b95b8b98 Avoid ClassLoader issue in Jetty10 WebSocket upgrade
Closes gh-29256
2023-01-31 11:50:22 +00:00
Sam Brannen 6bd7a7321e Revise generated default name for @JmsListener subscription
The previous commit changed the generated default name for a JMS
subscription to <FQCN>#<method name> -- for example:

- org.example.MyListener#myListenerMethod

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

- org.example.MyListener.myListenerMethod

This commit also introduces tests and documentation for these changes.

See gh-29902
2023-01-30 19:57:28 +01:00
Sam Brannen 11aaba9877 Polishing 2023-01-30 19:52:24 +01:00
fml2 07fd7606e7 Improve generated default name for a @JmsListener subscription
Prior to this commit, when using durable subscribers with @JmsListener
methods that do not specify a custom subscription name the generated
default subscription name was always
org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.
Consequently, multiple such @JmsListener methods were assigned the
same subscription name which violates the uniqueness requirement.

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

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

Closes gh-29902
2023-01-30 19:52:15 +01:00
Sam Brannen 40d2466334 Fix build due to Jackson Javadoc publication changes
The Jackson project no longer publishes Javadoc at
https://fasterxml.github.io which breaks the `javadoc` and `api` build
tasks due to their dependency on that web site for external Javadoc links.

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

See https://github.com/FasterXML/jackson-databind/issues/3440
Closes gh-29895
2023-01-29 12:43:11 +01:00
Sam Brannen 3d6d853bbc Include all Hibernate methods in SharedEntityManagerCreator's queryTerminatingMethods
Prior to this commit, we included Hibernate's Query.list() method in
SharedEntityManagerCreator's queryTerminatingMethods set but did not
include all of Hibernate's query-terminating methods.

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

Closes gh-29888
2023-01-28 20:59:46 +01:00
Sam Brannen 90ea39cc6b Update copyright headers 2023-01-28 20:49:13 +01:00
Arjen Poutsma 21c3d4f4a9 Support Jetty 10 in JettyClientHttpRequest
Though Jetty 10 was previously supported in the JettyClientHttpResponse,
this commit ensures support in the JettyClientHttpRequest.

Closes gh-29867
See gh-26123
2023-01-26 17:27:57 +01:00
Simon Baslé de53d77344 DatabaseClient uses SQL Supplier more lazily
This commit modifies the `DefaultDatabaseClient` implementation in order
to ensure lazier usage of the `Supplier<String>` passed to the sql
method (`DatabaseClient#sql(Supplier)`).

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

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

Backport of d72df5ace4
See gh-29367
Closes gh-29887
2023-01-26 15:20:38 +01:00
Sébastien Deleuze e4e90bbec0 Polish RouterFunctionDsl KDoc 2023-01-23 13:27:34 +01:00
Sébastien Deleuze d0828be0cd Remove WebClientIntegrationTests#exchangeWithRelativeUrl outdated test
This test can fail when a web server runs on port 80 and
is not relevant anymore due to the removal of related feature
via 6e936a4081.

Closes gh-29863
2023-01-20 12:24:41 +01:00
Sébastien Deleuze 4a4b332709 Refine Jackson2ObjectMapperBuilder#configureFeature exception handling
This commit changes the FatalBeanException previously thrown for
an IllegalArgumentException which seems more suitable for that
use case.

Closes gh-29860
2023-01-20 10:15:49 +01:00
Brian Clozel 33f1c9b614 Upgrade Gradle Enterprise & Conventions plugins
This is required to adapt to the repo.spring.io permission changes.
2023-01-19 11:34:05 +01:00
Arjen Poutsma 53ac812fb0 Updated sdkmanrc 2023-01-19 10:05:36 +01:00
Arjen Poutsma 60c89dd2df Fix IllegalStateException in empty ProducesRequestCondition
When comparing empty ProducesRequestCondition, compareTo would throw an
IllegalStateException if the Accept header was invalid. This commit
fixes that behavior.

See gh-29794
Closes gh-29836
2023-01-18 10:45:12 +01:00
Minsoo Cheong(Merlin) 4bd2531774 Fix R2dbcTransactionManager debug log: don't log a Mono (#29800)
When logging the current connection inside R2dbcTransactionManager
doBegin, the mono object was logged instead of the connection lambda
parameter.

Other similar debug-level logs do use the actual Connection object,
so this commit does the same.

Backport of gh-29800
Closes gh-29824
2023-01-16 11:30:35 +01:00
Spring Builds 4fd5630700 Next development version (v5.3.26-SNAPSHOT) 2023-01-11 11:19:35 +00:00
Juergen Hoeller 26cd33cb2b Upgrade to Reactor 2020.0.27
Includes HtmlUnit 2.69, AssertJ 3.24.1, Checkstyle 10.6

Closes gh-29798
2023-01-11 00:23:38 +01:00
Juergen Hoeller 2ee393ae71 Upgrade to Tomcat 9.0.70, Jetty 9.4.50, Netty 4.1.86, Undertow 2.2.22, HtmlUnit 2.67, Mockito 4.9, AssertJ 3.23.1, Checkstyle 10.5 2022-12-23 15:52:09 +01:00
Juergen Hoeller 0815d29e45 Defensive check for null returned from createConnection()
Closes gh-29706
2022-12-23 15:51:37 +01:00
Brian Clozel 777f01d786 Fix path within mapping when pattern contains ".*"
Prior to this commit, extracting the path within handler mapping would
result in "" if the matching path element would be a Regex and contain
".*". This could cause issues with resource handling if the handler
mapping pattern was similar to `"/folder/file.*.extension"`.

This commit introduces a new `isLiteral()` method in the `PathElement`
abstract class that expresses whether the path element can be compared
as a String for path matching or if it requires a more elaborate
matching process.

Using this method for extracting the path within handler mapping avoids
relying on wildcard count or other properties.

See gh-29712
Fixes gh-29716
2022-12-19 10:53:02 +01:00
Sam Brannen f8fea013fc Update Jakarta Mail info in ref docs
Closes gh-29708
2022-12-17 14:18:42 +01:00
Sam Brannen 916539178b Improve documentation for literals in SpEL expressions
Closes gh-29701
2022-12-16 14:51:48 +01:00
Sam Brannen fdf3bcc9d9 Remove obsolete AttributeMethods.hasOnlyValueAttribute() method
See gh-29685
2022-12-13 15:52:01 +01:00
Sam Brannen 5ddc984192 Support repeatable annotation containers with multiple attributes
Prior to this commit, there was a bug in the implementation of
StandardRepeatableContainers.computeRepeatedAnnotationsMethod() which
has existed since Spring Framework 5.2 (when
StandardRepeatableContainers was introduced). Specifically,
StandardRepeatableContainers ignored any repeatable container
annotation if it declared attributes other than `value()`. However,
Java permits any number of attributes in a repeatable container
annotation.

In addition, the changes made in conjunction with gh-20279 made the bug
in StandardRepeatableContainers apparent when using the
getMergedRepeatableAnnotations() or findMergedRepeatableAnnotations()
method in AnnotatedElementUtils, resulting in regressions for the
behavior of those two methods.

This commit fixes the regressions and bug by altering the logic in
StandardRepeatableContainers.computeRepeatedAnnotationsMethod() so that
it explicitly looks for the `value()` method and ignores any other
methods declared in a repeatable container annotation candidate.

See gh-29685
Closes gh-29686
2022-12-13 15:47:13 +01:00
Sam Brannen b2ce54e7f1 Revise RepeatableContainersTests 2022-12-13 15:47:13 +01:00
Juergen Hoeller 937ab5f4b2 Polishing (aligned with main) 2022-12-13 12:06:09 +01:00
Juergen Hoeller 064c618050 Drop SQLExceptionSubclassFactory and unify SQLStateSQLExceptionTranslator tests 2022-12-13 12:05:35 +01:00
Juergen Hoeller 8c80ec1138 Avoid NPE on BeanDescriptor access with SimpleBeanInfoFactory
Closes gh-29681

(cherry picked from commit d74191427e)
2022-12-13 11:43:43 +01:00
rstoyanchev 912fa7602a Improve invalid Content-Type handling in WebFlux
Closes gh-29565
2022-12-09 11:53:16 +00:00
rstoyanchev 525fc7a27e Optimize object creation PartialMatchHelper
Closes gh-29667
2022-12-09 11:27:03 +00:00
Sam Brannen 72285034ba Support arrays in AST string representations of SpEL expressions
Prior to this commit, SpEL's ConstructorReference did not provide
support for arrays when generating a string representation of the
internal AST. For example, 'new String[3]' was represented as 'new
String()' instead of 'new String[3]'.

This commit introduces support for standard array construction and array
construction with initializers in ConstructorReference's toStringAST()
implementation.

Closes gh-29666
2022-12-08 23:23:01 -05:00
Sam Brannen 933474000b Polishing 2022-12-08 18:45:02 -05:00
Sam Brannen 4e8aebcde7 Fix SpEL support for quotes within String literals
Prior to this commit, there were two bugs in the support for quotes
within String literals in SpEL expressions.

- Two double quotes ("") or two single quotes ('') were always replaced
  with one double quote or one single quote, respectively, regardless
  of which quote character was used to enclose the original String
  literal. This resulted in the loss of one of the double quotes when
  the String literal was enclosed in single quotes, and vice versa. For
  example, 'x "" y' became 'x " y'.

- A single quote which was properly escaped in a String literal
  enclosed within single quotes was not escaped in the AST string
  representation of the expression. For example, 'x '' y' became 'x ' y'.

This commit fixes both of these related issues in StringLiteral and
overhauls the structure of ParsingTests.

Closes gh-29604
Closes gh-28356
2022-12-07 16:03:49 -05:00
Sam Brannen dff5b1ff8e Polishing 2022-12-07 15:59:08 -05:00
Sam Brannen fa0a4a0a46 Improve Javadoc for SqlLobValue 2022-12-07 15:58:56 -05:00
Sam Brannen 41a6b7ec20 Update copyright headers for source code changed since August 2022
The changes in this commit were performed using the newly introduced
update_copyright_headers.sh script.
2022-12-03 17:23:21 -05:00
Sam Brannen cfaa4ba89c Apply update_copyright_headers.sh to staged files as well 2022-12-03 17:23:21 -05:00
Sam Brannen 598e9d586b Introduce update_copyright_headers.sh shell script
In order to automate maintenance of copyright headers in our source
code (especially when merging PRs from external contributors), this
commit introduces an update_copyright_headers.sh script (tested on
mac OS) that will update the copyright headers of all Java, Kotlin,
and Groovy source files that have been added or modified this year
(or at least as far back as the git log history supports it).

For example, running this script currently outputs the following.

Updating copyright headers in Java, Kotlin, and Groovy source code for year 2022
warning: log for 'main' only goes back to Tue, 16 Aug 2022 16:24:55 +0200
2022-12-03 17:23:21 -05:00
Sam Brannen 750a8b359f Stop using Mockito to spy() on JDK I/O streams
When running on JDK 16+, we are not able to spy() on JDK types. To
address this, this commit stops using Mockito to spy on JDK I/O streams
(such as ByteArrayInputStream and ByteArrayOutputStream).
2022-12-03 17:23:21 -05:00
Sam Brannen c838bcff3a Fix/Disable JMX & JNDI tests on JDK 16+ 2022-12-03 17:23:21 -05:00
Sam Brannen 109b00d24d Avoid use of deprecated Character/Double constructors in tests 2022-12-03 17:23:21 -05:00
Sam Brannen b6abf45a56 Introduce @Suite classes for individual modules 2022-12-03 16:32:27 -05:00
Juergen Hoeller 2d94b43faa Polishing 2022-12-02 11:15:03 +01:00
Sam Brannen f7f73439ab Modify MBeanTestUtils to work on JDK 17+ 2022-11-30 14:55:15 +01:00
Sam Brannen 5e55558a93 Fix SockJsServiceTests
See gh-29594
2022-11-28 17:12:08 +01:00
Sam Brannen eee50d3b8a Polishing 2022-11-28 17:06:22 +01:00
Sam Brannen 92af390ed2 Polish contribution
See gh-29594
2022-11-28 17:02:53 +01:00
Aashay Chapatwala 332d2a36bb Add title to SockJS iFrames for accessibility compliance
Closes gh-29594
2022-11-28 17:02:01 +01:00
Brian Clozel 92b2b828f5 Fix Java 17 test CI and remove Java 11 variant
This commit fixes configuration and runtime issues with the Java 17 test
CI variant and removes the Java 11 one, now that Spring Framework 5.3.x
is in maintenance mode.
2022-11-28 10:17:56 +01:00
Juergen Hoeller a11222f681 Polishing 2022-11-25 17:58:59 +01:00
Juergen Hoeller 7de8d81932 Explicit documentation notes on standard Java reflection
See gh-29531
2022-11-24 14:25:43 +01:00
Juergen Hoeller 0e33537d9d Consistent use of DefaultParameterNameResolver in tests 2022-11-23 11:17:58 +01:00
Sébastien Deleuze 00da70e26b Fix some typos in Kotlin WebClient example code
Closes gh-29542
2022-11-22 08:35:50 +01:00
Sam Brannen 72b44cebea Catch Error for SourceHttpMessageConverter in WebMvcConfigurationSupport
Prior to this commit, the addDefaultHttpMessageConverters() method in
WebMvcConfigurationSupport caught Throwable for SourceHttpMessageConverter
instantiation; whereas, the rest of the code base correctly catches Error
for SourceHttpMessageConverter instantiation (to handle errors such as
NoClassDefFoundError).

Throwable should not be caught since it can mask other categories of
failures (such as configuration errors).

This commit therefore switches to catching Error for SourceHttpMessageConverter
instantiation in WebMvcConfigurationSupport.

Closes gh-29537
2022-11-21 17:37:22 +01:00
Marten Deinum 1ee3777ac7 Fix link to Bean Utils Light Library in BeanUtils Javadoc
The URL for the BULL library has changed (not sure when, probably way back).

This updates it to the correct location.

Closes gh-29534, gh-29536
2022-11-21 17:25:50 +01:00
divcon cad6e8756d Fix link to WebFlux section in reference manual
Closes gh-29526
2022-11-19 14:51:03 +01:00
Sam Brannen c7bd685c54 Polishing 2022-11-19 14:49:26 +01:00
Sam Brannen 4f472d2ac4 Remove TODOs in WebFlux ref docs 2022-11-19 14:49:07 +01:00
Stephane Nicoll a18842b72b Fix link to WebFlux section
Closes gh-29517
2022-11-18 10:48:05 +01:00
Spring Builds a41f97bc2b Next development version (v5.3.25-SNAPSHOT) 2022-11-16 08:07:01 +00:00
355 changed files with 5991 additions and 3536 deletions
+4 -1
View File
@@ -28,6 +28,7 @@ buildSrc/build
/integration-tests/build
/src/asciidoc/build
target/
/target/
# Eclipse artifacts, including WTP generated manifests
.classpath
@@ -45,4 +46,6 @@ atlassian-ide-plugin.xml
.gradletasknamecache
# VS Code
.vscode/
.vscode/
cached-antora-playbook.yml
+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.352-librca
java=8.0.372-librca
+17 -17
View File
@@ -28,18 +28,18 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
mavenBom "io.netty:netty-bom:4.1.85.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.25"
mavenBom "io.netty:netty-bom:4.1.93.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.33"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.49.v20220914"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
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"
mavenBom "org.junit:junit-bom:5.8.2"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.19.0') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.20.0') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
@@ -92,7 +92,7 @@ configure(allprojects) { project ->
entry 'jibx-run'
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.30"
dependency "org.yaml:snakeyaml:1.33"
dependency "com.h2database:h2:2.1.214"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
@@ -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.68') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.75') {
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.68') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.75') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.21.Final') {
dependencySet(group: 'io.undertow', version: '2.2.24.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -191,14 +191,14 @@ configure(allprojects) { project ->
dependency "org.junit.support:testng-engine:1.0.4"
dependency "org.hamcrest:hamcrest:2.2"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.23.0"
dependency "org.assertj:assertj-core:3.24.2"
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.8.1') {
dependencySet(group: 'org.mockito', version: '4.9.0') { // spring-beans tests fail with 4.10+
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.66.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.70.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.66.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.70.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -238,7 +238,7 @@ configure(allprojects) { project ->
dependency "com.ibm.websphere:uow:6.0.2.17"
dependency "com.jamonapi:jamon:2.82"
dependency "joda-time:joda-time:2.10.13"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.12"
dependency "org.javamoney:moneta:1.3"
dependency "com.sun.activation:javax.activation:1.2.0"
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.4"
toolVersion = "10.9.3"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -377,9 +377,9 @@ configure([rootProject] + javaProjects) { project ->
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"https://www.ehcache.org/apidocs/2.10.4/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.12.7/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.12.7/",
"https://www.javadoc.io/doc/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/2.12.7/",
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
-1
View File
@@ -5,7 +5,6 @@ ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java8
ENV JAVA_HOME /opt/openjdk/java8
ENV JDK11 /opt/openjdk/java11
ENV JDK17 /opt/openjdk/java17
ENV PATH $JAVA_HOME/bin:$PATH
+2 -8
View File
@@ -3,16 +3,10 @@ set -e
case "$1" in
java8)
echo "https://github.com/bell-sw/Liberica/releases/download/8u345+1/bellsoft-jdk8u345+1-linux-amd64.tar.gz"
;;
java11)
echo "https://github.com/bell-sw/Liberica/releases/download/11.0.16+8/bellsoft-jdk11.0.16+8-linux-amd64.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/8u372+7/bellsoft-jdk8u372+7-linux-amd64.tar.gz"
;;
java17)
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.4+8/bellsoft-jdk17.0.4+8-linux-amd64.tar.gz"
;;
java18)
echo "https://github.com/bell-sw/Liberica/releases/download/18.0.2+10/bellsoft-jdk18.0.2+10-linux-amd64.tar.gz"
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.7+7/bellsoft-jdk17.0.7+7-linux-amd64.tar.gz"
;;
*)
echo $"Unknown java version"
+1 -1
View File
@@ -20,7 +20,7 @@ curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/c
mkdir -p /opt/openjdk
pushd /opt/openjdk > /dev/null
for jdk in java8 java11 java17
for jdk in java8 java17
do
JDK_URL=$( /get-jdk-url.sh $jdk )
mkdir $jdk
-3
View File
@@ -8,7 +8,4 @@ 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
+12 -93
View File
@@ -23,11 +23,6 @@ anchors:
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
registry-mirror-vars: &registry-mirror-vars
registry-mirror-host: ((registry-mirror-host))
registry-mirror-username: ((registry-mirror-username))
registry-mirror-password: ((registry-mirror-password))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
@@ -48,31 +43,31 @@ resource_types:
- name: registry-image
type: registry-image
source:
<<: *docker-resource-source
repository: concourse/registry-image-resource
tag: 1.5.0
tag: 1.7.1
- name: artifactory-resource
type: registry-image
source:
<<: *docker-resource-source
repository: springio/artifactory-resource
tag: 0.0.17
tag: 0.0.18
- name: github-release
type: registry-image
source:
<<: *docker-resource-source
repository: concourse/github-release-resource
tag: 1.5.5
tag: 1.8.0
- name: github-status-resource
type: registry-image
source:
<<: *docker-resource-source
repository: dpb587/github-status-resource
tag: master
- name: pull-request
type: registry-image
source:
repository: teliaoss/github-pr-resource
tag: v0.23.0
- name: slack-notification
type: registry-image
source:
<<: *docker-resource-source
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
@@ -101,6 +96,7 @@ resources:
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
tag: ((milestone))
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
@@ -109,14 +105,6 @@ resources:
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: git-pull-request
type: pull-request
icon: source-pull
source:
access_token: ((github-ci-pull-request-token))
repository: ((github-repo-name))
base_branch: ((branch))
ignore_paths: ["ci/*"]
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
@@ -125,14 +113,6 @@ resources:
access_token: ((github-ci-status-token))
branch: ((branch))
context: build
- name: repo-status-jdk11-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk11-build
- name: repo-status-jdk17-build
type: github-status-resource
icon: eye-check-outline
@@ -176,7 +156,7 @@ jobs:
image: ci-image
vars:
ci-image-name: ci-image
<<: *registry-mirror-vars
<<: *docker-resource-source
- put: ci-image
params:
image: ci-image/image.tar
@@ -237,34 +217,6 @@ jobs:
"zip.type": "schema"
get_params:
threads: 8
- name: jdk11-build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk11-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
image: ci-image
file: git-repo/ci/tasks/check-project.yml
privileged: true
timeout: ((task-timeout))
params:
TEST_TOOLCHAIN: 11
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk11-build
params: { state: "success", commit: "git-repo" }
- name: jdk17-build
serial: true
public: true
@@ -282,7 +234,7 @@ jobs:
privileged: true
timeout: ((task-timeout))
params:
TEST_TOOLCHAIN: 15
TEST_TOOLCHAIN: 17
<<: *build-project-task-params
on_failure:
do:
@@ -293,37 +245,6 @@ jobs:
<<: *slack-fail-params
- put: repo-status-jdk17-build
params: { state: "success", commit: "git-repo" }
- name: build-pull-requests
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
resource: git-pull-request
trigger: true
version: every
- do:
- put: git-pull-request
params:
path: git-repo
status: pending
- task: build-pr
image: ci-image
file: git-repo/ci/tasks/build-pr.yml
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
on_success:
put: git-pull-request
params:
path: git-repo
status: success
on_failure:
put: git-pull-request
params:
path: git-repo
status: failure
- name: stage-milestone
serial: true
plan:
@@ -471,10 +392,8 @@ jobs:
groups:
- name: "builds"
jobs: ["build", "jdk11-build", "jdk17-build"]
jobs: ["build", "jdk17-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
- name: "pull-requests"
jobs: [ "build-pull-requests" ]
+1 -1
View File
@@ -4,6 +4,6 @@ set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 \
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
popd > /dev/null
+3 -5
View File
@@ -4,11 +4,9 @@ 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))
tag: 0.10.0
username: ((docker-hub-username))
password: ((docker-hub-password))
inputs:
- name: ci-images-git-repo
outputs:
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.24-SNAPSHOT
version=5.3.28
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
+3 -4
View File
@@ -3,7 +3,7 @@ configurations {
}
dependencies {
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.5.0")
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.6.1")
}
repositories {
@@ -73,9 +73,8 @@ pluginManager.withPlugin("kotlin") {
}
task downloadResources(type: Download) {
def version = "0.2.5"
src "https://repo.spring.io/release/io/spring/docresources/" +
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
src "https://repo.spring.io/artifactory/snapshot/io/spring/docresources/" +
"spring-doc-resources/0.2.6-SNAPSHOT/spring-doc-resources-0.2.6-20210308.231804-2.zip"
dest project.file("$buildDir/docs/spring-doc-resources.zip")
onlyIfModified true
useETag "all"
+4 -15
View File
@@ -81,6 +81,10 @@ plugins.withType(JavaPlugin) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = testLanguageVersion
}
if(testLanguageVersion == JavaLanguageVersion.of(17)) {
jvmArgs(["--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED"])
}
}
}
}
@@ -130,21 +134,6 @@ pluginManager.withPlugin("kotlin") {
}
}
}
if (testToolchainConfigured()) {
def testLanguageVersion = testToolchainLanguageVersion()
def compiler = javaToolchains.compilerFor {
languageVersion = testLanguageVersion
}
// See https://kotlinlang.org/docs/gradle.html#attributes-specific-for-jvm
def javaVersion = testLanguageVersion.toString() == '8' ? '1.8' : testLanguageVersion.toString()
compileTestKotlin {
kotlinOptions {
jvmTarget = javaVersion
jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath
}
}
}
}
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
+2 -2
View File
@@ -7,8 +7,8 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.11.1"
id "io.spring.ge.conventions" version "0.0.11"
id "com.gradle.enterprise" version "3.12.1"
id "io.spring.ge.conventions" version "0.0.13"
}
include "spring-aop"
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,6 +38,14 @@ import org.springframework.util.StringUtils;
* for an advice method from the pointcut expression, returning, and throwing clauses.
* If an unambiguous interpretation is not available, it returns {@code null}.
*
* <h3>Algorithm Summary</h3>
* <p>If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* <h3>Algorithm Details</h3>
* <p>This class interprets arguments in the following way:
* <ol>
* <li>If the first parameter of the method is of type {@link JoinPoint}
@@ -65,15 +73,15 @@ import org.springframework.util.StringUtils;
* zero we proceed to the next stage. If {@code a} &gt; 1 then an
* {@code AmbiguousBindingException} is raised. If {@code a} == 1,
* and there are no unbound arguments of type {@code Annotation+},
* then an {@code IllegalArgumentException} is raised. if there is
* then an {@code IllegalArgumentException} is raised. If there is
* exactly one such argument, then the corresponding parameter name is
* assigned the value from the pointcut expression.</li>
* <li>If a returningName has been set, and there are no unbound arguments
* <li>If a {@code returningName} has been set, and there are no unbound arguments
* then an {@code IllegalArgumentException} is raised. If there is
* more than one unbound argument then an
* {@code AmbiguousBindingException} is raised. If there is exactly
* one unbound argument then the corresponding parameter name is assigned
* the value &lt;returningName&gt;.</li>
* the value of the {@code returningName}.</li>
* <li>If there remain unbound arguments, then the pointcut expression is
* examined once more for {@code this}, {@code target}, and
* {@code args} pointcut expressions used in the binding form (binding
@@ -99,20 +107,12 @@ import org.springframework.util.StringUtils;
* <p>The behavior on raising an {@code IllegalArgumentException} or
* {@code AmbiguousBindingException} is configurable to allow this discoverer
* to be used as part of a chain-of-responsibility. By default the condition will
* be logged and the {@code getParameterNames(..)} method will simply return
* be logged and the {@link #getParameterNames(Method)} method will simply return
* {@code null}. If the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property is set to {@code true}, the conditions will be thrown as
* {@code IllegalArgumentException} and {@code AmbiguousBindingException},
* respectively.
*
* <p>Was that perfectly clear? ;)
*
* <p>Short version: If an unambiguous binding can be deduced, then it is.
* If the advice requirements cannot possibly be satisfied, then {@code null}
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
* property to {@code true}, descriptive exceptions will be thrown instead of
* returning {@code null} in the case that the parameter names cannot be discovered.
*
* @author Adrian Colyer
* @author Juergen Hoeller
* @since 2.0
@@ -158,7 +158,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/** The pointcut expression associated with the advice, as a simple String. */
@Nullable
private String pointcutExpression;
private final String pointcutExpression;
private boolean raiseExceptions;
@@ -197,7 +197,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterReturning} advice binds the return value, the
* returning variable name must be specified.
* {@code returning} variable name must be specified.
* @param returningName the name of the returning variable
*/
public void setReturningName(@Nullable String returningName) {
@@ -206,18 +206,17 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/**
* If {@code afterThrowing} advice binds the thrown value, the
* throwing variable name must be specified.
* {@code throwing} variable name must be specified.
* @param throwingName the name of the throwing variable
*/
public void setThrowingName(@Nullable String throwingName) {
this.throwingName = throwingName;
}
/**
* Deduce the parameter names for an advice method.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
* for this class for details of the algorithm used.
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class-level javadoc}
* for this class for details on the algorithm used.
* @param method the target {@link Method}
* @return the parameter names
*/
@@ -316,13 +315,13 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
private void bindParameterName(int index, String name) {
private void bindParameterName(int index, @Nullable String name) {
this.parameterNameBindings[index] = name;
this.numberOfRemainingUnboundArguments--;
}
/**
* If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as
* If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as
* parameter name and return true, else return false.
*/
private boolean maybeBindThisJoinPoint() {
@@ -367,8 +366,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
if (throwableIndex == -1) {
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName
+ "' could not be completed as no available arguments are a subtype of Throwable");
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
"' could not be completed as no available arguments are a subtype of Throwable");
}
else {
bindParameterName(throwableIndex, this.throwingName);
@@ -400,7 +399,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/**
* Parse the string pointcut expression looking for:
* &#64;this, &#64;target, &#64;args, &#64;within, &#64;withincode, &#64;annotation.
@@ -465,7 +463,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
/*
/**
* If the token starts meets Java identifier conventions, it's in.
*/
@Nullable
@@ -533,7 +531,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
}
if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate this(), target() or args() variables but only one unbound argument slot");
@@ -609,7 +606,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
// else varNames.size must be 0 and we have nothing to bind.
}
/*
/**
* We've found the start of a binding pointcut at the given index into the
* token array. Now we need to extract the pointcut body and return it.
*/
@@ -709,7 +706,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return false;
}
/*
/**
* Return {@code true} if the given argument type is a subclass
* of the given supertype.
*/
@@ -737,7 +734,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
return count;
}
/*
/**
* Find the argument index with the given type, and bind the given
* {@code varName} in that position.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,10 +23,6 @@ import org.springframework.lang.Nullable;
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
* that returns {@link AspectMetadata} associated with AspectJ-annotated classes.
*
* <p>Ideally, AspectInstanceFactory would include this method itself, but because
* AspectMetadata uses Java-5-only {@link org.aspectj.lang.reflect.AjType},
* we need to split out this subinterface.
*
* @author Rod Johnson
* @since 2.0
* @see AspectMetadata
@@ -35,13 +31,13 @@ import org.springframework.lang.Nullable;
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
/**
* Return the AspectJ AspectMetadata for this factory's aspect.
* Get the AspectJ AspectMetadata for this factory's aspect.
* @return the aspect metadata
*/
AspectMetadata getAspectMetadata();
/**
* Return the best possible creation mutex for this factory.
* Get the best possible creation mutex for this factory.
* @return the mutex object (may be {@code null} for no mutex to use)
* @since 4.3
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -521,6 +521,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
copy.copyFrom(this);
copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic());
copy.advisorChainFactory = this.advisorChainFactory;
copy.methodCache = this.methodCache;
copy.interfaces = new ArrayList<>(this.interfaces);
copy.advisors = new ArrayList<>(this.advisors);
return copy;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -283,8 +283,8 @@ class CglibAopProxy implements AopProxy, Serializable {
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
@@ -899,9 +899,9 @@ class CglibAopProxy implements AopProxy, Serializable {
// Proxy is not yet available, but that shouldn't matter.
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean isFrozen = this.advised.isFrozen();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
if (exposeProxy) {
@@ -970,6 +970,9 @@ class CglibAopProxy implements AopProxy, Serializable {
if (this.advised.isExposeProxy() != otherAdvised.isExposeProxy()) {
return false;
}
if (this.advised.isOpaque() != otherAdvised.isOpaque()) {
return false;
}
if (this.advised.getTargetSource().isStatic() != otherAdvised.getTargetSource().isStatic()) {
return false;
}
@@ -1016,10 +1019,6 @@ class CglibAopProxy implements AopProxy, Serializable {
Advice advice = advisor.getAdvice();
hashCode = 13 * hashCode + advice.getClass().hashCode();
}
hashCode = 13 * hashCode + (this.advised.isFrozen() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isExposeProxy() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isOptimize() ? 1 : 0);
hashCode = 13 * hashCode + (this.advised.isOpaque() ? 1 : 0);
return hashCode;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -123,7 +123,33 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this);
}
/**
* Determine whether the JDK bootstrap or platform loader has been suggested ->
* use higher-level loader which can see Spring infrastructure classes instead.
*/
private ClassLoader determineClassLoader(@Nullable ClassLoader classLoader) {
if (classLoader == null) {
// JDK bootstrap loader -> use spring-aop ClassLoader instead.
return getClass().getClassLoader();
}
if (classLoader.getParent() == null) {
// Potentially the JDK platform loader on JDK 9+
ClassLoader aopClassLoader = getClass().getClassLoader();
ClassLoader aopParent = aopClassLoader.getParent();
while (aopParent != null) {
if (classLoader == aopParent) {
// Suggested ClassLoader is ancestor of spring-aop ClassLoader
// -> use spring-aop ClassLoader itself instead.
return aopClassLoader;
}
aopParent = aopParent.getParent();
}
}
// Regular case: use suggested ClassLoader as-is.
return classLoader;
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Convenient superclass for
@@ -81,6 +82,11 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
return this.beanFactory;
}
private ConfigurableBeanFactory getConfigurableBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory not set");
return this.beanFactory;
}
//---------------------------------------------------------------------
// Implementation of the TargetSourceCreator interface
@@ -104,7 +110,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
// We need to override just this bean definition, as it may reference other beans
// and we're happy to take the parent's definition for those.
// Always use prototype scope if demanded.
BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
BeanDefinition bd = getConfigurableBeanFactory().getMergedBeanDefinition(beanName);
GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
if (isPrototypeBased()) {
bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -126,7 +132,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
synchronized (this.internalBeanFactories) {
return this.internalBeanFactories.computeIfAbsent(beanName,
name -> buildInternalBeanFactory(this.beanFactory));
name -> buildInternalBeanFactory(getConfigurableBeanFactory()));
}
}
@@ -0,0 +1,10 @@
/**
* Various {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator}
* implementations for use with Spring's AOP auto-proxying support.
*/
@NonNullApi
@NonNullFields
package org.springframework.aop.framework.autoproxy.target;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.TargetSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
@@ -57,15 +59,18 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
protected final Log logger = LogFactory.getLog(getClass());
/** Name of the target bean we will create on each invocation. */
@Nullable
private String targetBeanName;
/** Class of the target. */
@Nullable
private volatile Class<?> targetClass;
/**
* BeanFactory that owns this TargetSource. We need to hold onto this
* reference so that we can create new prototype instances as necessary.
*/
@Nullable
private BeanFactory beanFactory;
@@ -86,6 +91,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
* Return the name of the target bean in the factory.
*/
public String getTargetBeanName() {
Assert.state(this.targetBeanName != null, "Target bean name not set");
return this.targetBeanName;
}
@@ -115,11 +121,13 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
* Return the owning BeanFactory.
*/
public BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory not set");
return this.beanFactory;
}
@Override
@Nullable
public Class<?> getTargetClass() {
Class<?> targetClass = this.targetClass;
if (targetClass != null) {
@@ -128,7 +136,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
synchronized (this) {
// Full check within synchronization, entering the BeanFactory interaction algorithm only once...
targetClass = this.targetClass;
if (targetClass == null && this.beanFactory != null) {
if (targetClass == null && this.beanFactory != null && this.targetBeanName != null) {
// Determine type of the target bean.
targetClass = this.beanFactory.getType(this.targetBeanName);
if (targetClass == null) {
@@ -182,18 +190,16 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
@Override
public int hashCode() {
int hashCode = getClass().hashCode();
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory);
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName);
return hashCode;
return getClass().hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.targetBeanName);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append(" for target bean '").append(this.targetBeanName).append('\'');
if (this.targetClass != null) {
sb.append(" of type [").append(this.targetClass.getName()).append(']');
Class<?> targetClass = this.targetClass;
if (targetClass != null) {
sb.append(" of type [").append(targetClass.getName()).append(']');
}
return sb.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ public abstract class AbstractLazyCreationTargetSource implements TargetSource {
protected final Log logger = LogFactory.getLog(getClass());
/** The lazily initialized target object. */
@Nullable
private Object lazyTarget;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,6 +70,7 @@ public final class EmptyTargetSource implements TargetSource, Serializable {
// Instance implementation
//---------------------------------------------------------------------
@Nullable
private final Class<?> targetClass;
private final boolean isStatic;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -95,8 +95,7 @@ public class HotSwappableTargetSource implements TargetSource, Serializable {
/**
* Two HotSwappableTargetSources are equal if the current target
* objects are equal.
* Two HotSwappableTargetSources are equal if the current target objects are equal.
*/
@Override
public boolean equals(Object other) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,14 +82,8 @@ public class SingletonTargetSource implements TargetSource, Serializable {
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof SingletonTargetSource)) {
return false;
}
SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
return this.target.equals(otherTargetSource.target);
return (this == other || (other instanceof SingletonTargetSource &&
this.target.equals(((SingletonTargetSource) other).target)));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,7 +58,12 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
* is meant to be per thread per instance of the ThreadLocalTargetSource class.
*/
private final ThreadLocal<Object> targetInThread =
new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'");
new NamedThreadLocal<Object>("Thread-local instance of bean") {
@Override
public String toString() {
return super.toString() + " '" + getTargetBeanName() + "'";
}
};
/**
* Set of managed targets, enabling us to keep track of the targets we've created.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,10 @@
package org.springframework.aop.framework;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.accessibility.Accessible;
@@ -380,6 +383,43 @@ public class ProxyFactoryTests {
assertThat(proxy.getName()).isEqualTo("tb");
}
@Test
public void testCharSequenceProxy() {
CharSequence target = "test";
ProxyFactory pf = new ProxyFactory(target);
ClassLoader cl = target.getClass().getClassLoader();
CharSequence proxy = (CharSequence) pf.getProxy(cl);
assertThat(proxy.toString()).isEqualTo(target);
}
@Test
public void testDateProxy() {
Date target = new Date();
ProxyFactory pf = new ProxyFactory(target);
pf.setProxyTargetClass(true);
ClassLoader cl = target.getClass().getClassLoader();
Date proxy = (Date) pf.getProxy(cl);
assertThat(proxy.getTime()).isEqualTo(target.getTime());
}
@Test
public void testJdbcSavepointProxy() throws SQLException {
Savepoint target = new Savepoint() {
@Override
public int getSavepointId() throws SQLException {
return 1;
}
@Override
public String getSavepointName() throws SQLException {
return "sp";
}
};
ProxyFactory pf = new ProxyFactory(target);
ClassLoader cl = Savepoint.class.getClassLoader();
Savepoint proxy = (Savepoint) pf.getProxy(cl);
assertThat(proxy.getSavepointName()).isEqualTo("sp");
}
@Order(2)
public static class A implements Runnable {
@@ -391,7 +431,7 @@ public class ProxyFactoryTests {
@Order(1)
public static class B implements Runnable{
public static class B implements Runnable {
@Override
public void run() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,7 +62,7 @@ import org.springframework.util.StringUtils;
* <p>Mainly for internal use within the framework, but to some degree also
* useful for application classes. Consider
* <a href="https://commons.apache.org/proper/commons-beanutils/">Apache Commons BeanUtils</a>,
* <a href="https://hotelsdotcom.github.io/bull/">BULL - Bean Utils Light Library</a>,
* <a href="https://github.com/ExpediaGroup/bull">BULL - Bean Utils Light Library</a>,
* or similar third-party frameworks for more comprehensive bean utilities.
*
* @author Rod Johnson
@@ -247,7 +247,8 @@ public abstract class BeanUtils {
// A single public constructor
return (Constructor<T>) ctors[0];
}
else if (ctors.length == 0){
else if (ctors.length == 0) {
// No public constructors -> check non-public
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
// A single non-public constructor, e.g. from a non-public record type
@@ -16,6 +16,7 @@
package org.springframework.beans;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
@@ -51,6 +52,10 @@ public class SimpleBeanInfoFactory implements BeanInfoFactory, Ordered {
PropertyDescriptorUtils.determineBasicProperties(beanClass);
return new SimpleBeanInfo() {
@Override
public BeanDescriptor getBeanDescriptor() {
return new BeanDescriptor(beanClass);
}
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
return pds.toArray(PropertyDescriptorUtils.EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -136,7 +136,10 @@ public interface BeanFactory {
* <p>Translates aliases back to the corresponding canonical bean name.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @return an instance of the bean
* @return an instance of the bean.
* Note that the return value will never be {@code null} but possibly a stub for
* {@code null} returned from a factory method, to be checked via {@code equals(null)}.
* Consider using {@link #getBeanProvider(Class)} for resolving optional dependencies.
* @throws NoSuchBeanDefinitionException if there is no bean with the specified name
* @throws BeansException if the bean could not be obtained
*/
@@ -152,7 +155,11 @@ public interface BeanFactory {
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @param requiredType type the bean must match; can be an interface or superclass
* @return an instance of the bean
* @return an instance of the bean.
* Note that the return value will never be {@code null}. In case of a stub for
* {@code null} from a factory method having been resolved for the requested bean, a
* {@code BeanNotOfRequiredTypeException} against the NullBean stub will be raised.
* Consider using {@link #getBeanProvider(Class)} for resolving optional dependencies.
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanNotOfRequiredTypeException if the bean is not of the required type
* @throws BeansException if the bean could not be created
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -665,7 +665,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
if (value != null && autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
@@ -778,7 +778,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
if (arguments[i] != null && beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import java.util.Set;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -240,10 +241,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
}
}
if (targetAnnotation == null) {
BeanFactory beanFactory = getBeanFactory();
// Look for matching annotation on the target class
if (getBeanFactory() != null) {
if (beanFactory != null) {
try {
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
Class<?> beanType = beanFactory.getType(bdHolder.getBeanName());
if (beanType != null) {
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -184,8 +184,9 @@ public abstract class YamlProcessor {
protected Yaml createYaml() {
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
new DumperOptions(), loaderOptions);
DumperOptions dumperOptions = new DumperOptions();
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(dumperOptions),
dumperOptions, loaderOptions);
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
@@ -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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,7 +102,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
private boolean singletonsCurrentlyInDestruction = false;
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
@@ -340,7 +340,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* (within the entire factory).
* @param beanName the name of the bean
*/
public boolean isSingletonCurrentlyInCreation(String beanName) {
public boolean isSingletonCurrentlyInCreation(@Nullable String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
@@ -554,7 +554,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
// Destroy the corresponding DisposableBean instance.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
disposableBean = this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,8 +68,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
private final Object bean;
@@ -214,12 +214,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
if (logger.isWarnEnabled()) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
}
@@ -240,12 +243,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (Throwable ex) {
String msg = "Invocation of close method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
if (logger.isWarnEnabled()) {
String msg = "Invocation of close method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
}
@@ -320,18 +326,23 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
catch (InvocationTargetException ex) {
String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" +
this.beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
if (logger.isWarnEnabled()) {
String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" +
this.beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
// Log at warn level like below but add the exception stacktrace only with debug level
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
}
}
catch (Throwable ex) {
logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName +
"' on bean with name '" + this.beanName + "'", ex);
if (logger.isWarnEnabled()) {
logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName +
"' on bean with name '" + this.beanName + "'", ex);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -547,7 +547,8 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
* @see DefaultNamespaceHandlerResolver#DefaultNamespaceHandlerResolver(ClassLoader)
*/
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
ResourceLoader resourceLoader = getResourceLoader();
ClassLoader cl = (resourceLoader != null ? resourceLoader.getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -77,6 +77,21 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
}
@Test
void replaceWrappedInstance() {
GetterBean target = new GetterBean();
BeanWrapperImpl accessor = createAccessor(target);
accessor.setPropertyValue("name", "tom");
assertThat(target.getAliasedName()).isEqualTo("tom");
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
target = new GetterBean();
accessor.setWrappedInstance(target);
accessor.setPropertyValue("name", "tom");
assertThat(target.getAliasedName()).isEqualTo("tom");
assertThat(accessor.getPropertyValue("aliasedName")).isEqualTo("tom");
}
@Test
void setValidAndInvalidPropertyValuesShouldContainExceptionDetails() {
TestBean target = new TestBean();
@@ -380,6 +395,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
@SuppressWarnings("try")
public static class ActiveResource implements AutoCloseable {
public ActiveResource getResource() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -436,7 +436,6 @@ class DefaultListableBeanFactoryTests {
@Test
void empty() {
ListableBeanFactory lbf = new DefaultListableBeanFactory();
assertThat(lbf.getBeanDefinitionNames() != null).as("No beans defined --> array != null").isTrue();
assertThat(lbf.getBeanDefinitionNames().length == 0).as("No beans defined after no arg constructor").isTrue();
assertThat(lbf.getBeanDefinitionCount() == 0).as("No beans defined after no arg constructor").isTrue();
@@ -778,21 +777,6 @@ class DefaultListableBeanFactoryTests {
assertThat(factory.getType("child")).isEqualTo(DerivedTestBean.class);
}
@Test
void nameAlreadyBound() {
Properties p = new Properties();
p.setProperty("kerry.(class)", TestBean.class.getName());
p.setProperty("kerry.age", "35");
registerBeanDefinitions(p);
try {
registerBeanDefinitions(p);
}
catch (BeanDefinitionStoreException ex) {
assertThat(ex.getBeanName()).isEqualTo("kerry");
// expected
}
}
private void singleTestBean(ListableBeanFactory lbf) {
assertThat(lbf.getBeanDefinitionCount() == 1).as("1 beans defined").isTrue();
String[] names = lbf.getBeanDefinitionNames();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,6 +133,26 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean2()).isSameAs(tb);
}
@Test
public void testResourceInjectionWithNullBean() {
RootBeanDefinition bd = new RootBeanDefinition(NonPublicResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean", tb);
NonPublicResourceInjectionBean bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
}
@Test
public void testExtendedResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
@@ -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.
@@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
@@ -148,7 +148,7 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
lbf.registerBeanDefinition(MARK, person2);
MethodParameter param = new MethodParameter(QualifiedTestBean.class.getDeclaredConstructor(Person.class), 0);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(param, false);
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
param.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(param.getParameterName()).isEqualTo("tpb");
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, qualifiedDescriptor)).isTrue();
@@ -174,9 +174,9 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
new MethodParameter(QualifiedTestBean.class.getDeclaredMethod("autowireNonqualified", Person.class), 0);
DependencyDescriptor qualifiedDescriptor = new DependencyDescriptor(qualifiedParam, false);
DependencyDescriptor nonqualifiedDescriptor = new DependencyDescriptor(nonqualifiedParam, false);
qualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
qualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(qualifiedParam.getParameterName()).isEqualTo("tpb");
nonqualifiedParam.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
nonqualifiedParam.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
assertThat(nonqualifiedParam.getParameterName()).isEqualTo("tpb");
assertThat(lbf.isAutowireCandidate(JUERGEN, null)).isTrue();
assertThat(lbf.isAutowireCandidate(JUERGEN, nonqualifiedDescriptor)).isTrue();
@@ -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.
@@ -502,7 +502,7 @@ class CustomEditorTests {
CharBean cb = new CharBean();
BeanWrapper bw = new BeanWrapperImpl(cb);
bw.setPropertyValue("myChar", new Character('c'));
bw.setPropertyValue("myChar", 'c');
assertThat(cb.getMyChar()).isEqualTo('c');
bw.setPropertyValue("myChar", "c");
@@ -526,16 +526,16 @@ class CustomEditorTests {
bw.registerCustomEditor(Character.class, new CharacterEditor(true));
bw.setPropertyValue("myCharacter", 'c');
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('c'));
assertThat(cb.getMyCharacter()).isEqualTo('c');
bw.setPropertyValue("myCharacter", "c");
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('c'));
assertThat(cb.getMyCharacter()).isEqualTo('c');
bw.setPropertyValue("myCharacter", "\u0041");
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf('A'));
assertThat(cb.getMyCharacter()).isEqualTo('A');
bw.setPropertyValue("myCharacter", " ");
assertThat(cb.getMyCharacter()).isEqualTo(Character.valueOf(' '));
assertThat(cb.getMyCharacter()).isEqualTo(' ');
bw.setPropertyValue("myCharacter", "");
assertThat(cb.getMyCharacter()).isNull();
@@ -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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@ import org.springframework.util.ObjectUtils;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Sam Brannen
* @author Brian Clozel
* @since 4.3
* @see CaffeineCache
*/
@@ -188,8 +189,13 @@ public class CaffeineCacheManager implements CacheManager {
@Override
@Nullable
public Cache getCache(String name) {
return this.cacheMap.computeIfAbsent(name, cacheName ->
this.dynamic ? createCaffeineCache(cacheName) : null);
if (this.dynamic) {
Cache cache = this.cacheMap.get(name);
return (cache != null) ? cache : this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
}
else {
return this.cacheMap.get(name);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,10 +132,10 @@ public class JavaMailSenderImpl implements JavaMailSender {
}
/**
* Allow {code Map} access to the JavaMail properties of this sender,
* Allow {@code Map} access to the JavaMail properties of this sender,
* with the option to add or override specific entries.
* <p>Useful for specifying entries directly, for example via
* {code javaMailProperties[mail.smtp.auth]}.
* {@code javaMailProperties[mail.smtp.auth]}.
*/
public Properties getJavaMailProperties() {
return this.javaMailProperties;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
/** Keys are method names; values are TransactionAttributes. */
private Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<>();
private final Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<>();
/**
@@ -117,8 +117,8 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
if (!(other instanceof NameMatchCacheOperationSource)) {
return false;
}
NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other;
return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
NameMatchCacheOperationSource otherCos = (NameMatchCacheOperationSource) other;
return ObjectUtils.nullSafeEquals(this.nameMap, otherCos.nameMap);
}
@Override
@@ -130,4 +130,5 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
public String toString() {
return getClass().getName() + ": " + this.nameMap;
}
}
@@ -274,7 +274,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
handleAsyncError(ex);
}
else if (event != null) {
publishEvent(event);
publishEvents(event);
}
});
}
@@ -468,6 +468,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
/**
* Inner class to avoid a hard dependency on the Reactive Streams API at runtime.
*/
private class ReactiveResultHandler {
public boolean subscribeToPublisher(Object result) {
@@ -481,6 +484,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
/**
* Reactive Streams Subscriber for publishing follow-up events.
*/
private class EventPublicationSubscriber implements Subscriber<Object> {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -447,7 +447,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
Assert.notNull(applicationStartup, "applicationStartup should not be null");
Assert.notNull(applicationStartup, "ApplicationStartup must not be null");
this.applicationStartup = applicationStartup;
}
@@ -729,9 +729,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* initialization. The initial definition resources will have been loaded but no
* post-processors will have run and no derived bean definitions will have been
* registered, and most importantly, no beans will have been instantiated yet.
* <p>This template method allows for registering special BeanPostProcessors
* etc in certain AbstractApplicationContext subclasses.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -117,9 +117,12 @@ public @interface Scheduled {
* last invocation and the start of the next.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the delay as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #fixedDelay()
*/
String fixedDelayString() default "";
@@ -135,9 +138,12 @@ public @interface Scheduled {
* Execute the annotated method with a fixed period between invocations.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the period as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #fixedRate()
*/
String fixedRateString() default "";
@@ -156,9 +162,12 @@ public @interface Scheduled {
* {@link #fixedRate} or {@link #fixedDelay} task.
* <p>The time unit is milliseconds by default but can be overridden via
* {@link #timeUnit}.
* <p>This attribute variant supports Spring-style "${...}" placeholders
* as well as SpEL expressions.
* @return the initial delay as a String value &mdash; for example, a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
* @see #initialDelay()
*/
String initialDelayString() default "";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,6 +83,9 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
private TaskExecutorAdapter adaptedExecutor;
@Nullable
private TaskDecorator taskDecorator;
/**
* Create a new ConcurrentTaskExecutor, using a single thread executor as default.
@@ -138,6 +141,7 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
* @since 4.3
*/
public final void setTaskDecorator(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
this.adaptedExecutor.setTaskDecorator(taskDecorator);
}
@@ -174,11 +178,15 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
}
private static TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) {
private TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) {
if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) {
return new ManagedTaskExecutorAdapter(concurrentExecutor);
}
return new TaskExecutorAdapter(concurrentExecutor);
TaskExecutorAdapter adapter = new TaskExecutorAdapter(concurrentExecutor);
if (this.taskDecorator != null) {
adapter.setTaskDecorator(this.taskDecorator);
}
return adapter;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,7 +100,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler() {
super();
this.scheduledExecutor = initScheduledExecutor(null);
initScheduledExecutor(null);
}
/**
@@ -115,7 +115,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) {
super(scheduledExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
initScheduledExecutor(scheduledExecutor);
}
/**
@@ -131,11 +131,11 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
*/
public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) {
super(concurrentExecutor);
this.scheduledExecutor = initScheduledExecutor(scheduledExecutor);
initScheduledExecutor(scheduledExecutor);
}
private ScheduledExecutorService initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
private void initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) {
if (scheduledExecutor != null) {
this.scheduledExecutor = scheduledExecutor;
this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null &&
@@ -145,7 +145,6 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
this.enterpriseConcurrentScheduler = false;
}
return this.scheduledExecutor;
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,10 @@ import org.springframework.lang.Nullable;
* Base class for setting up a {@link java.util.concurrent.ExecutorService}
* (typically a {@link java.util.concurrent.ThreadPoolExecutor} or
* {@link java.util.concurrent.ScheduledThreadPoolExecutor}).
* Defines common configuration settings and common lifecycle handling.
*
* <p>Defines common configuration settings and common lifecycle handling,
* inheriting thread customization options (name, priority, etc) from
* {@link org.springframework.util.CustomizableThreadCreator}.
*
* @author Juergen Hoeller
* @since 3.0
@@ -199,8 +202,7 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
/**
* Calls {@code shutdown} when the BeanFactory destroys
* the task executor instance.
* Calls {@code shutdown} when the BeanFactory destroys the executor instance.
* @see #shutdown()
*/
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -125,7 +125,7 @@ public class FieldError extends ObjectError {
@Override
public String toString() {
return "Field error in object '" + getObjectName() + "' on field '" + this.field +
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
"': rejected value [" + ObjectUtils.nullSafeConciseToString(this.rejectedValue) + "]; " +
resolvableToString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.aop.testfixture.advice.CountingBeforeAdvice;
import org.springframework.aop.testfixture.interceptor.NopInterceptor;
import org.springframework.beans.testfixture.beans.ITestBean;
@@ -35,6 +36,8 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -87,8 +90,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
AdvisedSupport pc = new AdvisedSupport(ITestBean.class);
pc.addAdvice(new NopInterceptor());
AopProxy aop = createAopProxy(pc);
assertThatExceptionOfType(AopConfigException.class).isThrownBy(
aop::getProxy);
assertThatExceptionOfType(AopConfigException.class).isThrownBy(aop::getProxy);
}
@Test
@@ -136,8 +138,8 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
Object proxy = aop.getProxy();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
assertThat(proxy instanceof ITestBean).isTrue();
assertThat(proxy instanceof TestBean).isTrue();
assertThat(proxy).isInstanceOf(ITestBean.class);
assertThat(proxy).isInstanceOf(TestBean.class);
TestBean tb = (TestBean) proxy;
assertThat(tb.getAge()).isEqualTo(32);
@@ -304,6 +306,8 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
CglibAopProxy cglib = new CglibAopProxy(as);
ITestBean proxy1 = (ITestBean) cglib.getProxy();
ITestBean proxy1a = (ITestBean) cglib.getProxy();
assertThat(proxy1a.getClass()).isSameAs(proxy1.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
@@ -312,7 +316,40 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
cglib = new CglibAopProxy(as);
ITestBean proxy2 = (ITestBean) cglib.getProxy();
assertThat(proxy2 instanceof Serializable).isTrue();
assertThat(proxy2).isInstanceOf(Serializable.class);
assertThat(proxy2.getClass()).isNotSameAs(proxy1.getClass());
ITestBean proxy2a = (ITestBean) cglib.getProxy();
assertThat(proxy2a).isInstanceOf(Serializable.class);
assertThat(proxy2a.getClass()).isSameAs(proxy2.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(Nullable.class), new NopInterceptor()));
cglib = new CglibAopProxy(as);
ITestBean proxy3 = (ITestBean) cglib.getProxy();
assertThat(proxy3).isInstanceOf(Serializable.class);
assertThat(proxy3.getClass()).isNotSameAs(proxy2.getClass());
ITestBean proxy3a = (ITestBean) cglib.getProxy();
assertThat(proxy3a).isInstanceOf(Serializable.class);
assertThat(proxy3a.getClass()).isSameAs(proxy3.getClass());
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(NonNull.class), new NopInterceptor()));
cglib = new CglibAopProxy(as);
ITestBean proxy4 = (ITestBean) cglib.getProxy();
assertThat(proxy4).isInstanceOf(Serializable.class);
assertThat(proxy4.getClass()).isNotSameAs(proxy3.getClass());
ITestBean proxy4a = (ITestBean) cglib.getProxy();
assertThat(proxy4a).isInstanceOf(Serializable.class);
assertThat(proxy4a.getClass()).isSameAs(proxy4.getClass());
}
@Test
@@ -331,7 +368,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
proxy.doTest();
}
catch (Exception ex) {
assertThat(ex instanceof ApplicationContextException).as("Invalid exception class").isTrue();
assertThat(ex).as("Invalid exception class").isInstanceOf(ApplicationContextException.class);
}
assertThat(proxy.isCatchInvoked()).as("Catch was not invoked").isTrue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ class ImportTests {
private DefaultListableBeanFactory processConfigurationClasses(Class<?>... classes) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setAllowBeanDefinitionOverriding(false);
for (Class<?> clazz : classes) {
beanFactory.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz));
}
@@ -56,9 +57,10 @@ class ImportTests {
for (Class<?> clazz : classes) {
beanFactory.getBean(clazz);
}
}
// ------------------------------------------------------------------------
@Test
void testProcessImportsWithAsm() {
int configClasses = 2;
@@ -158,6 +160,13 @@ class ImportTests {
assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class);
}
@Test
void testImportAnnotationWithThreeLevelRecursionAndDoubleImport() {
int configClasses = 5;
int beansInClasses = 5;
assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class, FirstLevelPlus.class);
}
// ------------------------------------------------------------------------
@Test
@@ -167,7 +176,6 @@ class ImportTests {
assertBeanDefinitionCount((configClasses + beansInClasses), WithMultipleArgumentsToImportAnnotation.class);
}
@Test
void testImportAnnotationWithMultipleArgumentsResultingInOverriddenBeanDefinition() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -245,6 +253,11 @@ class ImportTests {
}
}
@Configuration
@Import(ThirdLevel.class)
static class FirstLevelPlus {
}
@Configuration
@Import({ThirdLevel.class, InitBean.class})
static class SecondLevel {
@@ -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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,7 +133,7 @@ public class DateFormattingTests {
assertThat(exception)
.hasMessageContaining("for property 'styleDate'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value '99/01/01'")
.hasMessageContaining("for value [99/01/01]")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [99/01/01]")
.hasCauseInstanceOf(ParseException.class).cause()
@@ -353,7 +353,7 @@ public class DateFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value '210302'")
.hasMessageContaining("for value [210302]")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(ParseException.class).cause()
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -333,7 +333,7 @@ class DateTimeFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'isoLocalDate'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value '2009-31-10'")
.hasMessageContaining("for value [2009-31-10]")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [2009-31-10]")
.hasCauseInstanceOf(DateTimeParseException.class).cause()
@@ -540,7 +540,7 @@ class DateTimeFormattingTests {
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternLocalDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).cause()
.hasMessageContaining("for value '210302'")
.hasMessageContaining("for value [210302]")
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(DateTimeParseException.class).cause()
@@ -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.
@@ -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.
@@ -20,7 +20,6 @@ import java.beans.PropertyDescriptor;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
@@ -32,6 +31,7 @@ import org.springframework.beans.BeanWrapperImpl;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.TestDynamicMBean;
import org.springframework.util.MBeanTestUtils;
import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author Sam Brannen
*/
class JmxUtilsTests {
@@ -131,10 +132,11 @@ class JmxUtilsTests {
MBeanServer server = null;
try {
server = JmxUtils.locateMBeanServer();
assertThat(server).isNotNull();
}
finally {
if (server != null) {
MBeanServerFactory.releaseMBeanServer(server);
MBeanTestUtils.releaseMBeanServer(server);
}
}
}
@@ -21,21 +21,25 @@ import java.lang.reflect.Field;
import javax.naming.spi.NamingManager;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.condition.JRE.JAVA_16;
/**
* Tests for {@link JndiLocatorDelegate}.
*
* @author Phillip Webb
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class JndiLocatorDelegateTests {
@DisabledForJreRange(
min = JAVA_16,
disabledReason = "Cannot use reflection to set private static field in javax.naming.spi.NamingManager")
class JndiLocatorDelegateTests {
@Test
public void isDefaultJndiEnvironmentAvailableFalse() throws Exception {
void isDefaultJndiEnvironmentAvailableFalse() throws Exception {
Field builderField = NamingManager.class.getDeclaredField("initctx_factory_builder");
builderField.setAccessible(true);
Object oldBuilder = builderField.get(null);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.scheduling.concurrent;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@@ -26,6 +27,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.NoOpRunnable;
import org.springframework.core.task.TaskDecorator;
import org.springframework.util.Assert;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -69,10 +72,40 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
}
@Test
void passingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() {
void earlySetConcurrentExecutorCallRespectsConfiguredTaskDecorator() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
executor.setConcurrentExecutor(null);
executor.setConcurrentExecutor(new DecoratedExecutor());
executor.setTaskDecorator(new RunnableDecorator());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
@Test
void lateSetConcurrentExecutorCallRespectsConfiguredTaskDecorator() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
executor.setTaskDecorator(new RunnableDecorator());
executor.setConcurrentExecutor(new DecoratedExecutor());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
private static class DecoratedRunnable implements Runnable {
@Override
public void run() {
}
}
private static class RunnableDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return new DecoratedRunnable();
}
}
private static class DecoratedExecutor implements Executor {
@Override
public void execute(Runnable command) {
Assert.state(command instanceof DecoratedRunnable, "TaskDecorator not applied");
}
}
}
@@ -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,37 +18,59 @@ package org.springframework.util;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.EnumSet;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import org.junit.jupiter.api.condition.JRE;
/**
* Utilities for MBean tests.
*
* @author Phillip Webb
* @author Sam Brannen
*/
public class MBeanTestUtils {
/**
* Resets MBeanServerFactory and ManagementFactory to a known consistent state.
* <p>This involves releasing all currently registered MBeanServers and resetting
* the platformMBeanServer to null.
* Reset the {@link MBeanServerFactory} to a known consistent state. This involves
* {@linkplain #releaseMBeanServer(MBeanServer) releasing} all currently registered
* MBeanServers.
* <p>On JDK 8 - JDK 16, this method also resets the platformMBeanServer field
* in {@link ManagementFactory} to {@code null}.
*/
public static synchronized void resetMBeanServers() throws Exception {
for (MBeanServer server : MBeanServerFactory.findMBeanServer(null)) {
try {
MBeanServerFactory.releaseMBeanServer(server);
}
catch (IllegalArgumentException ex) {
if (!ex.getMessage().contains("not in list")) {
throw ex;
}
}
releaseMBeanServer(server);
}
Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
field.setAccessible(true);
field.set(null, null);
if (!isCurrentJreWithinRange(JRE.JAVA_16, JRE.OTHER)) {
Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
field.setAccessible(true);
field.set(null, null);
}
}
/**
* Attempt to release the supplied {@link MBeanServer}.
* <p>Ignores any {@link IllegalArgumentException} thrown by
* {@link MBeanServerFactory#releaseMBeanServer(MBeanServer)} whose error
* message contains the text "not in list".
*/
public static void releaseMBeanServer(MBeanServer server) {
try {
MBeanServerFactory.releaseMBeanServer(server);
}
catch (IllegalArgumentException ex) {
if (!ex.getMessage().contains("not in list")) {
throw ex;
}
}
}
static boolean isCurrentJreWithinRange(JRE min, JRE max) {
return EnumSet.range(min, max).contains(JRE.currentVersion());
}
}
@@ -82,6 +82,17 @@ public abstract class AnnotationVisitor {
this.av = annotationVisitor;
}
/**
* The annotation visitor to which this visitor must delegate method calls. May be {@literal
* null}.
*
* @return the annotation visitor to which this visitor must delegate method calls, or {@literal
* null}.
*/
public AnnotationVisitor getDelegate() {
return av;
}
/**
* Visits a primitive value of the annotation.
*
@@ -194,7 +194,7 @@ public class ClassReader {
this.b = classFileBuffer;
// Check the class' major_version. This field is after the magic and minor_version fields, which
// use 4 and 2 bytes respectively.
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V19) {
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V21) {
throw new IllegalArgumentException(
"Unsupported class file major version " + readShort(classFileOffset + 6));
}
@@ -308,6 +308,7 @@ public class ClassReader {
* @return the content of the given input stream.
* @throws IOException if a problem occurs during reading.
*/
@SuppressWarnings("PMD.UseTryWithResources")
private static byte[] readStream(final InputStream inputStream, final boolean close)
throws IOException {
if (inputStream == null) {
@@ -376,7 +377,7 @@ public class ClassReader {
}
/**
* Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
* Returns the internal name of the super class (see {@link Type#getInternalName()}). For
* interfaces, the super class is {@link Object}.
*
* @return the internal name of the super class, or {@literal null} for {@link Object} class.
@@ -42,7 +42,8 @@ public final class ClassTooLargeException extends IndexOutOfBoundsException {
/**
* Constructs a new {@link ClassTooLargeException}.
*
* @param className the internal name of the class.
* @param className the internal name of the class (see {@link
* org.objectweb.asm.Type#getInternalName()}).
* @param constantPoolCount the number of constant pool items of the class.
*/
public ClassTooLargeException(final String className, final int constantPoolCount) {
@@ -52,7 +53,7 @@ public final class ClassTooLargeException extends IndexOutOfBoundsException {
}
/**
* Returns the internal name of the class.
* Returns the internal name of the class (see {@link org.objectweb.asm.Type#getInternalName()}).
*
* @return the internal name of the class.
*/
@@ -81,6 +81,15 @@ public abstract class ClassVisitor {
this.cv = classVisitor;
}
/**
* The class visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the class visitor to which this visitor must delegate method calls, or {@literal null}.
*/
public ClassVisitor getDelegate() {
return cv;
}
/**
* Visits the header of the class.
*
@@ -155,7 +164,8 @@ public abstract class ClassVisitor {
* implicitly its own nest, so it's invalid to call this method with the visited class name as
* argument.
*
* @param nestHost the internal name of the host class of the nest.
* @param nestHost the internal name of the host class of the nest (see {@link
* Type#getInternalName()}).
*/
public void visitNestHost(final String nestHost) {
if (api < Opcodes.ASM7) {
@@ -167,14 +177,19 @@ public abstract class ClassVisitor {
}
/**
* Visits the enclosing class of the class. This method must be called only if the class has an
* enclosing class.
* Visits the enclosing class of the class. This method must be called only if this class is a
* local or anonymous class. See the JVMS 4.7.7 section for more details.
*
* @param owner internal name of the enclosing class of the class.
* @param owner internal name of the enclosing class of the class (see {@link
* Type#getInternalName()}).
* @param name the name of the method that contains the class, or {@literal null} if the class is
* not enclosed in a method of its enclosing class.
* not enclosed in a method or constructor of its enclosing class (e.g. if it is enclosed in
* an instance initializer, static initializer, instance variable initializer, or class
* variable initializer).
* @param descriptor the descriptor of the method that contains the class, or {@literal null} if
* the class is not enclosed in a method of its enclosing class.
* the class is not enclosed in a method or constructor of its enclosing class (e.g. if it is
* enclosed in an instance initializer, static initializer, instance variable initializer, or
* class variable initializer).
*/
public void visitOuterClass(final String owner, final String name, final String descriptor) {
if (cv != null) {
@@ -241,7 +256,7 @@ public abstract class ClassVisitor {
* the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
* it's invalid to call this method with the visited class name as argument.
*
* @param nestMember the internal name of a nest member.
* @param nestMember the internal name of a nest member (see {@link Type#getInternalName()}).
*/
public void visitNestMember(final String nestMember) {
if (api < Opcodes.ASM7) {
@@ -256,7 +271,8 @@ public abstract class ClassVisitor {
* Visits a permitted subclasses. A permitted subclass is one of the allowed subclasses of the
* current class.
*
* @param permittedSubclass the internal name of a permitted subclass.
* @param permittedSubclass the internal name of a permitted subclass (see {@link
* Type#getInternalName()}).
*/
public void visitPermittedSubclass(final String permittedSubclass) {
if (api < Opcodes.ASM9) {
@@ -269,15 +285,18 @@ public abstract class ClassVisitor {
/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited.
* class being visited. More precisely, every class or interface C which is referenced by this
* class and which is not a package member must be visited with this method. This class must
* reference its nested class or interface members, and its enclosing class, if any. See the JVMS
* 4.7.6 section for more details.
*
* @param name the internal name of an inner class (see {@link Type#getInternalName()}).
* @param outerName the internal name of the class to which the inner class belongs (see {@link
* Type#getInternalName()}). May be {@literal null} for not member classes.
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
* {@literal null} for anonymous inner classes.
* @param access the access flags of the inner class as originally declared in the enclosing
* class.
* @param name the internal name of C (see {@link Type#getInternalName()}).
* @param outerName the internal name of the class or interface C is a member of (see {@link
* Type#getInternalName()}). Must be {@literal null} if C is not the member of a class or
* interface (e.g. for local or anonymous classes).
* @param innerName the (simple) name of C. Must be {@literal null} for anonymous inner classes.
* @param access the access flags of C originally declared in the source code from which this
* class was compiled.
*/
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
@@ -842,7 +842,7 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param value the internal name of the class.
* @param value the internal name of the class (see {@link Type#getInternalName()}).
* @return the index of a new or already existing class reference item.
*/
public int newClass(final String value) {
@@ -894,7 +894,8 @@ public class ClassWriter extends ClassVisitor {
* Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the field or method owner class.
* @param owner the internal name of the field or method owner class (see {@link
* Type#getInternalName()}).
* @param name the name of the field or method.
* @param descriptor the descriptor of the field or method.
* @return the index of a new or already existing method type reference item.
@@ -916,7 +917,8 @@ public class ClassWriter extends ClassVisitor {
* Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the field or method owner class.
* @param owner the internal name of the field or method owner class (see {@link
* Type#getInternalName()}).
* @param name the name of the field or method.
* @param descriptor the descriptor of the field or method.
* @param isInterface true if the owner is an interface.
@@ -978,7 +980,7 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param owner the internal name of the field's owner class.
* @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}).
* @param name the field's name.
* @param descriptor the field's descriptor.
* @return the index of a new or already existing field reference item.
@@ -992,7 +994,8 @@ public class ClassWriter extends ClassVisitor {
* constant pool already contains a similar item. <i>This method is intended for {@link Attribute}
* sub classes, and is normally not needed by class generators or adapters.</i>
*
* @param owner the internal name of the method's owner class.
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor.
* @param isInterface {@literal true} if {@code owner} is an interface.
@@ -1028,9 +1031,10 @@ public class ClassWriter extends ClassVisitor {
* currently being generated by this ClassWriter, which can of course not be loaded since it is
* under construction.
*
* @param type1 the internal name of a class.
* @param type2 the internal name of another class.
* @return the internal name of the common super class of the two given classes.
* @param type1 the internal name of a class (see {@link Type#getInternalName()}).
* @param type2 the internal name of another class (see {@link Type#getInternalName()}).
* @return the internal name of the common super class of the two given classes (see {@link
* Type#getInternalName()}).
*/
protected String getCommonSuperClass(final String type1, final String type2) {
ClassLoader classLoader = getClassLoader();
@@ -78,6 +78,15 @@ public abstract class FieldVisitor {
this.fv = fieldVisitor;
}
/**
* The field visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the field visitor to which this visitor must delegate method calls, or {@literal null}.
*/
public FieldVisitor getDelegate() {
return fv;
}
/**
* Visits an annotation of the field.
*
@@ -367,11 +367,12 @@ class Frame {
typeValue = REFERENCE_KIND | symbolTable.addType(internalName);
break;
default:
throw new IllegalArgumentException();
throw new IllegalArgumentException(
"Invalid descriptor fragment: " + buffer.substring(elementDescriptorOffset));
}
return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue;
default:
throw new IllegalArgumentException();
throw new IllegalArgumentException("Invalid descriptor: " + buffer.substring(offset));
}
}
@@ -65,7 +65,7 @@ public final class Handle {
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
* handle (see {@link Type#getInternalName()}).
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
@@ -85,7 +85,7 @@ public final class Handle {
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
* handle (see {@link Type#getInternalName()}).
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @param isInterface whether the owner is an interface or not.
@@ -118,7 +118,8 @@ public final class Handle {
/**
* Returns the internal name of the class that owns the field or method designated by this handle.
*
* @return the internal name of the class that owns the field or method designated by this handle.
* @return the internal name of the class that owns the field or method designated by this handle
* (see {@link Type#getInternalName()}).
*/
public String getOwner() {
return owner;
@@ -44,7 +44,7 @@ public final class MethodTooLargeException extends IndexOutOfBoundsException {
/**
* Constructs a new {@link MethodTooLargeException}.
*
* @param className the internal name of the owner class.
* @param className the internal name of the owner class (see {@link Type#getInternalName()}).
* @param methodName the name of the method.
* @param descriptor the descriptor of the method.
* @param codeSize the size of the method's Code attribute, in bytes.
@@ -64,7 +64,7 @@ public final class MethodTooLargeException extends IndexOutOfBoundsException {
/**
* Returns the internal name of the owner class.
*
* @return the internal name of the owner class.
* @return the internal name of the owner class (see {@link Type#getInternalName()}).
*/
public String getClassName() {
return className;
@@ -94,6 +94,16 @@ public abstract class MethodVisitor {
this.mv = methodVisitor;
}
/**
* The method visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the method visitor to which this visitor must delegate method calls, or {@literal
* null}.
*/
public MethodVisitor getDelegate() {
return mv;
}
// -----------------------------------------------------------------------------------------------
// Parameters, annotations and non standard attributes
// -----------------------------------------------------------------------------------------------
@@ -120,7 +130,7 @@ public abstract class MethodVisitor {
* @return a visitor to the visit the actual default value of this annotation interface method, or
* {@literal null} if this visitor is not interested in visiting this default value. The
* 'name' parameters passed to the methods of this annotation visitor are ignored. Moreover,
* exacly one visit method must be called on this annotation visitor, followed by visitEnd.
* exactly one visit method must be called on this annotation visitor, followed by visitEnd.
*/
public AnnotationVisitor visitAnnotationDefault() {
if (mv != null) {
@@ -273,15 +283,17 @@ public abstract class MethodVisitor {
* @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
* Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
* @param numLocal the number of local variables in the visited frame.
* @param numLocal the number of local variables in the visited frame. Long and double values
* count for one variable.
* @param local the local variable types in this frame. This array must not be modified. Primitive
* types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link
* Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element).
* Reference types are represented by String objects (representing internal names), and
* uninitialized types by Label objects (this label designates the NEW instruction that
* created this uninitialized value).
* @param numStack the number of operand stack elements in the visited frame.
* Reference types are represented by String objects (representing internal names, see {@link
* Type#getInternalName()}), and uninitialized types by Label objects (this label designates
* the NEW instruction that created this uninitialized value).
* @param numStack the number of operand stack elements in the visited frame. Long and double
* values count for one stack element.
* @param stack the operand stack types in this frame. This array must not be modified. Its
* content has the same format as the "local" array.
* @throws IllegalStateException if a frame is visited just after another one, without any
@@ -360,7 +372,7 @@ public abstract class MethodVisitor {
/**
* Visits a type instruction. A type instruction is an instruction that takes the internal name of
* a class as parameter.
* a class as parameter (see {@link Type#getInternalName()}).
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either NEW,
* ANEWARRAY, CHECKCAST or INSTANCEOF.
@@ -552,12 +564,12 @@ public abstract class MethodVisitor {
/**
* Visits an IINC instruction.
*
* @param var index of the local variable to be incremented.
* @param varIndex index of the local variable to be incremented.
* @param increment amount to increment the local variable by.
*/
public void visitIincInsn(final int var, final int increment) {
public void visitIincInsn(final int varIndex, final int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
mv.visitIincInsn(varIndex, increment);
}
}
@@ -643,8 +655,9 @@ public abstract class MethodVisitor {
* @param start the beginning of the exception handler's scope (inclusive).
* @param end the end of the exception handler's scope (exclusive).
* @param handler the beginning of the exception handler's code.
* @param type the internal name of the type of exceptions handled by the handler, or {@literal
* null} to catch any exceptions (for "finally" blocks).
* @param type the internal name of the type of exceptions handled by the handler (see {@link
* Type#getInternalName()}), or {@literal null} to catch any exceptions (for "finally"
* blocks).
* @throws IllegalArgumentException if one of the labels has already been visited by this visitor
* (by the {@link #visitLabel} method).
*/
@@ -284,6 +284,8 @@ public interface Opcodes {
int V17 = 0 << 16 | 61;
int V18 = 0 << 16 | 62;
int V19 = 0 << 16 | 63;
int V20 = 0 << 16 | 64;
int V21 = 0 << 16 | 65;
/**
* Version flag indicating that the class is using 'preview' features.
@@ -45,7 +45,7 @@ public abstract class RecordComponentVisitor {
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*/
/*package-private*/ RecordComponentVisitor delegate;
protected RecordComponentVisitor delegate;
/**
* Constructs a new {@link RecordComponentVisitor}.
@@ -83,7 +83,8 @@ public abstract class RecordComponentVisitor {
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the record visitor to which this visitor must delegate method calls or {@literal null}.
* @return the record visitor to which this visitor must delegate method calls, or {@literal
* null}.
*/
public RecordComponentVisitor getDelegate() {
return delegate;
@@ -37,7 +37,7 @@ final class RecordComponentWriter extends RecordComponentVisitor {
/** The name_index field of the Record attribute. */
private final int nameIndex;
/** The descriptor_index field of the the Record attribute. */
/** The descriptor_index field of the Record attribute. */
private final int descriptorIndex;
/**
@@ -245,7 +245,7 @@ public final class Type {
/**
* Returns the {@link Type} corresponding to the given internal name.
*
* @param internalName an internal name.
* @param internalName an internal name (see {@link Type#getInternalName()}).
* @return the {@link Type} corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
@@ -708,8 +708,8 @@ public final class Type {
*
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code
* i >> 2}, and returnSize to {@code i & 0x03}).
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
@@ -721,8 +721,8 @@ public final class Type {
* @param methodDescriptor a method descriptor.
* @return the size of the arguments of the method (plus one for the implicit this argument),
* argumentsSize, and the size of its return value, returnSize, packed into a single int i =
* {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code
* i >> 2}, and returnSize to {@code i & 0x03}).
* {@code (argumentsSize &lt;&lt; 2) | returnSize} (argumentsSize is therefore equal to {@code
* i &gt;&gt; 2}, and returnSize to {@code i &amp; 0x03}).
*/
public static int getArgumentsAndReturnSizes(final String methodDescriptor) {
int argumentsSize = 1;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,6 +68,7 @@ public final class CollectionFactory {
approximableCollectionTypes.add(SortedSet.class);
approximableCollectionTypes.add(NavigableSet.class);
approximableMapTypes.add(Map.class);
approximableMapTypes.add(MultiValueMap.class);
approximableMapTypes.add(SortedMap.class);
approximableMapTypes.add(NavigableMap.class);
@@ -80,6 +81,7 @@ public final class CollectionFactory {
approximableCollectionTypes.add(EnumSet.class);
approximableMapTypes.add(HashMap.class);
approximableMapTypes.add(LinkedHashMap.class);
approximableMapTypes.add(LinkedMultiValueMap.class);
approximableMapTypes.add(TreeMap.class);
approximableMapTypes.add(EnumMap.class);
}
@@ -121,13 +123,7 @@ public final class CollectionFactory {
*/
@SuppressWarnings({"rawtypes", "unchecked", "cast"})
public static <E> Collection<E> createApproximateCollection(@Nullable Object collection, int capacity) {
if (collection instanceof LinkedList) {
return new LinkedList<>();
}
else if (collection instanceof List) {
return new ArrayList<>(capacity);
}
else if (collection instanceof EnumSet) {
if (collection instanceof EnumSet) {
// Cast is necessary for compilation in Eclipse 4.4.1.
Collection<E> enumSet = (Collection<E>) EnumSet.copyOf((EnumSet) collection);
enumSet.clear();
@@ -136,6 +132,12 @@ public final class CollectionFactory {
else if (collection instanceof SortedSet) {
return new TreeSet<>(((SortedSet<E>) collection).comparator());
}
if (collection instanceof LinkedList) {
return new LinkedList<>();
}
else if (collection instanceof List) {
return new ArrayList<>(capacity);
}
else {
return new LinkedHashSet<>(capacity);
}
@@ -181,7 +183,7 @@ public final class CollectionFactory {
@SuppressWarnings({"unchecked", "cast"})
public static <E> Collection<E> createCollection(Class<?> collectionType, @Nullable Class<?> elementType, int capacity) {
Assert.notNull(collectionType, "Collection type must not be null");
if (LinkedHashSet.class == collectionType || HashSet.class == collectionType ||
if (LinkedHashSet.class == collectionType ||
Set.class == collectionType || Collection.class == collectionType) {
return new LinkedHashSet<>(capacity);
}
@@ -191,8 +193,8 @@ public final class CollectionFactory {
else if (LinkedList.class == collectionType) {
return new LinkedList<>();
}
else if (TreeSet.class == collectionType || NavigableSet.class == collectionType
|| SortedSet.class == collectionType) {
else if (TreeSet.class == collectionType || NavigableSet.class == collectionType ||
SortedSet.class == collectionType) {
return new TreeSet<>();
}
else if (EnumSet.class.isAssignableFrom(collectionType)) {
@@ -200,6 +202,9 @@ public final class CollectionFactory {
// Cast is necessary for compilation in Eclipse 4.4.1.
return (Collection<E>) EnumSet.noneOf(asEnumType(elementType));
}
else if (HashSet.class == collectionType) {
return new HashSet<>(capacity);
}
else {
if (collectionType.isInterface() || !Collection.class.isAssignableFrom(collectionType)) {
throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName());
@@ -251,6 +256,9 @@ public final class CollectionFactory {
else if (map instanceof SortedMap) {
return new TreeMap<>(((SortedMap<K, V>) map).comparator());
}
else if (map instanceof MultiValueMap) {
return new LinkedMultiValueMap(capacity);
}
else {
return new LinkedHashMap<>(capacity);
}
@@ -297,26 +305,24 @@ public final class CollectionFactory {
@SuppressWarnings({"rawtypes", "unchecked"})
public static <K, V> Map<K, V> createMap(Class<?> mapType, @Nullable Class<?> keyType, int capacity) {
Assert.notNull(mapType, "Map type must not be null");
if (mapType.isInterface()) {
if (Map.class == mapType) {
return new LinkedHashMap<>(capacity);
}
else if (SortedMap.class == mapType || NavigableMap.class == mapType) {
return new TreeMap<>();
}
else if (MultiValueMap.class == mapType) {
return new LinkedMultiValueMap();
}
else {
throw new IllegalArgumentException("Unsupported Map interface: " + mapType.getName());
}
if (LinkedHashMap.class == mapType || Map.class == mapType) {
return new LinkedHashMap<>(capacity);
}
else if (LinkedMultiValueMap.class == mapType || MultiValueMap.class == mapType) {
return new LinkedMultiValueMap();
}
else if (TreeMap.class == mapType || SortedMap.class == mapType || NavigableMap.class == mapType) {
return new TreeMap<>();
}
else if (EnumMap.class == mapType) {
Assert.notNull(keyType, "Cannot create EnumMap for unknown key type");
return new EnumMap(asEnumType(keyType));
}
else if (HashMap.class == mapType) {
return new HashMap<>(capacity);
}
else {
if (!Map.class.isAssignableFrom(mapType)) {
if (mapType.isInterface() || !Map.class.isAssignableFrom(mapType)) {
throw new IllegalArgumentException("Unsupported Map type: " + mapType.getName());
}
try {
@@ -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.
@@ -18,9 +18,9 @@ package org.springframework.core;
/**
* Default implementation of the {@link ParameterNameDiscoverer} strategy interface,
* using the Java 8 standard reflection mechanism (if available), and falling back
* to the ASM-based {@link LocalVariableTableParameterNameDiscoverer} for checking
* debug information in the class file.
* using the Java 8 standard reflection mechanism, and falling back to the ASM-based
* {@link LocalVariableTableParameterNameDiscoverer} for checking debug information
* in the class file (e.g. for classes compiled with earlier Java versions).
*
* <p>If a Kotlin reflection implementation is present,
* {@link KotlinReflectionParameterNameDiscoverer} is added first in the list and
@@ -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.
@@ -31,11 +31,13 @@ import org.springframework.lang.Nullable;
* {@link ParameterNameDiscoverer} implementation which uses Kotlin's reflection facilities
* for introspecting parameter names.
*
* Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
* <p>Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
* determine interface parameter names without requiring Java 8 -parameters compiler flag.
*
* @author Sebastien Deleuze
* @since 5.0
* @see StandardReflectionParameterNameDiscoverer
* @see DefaultParameterNameDiscoverer
*/
public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
@@ -47,12 +47,18 @@ import org.springframework.util.ClassUtils;
* caches the ASM discovered information for each introspected Class, in a thread-safe
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
*
* <p>This discoverer variant is effectively superseded by the Java 8 based
* {@link StandardReflectionParameterNameDiscoverer} but included as a fallback still
* (for code not compiled with the standard "-parameters" compiler flag).
*
* @author Adrian Colyer
* @author Costin Leau
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @since 2.0
* @see StandardReflectionParameterNameDiscoverer
* @see DefaultParameterNameDiscoverer
*/
public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -781,6 +781,7 @@ public class MethodParameter {
return new MethodParameter(this);
}
/**
* Create a new MethodParameter for the given method or constructor.
* <p>This is a convenience factory method for scenarios where 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.
@@ -26,10 +26,15 @@ import org.springframework.lang.Nullable;
* {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities
* for introspecting parameter names (based on the "-parameters" compiler flag).
*
* <p>This is a key element of {@link DefaultParameterNameDiscoverer} where it is being
* combined with {@link KotlinReflectionParameterNameDiscoverer} if Kotlin is present.
*
* @author Juergen Hoeller
* @since 4.0
* @see java.lang.reflect.Method#getParameters()
* @see java.lang.reflect.Parameter#getName()
* @see KotlinReflectionParameterNameDiscoverer
* @see DefaultParameterNameDiscoverer
*/
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
@@ -86,17 +86,6 @@ final class AttributeMethods {
}
/**
* Determine if this instance only contains a single attribute named
* {@code value}.
* @return {@code true} if there is only a value attribute
*/
boolean hasOnlyValueAttribute() {
return (this.attributeMethods.length == 1 &&
MergedAnnotation.VALUE.equals(this.attributeMethods[0].getName()));
}
/**
* Determine if values from the given annotation can be safely accessed without
* causing any {@link TypeNotPresentException TypeNotPresentExceptions}.
@@ -166,8 +166,8 @@ public abstract class RepeatableContainers {
private static Object computeRepeatedAnnotationsMethod(Class<? extends Annotation> annotationType) {
AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType);
if (methods.hasOnlyValueAttribute()) {
Method method = methods.get(0);
Method method = methods.get(MergedAnnotation.VALUE);
if (method != null) {
Class<?> returnType = method.getReturnType();
if (returnType.isArray()) {
Class<?> componentType = returnType.getComponentType();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ public class ConversionFailedException extends ConversionException {
@Nullable Object value, Throwable cause) {
super("Failed to convert from type [" + sourceType + "] to type [" + targetType +
"] for value '" + ObjectUtils.nullSafeToString(value) + "'", cause);
"] for value [" + ObjectUtils.nullSafeConciseToString(value) + "]", cause);
this.sourceType = sourceType;
this.targetType = targetType;
this.value = value;
@@ -57,6 +57,8 @@ package org.springframework.core.env;
* of property sources prior to application context {@code refresh()}.
*
* @author Chris Beams
* @author Phillip Webb
* @author Sam Brannen
* @since 3.1
* @see PropertyResolver
* @see EnvironmentCapable
@@ -95,25 +97,56 @@ public interface Environment extends PropertyResolver {
String[] getDefaultProfiles();
/**
* Return whether one or more of the given profiles is active or, in the case of no
* explicit active profiles, whether one or more of the given profiles is included in
* the set of default profiles. If a profile begins with '!' the logic is inverted,
* i.e. the method will return {@code true} if the given profile is <em>not</em> active.
* For example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true} if
* profile 'p1' is active or 'p2' is not active.
* @throws IllegalArgumentException if called with zero arguments
* or if any profile is {@code null}, empty, or whitespace only
* Determine whether one or more of the given profiles is active &mdash; or
* in the case of no explicit {@linkplain #getActiveProfiles() active profiles},
* whether one or more of the given profiles is included in the set of
* {@linkplain #getDefaultProfiles() default profiles}.
* <p>If a profile begins with '!' the logic is inverted, meaning this method
* will return {@code true} if the given profile is <em>not</em> active. For
* example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true}
* if profile 'p1' is active or 'p2' is not active.
* @throws IllegalArgumentException if called with a {@code null} array, an
* empty array, zero arguments or if any profile is {@code null}, empty, or
* whitespace only
* @see #getActiveProfiles
* @see #getDefaultProfiles
* @see #matchesProfiles(String...)
* @see #acceptsProfiles(Profiles)
* @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)}
* @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)} or
* {@link #matchesProfiles(String...)}
*/
@Deprecated
boolean acceptsProfiles(String... profiles);
/**
* Return whether the {@linkplain #getActiveProfiles() active profiles}
* match the given {@link Profiles} predicate.
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether the given {@link Profiles} predicate matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether the given {@code Profiles} predicate
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>If you wish provide profile expressions directly as strings, use
* {@link #matchesProfiles(String...)} instead.
* @since 5.1
* @see #matchesProfiles(String...)
* @see Profiles#of(String...)
*/
boolean acceptsProfiles(Profiles profiles);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,32 +43,32 @@ public interface Profiles {
/**
* Create a new {@link Profiles} instance that checks for matches against
* the given <em>profile strings</em>.
* the given <em>profile expressions</em>.
* <p>The returned instance will {@linkplain Profiles#matches(Predicate) match}
* if any one of the given profile strings matches.
* <p>A profile string may contain a simple profile name (for example
* {@code "production"}) or a profile expression. A profile expression allows
* if any one of the given profile expressions matches.
* <p>A profile expression may contain a simple profile name (for example
* {@code "production"}) or a compound expression. A compound expression allows
* for more complicated profile logic to be expressed, for example
* {@code "production & cloud"}.
* <p>The following operators are supported in profile expressions.
* <ul>
* <li>{@code !} - A logical <em>NOT</em> of the profile or profile expression</li>
* <li>{@code &} - A logical <em>AND</em> of the profiles or profile expressions</li>
* <li>{@code |} - A logical <em>OR</em> of the profiles or profile expressions</li>
* <li>{@code !} - A logical <em>NOT</em> of the profile name or compound expression</li>
* <li>{@code &} - A logical <em>AND</em> of the profile names or compound expressions</li>
* <li>{@code |} - A logical <em>OR</em> of the profile names or compound expressions</li>
* </ul>
* <p>Please note that the {@code &} and {@code |} operators may not be mixed
* without using parentheses. For example {@code "a & b | c"} is not a valid
* expression; it must be expressed as {@code "(a & b) | c"} or
* without using parentheses. For example, {@code "a & b | c"} is not a valid
* expression: it must be expressed as {@code "(a & b) | c"} or
* {@code "a & (b | c)"}.
* <p>As of Spring Framework 5.1.17, two {@code Profiles} instances returned
* by this method are considered equivalent to each other (in terms of
* {@code equals()} and {@code hashCode()} semantics) if they are created
* with identical <em>profile strings</em>.
* @param profiles the <em>profile strings</em> to include
* with identical <em>profile expressions</em>.
* @param profileExpressions the <em>profile expressions</em> to include
* @return a new {@link Profiles} instance
*/
static Profiles of(String... profiles) {
return ProfilesParser.parse(profiles);
static Profiles of(String... profileExpressions) {
return ProfilesParser.parse(profileExpressions);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@ final class ProfilesParser {
static Profiles parse(String... expressions) {
Assert.notEmpty(expressions, "Must specify at least one profile");
Assert.notEmpty(expressions, "Must specify at least one profile expression");
Profiles[] parsed = new Profiles[expressions.length];
for (int i = 0; i < expressions.length; i++) {
parsed[i] = parseExpression(expressions[i]);
@@ -71,8 +71,8 @@ final class ProfilesParser {
}
switch (token) {
case "(":
Profiles contents = parseTokens(expression, tokens, Context.BRACKET);
if (context == Context.INVERT) {
Profiles contents = parseTokens(expression, tokens, Context.PARENTHESIS);
if (context == Context.NEGATE) {
return contents;
}
elements.add(contents);
@@ -86,11 +86,11 @@ final class ProfilesParser {
operator = Operator.OR;
break;
case "!":
elements.add(not(parseTokens(expression, tokens, Context.INVERT)));
elements.add(not(parseTokens(expression, tokens, Context.NEGATE)));
break;
case ")":
Profiles merged = merge(expression, elements, operator);
if (context == Context.BRACKET) {
if (context == Context.PARENTHESIS) {
return merged;
}
elements.clear();
@@ -99,7 +99,7 @@ final class ProfilesParser {
break;
default:
Profiles value = equals(token);
if (context == Context.INVERT) {
if (context == Context.NEGATE) {
return value;
}
elements.add(value);
@@ -137,15 +137,14 @@ final class ProfilesParser {
return activeProfile -> activeProfile.test(profile);
}
private static Predicate<Profiles> isMatch(Predicate<String> activeProfile) {
return profiles -> profiles.matches(activeProfile);
private static Predicate<Profiles> isMatch(Predicate<String> activeProfiles) {
return profiles -> profiles.matches(activeProfiles);
}
private enum Operator {AND, OR}
private enum Operator { AND, OR }
private enum Context {NONE, INVERT, BRACKET}
private enum Context { NONE, NEGATE, PARENTHESIS }
private static class ParsedProfiles implements Profiles {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import org.apache.commons.logging.Log;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Utility methods for formatting and logging messages.
@@ -78,7 +79,7 @@ public abstract class LogFormatUtils {
result = ObjectUtils.nullSafeToString(ex);
}
if (maxLength != -1) {
result = (result.length() > maxLength ? result.substring(0, maxLength) + " (truncated)..." : result);
result = StringUtils.truncate(result, maxLength);
}
if (replaceNewlinesAndControlCharacters) {
result = NEWLINE_PATTERN.matcher(result).replaceAll("<EOL>");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,12 +22,13 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A simple log message type for use with Commons Logging, allowing
* for convenient lazy resolution of a given {@link Supplier} instance
* (typically bound to a Java 8 lambda expression) or a printf-style
* format string ({@link String#format}) in its {@link #toString()}.
* A simple log message type for use with Commons Logging, allowing for convenient
* lazy resolution of a given {@link Supplier} instance (typically bound to a lambda
* expression) or a printf-style format string ({@link String#format}) in its
* {@link #toString()}.
*
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 5.2
* @see #of(Supplier)
* @see #format(String, Object)
@@ -77,7 +78,7 @@ public abstract class LogMessage implements CharSequence {
/**
* Build a lazily resolving message from the given supplier.
* @param supplier the supplier (typically bound to a Java 8 lambda expression)
* @param supplier the supplier (typically bound to a lambda expression)
* @see #toString()
*/
public static LogMessage of(Supplier<? extends CharSequence> supplier) {
@@ -87,63 +88,68 @@ public abstract class LogMessage implements CharSequence {
/**
* Build a lazily formatted message from the given format string and argument.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the argument
* @param arg1 the argument (can be {@code null})
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, Object arg1) {
public static LogMessage format(String format, @Nullable Object arg1) {
return new FormatMessage1(format, arg1);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, Object arg1, Object arg2) {
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2) {
return new FormatMessage2(format, arg1, arg2);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @param arg3 the third argument (can be {@code null})
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3) {
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
return new FormatMessage3(format, arg1, arg2, arg3);
}
/**
* Build a lazily formatted message from the given format string and arguments.
* @param format the format string (following {@link String#format} rules)
* @param arg1 the first argument
* @param arg2 the second argument
* @param arg3 the third argument
* @param arg4 the fourth argument
* @param arg1 the first argument (can be {@code null})
* @param arg2 the second argument (can be {@code null})
* @param arg3 the third argument (can be {@code null})
* @param arg4 the fourth argument (can be {@code null})
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
public static LogMessage format(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3,
@Nullable Object arg4) {
return new FormatMessage4(format, arg1, arg2, arg3, arg4);
}
/**
* Build a lazily formatted message from the given format string and varargs.
* <p>This varargs {@code format()} variant may be costly. You should therefore
* use the individual argument variants whenever possible:
* {@link #format(String, Object)}, {@link #format(String, Object, Object)}, etc.
* @param format the format string (following {@link String#format} rules)
* @param args the varargs array (costly, prefer individual arguments)
* @param args the varargs array (can be {@code null} and can contain {@code null}
* elements)
* @see String#format(String, Object...)
*/
public static LogMessage format(String format, Object... args) {
public static LogMessage format(String format, @Nullable Object... args) {
return new FormatMessageX(format, args);
}
private static final class SupplierMessage extends LogMessage {
private Supplier<? extends CharSequence> supplier;
private final Supplier<? extends CharSequence> supplier;
SupplierMessage(Supplier<? extends CharSequence> supplier) {
Assert.notNull(supplier, "Supplier must not be null");
@@ -170,9 +176,10 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage1 extends FormatMessage {
@Nullable
private final Object arg1;
FormatMessage1(String format, Object arg1) {
FormatMessage1(String format, @Nullable Object arg1) {
super(format);
this.arg1 = arg1;
}
@@ -186,11 +193,13 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage2 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
FormatMessage2(String format, Object arg1, Object arg2) {
FormatMessage2(String format, @Nullable Object arg1, @Nullable Object arg2) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -205,13 +214,16 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage3 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
@Nullable
private final Object arg3;
FormatMessage3(String format, Object arg1, Object arg2, Object arg3) {
FormatMessage3(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -227,15 +239,20 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessage4 extends FormatMessage {
@Nullable
private final Object arg1;
@Nullable
private final Object arg2;
@Nullable
private final Object arg3;
@Nullable
private final Object arg4;
FormatMessage4(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
FormatMessage4(String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3,
@Nullable Object arg4) {
super(format);
this.arg1 = arg1;
this.arg2 = arg2;
@@ -252,9 +269,10 @@ public abstract class LogMessage implements CharSequence {
private static final class FormatMessageX extends FormatMessage {
@Nullable
private final Object[] args;
FormatMessageX(String format, Object... args) {
FormatMessageX(String format, @Nullable Object... args) {
super(format);
this.args = args;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,6 +50,7 @@ public class DefaultDeserializer implements Deserializer<Object> {
/**
* Create a {@code DefaultDeserializer} for using an {@link ObjectInputStream}
* with the given {@code ClassLoader}.
* @param classLoader the ClassLoader to use
* @since 4.2.1
* @see ConfigurableObjectInputStream#ConfigurableObjectInputStream(InputStream, ClassLoader)
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.Deserializer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -50,10 +51,11 @@ public class DeserializingConverter implements Converter<byte[], Object> {
/**
* Create a {@code DeserializingConverter} for using an {@link java.io.ObjectInputStream}
* with the given {@code ClassLoader}.
* @param classLoader the ClassLoader to use
* @since 4.2.1
* @see DefaultDeserializer#DefaultDeserializer(ClassLoader)
*/
public DeserializingConverter(ClassLoader classLoader) {
public DeserializingConverter(@Nullable ClassLoader classLoader) {
this.deserializer = new DefaultDeserializer(classLoader);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,4 +90,9 @@ public class ExecutorServiceAdapter extends AbstractExecutorService {
return false;
}
// @Override on JDK 19
public void close() {
// no-op in order to avoid container-triggered shutdown call which would lead to exception logging
}
}
@@ -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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,10 +68,10 @@ public abstract class FileSystemUtils {
}
/**
* Delete the supplied {@link File} &mdash; for directories,
* Delete the supplied {@link Path} &mdash; for directories,
* recursively delete any nested directories or files as well.
* @param root the root {@code File} to delete
* @return {@code true} if the {@code File} existed and was deleted,
* @param root the root {@code Path} to delete
* @return {@code true} if the {@code Path} existed and was deleted,
* or {@code false} if it did not exist
* @throws IOException in the case of I/O errors
* @since 5.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@ public class InstanceFilter<T> {
/**
* Determine if the specified {code instance} matches this filter.
* Determine if the specified {@code instance} matches this filter.
*/
public boolean match(T instance) {
Assert.notNull(instance, "Instance to match must not be null");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,11 +17,17 @@
package org.springframework.util;
import java.lang.reflect.Array;
import java.net.URI;
import java.net.URL;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.UUID;
import org.springframework.lang.Nullable;
@@ -653,6 +659,7 @@ public abstract class ObjectUtils {
* Returns a {@code "null"} String if {@code obj} is {@code null}.
* @param obj the object to build a String representation for
* @return a String representation of {@code obj}
* @see #nullSafeConciseToString(Object)
*/
public static String nullSafeToString(@Nullable Object obj) {
if (obj == null) {
@@ -908,4 +915,70 @@ public abstract class ObjectUtils {
return stringJoiner.toString();
}
/**
* Generate a null-safe, concise string representation of the supplied object
* as described below.
* <p>Favor this method over {@link #nullSafeToString(Object)} when you need
* the length of the generated string to be limited.
* <p>Returns:
* <ul>
* <li>{@code "null"} if {@code obj} is {@code null}</li>
* <li>{@linkplain Class#getName() Class name} if {@code obj} is a {@link Class}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a {@link String} or {@link CharSequence}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a <em>simple value type</em> whose {@code toString()} method
* returns a non-null value.</li>
* <li>Otherwise, a string representation of the object's type name concatenated
* with {@code @} and a hex string form of the object's identity hash code</li>
* </ul>
* <p>In the context of this method, a <em>simple value type</em> is any of the following:
* a primitive wrapper (excluding {@code Void}), an {@code Enum}, a {@code Number},
* a {@code Date}, a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL},
* or a {@code Locale}.
* @param obj the object to build a string representation for
* @return a concise string representation of the supplied object
* @since 5.3.27
* @see #nullSafeToString(Object)
* @see StringUtils#truncate(CharSequence)
*/
public static String nullSafeConciseToString(@Nullable Object obj) {
if (obj == null) {
return "null";
}
if (obj instanceof Class<?>) {
return ((Class<?>) obj).getName();
}
if (obj instanceof CharSequence) {
return StringUtils.truncate((CharSequence) obj);
}
Class<?> type = obj.getClass();
if (isSimpleValueType(type)) {
String str = obj.toString();
if (str != null) {
return StringUtils.truncate(str);
}
}
return type.getTypeName() + "@" + getIdentityHexString(obj);
}
/**
* Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}.
* As of 5.3.28, considering {@code UUID} in addition to the bean-level check.
*/
private static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
UUID.class == type ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
}

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