Compare commits

..

151 Commits

Author SHA1 Message Date
Spring Buildmaster f5a7a834a8 Release v5.2.16.RELEASE 2021-07-14 07:50:53 +00:00
Stephane Nicoll 14adefa867 Remove coroutines links until the javadoc publication is fixed
See gh-27169
2021-07-14 07:48:42 +02:00
Juergen Hoeller fe3357d6b9 Polishing (backported) 2021-07-13 19:07:15 +02:00
Juergen Hoeller 11c51d8633 Upgrade to Reactor Dysprosium-SR21
Closes gh-27163
2021-07-13 19:06:22 +02:00
Juergen Hoeller bdbd999619 Make proxyTargetClass=true with introduction advice work for JDK proxy targets
Closes gh-27044

(cherry picked from commit c45c46dad7)
2021-07-13 18:34:49 +02:00
Juergen Hoeller bc4af15e9e BeanCreationException message includes declaring class of constructor/factory method
Closes gh-27139

(cherry picked from commit 74f91339e2)
2021-07-13 18:34:42 +02:00
Stephane Nicoll 348dc826f9 Fix CI build badge in README 2021-07-12 09:51:51 +02:00
Sam Brannen 43901b2c6a Fix bug in SimpleMethodMetadataReadingVisitor.Source.toString()
Prior to this commit, the toString() implementation did not separate
method argument types with a comma or any form of separator, leading
to results such as:

    org.example.MyClass.myMethod(java.lang.Stringjava.lang.Integer)

instead of:

    org.example.MyClass.myMethod(java.lang.String,java.lang.Integer)

Closes gh-27095
2021-06-24 16:46:52 +02:00
Arjen Poutsma 7b34bf2a6c Synchronoss should create temp directory lazily
The SynchronossPartHttpMessageReader should only create temp directory
when needed, not at startup.

Closes gh-27092
2021-06-23 16:04:08 +02:00
Sam Brannen c5a138a167 Ensure DefaultPathSegment does not allow parameters to be mutated
Prior to this commit, if a PathContainer was created using
Options.MESSAGE_ROUTE, DefaultPathSegment#parameters() returned a
mutable map which would allow the user to modify the contents of the
static, shared EMPTY_PARAMS map in DefaultPathContainer.

This commit prevents corruption of the shared EMPTY_PARAMS map by
ensuring that parameters stored in DefaultPathSegment are always
immutable.

Closes gh-27064
2021-06-15 15:57:35 +02:00
Sam Brannen 1f098e1f22 Polish DefaultPathContainerTests 2021-06-15 15:51:21 +02:00
Juergen Hoeller 67fccc3c7e Nullability refinements and related polishing (backported) 2021-06-08 14:58:58 +02:00
Sam Brannen 70e6606f0f Improve @Transactional docs regarding method visibility
Closes gh-27003
2021-05-30 17:16:08 +02:00
Sviatoslav Hryb 5b55cefd64 Fix @Transactional docs regarding method visibility
Closes gh-27001
2021-05-30 17:13:14 +02:00
Sam Brannen 911aca17ea Doc tx semantics for @TransactionalEventListener after completion phases
This commit improves the Javadoc regarding transactional semantics for
@TransactionalEventListener methods invoked in the AFTER_COMMIT,
AFTER_ROLLBACK, or AFTER_COMPLETION phase. Specifically, the
documentation now points out that interactions with the underlying
transactional resource will not be committed in those phases.

Closes gh-26974
2021-05-26 14:27:16 +02:00
Sam Brannen 90183568ba Deprecate internal APIs in ScriptUtils
Many of the utility methods in ScriptUtils are public only because they
were once invoked from JdbdTestUtils in spring-test, which is no longer
the case. Consequently, there should no longer be a need for any
external clients to invoke such methods.

To address, this commit formally deprecates the following methods in
ScriptUtils in spring-jdbc.

- readScript(...)
- containsSqlScriptDelimiters(...)
- splitSqlScript(...)

Closes gh-26947
2021-05-18 15:59:57 +02:00
Sam Brannen b5ce514b27 Logically reorganize methods in ScriptUtils
See gh-26947
2021-05-18 15:47:39 +02:00
Sam Brannen 9ae6268a1a Polish ScriptUtils implementation 2021-05-14 15:18:26 +02:00
Sam Brannen e4d843e41e Ignore comments when searching for statement delimiter in ScriptUtils
Prior to this commit, the implementation of
ScriptUtils.containsSqlScriptDelimiters() did not ignore comments when
searching for the statement delimiter within an SQL script. This
resulted in subtle bugs if a comment contained a single single-quote or
single double-quote, since the absence of the closing single-quote or
double-quote led the algorithm to believe that it was still "within a
text literal". Similar issues could arise if a comment contained the
sought statement delimiter but the rest of the script did not contain
the sought statement delimiter. In such cases, the algorithms in
ScriptUtils could erroneously choose an incorrect statement delimiter
-- for example, using the fallback statement delimiter instead of the
delimiter specified by the user.

This commit avoids such bugs by ignoring single-line comments and block
comments when searching for the statement delimiter within an SQL
script.

Closes gh-26911
2021-05-14 14:33:07 +02:00
Sam Brannen 22256966fb Ignore delimiter enclosed in double quotes in ScriptUtils
Prior to this commit, the containsSqlScriptDelimiters() method in
ScriptUtils ignored delimiters enclosed in single quotes but not those
enclosed within double quotes, which contradicts the algorithm in
splitSqlScript() and therefore constitutes a bug.

This commit fixes this bug in the ScriptUtils implementation in
spring-jdbc.

Closes gh-26935
2021-05-12 13:06:00 +02:00
Spring Buildmaster 7c74459cb0 Next development version (v5.2.16.BUILD-SNAPSHOT) 2021-05-12 06:16:21 +00:00
Arjen Poutsma 85ad63bd35 Ensure Synchronoss temp directories do not collide
This commit makes sure that Synchronoss uses a random temporary
directory to store uploaded files, so that two instances do not collide.

Closes gh-26931
2021-05-11 21:19:27 +02:00
Juergen Hoeller a2ff769bc1 Polishing (backported from master) 2021-05-11 17:32:23 +02:00
Juergen Hoeller 9523f1ffd6 Correct clientInboundChannel assertion (includes constructor javadoc)
Closes gh-26896
2021-05-11 17:31:04 +02:00
Juergen Hoeller cd0570ee39 Log resource path resolution failure at debug level (instead of warn)
Closes gh-26828
2021-05-11 17:30:57 +02:00
Juergen Hoeller 05d767b1cf Always propagate checked exceptions from Kotlin code behind CGLIB proxies
Closes gh-23844
2021-05-11 17:29:40 +02:00
Stephane Nicoll 30655555bd Remove .RELEASE suffix before querying GitHub
This commit removes the `.RELEASE` suffix of the released version, if
necessary. Such commit is not present on GitHub and the changelog
generation process fails to find the milestone to use to generate the
changelog.

Closes gh-26796
2021-05-11 16:20:28 +02:00
Stephane Nicoll 0ee8790a9a Upgrade to Reactor Dysprosium-SR20
Closes gh-26891
2021-05-11 15:35:50 +02:00
Sam Brannen bcd8896689 Polish contribution
See gh-25200
2021-05-10 12:50:13 +02:00
Vlad Kisel 53b8d73078 Support single-value request param resolution for data class constructors
Prior to this commit, when Web MVC attempted to resolve a constructor
argument for a data class constructor with @ModelAttribute binding,
ModelAttributeMethodProcessor failed to unwrap the array returned by
WebRequest.getParameter(String).

According to the Javadoc for WebRequest.getParameter(String), "a
single-value parameter will be exposed as an array with a single
element."

This commit fixes this issue by extracting the single value from such
an array and using that as the constructor argument (potentially
converted by the WebDataBinder).

Closes gh-25200
2021-05-10 12:47:47 +02:00
ShindongLee 3ab270e0f1 Fix parameter bug of handler inside the filterFunction DSL
Co-authored-by: hojongs <hojong.jjh@gmail.com>
Co-authored-by: bjh970913 <bjh970913@gmail.com>

Closes gh-26921
2021-05-10 10:22:13 +02:00
Rossen Stoyanchev ddb727bee8 Switch to Reactor Dysprosium snapshots
See gh-26891
2021-05-04 17:12:19 +01:00
Sam Brannen a33adac6c8 Support @ModelAttribute(binding=false) with WebFlux
Prior to this commit, @ModelAttribute(binding=false) was honored with
Spring Web MVC but not with WebFlux.

This commit adds support for disabling binding via @ModelAttribute with
WebFlux by adding a check to resolveArgument(...) in
ModelAttributeMethodArgumentResolver.

Closes gh-26856
2021-05-03 19:13:16 +02:00
Sam Brannen 08663d4792 Polish Javadoc 2021-05-03 18:58:12 +02:00
Stephane Nicoll 30b5a7b5c3 Backport "Remove leftover Javadoc from WebClient"
Closes gh-26809
2021-04-15 09:57:21 +02:00
Spring Buildmaster 620023cbc3 Next development version (v5.2.15.BUILD-SNAPSHOT) 2021-04-13 11:46:36 +00:00
Juergen Hoeller 19474e2d03 Nullability refinements
(cherry picked from commit f31933e67e)
2021-04-13 12:32:16 +02:00
Juergen Hoeller 43071109f7 Polishing (backported from master) 2021-04-13 11:48:55 +02:00
Juergen Hoeller bb530dca5b Polishing (backported from master) 2021-04-12 23:39:24 +02:00
Juergen Hoeller e4e2212817 Bypass root path resolution for "file:" prefix only
See gh-26702
2021-04-12 23:39:18 +02:00
Stephane Nicoll 34fcbfbcc5 Upgrade to Reactor Dysprosium-SR19
Closes gh-26768
2021-04-12 18:09:16 +02:00
Stephane Nicoll 20cbd684d4 Start building against Reactor Dysprosium SR19 snapshots
See gh-26768
2021-04-07 09:52:32 +02:00
Brian Clozel 5f9a6ce98e Upgrade to Concourse Release Scripts 0.3.2 2021-03-23 13:58:04 +01:00
Juergen Hoeller 07e18df0b9 Polishing 2021-03-22 23:14:20 +01:00
Sam Brannen 4a6fea353f Honor class-level @DirtiesContext if test class is disabled via SpEL
Prior to this commit, if a test class annotated with @DirtiesContext
and @EnabledIf/@DisabledIf with `loadContext = true` was disabled due
to the evaluated SpEL expression, the ApplicationContext would not be
marked as dirty and closed.

The reason is that @EnabledIf/@DisabledIf are implemented via JUnit
Jupiter's ExecutionCondition extension API which results in the entire
test class (as well as any associated extension callbacks) being
skipped if the condition evaluates to `disabled`. This effectively
prevents any of Spring's TestExecutionListener APIs from being invoked.
Consequently, the DirtiesContextTestExecutionListener does not get a
chance to honor the class-level @DirtiesContext declaration.

This commit fixes this by implementing part of the logic of
DirtiesContextTestExecutionListener in
AbstractExpressionEvaluatingCondition (i.e., the base class for
@EnabledIf/@DisabledIf support). Specifically, if the test class for an
eagerly loaded ApplicationContext is disabled,
AbstractExpressionEvaluatingCondition will now mark the test
ApplicationContext as dirty if the test class is annotated with
@DirtiesContext.

Closes gh-26694
2021-03-18 14:21:05 +01:00
Brian Clozel f76504512e Fix release pipeline for Maven Central publication
This commit fixes the missing pieces in our Maven Central publication
pipeline. Our first attempt at releasing with it showed a few problems:

* the promote task did not have the artifacts downladed with the
  artifactory repository
* we applied the wrong Sonatype credentials to the task
* the github changelog task would fail because of docker rate limiting
  since we were not using the right type of resource, which is
  configured with the proper caching mechanism

See gh-26654
2021-03-16 14:34:10 +01:00
Juergen Hoeller 215514f27b Polishing (backported from master) 2021-03-12 15:29:29 +01:00
Juergen Hoeller ae2711866a Polishing 2021-03-12 11:07:19 +01:00
Juergen Hoeller a6ab7164a3 Use getRawStatusCode() for custom status code support in value methods
Closes gh-26658
2021-03-12 10:50:55 +01:00
Brian Clozel a7db92b44e Use ".RELEASE" suffix for releases on 5.2.x branch
This commit ensures that the release scripts generate a ".RELEASE"
suffixed release version, since the 5.2.x branch is still using this
naming scheme.

See https://github.com/spring-io/concourse-java-scripts#get_next_release
See gh-26659
2021-03-11 10:04:22 +01:00
Stephane Nicoll 63912f802a Merge branch 'ci' into 5.2.x
Closes gh-26659
2021-03-10 15:10:49 +01:00
Stephane Nicoll 3fbf3a597a Backport CI build
See gh-26659
2021-03-10 14:57:06 +01:00
Stephane Nicoll 5291c5b233 Remove artifactory plugin from build
Backport of gh-22490

See gh-26659
2021-03-10 14:57:06 +01:00
Juergen Hoeller c978fb4466 Documentation fixes etc (backported from master) 2021-03-09 16:57:04 +01:00
Juergen Hoeller 0fc831e8bd Polishing (backported from master) 2021-03-09 00:05:55 +01:00
Rossen Stoyanchev dd967215fe Upgrade to RSocket 1.0.4 2021-03-04 22:18:11 +00:00
Sam Brannen 31c5fc6417 Polish contribution
See gh-26619
2021-03-02 14:28:01 +01:00
GungnirLaevatain e8f685ecc8 Ensure local @CrossOrigin maxAge overrides global value
Prior to this commit, a method-level @CrossOrigin maxAge value did not
override a class-level @CrossOrigin maxAge value. This contradicts the
Javadoc for @CrossOrgin which states the following.

    For those attributes where only a single value can be accepted such
    as allowCredentials and maxAge, the local overrides the global
    value.

This commit ensures that a method-level @CrossOrigin maxAge value
overrides a class-level @CrossOrigin maxAge value.

Closes gh-26619
2021-03-02 14:27:49 +01:00
Juergen Hoeller 428dbc43da Add missing nullable annotation to ResponseEntity ok convenience method
Closes gh-26613
2021-02-26 17:42:05 +01:00
Juergen Hoeller dd3262bfe3 Polishing (backported from master) 2021-02-25 19:08:53 +01:00
Juergen Hoeller fdafd38d2f Fix handling of file: paths to non-existent files
For setAsText, if the text argument is a file: URL for a path that does not exist, Paths.get(text) is called where text is a file: URL, which doesn't work - the result is an InvalidPathException.

To fix this issue, also check that the resource isn't a file before calling Paths.get(). That way, resources that are files skip to the other branch.

Closes gh-26575
2021-02-25 19:08:18 +01:00
Juergen Hoeller 74b248a6b3 getResource can throw IllegalArgumentException
Class.getResource, ClassLoader.getResource, and ClassLoader.getSystemResource will throw IllegalArgumentException if a malformed URL is provided to them.

According to its javadoc, resolveURL should return null if not resolvable, so catch the IllegalArgumentException and return null.

Closes gh-26574
2021-02-25 19:07:58 +01:00
Sam Brannen 60e418959a Polish contribution
See gh-26600
2021-02-25 11:43:10 +01:00
nullzl 4530e36867 Correctly set auto-growing array's element
Prior to this commit, the implementation of processKeyedProperty() in
AbstractNestablePropertyAccessor resulted in a
`java.lang.IllegalArgumentException: array element type mismatch` when
the property expression had more than one property key and the last key
should cause the array to grow automatically.

For example, given a property `int[][] multiArray` and property
expression `multiArray[1][3]`, the `processKeyedProperty()` method
created a new array object and assigned it to `multiArray`; whereas,
the new array object should have be assigned to `multiArray[1]`.

This commit fixes this issue.

Closes gh-26600
2021-02-25 11:42:56 +01:00
Sam Brannen 2ec7d5c785 Support load-time weaving for @Component classes again
Since Spring Framework 5.2, the LoadTimeWeaver no longer weaves bean
classes annotated with @Component. This is a regression caused by the
changes in 40c62139ae, stemming from the fact that any class annotated
or meta-annotated with @Component is considered to be a candidate
configuration class in 'configuration lite' mode (i.e., a class without
the @Configuration annotation and without any @Bean methods) and
therefore now has its class eagerly loaded. This results in the class
being loaded before the LoadTimeWeaver has a chance to weave it.

This commit fixes this regression by explicitly avoiding eager class
loading for any 'lite' @Configuration or @Component class without @Bean
methods.

Closes gh-26199
2021-02-22 10:28:58 +01:00
Brian Clozel 9f7c8aea94 Fix ResourceUrlProvider handler auto-detection
Prior to this commit, `ResourceUrlProvider` would listen and consider
all `ContextRefreshedEvent` and use the given context to detect
`SimpleUrlHandlerMapping`.

This could lead to situations where a `ResourceUrlProvider` uses another
application context than its own (in a parent/child context setup) and
detect the wrong set of handlers.

Because `ResourceUrlProvider` locks itself once the auto-detection is
done, we need to ensure that it considers only events sent by its
application context.

Fixes gh-26562
2021-02-17 22:10:29 +01:00
Sam Brannen 792656097a Polish MockHttpServletResponseTests
See gh-26558
2021-02-17 14:51:19 +01:00
Sam Brannen 33add3350b Sync changes in MockHttpServletResponse test fixture
See gh-26558
2021-02-17 14:51:09 +01:00
Koos Gadellaa 8f2010d669 Support cookie w/ only Expires attribute in MockHttpServletResponse
Prior to this commit, MockHttpServletResponse only included the Expires
attribute in the generated Cookie header if the Max-Age attribute had
also been set.

This commit supports including the Expires attribute in the generated
Cookie Header even when the Max-Age attribute has not been set.

Closes gh-26558
2021-02-17 14:50:59 +01:00
Sam Brannen 9d4bfb1769 Implement toString() in MockCookie 2021-02-17 14:50:39 +01:00
Spring Buildmaster da5f410af4 Next Development Version 2021-02-16 11:39:43 +00:00
Juergen Hoeller 940f57d023 Document ASM version as 7.x (effectively 7.3 at present) 2021-02-16 00:15:50 +01:00
Rossen Stoyanchev 29799be474 Upgrade to Dysprosium-SR17
Closes gh-26549
2021-02-15 17:33:30 +00:00
Juergen Hoeller 67979c93c3 Upgrade to Hibernate ORM 5.4.28 and OpenPDF 1.3.25 2021-02-15 17:34:29 +01:00
Juergen Hoeller 4ae3ab14ec Avoid unnecessary wrapping for SqlParameterValue
Closes gh-26471
2021-02-15 11:49:59 +01:00
Juergen Hoeller 81f0d76f3d Upgrade to Apache Johnzon 1.2.10, Joda-Time 2.10.10, RxJava 2.2.21 2021-02-14 18:49:33 +01:00
Juergen Hoeller 9f1e822f3e Polishing 2021-02-14 18:48:49 +01:00
Juergen Hoeller b4baa86bfa Close mapping streams after the ValidatorFactory has been built
Closes gh-26418
2021-02-14 18:48:31 +01:00
Juergen Hoeller 81be4c22d0 Re-resolve cached arguments in case of NoSuchBeanDefinitionException
Closes gh-26517

(cherry picked from commit 99a1388bbd)
2021-02-14 18:17:06 +01:00
Juergen Hoeller a17c2ccb4e Preserve resolved destroy method name in RootBeanDefinition
Closes gh-26498

(cherry picked from commit 809813dd52)
2021-02-14 18:16:11 +01:00
Juergen Hoeller 64df93168d Consider non-initialized holders as equal to empty holders
Closes gh-26433

(cherry picked from commit d5e5dcb7e1)
2021-02-14 18:08:20 +01:00
Juergen Hoeller 27c5480c82 Fail early FactoryBean instantiation for LinkageError
Closes gh-26425

(cherry picked from commit defc2466b0)
2021-02-14 18:08:15 +01:00
Sam Brannen 594ec8f8a9 Update copyright date in reference manual 2021-02-10 17:57:23 +01:00
Arjen Poutsma c09b2513e0 Ensure StringDecoder supports multiline delimiters
This commit makes sure the StringDecoder supports stripping off
multi-line delimiters, such as \r\n. Specifically, we ensure that the
delimiter is stripped from the joined buffer.

Closes gh-26511
2021-02-08 15:59:02 +01:00
Sam Brannen 6c22f7ef5e Fix StoredProcedure documentation in reference manual
This commit aligns the documentation in the reference manual with the
actual source code for StoredProcedure with regard to public execute()
methods.

Closes gh-26505
2021-02-04 11:12:31 +01:00
Sam Brannen 236623f630 Do not retain partial column metadata in SimpleJdbcInsert
Prior to this commit, if an SQLException was thrown while retrieving
column metadata from the database, SimpleJdbcInsert would generate an
INSERT statement that was syntactically valid but missing columns,
which could lead to data silently missing in the database (for nullable
columns).

This commit fixes this by clearing all collected column metadata if an
SQLException is thrown while processing the metadata. The result is
that an InvalidDataAccessApiUsageException will be thrown later while
generating the INSERT statement. The exception message now contains an
additional hint to make use of SimpleJdbcInsert#usingColumns() in order
to ensure that all required columns are included in the generated
INSERT statement.

SimpleJdbcCall can also encounter an SQLException while retrieving
column metadata for a stored procedure/function, but an exception is
not thrown since a later invocation of the stored procedure/function
will likely fail anyway due to missing arguments. Consequently, this
commit only improves the warning level log message by including a hint
to make use of SimpleJdbcCall#addDeclaredParameter().

Closes gh-26486
2021-02-03 18:53:32 +01:00
Sam Brannen e18fba1626 Polishing 2021-02-03 18:52:15 +01:00
Sam Brannen 070c596a66 Use api-spring-framework attribute for links to SpringProperties
See gh-26492
2021-02-02 14:04:20 +01:00
Sam Brannen 7a9bf1578e Link to SpringProperties Javadoc from the Testing chapter
Closes gh-26492
2021-02-02 13:52:08 +01:00
Rossen Stoyanchev 8a150ee3a4 Fix order of headers in DefaultHandlerExceptionResolver
Closes gh-26470
2021-01-29 20:49:19 +00:00
Rossen Stoyanchev 6051f4ecbd Handle forwarded header parse issues
Closes gh-26459
2021-01-29 20:48:51 +00:00
Rossen Stoyanchev 698e74f7cd WebSocketExtension#equals matches sub-classes too
Closes gh-26449
2021-01-29 20:48:51 +00:00
Sam Brannen 51079a40ae Upgrade io.spring.ge.conventions plugin to version 0.0.7
This will hopefully allow the build to pass again on the CI server.
2021-01-27 18:09:13 +01:00
Sam Brannen 94ac2e4de7 Fix UriComponentsBuilder examples in ref docs
Closes gh-26453
2021-01-27 15:17:32 +01:00
Stephane Nicoll 271a9097ac Clarify behaviour of condition attribute of CachePut
Closes gh-26404
2021-01-19 15:15:38 +01:00
Juergen Hoeller 3c030edbf2 Upgrade to RxJava 2.2.20, OpenPDF 1.3.24, Hibernate ORM 5.4.27, Joda-Time 2.10.9, Apache Johnzon 1.2.9 2021-01-14 18:30:52 +01:00
Sam Brannen 059cff52b7 Remove obsolete commandName attribute in spring-form.tld
Since support for the commandName attribute was removed from the
implementation of FormTag in Spring Framework 5.0, the presence of the
commandName attribute in the spring-form.tld file is no longer valid
and can lead one to assume that the commandName attribute is still
supported -- for example when using code completion in a JSP editor.

This commit therefore removes the obsolete commandName attribute in
spring-form.tld.

Closes gh-26337
2021-01-03 17:50:15 +01:00
Sam Brannen 619a3edae5 Fix syntax in Kotlin example 2020-12-19 15:30:42 +01:00
Juergen Hoeller eb3811e590 Upgrade to Hibernate Validator 6.1.7, Caffeine 2.8.8, Joda-Time 2.10.8 2020-12-17 11:06:16 +01:00
Juergen Hoeller f011e58f90 Polishing 2020-12-17 11:05:58 +01:00
Juergen Hoeller 7325a863bb Consistent declarations and assertions in MockMultipartFile
See gh-26261

(cherry picked from commit fbd2ffdd23)
2020-12-17 10:50:47 +01:00
Brian Clozel fe26b7d3fd Fix NPE when calling NettyHeadersAdapter.add()
Prior to this commit, the `NettyHeadersAdapter` would directly delegate
the `add()` and `set()` calls to the adapted
`io.netty.handler.codec.http.HttpHeaders`. This implementation rejects
`null` values with exceptions.

This commit aligns the behavior here with other implementations, by not
rejecting null values but simply ignoring them.

Fixes gh-26277
(cherry-picked from commit 83c19cd60e)
2020-12-15 13:36:03 +01:00
Juergen Hoeller cfdceae70f Defensively handle loadClass null result in BeanUtils.findEditorByConvention
Closes gh-26252

(cherry picked from commit 2a47751fcd)
2020-12-10 16:26:47 +01:00
Spring Buildmaster 17647801aa Next Development Version 2020-12-09 06:34:43 +00:00
Rossen Stoyanchev 33476a2eae Backport fixes for discarding data buffers
Closes gh-26232
2020-12-08 22:00:28 +00:00
Brian Clozel a8091b916b Avoid closing Jackson JsonGenerator for error cases
Prior to this commit, a change introduced in gh-25910 would close the
`JsonGenerator` after it's been used for JSON serialization. This would
not only close it and recycle resources, but also flush the underlyning
buffer to the output.
In a case where the JSON serialization process would throw an exception,
the buffer would be still flushed to the response output. Before the
change introduced in gh-25910, the response body could be still empty at
that point and error handling could write an error body instead.

This commits only closes the `JsonGenerator` when serialization has been
successful.

Note that we're changing this in the spirit of backwards compatibility
in the 5.2.x line, but change this won't be merged forward on the 5.3.x
line, for several reasons:

* this behavior is not consistent. If the JSON output exceeds a
certain size, or if Jackson has been configured to flush after each
write, the response output might still contain an incomplete JSON
payload (just like before this change)

* this behavior is not consistent with the WebFlux and Messaging codecs,
which are flushing or closing the generator

* not closing the generator for error cases prevents resources from
being recycled as expected by Jackson

Fixes gh-26246
2020-12-08 20:50:26 +01:00
Juergen Hoeller 396fdf125f Remove duplicate "property" in PropertyCacheKey.toString()
Closes gh-26237
2020-12-08 15:03:33 +01:00
Stephane Nicoll 085825fbc0 Upgrade to Reactor Dysprosium-SR15
Closes gh-26175
2020-12-08 05:50:48 +01:00
Juergen Hoeller b0c6e5e322 Polishing
(cherry picked from commit c970c318f4)
2020-12-07 22:09:43 +01:00
Juergen Hoeller a7efa9659a Clarify intended advice execution behavior (includes related polishing)
Closes gh-26202

(cherry picked from commit 834032df1f)
2020-12-07 22:09:30 +01:00
Juergen Hoeller f7605eaf58 Upgrade to Hibernate ORM 5.4.25 and Checkstyle 8.38 2020-12-02 17:37:59 +01:00
Juergen Hoeller ce67b89861 Support for multi-threaded addConverter calls
Closes gh-26183

(cherry picked from commit 396fb0cd51)
2020-12-02 12:35:21 +01:00
Rossen Stoyanchev 736af46fc0 ContentCachingResponseWrapper skips contentLength for chunked responses
Closes gh-26182
2020-12-01 17:50:07 +00:00
Stephane Nicoll a495bd6679 Start building against Reactor Dysprosium-SR15 snapshots
See gh-26175
2020-11-30 07:23:19 +01:00
Juergen Hoeller 7c33c70742 Polishing 2020-11-27 21:58:55 +01:00
Juergen Hoeller 81c1b60f19 Register @Bean definitions as dependent on containing configuration class
Closes gh-26167
2020-11-27 21:57:55 +01:00
Rossen Stoyanchev 3703be5aaf MessageHeaderAccessor handle self-copy correctly
1. Revert changes in setHeader from 5.2.9 that caused regression on self-copy.
2. Update copyHeaders/IfAbsent to ensure a copy of native headers.
3. Exit if source and target are the same instance, as an optimization.

Closes gh-26155
2020-11-26 21:56:17 +00:00
Сергей Цыпанов b929edb221 Remove unused package-private class o.s.w.u.p.SubSequence
(cherry picked from commit 42216b77df)
2020-11-26 15:38:14 +01:00
Juergen Hoeller 50803ce142 Remove misleading default note on ISO.DATE_TIME
Closes gh-26134

(cherry picked from commit 86f9716fef)
2020-11-26 15:38:05 +01:00
Sam Brannen 346445ee7e Fix broken links to XSD schemas in ref docs
Closes gh-26129
2020-11-23 14:52:47 +01:00
Juergen Hoeller e238c8a87c Declare resolvedCharset as transient (restoring serializability)
Closes gh-26127
2020-11-20 18:57:30 +01:00
Juergen Hoeller 9e99fd5df2 Upgrade to Hibernate ORM 5.4.24
(cherry picked from commit 135682e073)
2020-11-19 16:03:03 +01:00
Juergen Hoeller 990c74b1e2 Upgrade to Apache HttpClient 4.5.13 (and consistent Caffeine declarations) 2020-11-19 15:19:29 +01:00
Rossen Stoyanchev 37bda566eb Allow "*" for Access-Control-Expose-Headers
Closes gh-26113
2020-11-19 09:48:41 +00:00
Juergen Hoeller 322babc04a Document that @Transactional does not propagate to new threads
Closes gh-25439
2020-11-17 16:16:24 +01:00
Juergen Hoeller 4e720e8104 Encode hash symbol in jar file path (for compatibility with JDK 11+)
Closes gh-26104

(cherry picked from commit b29723623b)
2020-11-17 16:11:07 +01:00
Juergen Hoeller fdab75a1d8 Upgrade to Reactor Dysprosium-SR14, OpenPDF 1.3.23, AssertJ 3.18.1, MockK 1.10.2, Checkstyle 8.37 2020-11-16 21:08:24 +01:00
Juergen Hoeller 240cfb1224 Polishing 2020-11-16 17:50:15 +01:00
Rossen Stoyanchev db2786264b UrlPathHelper.removeJsessionid correctly appends remainder
Closes gh-26079
2020-11-16 11:18:20 +00:00
Juergen Hoeller 763fa98bdf Early log entry for async EntityManagerFactory initialization failure
Closes gh-26093
2020-11-13 17:59:14 +01:00
Sam Brannen 25cbc263f0 Assert same instance returned for cached merged BeanDefinition 2020-11-12 14:58:58 +01:00
Juergen Hoeller 9949a91048 Fix javadoc and assertion glitches 2020-11-12 14:19:12 +01:00
Juergen Hoeller d8b7a593c5 Individually apply the SQL type from each SqlParameterSource argument
Closes gh-26071
2020-11-12 14:18:23 +01:00
Rossen Stoyanchev d3d8f1a487 LimitedDataBufferList adds or raises error
Closes gh-26060
2020-11-10 20:12:38 +00:00
Spring Buildmaster a637f6a27c Next Development Version 2020-11-10 07:09:28 +00:00
Juergen Hoeller e9416b369e Polishing 2020-11-09 18:23:45 +01:00
Juergen Hoeller cde95e1446 Polishing 2020-11-09 13:52:34 +01:00
Sam Brannen da4e37dc1d Do not create intermediate list in MergedAnnotationCollectors.toAnnotationSet()
Prior to this commit, MergedAnnotationCollectors.toAnnotationSet()
created an intermediate ArrayList for storing the results prior to
creating a LinkedHashSet in the finishing step.

Since the creation of the intermediate list is unnecessary, this commit
simplifies the implementation of toAnnotationSet() by using the
Collector.of() factory method that does not accept a `finisher` argument.
The resulting Collector internally uses a `castingIdentity()` function
as the `finisher`.

Closes gh-26031
2020-11-08 15:20:18 +01:00
Rossen Stoyanchev 010d0947c7 Refine logging in StompErrorHandler
Avoid a full stacktrace at ERROR level for a client message that could
not be sent to a MessageChannel.

See gh-26026
2020-11-05 21:51:16 +00:00
Juergen Hoeller 5b06c23a1b Consistent javadoc within SpelCompiler 2020-11-05 18:33:12 +01:00
Juergen Hoeller 7881329cf7 Polishing 2020-11-05 18:18:38 +01:00
Juergen Hoeller 58aa0659cc Suppress NotWritablePropertyException in case of ignoreUnknown=true
Closes gh-25986
2020-11-05 18:15:59 +01:00
Juergen Hoeller dbbedc6c86 Add FullyQualifiedAnnotationBeanNameGenerator.INSTANCE
Closes gh-26025
2020-11-05 18:15:29 +01:00
Juergen Hoeller 09c1e986b9 Upgrade to Hibernate ORM 5.4.23
(cherry picked from commit b815accca9)
2020-11-05 17:54:18 +01:00
Juergen Hoeller 10bff054a9 Reliably refresh metadata for dynamically changing prototype bean class
Closes gh-26019

(cherry picked from commit 412aa06d86)
2020-11-05 17:50:24 +01:00
Sam Brannen e713e0d6d5 Preserve registration order in @ActiveProfiles
With this commit, bean definition profiles declared via @ActiveProfiles
are once again stored in registration order, in order to support use
cases in Spring Boot and other frameworks that depend on the
registration order.

This effectively reverts the changes made in conjunction with gh-25973.

Closes gh-26004
2020-11-02 22:40:59 +01:00
Rossen Stoyanchev b4f8fc8177 Use static accessors in DefaultSimpUserRegistry
Closes gh-26010
2020-11-02 17:32:12 +00:00
Rossen Stoyanchev 8c3cdc6118 Remove unused import 2020-10-30 18:43:19 +00:00
Rossen Stoyanchev 01827fd8d2 Ensure response not closed by MappingJackson2HttpMessageConverter
Closes gh-25987
2020-10-30 18:42:11 +00:00
Stephane Nicoll af1d721aa3 Fix a broken Asciidoctor syntax in core-resources.adoc
Closes gh-26000
2020-10-30 09:33:36 +01:00
Arjen Poutsma 0acb1e5513 Copy default headers, cookies in WebClient builder
This commit makes copies of the default headers and cookies when a
WebClient is built, so that subsequent changes to these do not affect
previously built clients.

Closes: gh-25992
2020-10-29 13:36:26 +01:00
1788 changed files with 47621 additions and 72190 deletions
+1 -5
View File
@@ -1,4 +1,4 @@
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-5.3.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build")
# <img src="src/docs/asciidoc/images/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-5.2.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x?groups=Build")
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
@@ -17,10 +17,6 @@ For access to artifacts or a distribution zip, see the [Spring Framework Artifac
The Spring Framework maintains reference documentation ([published](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/) and [source](src/docs/asciidoc)), Github [wiki pages](https://github.com/spring-projects/spring-framework/wiki), and an
[API reference](https://docs.spring.io/spring-framework/docs/current/javadoc-api/). There are also [guides and tutorials](https://spring.io/guides) across Spring projects.
## Micro-Benchmarks
See the [Micro-Benchmarks](https://github.com/spring-projects/spring-framework/wiki/Micro-Benchmarks) Wiki page.
## Build from Source
See the [Build from Source](https://github.com/spring-projects/spring-framework/wiki/Build-from-Source) Wiki page and the [CONTRIBUTING.md](CONTRIBUTING.md) file.
+51 -66
View File
@@ -1,17 +1,18 @@
plugins {
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.ge.conventions' version '0.0.7'
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.4.10' apply false
id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.asciidoctor.jvm.convert' version '3.1.0'
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
id 'org.asciidoctor.jvm.convert' version '2.4.0'
id 'org.asciidoctor.jvm.pdf' version '2.4.0'
id 'de.undercouch.download' version '4.1.1'
id "io.freefair.aspectj" version '5.1.1' apply false
id "io.freefair.aspectj" version '4.1.6' apply false
id "com.github.ben-manes.versions" version '0.28.0'
id "me.champeau.gradle.jmh" version "0.5.0" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.10" apply false
id 'com.gradle.build-scan' version '3.2'
}
apply from: "$rootDir/gradle/build-scan-user-data.gradle"
ext {
moduleProjects = subprojects.findAll { it.name.startsWith("spring-") }
javaProjects = subprojects - project(":framework-bom")
@@ -25,15 +26,14 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.11.3"
mavenBom "io.netty:netty-bom:4.1.53.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.0"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR8"
mavenBom "io.rsocket:rsocket-bom:1.1.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.34.v20201102"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.10"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.1"
mavenBom "org.junit:junit-bom:5.7.0"
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.5"
mavenBom "io.netty:netty-bom:4.1.51.Final"
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR21"
mavenBom "io.rsocket:rsocket-bom:1.0.4"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.31.v20200723"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.72"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.5"
mavenBom "org.junit:junit-bom:5.6.3"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.3') {
@@ -43,9 +43,6 @@ configure(allprojects) { project ->
entry 'log4j-slf4j-impl'
}
dependency "org.slf4j:slf4j-api:1.7.30"
dependency("com.google.code.findbugs:findbugs:3.0.1") {
exclude group: "dom4j", name: "dom4j"
}
dependency "com.google.code.findbugs:jsr305:3.0.2"
dependencySet(group: 'org.aspectj', version: '1.9.6') {
@@ -53,18 +50,17 @@ configure(allprojects) { project ->
entry 'aspectjtools'
entry 'aspectjweaver'
}
dependencySet(group: 'org.codehaus.groovy', version: '3.0.6') {
dependencySet(group: 'org.codehaus.groovy', version: '2.5.13') {
entry 'groovy'
entry 'groovy-jsr223'
entry 'groovy-templates' // requires findbugs for warning-free compilation
entry 'groovy-templates'
entry 'groovy-test'
entry 'groovy-xml'
}
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.19"
dependency "io.reactivex.rxjava3:rxjava:3.0.7"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
dependency "com.caucho:hessian:4.0.63"
@@ -73,13 +69,13 @@ configure(allprojects) { project ->
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
dependency "com.google.protobuf:protobuf-java-util:3.13.0"
dependency "com.google.protobuf:protobuf-java-util:3.11.4"
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
dependency("com.thoughtworks.xstream:xstream:1.4.13") {
dependency("com.thoughtworks.xstream:xstream:1.4.11.1") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
dependency "org.apache.johnzon:johnzon-jsonb:1.2.8"
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
dependency("org.codehaus.jettison:jettison:1.3.8") {
exclude group: "stax", name: "stax-api"
}
@@ -89,19 +85,15 @@ configure(allprojects) { project ->
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.27"
dependencySet(group: 'org.jetbrains.kotlinx', version: '1.0.0') {
entry 'kotlinx-serialization-core'
entry 'kotlinx-serialization-json'
}
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.6"
dependency "com.github.librepdf:openpdf:1.3.22"
dependency "com.rometools:rome:1.15.0"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.8"
dependency "com.github.librepdf:openpdf:1.3.25"
dependency "com.rometools:rome:1.12.2"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.3"
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
dependencySet(group: 'org.apache.activemq', version: '5.16.0') {
dependencySet(group: 'org.apache.activemq', version: '5.8.0') {
entry 'activemq-broker'
entry('activemq-kahadb-store') {
exclude group: "org.springframework", name: "spring-context"
@@ -109,7 +101,7 @@ configure(allprojects) { project ->
entry 'activemq-stomp'
}
dependency "org.apache.bcel:bcel:6.0"
dependency "org.apache.commons:commons-pool2:2.9.0"
dependency "org.apache.commons:commons-pool2:2.8.1"
dependencySet(group: 'org.apache.derby', version: '10.14.2.0') {
entry 'derby'
entry 'derbyclient'
@@ -123,23 +115,23 @@ configure(allprojects) { project ->
dependency "net.sf.ehcache:ehcache:2.10.6"
dependency "org.ehcache:jcache:1.0.1"
dependency "org.ehcache:ehcache:3.4.0"
dependency "org.hibernate:hibernate-core:5.4.23.Final"
dependency "org.hibernate:hibernate-validator:6.1.6.Final"
dependency "org.hibernate:hibernate-core:5.4.28.Final"
dependency "org.hibernate:hibernate-validator:6.1.7.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.39') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.37') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.39') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.37') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.2.Final') {
dependencySet(group: 'io.undertow', version: '2.0.32.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -154,61 +146,58 @@ configure(allprojects) { project ->
entry 'okhttp'
entry 'mockwebserver'
}
dependency("org.apache.httpcomponents:httpclient:4.5.12") {
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.2'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
dependency "org.jruby:jruby:9.2.13.0"
dependency "org.jruby:jruby:9.2.11.1"
dependency "org.python:jython-standalone:2.7.1"
dependency "org.mozilla:rhino:1.7.11"
dependency "commons-fileupload:commons-fileupload:1.4"
dependency "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
dependency("org.dom4j:dom4j:2.1.3") {
exclude group: "jaxen", name: "jaxen"
exclude group: "net.java.dev.msv", name: "xsdlib"
exclude group: "pull-parser", name: "pull-parser"
exclude group: "xpp3", name: "xpp3"
dependency("dom4j:dom4j:1.6.1") {
exclude group: "xml-apis", name: "xml-apis"
}
dependency("jaxen:jaxen:1.2.0") {
exclude group: "dom4j", name: "dom4j"
dependency("jaxen:jaxen:1.1.1") {
exclude group: "xml-apis", name: "xml-apis"
exclude group: "xom", name: "xom"
exclude group: "xerces", name: "xercesImpl"
}
dependency("junit:junit:4.13.1") {
dependency("junit:junit:4.12") {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
dependency("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1") {
exclude group: "junit", name: "junit"
}
dependency "org.testng:testng:7.3.0"
dependency "org.testng:testng:6.14.3"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.18.0"
dependency "org.assertj:assertj-core:3.18.1"
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.6.0') {
dependencySet(group: 'org.mockito', version: '3.3.3') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
entry 'mockito-junit-jupiter'
}
dependency "io.mockk:mockk:1.10.0"
dependency "io.mockk:mockk:1.10.2"
dependency("net.sourceforge.htmlunit:htmlunit:2.44.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.43.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.44.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.43.1") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -217,7 +206,6 @@ configure(allprojects) { project ->
}
dependency "org.skyscreamer:jsonassert:1.5.0"
dependency "com.jayway.jsonpath:json-path:2.4.0"
dependency "org.bouncycastle:bcpkix-jdk15on:1.66"
dependencySet(group: 'org.apache.tiles', version: '3.0.8') {
entry 'tiles-api'
@@ -236,7 +224,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.6"
dependency "joda-time:joda-time:2.10.10"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
dependency "org.javamoney:moneta:1.3"
@@ -316,8 +304,6 @@ configure([rootProject] + javaProjects) { project ->
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
languageVersion = "1.3"
apiVersion = "1.3"
freeCompilerArgs = ["-Xjsr305=strict"]
allWarningsAsErrors = true
}
@@ -339,8 +325,8 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.36.2"
configDirectory.set(rootProject.file("src/checkstyle"))
toolVersion = "8.38"
configDir = rootProject.file("src/checkstyle")
}
dependencies {
@@ -379,9 +365,8 @@ configure([rootProject] + javaProjects) { project ->
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.1/",
"https://junit.org/junit5/docs/5.7.0/api/"
"https://junit.org/junit4/javadoc/4.12/",
"https://junit.org/junit5/docs/5.6.3/api/"
] as String[]
}
+1
View File
@@ -0,0 +1 @@
apply from: "../gradle/build-cache-settings.gradle"
+10 -4
View File
@@ -1,7 +1,8 @@
== Spring Framework Concourse pipeline
The Spring Framework is using https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io.
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x[Spring Framework 5.2.x].
=== Setting up your development environment
@@ -25,13 +26,17 @@ spring https://ci.spring.io spring-framework Wed, 25 Mar 20
----
=== Pipeline configuration and structure
The build pipelines are described in `pipeline.yml` file.
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
You'll find in this folder the following resources:
* `pipeline.yml` the build pipeline
* `parameters.yml` the build parameters used for the pipeline
* `images/` holds the container images definitions used in this pipeline
@@ -41,11 +46,12 @@ You'll find in this folder the following resources:
=== Updating the build pipeline
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
The pipeline can be deployed using the following command:
[source]
----
$ fly -t spring set-pipeline -p spring-framework-5.3.x -c ci/pipeline.yml -l ci/parameters.yml
$ fly -t spring set-pipeline -p spring-framework-5.2.x -c ci/pipeline.yml -l ci/parameters.yml
----
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
+5 -4
View File
@@ -1,9 +1,10 @@
logging:
level:
io.spring.concourse: DEBUG
distribute:
optional-deployments:
- '.*\\.zip'
spring:
main:
banner-mode: off
banner-mode: off
sonatype:
exclude:
- 'build-info\.json'
- '.*\.zip'
@@ -1,4 +1,4 @@
FROM ubuntu:bionic-20200713
FROM ubuntu:focal-20210119
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
@@ -1,4 +1,4 @@
FROM ubuntu:bionic-20200713
FROM ubuntu:focal-20210119
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
+2 -8
View File
@@ -3,17 +3,11 @@ set -e
case "$1" in
java8)
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u265-b01/OpenJDK8U-jdk_x64_linux_hotspot_8u265b01.tar.gz"
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u282-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u282b08.tar.gz"
;;
java11)
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.8_10.tar.gz"
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
;;
java14)
echo "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_linux_hotspot_14.0.2_12.tar.gz"
;;
java15)
echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_linux_hotspot_15_36.tar.gz"
;;
*)
echo $"Unknown java version"
exit 1
+6 -3
View File
@@ -5,13 +5,16 @@ set -ex
# UTILS
###########################################################
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
dpkg-reconfigure --frontend noninteractive tzdata
rm -rf /var/lib/apt/lists/*
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.3/concourse-java.sh > /opt/concourse-java.sh
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.2.1/concourse-release-scripts-0.2.1.jar
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
###########################################################
# JAVA
@@ -1,8 +0,0 @@
FROM ubuntu:bionic-20200713
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java14
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
@@ -1,8 +0,0 @@
FROM ubuntu:bionic-20200713
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java15
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
+3 -4
View File
@@ -5,10 +5,9 @@ github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "master"
branch: "5.2.x"
milestone: "5.2.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
bintray-subject: "spring"
bintray-repo: "jars"
task-timeout: 1h00m
task-timeout: 1h00m
+65 -166
View File
@@ -1,21 +1,32 @@
anchors:
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
bintray-task-params: &bintray-task-params
BINTRAY_SUBJECT: ((bintray-subject))
BINTRAY_REPO: ((bintray-repo))
BINTRAY_USERNAME: ((bintray-username))
BINTRAY_API_KEY: ((bintray-api-key))
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: 5.3.x
git-repo-resource-source: &git-repo-resource-source
uri: ((github-repo))
username: ((github-username))
password: ((github-password))
branch: ((branch))
gradle-enterprise-task-params: &gradle-enterprise-task-params
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
sonatype-task-params: &sonatype-task-params
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
build-project-task-params: &build-project-task-params
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
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!>
@@ -24,9 +35,6 @@ anchors:
silent: true
icon_emoji: ":concourse:"
username: concourse-ci
sonatype-task-params: &sonatype-task-params
SONATYPE_USER_TOKEN: ((sonatype-user-token))
SONATYPE_PASSWORD_TOKEN: ((sonatype-user-token-password))
changelog-task-params: &changelog-task-params
name: generated-changelog/tag
tag: generated-changelog/tag
@@ -37,30 +45,26 @@ anchors:
resource_types:
- name: artifactory-resource
type: docker-image
type: registry-image
source:
repository: springio/artifactory-resource
tag: 0.0.12
tag: 0.0.13
- name: github-status-resource
type: docker-image
type: registry-image
source:
repository: dpb587/github-status-resource
tag: master
- name: slack-notification
type: docker-image
type: registry-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
- name: git-repo
type: git
icon: github
source:
uri: ((github-repo))
username: ((github-username))
password: ((github-password))
branch: ((branch))
<<: *git-repo-resource-source
- name: every-morning
type: time
icon: alarm
@@ -75,30 +79,18 @@ resources:
uri: ((github-repo))
branch: ((branch))
paths: ["ci/images/*"]
- name: spring-framework-ci-image
- name: ci-image
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci-image
- name: spring-framework-jdk11-ci-image
repository: ((docker-hub-organization))/spring-framework-ci
- name: ci-image-jdk11
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-jdk11-ci-image
- name: spring-framework-jdk14-ci-image
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-jdk14-ci-image
- name: spring-framework-jdk15-ci-image
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-jdk15-ci-image
repository: ((docker-hub-organization))/spring-framework-ci-jdk11
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
@@ -123,22 +115,6 @@ resources:
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk11-build
- name: repo-status-jdk14-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk14-build
- name: repo-status-jdk15-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk15-build
- name: slack-alert
type: slack-notification
icon: slack
@@ -161,47 +137,34 @@ resources:
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: false
jobs:
- name: build-spring-framework-ci-images
- name: build-ci-images
plan:
- get: ci-images-git-repo
trigger: true
- in_parallel:
- put: spring-framework-ci-image
- put: ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/spring-framework-ci-image/Dockerfile
- put: spring-framework-jdk11-ci-image
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
- put: ci-image-jdk11
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk11-ci-image/Dockerfile
- put: spring-framework-jdk14-ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk14-ci-image/Dockerfile
- put: spring-framework-jdk15-ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk15-ci-image/Dockerfile
dockerfile: ci-images-git-repo/ci/images/ci-image-jdk11/Dockerfile
- name: build
serial: true
public: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: true
- put: repo-status-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
privileged: true
timeout: ((task-timeout))
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/build-project.yml
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-build
@@ -213,6 +176,8 @@ jobs:
params: { state: "success", commit: "git-repo" }
- put: artifactory-repo
params: &artifactory-params
signing_key: ((signing-key))
signing_passphrase: ((signing-passphrase))
repo: libs-snapshot-local
folder: distribution-repository
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
@@ -244,7 +209,7 @@ jobs:
serial: true
public: true
plan:
- get: spring-framework-jdk11-ci-image
- get: ci-image-jdk11
- get: git-repo
- get: every-morning
trigger: true
@@ -252,13 +217,9 @@ jobs:
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
privileged: true
timeout: ((task-timeout))
image: spring-framework-jdk11-ci-image
image: ci-image-jdk11
file: git-repo/ci/tasks/check-project.yml
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
@@ -268,70 +229,14 @@ jobs:
<<: *slack-fail-params
- put: repo-status-jdk11-build
params: { state: "success", commit: "git-repo" }
- name: jdk14-build
serial: true
public: true
plan:
- get: spring-framework-jdk14-ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk14-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
privileged: true
timeout: ((task-timeout))
image: spring-framework-jdk14-ci-image
file: git-repo/ci/tasks/check-project.yml
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
on_failure:
do:
- put: repo-status-jdk14-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk14-build
params: { state: "success", commit: "git-repo" }
- name: jdk15-build
serial: true
public: true
plan:
- get: spring-framework-jdk15-ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk15-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
privileged: true
timeout: ((task-timeout))
image: spring-framework-jdk15-ci-image
file: git-repo/ci/tasks/check-project.yml
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
on_failure:
do:
- put: repo-status-jdk15-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk15-build
params: { state: "success", commit: "git-repo" }
- name: stage-milestone
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: M
@@ -346,7 +251,7 @@ jobs:
- name: promote-milestone
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
@@ -356,7 +261,7 @@ jobs:
download_artifacts: false
save_build_info: true
- task: promote
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: M
@@ -372,11 +277,11 @@ jobs:
- name: stage-rc
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RC
@@ -391,7 +296,7 @@ jobs:
- name: promote-rc
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
@@ -401,7 +306,7 @@ jobs:
download_artifacts: false
save_build_info: true
- task: promote
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RC
@@ -417,11 +322,11 @@ jobs:
- name: stage-release
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RELEASE
@@ -436,26 +341,26 @@ jobs:
- name: promote-release
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-release]
params:
download_artifacts: false
download_artifacts: true
save_build_info: true
- task: promote
image: spring-framework-ci-image
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *artifactory-task-params
<<: *bintray-task-params
- name: sync-to-maven-central
<<: *sonatype-task-params
- name: create-github-release
serial: true
plan:
- get: spring-framework-ci-image
- get: ci-image
- get: git-repo
- get: artifactory-repo
trigger: true
@@ -463,12 +368,6 @@ jobs:
params:
download_artifacts: false
save_build_info: true
- task: sync-to-maven-central
image: spring-framework-ci-image
file: git-repo/ci/tasks/sync-to-maven-central.yml
params:
<<: *bintray-task-params
<<: *sonatype-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
@@ -480,8 +379,8 @@ jobs:
groups:
- name: "builds"
jobs: ["build", "jdk11-build", "jdk14-build", "jdk15-build"]
jobs: ["build", "jdk11-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone","promote-rc", "promote-release", "sync-to-maven-central"]
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-spring-framework-ci-images"]
jobs: ["build-ci-images"]
+7 -2
View File
@@ -2,11 +2,16 @@
set -e
CONFIG_DIR=git-repo/ci/config
version=$( cat version/version )
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
milestone=${version}
if [[ $RELEASE_TYPE = "RELEASE" ]]; then
milestone=${version%.RELEASE}
fi
java -jar /github-changelog-generator.jar \
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
${version} generated-changelog/changelog.md
${milestone} generated-changelog/changelog.md
echo ${version} > generated-changelog/version
echo v${version} > generated-changelog/tag
+4 -2
View File
@@ -6,11 +6,13 @@ CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
distribute $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
echo "Promotion complete"
echo $version > version/version
+1 -1
View File
@@ -20,7 +20,7 @@ elif [[ $RELEASE_TYPE = "RC" ]]; then
stageVersion=$( get_next_rc_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RELEASE" ]]; then
stageVersion=$( get_next_release $snapshotVersion)
stageVersion=$( get_next_release $snapshotVersion "RELEASE")
nextVersion=$( bump_version_number $snapshotVersion)
else
echo "Unknown release type $RELEASE_TYPE" >&2; exit 1;
+3 -3
View File
@@ -1,13 +1,13 @@
---
platform: linux
image_resource:
type: docker-image
type: registry-image
source:
repository: springio/github-changelog-generator
tag: '0.0.4'
tag: '0.0.6'
inputs:
- name: git-repo
- name: version
- name: artifactory-repo
outputs:
- name: generated-changelog
params:
+4 -4
View File
@@ -10,9 +10,9 @@ params:
ARTIFACTORY_SERVER:
ARTIFACTORY_USERNAME:
ARTIFACTORY_PASSWORD:
BINTRAY_SUBJECT:
BINTRAY_REPO:
BINTRAY_USERNAME:
BINTRAY_API_KEY:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE_ID:
run:
path: git-repo/ci/scripts/promote-version.sh
-16
View File
@@ -1,16 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: version
params:
BINTRAY_REPO:
BINTRAY_SUBJECT:
BINTRAY_USERNAME:
BINTRAY_API_KEY:
SONATYPE_USER_TOKEN:
SONATYPE_PASSWORD_TOKEN:
run:
path: git-repo/ci/scripts/sync-to-maven-central.sh
+6
View File
@@ -18,6 +18,12 @@ publishing {
mavenJava(MavenPublication) {
artifactId = 'spring-framework-bom'
from components.javaPlatform
// remove scope information from published BOM
pom.withXml {
asNode().dependencyManagement.first().dependencies.first().each {
it.remove(it.scope.first())
}
}
}
}
}
+1 -2
View File
@@ -1,5 +1,4 @@
version=5.3.1
version=5.2.16.RELEASE
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
kotlin.stdlib.default.dependency=false
+18
View File
@@ -0,0 +1,18 @@
buildCache {
local {
enabled = true
}
remote(HttpBuildCache) {
enabled = true
url = 'https://ge.spring.io/cache/'
def cacheUsername = System.getenv('GRADLE_ENTERPRISE_CACHE_USERNAME')
def cachePassword = System.getenv('GRADLE_ENTERPRISE_CACHE_PASSWORD')
if (cacheUsername && cachePassword) {
push = true
credentials {
username = cacheUsername
password = cachePassword
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
addCustomJavaHomeMetadata()
addCustomJavaSourceVersionMetadata()
void addCustomJavaHomeMetadata() {
def customJavaHome = System.getProperty("customJavaHome")
if (customJavaHome) {
buildScan.value "Custom JAVA_HOME", customJavaHome
}
}
void addCustomJavaSourceVersionMetadata() {
def customJavaSourceVersion = System.getProperty("customJavaSourceVersion")
if (customJavaSourceVersion) {
buildScan.value "Custom Java Source Version", customJavaSourceVersion
}
}
+11 -13
View File
@@ -3,7 +3,7 @@ configurations {
}
dependencies {
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.3.RELEASE")
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.0.RELEASE")
}
repositories {
@@ -103,17 +103,11 @@ dokka {
externalDocumentationLink {
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
}
externalDocumentationLink {
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
}
externalDocumentationLink {
url = new URL("https://r2dbc.io/spec/0.8.3.RELEASE/api/")
}
}
}
task downloadResources(type: Download) {
def version = "0.2.2.RELEASE"
def version = "0.2.1.RELEASE"
src "https://repo.spring.io/release/io/spring/docresources/" +
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
dest project.file("$buildDir/docs/spring-doc-resources.zip")
@@ -127,7 +121,11 @@ task extractDocResources(type: Copy, dependsOn: downloadResources) {
}
asciidoctorj {
version = '2.4.1'
modules {
pdf {
version '1.5.0-beta.8'
}
}
fatalWarnings ".*"
options doctype: 'book', eruby: 'erubis'
attributes([
@@ -140,7 +138,7 @@ asciidoctorj {
sectnums: '',
'source-highlighter': 'highlight.js',
highlightjsdir: 'js/highlight',
'highlightjs-theme': 'googlecode',
'highlightjs-theme': 'github', // 'googlecode',
stylesdir: 'css/',
stylesheet: 'stylesheet.css',
'spring-version': project.version
@@ -161,7 +159,7 @@ asciidoctor {
logDocuments = true
resources {
from(sourceDir) {
include 'images/*.png', 'css/**', 'js/**'
include 'images/*', 'css/**', 'js/**'
}
from extractDocResources
}
@@ -198,10 +196,10 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', 'dok
into "javadoc-api"
}
from ("$asciidoctor.outputDir") {
into "reference/html"
into "spring-framework-reference"
}
from ("$asciidoctorPdf.outputDir") {
into "reference/pdf"
into "spring-framework-reference/pdf"
}
from (dokka) {
into "kdoc-api"
+1 -2
View File
@@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath ->
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
}
// Use separate main/test outputs (prevents WTP from packaging test classes)
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
eclipse.classpath.file.beforeMerged { classpath ->
classpath.entries.findAll{ it instanceof SourceFolder }.each {
if(it.output.startsWith("bin/")) {
if (it.output.startsWith("bin/")) {
it.output = null
}
}
+6 -12
View File
@@ -1,17 +1,7 @@
apply plugin: 'org.springframework.build.compile'
apply plugin: 'org.springframework.build.optional-dependencies'
apply plugin: 'me.champeau.gradle.jmh'
apply from: "$rootDir/gradle/publications.gradle"
dependencies {
jmh 'org.openjdk.jmh:jmh-core:1.23'
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
jmh 'net.sf.jopt-simple:jopt-simple:4.6'
}
jmh {
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
}
jar {
manifest.attributes["Implementation-Title"] = project.name
manifest.attributes["Implementation-Version"] = project.version
@@ -73,5 +63,9 @@ publishing {
}
// Disable publication of test fixture artifacts.
components.java.withVariantsFromConfiguration(configurations.testFixturesApiElements) { skip() }
components.java.withVariantsFromConfiguration(configurations.testFixturesRuntimeElements) { skip() }
//
// Once we upgrade to Gradle 6.x, we will need to delete the following line ...
components.java.variants.removeAll { it.outgoingConfiguration.name.startsWith("testFixtures") }
// ... and uncomment the following two lines.
// components.java.withVariantsFromConfiguration(configurations.testFixturesApiElements) { skip() }
// components.java.withVariantsFromConfiguration(configurations.testFixturesRuntimeElements) { skip() }
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+17 -14
View File
@@ -82,7 +82,6 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -130,7 +129,6 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -156,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
i=$((i+1))
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -177,9 +175,14 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+18 -7
View File
@@ -29,9 +29,6 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -40,7 +37,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +51,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +61,28 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
@@ -70,7 +70,7 @@ class AopNamespaceHandlerScopeIntegrationTests {
assertThat(singletonScoped.getName()).isEqualTo(rob);
singletonScoped.setName(bram);
assertThat(singletonScoped.getName()).isEqualTo(bram);
ITestBean deserialized = SerializationTestUtils.serializeAndDeserialize(singletonScoped);
ITestBean deserialized = (ITestBean) SerializationTestUtils.serializeAndDeserialize(singletonScoped);
assertThat(deserialized.getName()).isEqualTo(bram);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import org.springframework.transaction.testfixture.CallCountingTransactionManage
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
import static org.springframework.core.testfixture.TestGroup.PERFORMANCE;
/**
* Integration tests cornering bug SPR-8651, which revealed that @Scheduled methods may
@@ -52,7 +52,7 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
* @since 3.1
*/
@SuppressWarnings("resource")
@EnabledForTestGroups(LONG_RUNNING)
@EnabledForTestGroups(PERFORMANCE)
class ScheduledAndTransactionalAnnotationIntegrationTests {
@Test
@@ -61,7 +61,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(Config.class, JdkProxyTxConfig.class, RepoConfigA.class);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(ctx::refresh)
.withCauseInstanceOf(IllegalStateException.class);
.satisfies(ex -> assertThat(ex.getRootCause()).isInstanceOf(IllegalStateException.class));
}
@Test
@@ -182,7 +182,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
@Aspect
public static class MyAspect {
private final AtomicInteger count = new AtomicInteger();
private final AtomicInteger count = new AtomicInteger(0);
@org.aspectj.lang.annotation.Before("execution(* scheduled())")
public void checkTransaction() {
@@ -200,7 +200,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
@Repository
static class MyRepositoryImpl implements MyRepository {
private final AtomicInteger count = new AtomicInteger();
private final AtomicInteger count = new AtomicInteger(0);
@Transactional
@Scheduled(fixedDelay = 5)
@@ -226,7 +226,7 @@ class ScheduledAndTransactionalAnnotationIntegrationTests {
@Repository
static class MyRepositoryWithScheduledMethodImpl implements MyRepositoryWithScheduledMethod {
private final AtomicInteger count = new AtomicInteger();
private final AtomicInteger count = new AtomicInteger(0);
@Autowired(required = false)
private MyAspect myAspect;
+1 -27
View File
@@ -4,11 +4,7 @@ pluginManagement {
maven { url 'https://repo.spring.io/plugins-release' }
}
}
plugins {
id "com.gradle.enterprise" version "3.2"
id "io.spring.gradle-enterprise-conventions" version "0.0.2"
}
apply from: "$rootDir/gradle/build-cache-settings.gradle"
include "spring-aop"
include "spring-aspects"
@@ -27,7 +23,6 @@ include "spring-jms"
include "spring-messaging"
include "spring-orm"
include "spring-oxm"
include "spring-r2dbc"
include "spring-test"
include "spring-tx"
include "spring-web"
@@ -41,24 +36,3 @@ rootProject.name = "spring"
rootProject.children.each {project ->
project.buildFileName = "${project.name}.gradle"
}
settings.gradle.projectsLoaded {
gradleEnterprise {
buildScan {
if (settings.gradle.rootProject.hasProperty('customJavaHome')) {
value("Custom JAVA_HOME", settings.gradle.rootProject.getProperty('customJavaHome'))
}
if (settings.gradle.rootProject.hasProperty('customJavaSourceVersion')) {
value("Custom Java Source Version", settings.gradle.rootProject.getProperty('customJavaSourceVersion'))
}
File buildDir = settings.gradle.rootProject.getBuildDir()
buildDir.mkdirs()
new File(buildDir, "build-scan-uri.txt").text = "(build scan not generated)"
buildScanPublished { scan ->
if (buildDir.exists()) {
new File(buildDir, "build-scan-uri.txt").text = "${scan.buildScanUri}\n"
}
}
}
}
}
@@ -16,8 +16,6 @@
package org.aopalliance.intercept;
import javax.annotation.Nonnull;
/**
* Intercepts the construction of a new object.
*
@@ -56,7 +54,6 @@ public interface ConstructorInterceptor extends Interceptor {
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
@Nonnull
Object construct(ConstructorInvocation invocation) throws Throwable;
}
@@ -18,8 +18,6 @@ package org.aopalliance.intercept;
import java.lang.reflect.Constructor;
import javax.annotation.Nonnull;
/**
* Description of an invocation to a constructor, given to an
* interceptor upon constructor-call.
@@ -38,7 +36,6 @@ public interface ConstructorInvocation extends Invocation {
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the constructor being called
*/
@Nonnull
Constructor<?> getConstructor();
}
@@ -16,8 +16,6 @@
package org.aopalliance.intercept;
import javax.annotation.Nonnull;
/**
* This interface represents an invocation in the program.
*
@@ -34,7 +32,6 @@ public interface Invocation extends Joinpoint {
* array to change the arguments.
* @return the argument of the invocation
*/
@Nonnull
Object[] getArguments();
}
@@ -18,9 +18,6 @@ package org.aopalliance.intercept;
import java.lang.reflect.AccessibleObject;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* This interface represents a generic runtime joinpoint (in the AOP
* terminology).
@@ -49,7 +46,6 @@ public interface Joinpoint {
* @return see the children interfaces' proceed definition
* @throws Throwable if the joinpoint throws an exception
*/
@Nullable
Object proceed() throws Throwable;
/**
@@ -57,7 +53,6 @@ public interface Joinpoint {
* <p>For instance, the target object for an invocation.
* @return the object (can be null if the accessible object is static)
*/
@Nullable
Object getThis();
/**
@@ -65,7 +60,6 @@ public interface Joinpoint {
* <p>The static part is an accessible object on which a chain of
* interceptors are installed.
*/
@Nonnull
AccessibleObject getStaticPart();
}
@@ -16,9 +16,6 @@
package org.aopalliance.intercept;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Intercepts calls on an interface on its way to the target. These
* are nested "on top" of the target.
@@ -55,7 +52,6 @@ public interface MethodInterceptor extends Interceptor {
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
@Nullable
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
Object invoke(MethodInvocation invocation) throws Throwable;
}
@@ -18,8 +18,6 @@ package org.aopalliance.intercept;
import java.lang.reflect.Method;
import javax.annotation.Nonnull;
/**
* Description of an invocation to a method, given to an interceptor
* upon method-call.
@@ -38,7 +36,6 @@ public interface MethodInvocation extends Invocation {
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the method being called
*/
@Nonnull
Method getMethod();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2021 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,7 +26,7 @@ import org.aopalliance.aop.Advice;
* <p>Introductions are often <b>mixins</b>, enabling the building of composite
* objects that can achieve many of the goals of multiple inheritance in Java.
*
* <p>Compared to {qlink IntroductionInfo}, this interface allows an advice to
* <p>Compared to {@link IntroductionInfo}, this interface allows an advice to
* implement a range of interfaces that is not necessarily known in advance.
* Thus an {@link IntroductionAdvisor} can be used to specify which interfaces
* will be exposed in an advised object.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterAdvice;
import org.springframework.lang.Nullable;
/**
* Spring AOP advice wrapping an AspectJ after advice method.
@@ -43,7 +42,6 @@ public class AspectJAfterAdvice extends AbstractAspectJAdvice
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterAdvice;
import org.springframework.lang.Nullable;
/**
* Spring AOP advice wrapping an AspectJ after-throwing advice method.
@@ -58,7 +57,6 @@ public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.lang.Nullable;
/**
* Spring AOP around advice (MethodInterceptor) that wraps
@@ -61,7 +60,6 @@ public class AspectJAroundAdvice extends AbstractAspectJAdvice implements Method
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
@@ -84,13 +84,11 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
}
@Override
@Nullable
public Object proceed() throws Throwable {
return this.methodInvocation.invocableClone().proceed();
}
@Override
@Nullable
public Object proceed(Object[] arguments) throws Throwable {
Assert.notNull(arguments, "Argument array passed to proceed cannot be null");
if (arguments.length != this.methodInvocation.getArguments().length) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -160,12 +160,23 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
}
/**
* Get the singleton aspect instance for the supplied aspect type.
* An instance is created if one cannot be found in the instance cache.
* Get the singleton aspect instance for the supplied aspect type. An instance
* is created if one cannot be found in the instance cache.
*/
private Object getSingletonAspectInstance(Class<?> aspectClass) {
return aspectCache.computeIfAbsent(aspectClass,
clazz -> new SimpleAspectInstanceFactory(clazz).getAspectInstance());
// Quick check without a lock...
Object instance = aspectCache.get(aspectClass);
if (instance == null) {
synchronized (aspectCache) {
// To be safe, check within full lock now...
instance = aspectCache.get(aspectClass);
if (instance == null) {
instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
aspectCache.put(aspectClass, instance);
}
}
}
return instance;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -114,15 +114,6 @@ public interface Advised extends TargetClassAware {
*/
Advisor[] getAdvisors();
/**
* Return the number of advisors applying to this proxy.
* <p>The default implementation delegates to {@code getAdvisors().length}.
* @since 5.3.1
*/
default int getAdvisorCount() {
return getAdvisors().length;
}
/**
* Add an advisor at the end of the advisor chain.
* <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -95,6 +95,12 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
private List<Advisor> advisors = new ArrayList<>();
/**
* Array updated on changes to the advisors list, which is easier
* to manipulate internally.
*/
private Advisor[] advisorArray = new Advisor[0];
/**
* No-arg constructor for use as a JavaBean.
@@ -238,12 +244,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
@Override
public final Advisor[] getAdvisors() {
return this.advisors.toArray(new Advisor[0]);
}
@Override
public int getAdvisorCount() {
return this.advisors.size();
return this.advisorArray;
}
@Override
@@ -291,6 +292,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
}
updateAdvisorArray();
adviceChanged();
}
@@ -337,6 +339,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
}
@@ -360,18 +363,27 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
this.advisors.add(pos, advisor);
updateAdvisorArray();
adviceChanged();
}
/**
* Bring the array up to date with the list.
*/
protected final void updateAdvisorArray() {
this.advisorArray = this.advisors.toArray(new Advisor[0]);
}
/**
* Allows uncontrolled access to the {@link List} of {@link Advisor Advisors}.
* <p>Use with care, and remember to {@link #adviceChanged() fire advice changed events}
* when making any modifications.
* <p>Use with care, and remember to {@link #updateAdvisorArray() refresh the advisor array}
* and {@link #adviceChanged() fire advice changed events} when making any modifications.
*/
protected final List<Advisor> getAdvisorsInternal() {
return this.advisors;
}
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
@@ -509,6 +521,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
Assert.notNull(advisor, "Advisor must not be null");
this.advisors.add(advisor);
}
updateAdvisorArray();
adviceChanged();
}
@@ -523,6 +536,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
copy.advisorChainFactory = this.advisorChainFactory;
copy.interfaces = this.interfaces;
copy.advisors = this.advisors;
copy.updateAdvisorArray();
return copy;
}
@@ -539,6 +553,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
this.methodCache = new ConcurrentHashMap<>(32);
}
@Override
public String toProxyConfigString() {
return toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -206,7 +206,7 @@ public abstract class AopProxyUtils {
* Check equality of the advisors behind the given AdvisedSupport objects.
*/
public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
return a.getAdvisorCount() == b.getAdvisorCount() && Arrays.equals(a.getAdvisors(), b.getAdvisors());
return Arrays.equals(a.getAdvisors(), b.getAdvisors());
}
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -48,11 +49,11 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.core.KotlinDetector;
import org.springframework.core.SmartClassLoader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@@ -125,7 +126,7 @@ class CglibAopProxy implements AopProxy, Serializable {
*/
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
@@ -325,7 +326,7 @@ class CglibAopProxy implements AopProxy, Serializable {
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);
this.fixedInterceptorMap = new HashMap<>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
@@ -752,10 +753,17 @@ class CglibAopProxy implements AopProxy, Serializable {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
// Propagate original exception if declared on the target method
// (with callers expecting it). Always propagate it for Kotlin code
// since checked exceptions do not have to be explicitly declared there.
throw ex;
}
else {
// Checked exception thrown in the interceptor but not declared on the
// target method signature -> apply an UndeclaredThrowableException,
// aligned with standard JDK dynamic proxy behavior.
throw new UndeclaredThrowableException(ex);
}
}
@@ -942,11 +950,11 @@ class CglibAopProxy implements AopProxy, Serializable {
}
// Advice instance identity is unimportant to the proxy class:
// All that matters is type and ordering.
if (this.advised.getAdvisorCount() != otherAdvised.getAdvisorCount()) {
return false;
}
Advisor[] thisAdvisors = this.advised.getAdvisors();
Advisor[] thatAdvisors = otherAdvised.getAdvisors();
if (thisAdvisors.length != thatAdvisors.length) {
return false;
}
for (int i = 0; i < thisAdvisors.length; i++) {
Advisor thisAdvisor = thisAdvisors[i];
Advisor thatAdvisor = thatAdvisors[i];
@@ -38,7 +38,6 @@ import org.springframework.aop.SpringProxy;
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 12.03.2004
* @see AdvisedSupport#setOptimize
* @see AdvisedSupport#setProxyTargetClass
@@ -47,18 +46,9 @@ import org.springframework.aop.SpringProxy;
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!IN_NATIVE_IMAGE &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,7 +57,6 @@ import org.springframework.util.ClassUtils;
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
* @author Sergey Tsypanov
* @see java.lang.reflect.Proxy
* @see AdvisedSupport
* @see ProxyFactory
@@ -83,8 +82,6 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
/** Config used to configure this proxy. */
private final AdvisedSupport advised;
private final Class<?>[] proxiedInterfaces;
/**
* Is the {@link #equals} method defined on the proxied interfaces?
*/
@@ -104,12 +101,10 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
@@ -123,7 +118,9 @@ 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);
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.aop.framework;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.springframework.util.Assert;
@@ -34,7 +34,7 @@ public class ProxyCreatorSupport extends AdvisedSupport {
private AopProxyFactory aopProxyFactory;
private final List<AdvisedSupportListener> listeners = new ArrayList<>();
private final List<AdvisedSupportListener> listeners = new LinkedList<>();
/** Set to true when the first AOP proxy has been created. */
private boolean active = false;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -52,7 +51,6 @@ public class AfterReturningAdviceInterceptor implements MethodInterceptor, After
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
@@ -23,7 +23,6 @@ import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -52,7 +51,6 @@ public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeA
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -107,7 +107,6 @@ public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.aop.framework.autoproxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -271,9 +272,19 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
return pvs; // skip postProcessPropertyValues
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
/**
@@ -439,7 +450,17 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
@@ -503,7 +524,10 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (specificInterceptors.length > 0) {
// specificInterceptors may equals PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
allInterceptors.addAll(Arrays.asList(specificInterceptors));
}
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,6 @@ import org.springframework.util.StringUtils;
* "interceptorNames" property.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 10.10.2003
* @see #setBeanNames
* @see #isMatch
@@ -47,8 +46,6 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial")
public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
private static final String[] NO_ALIASES = new String[0];
@Nullable
private List<String> beanNames;
@@ -75,70 +72,40 @@ public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
/**
* Delegate to {@link AbstractAutoProxyCreator#getCustomTargetSource(Class, String)}
* if the bean name matches one of the names in the configured list of supported
* names, returning {@code null} otherwise.
* @since 5.3
* @see #setBeanNames(String...)
*/
@Override
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
return (isSupportedBeanName(beanClass, beanName) ?
super.getCustomTargetSource(beanClass, beanName) : null);
}
/**
* Identify as a bean to proxy if the bean name matches one of the names in
* the configured list of supported names.
* @see #setBeanNames(String...)
* Identify as bean to proxy if the bean name is in the configured list of names.
*/
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
return (isSupportedBeanName(beanClass, beanName) ?
PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS : DO_NOT_PROXY);
}
/**
* Determine if the bean name for the given bean class matches one of the names
* in the configured list of supported names.
* @param beanClass the class of the bean to advise
* @param beanName the name of the bean
* @return {@code true} if the given bean name is supported
* @see #setBeanNames(String...)
*/
private boolean isSupportedBeanName(Class<?> beanClass, String beanName) {
if (this.beanNames != null) {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
for (String mappedName : this.beanNames) {
if (isFactoryBean) {
if (FactoryBean.class.isAssignableFrom(beanClass)) {
if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
continue;
}
mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
if (isMatch(beanName, mappedName)) {
return true;
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
BeanFactory beanFactory = getBeanFactory();
String[] aliases = (beanFactory != null ? beanFactory.getAliases(beanName) : NO_ALIASES);
for (String alias : aliases) {
for (String mappedName : this.beanNames) {
if (isMatch(alias, mappedName)) {
return true;
BeanFactory beanFactory = getBeanFactory();
if (beanFactory != null) {
String[] aliases = beanFactory.getAliases(beanName);
for (String alias : aliases) {
if (isMatch(alias, mappedName)) {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
}
}
}
return false;
return DO_NOT_PROXY;
}
/**
* Determine if the given bean name matches the mapped name.
* Return if the given bean name matches the mapped name.
* <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
* as well as direct equality. Can be overridden in subclasses.
* @param beanName the bean name to check
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2014 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,32 +23,30 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.lang.Nullable;
/**
* {@code TargetSourceCreator} that enforces a {@link LazyInitTargetSource} for
* each bean that is defined as "lazy-init". This will lead to a proxy created for
* each of those beans, allowing to fetch a reference to such a bean without
* actually initializing the target bean instance.
* TargetSourceCreator that enforces a LazyInitTargetSource for each bean
* that is defined as "lazy-init". This will lead to a proxy created for
* each of those beans, allowing to fetch a reference to such a bean
* without actually initializing the target bean instance.
*
* <p>To be registered as custom {@code TargetSourceCreator} for an auto-proxy
* creator, in combination with custom interceptors for specific beans or for the
* creation of lazy-init proxies only. For example, as an autodetected
* <p>To be registered as custom TargetSourceCreator for an auto-proxy creator,
* in combination with custom interceptors for specific beans or for the
* creation of lazy-init proxies only. For example, as autodetected
* infrastructure bean in an XML application context definition:
*
* <pre class="code">
* &lt;bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;
* &lt;property name="beanNames" value="*" /&gt; &lt;!-- apply to all beans --&gt;
* &lt;property name="customTargetSourceCreators"&gt;
* &lt;list&gt;
* &lt;bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator" /&gt;
* &lt;bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="myLazyInitBean" class="mypackage.MyBeanClass" lazy-init="true"&gt;
* &lt;!-- ... --&gt;
* ...
* &lt;/bean&gt;</pre>
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.2
* @see org.springframework.beans.factory.config.BeanDefinition#isLazyInit
* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#setCustomTargetSourceCreators
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Base {@code MethodInterceptor} implementation for tracing.
@@ -152,7 +151,6 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
}
else {
Object target = invocation.getThis();
Assert.state(target != null, "Target must not be null");
return LogFactory.getLog(getClassForLogging(target));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
import org.springframework.util.ConcurrencyThrottleSupport;
/**
@@ -49,7 +48,6 @@ public class ConcurrencyThrottleInterceptor extends ConcurrencyThrottleSupport
}
@Override
@Nullable
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
beforeAccess();
try {
@@ -296,8 +296,6 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
@Nullable Object returnValue, @Nullable Throwable throwable, long invocationTime) {
Matcher matcher = PATTERN.matcher(message);
Object target = methodInvocation.getThis();
Assert.state(target != null, "Target must not be null");
StringBuffer output = new StringBuffer();
while (matcher.find()) {
@@ -306,11 +304,11 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
matcher.appendReplacement(output, Matcher.quoteReplacement(methodInvocation.getMethod().getName()));
}
else if (PLACEHOLDER_TARGET_CLASS_NAME.equals(match)) {
String className = getClassForLogging(target).getName();
String className = getClassForLogging(methodInvocation.getThis()).getName();
matcher.appendReplacement(output, Matcher.quoteReplacement(className));
}
else if (PLACEHOLDER_TARGET_CLASS_SHORT_NAME.equals(match)) {
String shortName = ClassUtils.getShortName(getClassForLogging(target));
String shortName = ClassUtils.getShortName(getClassForLogging(methodInvocation.getThis()));
matcher.appendReplacement(output, Matcher.quoteReplacement(shortName));
}
else if (PLACEHOLDER_ARGUMENTS.equals(match)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2012 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,8 +18,6 @@ package org.springframework.aop.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
/**
* AOP Alliance {@code MethodInterceptor} that can be introduced in a chain
* to display verbose information about intercepted invocations to the logger.
@@ -58,7 +56,6 @@ public class DebugInterceptor extends SimpleTraceInterceptor {
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
synchronized (this) {
this.count++;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.beans.factory.NamedBean;
import org.springframework.lang.Nullable;
/**
* Convenient methods for creating advisors that may be used when autoproxying beans
@@ -111,7 +110,6 @@ public abstract class ExposeBeanNameAdvisors {
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
@@ -136,7 +134,6 @@ public abstract class ExposeBeanNameAdvisors {
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
@@ -25,7 +25,6 @@ import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.PriorityOrdered;
import org.springframework.lang.Nullable;
/**
* Interceptor that exposes the current {@link org.aopalliance.intercept.MethodInvocation}
@@ -89,7 +88,6 @@ public final class ExposeInvocationInterceptor implements MethodInterceptor, Pri
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@ package org.springframework.aop.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.springframework.util.Assert;
/**
* Simple AOP Alliance {@code MethodInterceptor} that can be introduced
* in a chain to display verbose trace information about intercepted method
@@ -75,9 +73,7 @@ public class SimpleTraceInterceptor extends AbstractTraceInterceptor {
* @return the description
*/
protected String getInvocationDescription(MethodInvocation invocation) {
Object target = invocation.getThis();
Assert.state(target != null, "Target must not be null");
String className = target.getClass().getName();
String className = invocation.getThis().getClass().getName();
return "method '" + invocation.getMethod().getName() + "' of class [" + className + "]";
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
@Nullable
private final String methodName;
private final AtomicInteger evaluations = new AtomicInteger();
private final AtomicInteger evaluations = new AtomicInteger(0);
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,7 +71,8 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
if (introductionInfo != null) {
Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
if (introducedInterfaces.length == 0) {
throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");
throw new IllegalArgumentException(
"IntroductionInfo defines no interfaces to introduce: " + introductionInfo);
}
for (Class<?> ifc : introducedInterfaces) {
addInterface(ifc);
@@ -114,13 +114,12 @@ public class DelegatePerTargetObjectIntroductionInterceptor extends Introduction
* that it is introduced into. This method is <strong>never</strong> called for
* {@link MethodInvocation MethodInvocations} on the introduced interfaces.
*/
@Nullable
protected Object doProceed(MethodInvocation mi) throws Throwable {
// If we get here, just pass the invocation on.
return mi.proceed();
}
private Object getIntroductionDelegateFor(@Nullable Object targetObject) {
private Object getIntroductionDelegateFor(Object targetObject) {
synchronized (this.delegateMap) {
if (this.delegateMap.containsKey(targetObject)) {
return this.delegateMap.get(targetObject);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -131,7 +131,6 @@ public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport
* that it is introduced into. This method is <strong>never</strong> called for
* {@link MethodInvocation MethodInvocations} on the introduced interfaces.
*/
@Nullable
protected Object doProceed(MethodInvocation mi) throws Throwable {
// If we get here, just pass the invocation on.
return mi.proceed();
@@ -275,7 +275,7 @@ public class AspectJAdviceParameterNameDiscovererTests {
private static String format(String[] names) {
StringBuilder sb = new StringBuilder();
StringBuffer sb = new StringBuffer();
sb.append("(");
for (int i = 0; i < names.length; i++) {
sb.append(names[i]);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -198,8 +198,8 @@ public class AspectJExpressionPointcutTests {
// not currently testable in a reliable fashion
//assertDoesNotMatchStringClass(classFilter);
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 12D)).as("Should match with setSomeNumber with Double input").isTrue();
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 11)).as("Should not match setSomeNumber with Integer input").isFalse();
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, new Double(12))).as("Should match with setSomeNumber with Double input").isTrue();
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, new Integer(11))).as("Should not match setSomeNumber with Integer input").isFalse();
assertThat(methodMatcher.matches(getAge, TestBean.class)).as("Should not match getAge").isFalse();
assertThat(methodMatcher.isRuntime()).as("Should be a runtime match").isTrue();
}
@@ -224,10 +224,10 @@ public class AspectJExpressionPointcutTests {
TestBean testBean = getAdvisedProxy(expression, interceptor);
assertThat(interceptor.getCount()).as("Calls should be 0").isEqualTo(0);
testBean.setSomeNumber(30D);
testBean.setSomeNumber(new Double(30));
assertThat(interceptor.getCount()).as("Calls should be 1").isEqualTo(1);
testBean.setSomeNumber(90);
testBean.setSomeNumber(new Integer(90));
assertThat(interceptor.getCount()).as("Calls should be 1").isEqualTo(1);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,8 +91,9 @@ public class TrickyAspectJPointcutExpressionTests {
// Make sure the interface is loaded from the parent class loader
loader.excludeClass(TestService.class.getName());
loader.excludeClass(TestException.class.getName());
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).getDeclaredConstructor().newInstance();
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
@@ -126,6 +127,7 @@ public class TrickyAspectJPointcutExpressionTests {
public SimpleThrowawayClassLoader(ClassLoader parent) {
super(parent);
}
}
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.aspectj.lang.JoinPoint;
@@ -135,7 +136,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
int realAge = 65;
target.setAge(realAge);
List<Advisor> advisors = new ArrayList<>();
List<Advisor> advisors = new LinkedList<>();
PerTargetAspect aspect1 = new PerTargetAspect();
aspect1.count = 100;
aspect1.setOrder(10);
@@ -163,7 +164,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
int realAge = 65;
target.setAge(realAge);
List<Advisor> advisors = new ArrayList<>();
List<Advisor> advisors = new LinkedList<>();
PerTargetAspectWithOrderAnnotation10 aspect1 = new PerTargetAspectWithOrderAnnotation10();
aspect1.count = 100;
advisors.addAll(
@@ -391,7 +392,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
@Test
void introductionOnTargetExcludedByTypePattern() {
ArrayList<Object> target = new ArrayList<>();
LinkedList<Object> target = new LinkedList<>();
List<?> proxy = (List<?>) createProxy(target,
AopUtils.findAdvisorsThatCanApply(
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,7 +89,7 @@ public class AspectProxyFactoryTests {
proxyFactory.addAspect(LoggingAspectOnVarargs.class);
ITestBean proxy = proxyFactory.getProxy();
assertThat(proxy.doWithVarargs(MyEnum.A, MyOtherEnum.C)).isTrue();
ITestBean tb = SerializationTestUtils.serializeAndDeserialize(proxy);
ITestBean tb = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
assertThat(tb.doWithVarargs(MyEnum.A, MyOtherEnum.C)).isTrue();
}
@@ -108,14 +108,15 @@ public class AspectProxyFactoryTests {
ITestBean proxy = proxyFactory.getProxy();
assertThat(proxy.getAge()).isEqualTo((target.getAge() * multiple));
ITestBean serializedProxy = SerializationTestUtils.serializeAndDeserialize(proxy);
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
assertThat(serializedProxy.getAge()).isEqualTo((target.getAge() * multiple));
}
@Test
public void testWithNonSingletonAspectInstance() throws Exception {
AspectJProxyFactory pf = new AspectJProxyFactory();
assertThatIllegalArgumentException().isThrownBy(() -> pf.addAspect(new PerThisAspect()));
assertThatIllegalArgumentException().isThrownBy(() ->
pf.addAspect(new PerThisAspect()));
}
@Test // SPR-13328
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -183,7 +183,7 @@ public class ProxyFactoryTests {
}
@Test
public void testGetsAllInterfaces() throws Exception {
public void testGetsAllInterfaces() {
// Extend to get new interface
class TestBeanSubclass extends TestBean implements Comparable<Object> {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public class ConcurrencyThrottleInterceptorTests {
ITestBean proxy = (ITestBean) proxyFactory.getProxy();
proxy.getAge();
ITestBean serializedProxy = SerializationTestUtils.serializeAndDeserialize(proxy);
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
Advised advised = (Advised) serializedProxy;
ConcurrencyThrottleInterceptor serializedCti =
(ConcurrencyThrottleInterceptor) advised.getAdvisors()[0].getAdvice();
@@ -136,20 +136,20 @@ public class CustomizableTraceInterceptorTests {
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString", new Class[0]));
given(methodInvocation.getThis()).willReturn(this);
given(methodInvocation.getArguments()).willReturn(new Object[]{"$ One \\$", 2L});
given(methodInvocation.getArguments()).willReturn(new Object[]{"$ One \\$", new Long(2)});
given(methodInvocation.proceed()).willReturn("Hello!");
Log log = mock(Log.class);
given(log.isTraceEnabled()).willReturn(true);
CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log);
interceptor.setEnterMessage(new StringBuilder()
interceptor.setEnterMessage(new StringBuffer()
.append("Entering the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME)
.append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_NAME)
.append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS)
.append(") and arg types (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENT_TYPES)
.append(").").toString());
interceptor.setExitMessage(new StringBuilder()
interceptor.setExitMessage(new StringBuffer()
.append("Exiting the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME)
.append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_SHORT_NAME)
.append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,13 @@
package org.springframework.aop.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource;
@@ -46,3 +48,33 @@ public class ExposeInvocationInterceptorTests {
}
}
abstract class ExposedInvocationTestBean extends TestBean {
@Override
public String getName() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
return super.getName();
}
@Override
public void absquatulate() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
super.absquatulate();
}
protected abstract void assertions(MethodInvocation invocation);
}
class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean {
@Override
protected void assertions(MethodInvocation invocation) {
assertThat(invocation.getThis() == this).isTrue();
assertThat(ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass())).as("Invocation should be on ITestBean: " + invocation.getMethod()).isTrue();
}
}
@@ -1,40 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.testfixture.beans.TestBean;
abstract class ExposedInvocationTestBean extends TestBean {
@Override
public String getName() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
return super.getName();
}
@Override
public void absquatulate() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
super.absquatulate();
}
protected abstract void assertions(MethodInvocation invocation);
}
@@ -1,32 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.testfixture.beans.ITestBean;
import static org.assertj.core.api.Assertions.assertThat;
class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean {
@Override
protected void assertions(MethodInvocation invocation) {
assertThat(invocation.getThis() == this).isTrue();
assertThat(ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass())).as("Invocation should be on ITestBean: " + invocation.getMethod()).isTrue();
}
}
@@ -49,7 +49,7 @@ public abstract class AbstractRegexpMethodPointcutTests {
@Test
public void testSerializationWithNoPatternSupplied() throws Exception {
rpc = SerializationTestUtils.serializeAndDeserialize(rpc);
rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc);
noPatternSuppliedTests(rpc);
}
@@ -63,7 +63,7 @@ public abstract class AbstractRegexpMethodPointcutTests {
public void testExactMatch() throws Exception {
rpc.setPattern("java.lang.Object.hashCode");
exactMatchTests(rpc);
rpc = SerializationTestUtils.serializeAndDeserialize(rpc);
rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc);
exactMatchTests(rpc);
}
@@ -239,7 +239,7 @@ public class DelegatingIntroductionInterceptorTests {
assertThat(p.getName()).isEqualTo(name);
assertThat(((TimeStamped) p).getTimeStamp()).isEqualTo(time);
Person p1 = SerializationTestUtils.serializeAndDeserialize(p);
Person p1 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertThat(p1.getName()).isEqualTo(name);
assertThat(((TimeStamped) p1).getTimeStamp()).isEqualTo(time);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -109,7 +109,7 @@ public class NameMatchMethodPointcutTests {
public void testSerializable() throws Throwable {
testSets();
// Count is now 2
Person p2 = SerializationTestUtils.serializeAndDeserialize(proxied);
Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(proxied);
NopInterceptor nop2 = (NopInterceptor) ((Advised) p2).getAdvisors()[0].getAdvice();
p2.getName();
assertThat(nop2.getCount()).isEqualTo(2);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -109,7 +109,7 @@ public class RegexpMethodPointcutAdvisorIntegrationTests {
assertThat(nop.getCount()).isEqualTo(2);
// Serialize and continue...
p = SerializationTestUtils.serializeAndDeserialize(p);
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertThat(p.getAge()).isEqualTo(newAge);
// Remembers count, but we need to get a new reference to nop...
nop = (SerializableNopInterceptor) ((Advised) p).getAdvisors()[0].getAdvice();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -134,7 +134,7 @@ public class HotSwappableTargetSourceTests {
hts.swap(sp2);
assertThat(p.getName()).isEqualTo(sp2.getName());
p = SerializationTestUtils.serializeAndDeserialize(p);
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
// We need to get a reference to the client-side targetsource
hts = (HotSwappableTargetSource) ((Advised) p).getTargetSource();
assertThat(p.getName()).isEqualTo(sp2.getName());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ public class PrototypeBasedTargetSourceTests {
bf.registerBeanDefinition("person", bd);
TestTargetSource cpts = (TestTargetSource) bf.getBean("ts");
TargetSource serialized = SerializationTestUtils.serializeAndDeserialize(cpts);
TargetSource serialized = (TargetSource) SerializationTestUtils.serializeAndDeserialize(cpts);
boolean condition = serialized instanceof SingletonTargetSource;
assertThat(condition).as("Changed to SingletonTargetSource on deserialization").isTrue();
SingletonTargetSource sts = (SingletonTargetSource) serialized;
@@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.testfixture.EnabledForTestGroups;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
import static org.springframework.core.testfixture.TestGroup.PERFORMANCE;
/**
* @author Rob Harrop
@@ -77,7 +77,7 @@ public class RefreshableTargetSourceTests {
}
@Test
@EnabledForTestGroups(LONG_RUNNING)
@EnabledForTestGroups(PERFORMANCE)
public void testRefreshOverTime() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(100);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ import org.springframework.context.annotation.Role;
* @see org.springframework.cache.annotation.EnableCaching
* @see org.springframework.cache.annotation.CachingConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ package org.springframework.cache.aspectj;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.config.CacheManagementConfigUtils;
import org.springframework.cache.jcache.config.AbstractJCacheConfiguration;
import org.springframework.cache.jcache.interceptor.JCacheOperationSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
@@ -34,15 +33,15 @@ import org.springframework.context.annotation.Role;
* @see org.springframework.cache.annotation.EnableCaching
* @see org.springframework.cache.annotation.CachingConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJJCacheConfiguration extends AbstractJCacheConfiguration {
@Bean(name = CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JCacheCacheAspect cacheAspect(JCacheOperationSource jCacheOperationSource) {
public JCacheCacheAspect cacheAspect() {
JCacheCacheAspect cacheAspect = JCacheCacheAspect.aspectOf();
cacheAspect.setCacheOperationSource(jCacheOperationSource);
cacheAspect.setCacheOperationSource(cacheOperationSource());
return cacheAspect;
}
@@ -36,7 +36,7 @@ import org.springframework.scheduling.config.TaskManagementConfigUtils;
* @see org.springframework.scheduling.annotation.AsyncConfigurationSelector
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
*/
@Configuration(proxyBeanMethods = false)
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,7 +59,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
@Override
public void destroy() {
clearTransactionManagerCache(); // An aspect is basically a singleton
// An aspect is basically a singleton -> cleanup on destruction
clearTransactionManagerCache();
}
@SuppressAjWarnings("adviceDidNotMatch")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -412,15 +412,15 @@ public abstract class AbstractCacheAnnotationTests {
}
protected void testConditionalCacheUpdate(CacheableService<?> service) {
int one = 1;
int three = 3;
Integer one = 1;
Integer three = 3;
Cache cache = this.cm.getCache("testCache");
assertThat(Integer.parseInt(service.conditionalUpdate(one).toString())).isEqualTo(one);
assertThat((int) Integer.valueOf(service.conditionalUpdate(one).toString())).isEqualTo((int) one);
assertThat(cache.get(one)).isNull();
assertThat(Integer.parseInt(service.conditionalUpdate(three).toString())).isEqualTo(three);
assertThat(Integer.parseInt(cache.get(three).get().toString())).isEqualTo(three);
assertThat((int) Integer.valueOf(service.conditionalUpdate(three).toString())).isEqualTo((int) three);
assertThat((int) Integer.valueOf(cache.get(three).get().toString())).isEqualTo((int) three);
}
protected void testMultiCache(CacheableService<?> service) {
@@ -38,7 +38,7 @@ import org.springframework.util.ReflectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
import static org.springframework.core.testfixture.TestGroup.PERFORMANCE;
/**
* Unit tests for {@link AnnotationAsyncExecutionAspect}.
@@ -46,7 +46,7 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
* @author Ramnivas Laddad
* @author Stephane Nicoll
*/
@EnabledForTestGroups(LONG_RUNNING)
@EnabledForTestGroups(PERFORMANCE)
public class AnnotationAsyncExecutionAspectTests {
private static final long WAIT_TIME = 1000; //milliseconds
+4 -8
View File
@@ -30,11 +30,7 @@ compileGroovy {
// This module also builds Kotlin code and the compileKotlin task naturally depends on
// compileJava. We need to redefine dependencies to break task cycles.
tasks.named('compileGroovy') {
// Groovy only needs the declared dependencies (and not the result of Java compilation)
classpath = sourceSets.main.compileClasspath
}
tasks.named('compileKotlin') {
// Kotlin also depends on the result of Groovy compilation
classpath += files(sourceSets.main.groovy.classesDirectory)
}
def deps = compileGroovy.taskDependencies.immutableValues + compileGroovy.taskDependencies.mutableValues
compileGroovy.dependsOn = deps - "compileJava"
compileKotlin.dependsOn(compileGroovy)
compileKotlin.classpath += files(compileGroovy.destinationDir)
@@ -1,101 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
/**
* Benchmark for {@link AbstractPropertyAccessor} use on beans.
*
* @author Brian Clozel
*/
@BenchmarkMode(Mode.Throughput)
public class AbstractPropertyAccessorBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
@Param({"DirectFieldAccessor", "BeanWrapper"})
public String accessor;
@Param({"none", "stringTrimmer", "numberOnPath", "numberOnNestedPath", "numberOnType"})
public String customEditor;
public int[] input;
public PrimitiveArrayBean target;
public AbstractPropertyAccessor propertyAccessor;
@Setup
public void setup() {
this.target = new PrimitiveArrayBean();
this.input = new int[1024];
if (this.accessor.equals("DirectFieldAccessor")) {
this.propertyAccessor = new DirectFieldAccessor(this.target);
}
else {
this.propertyAccessor = new BeanWrapperImpl(this.target);
}
switch (this.customEditor) {
case "stringTrimmer":
this.propertyAccessor.registerCustomEditor(String.class, new StringTrimmerEditor(false));
break;
case "numberOnPath":
this.propertyAccessor.registerCustomEditor(int.class, "array.somePath", new CustomNumberEditor(Integer.class, false));
break;
case "numberOnNestedPath":
this.propertyAccessor.registerCustomEditor(int.class, "array[0].somePath", new CustomNumberEditor(Integer.class, false));
break;
case "numberOnType":
this.propertyAccessor.registerCustomEditor(int.class, new CustomNumberEditor(Integer.class, false));
break;
}
}
}
@Benchmark
public PrimitiveArrayBean setPropertyValue(BenchmarkState state) {
state.propertyAccessor.setPropertyValue("array", state.input);
return state.target;
}
@SuppressWarnings("unused")
private static class PrimitiveArrayBean {
private int[] array;
public int[] getArray() {
return this.array;
}
public void setArray(int[] array) {
this.array = array;
}
}
}
@@ -1,83 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource;
/**
* Benchmark for creating prototype beans in a concurrent fashion.
* This benchmark requires to customize the number of worker threads {@code -t <int>} on the
* CLI when running this particular benchmark to leverage concurrency.
*
* @author Brian Clozel
*/
@BenchmarkMode(Mode.Throughput)
public class ConcurrentBeanFactoryBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
public DefaultListableBeanFactory factory;
@Setup
public void setup() {
this.factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(this.factory).loadBeanDefinitions(
qualifiedResource(ConcurrentBeanFactoryBenchmark.class, "context.xml"));
this.factory.addPropertyEditorRegistrar(
registry -> registry.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy/MM/dd"), false)));
}
}
@Benchmark
public void concurrentBeanCreation(BenchmarkState state, Blackhole bh) {
bh.consume(state.factory.getBean("bean1"));
bh.consume(state.factory.getBean("bean2"));
}
public static class ConcurrentBean {
private Date date;
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
}
}
@@ -1,142 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.LifecycleBean;
import org.springframework.beans.testfixture.beans.TestBean;
/**
* Benchmark for retrieving various bean types from the {@link DefaultListableBeanFactory}.
*
* @author Brian Clozel
*/
@BenchmarkMode(Mode.Throughput)
public class DefaultListableBeanFactoryBenchmark {
public static class Shared {
public DefaultListableBeanFactory beanFactory;
}
@State(Scope.Benchmark)
public static class PrototypeCreationState extends Shared {
@Param({"simple", "dependencyCheck", "constructor", "constructorArgument", "properties", "resolvedProperties"})
public String mode;
@Setup
public void setup() {
this.beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
switch (this.mode) {
case "simple":
break;
case "dependencyCheck":
rbd = new RootBeanDefinition(LifecycleBean.class);
rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
this.beanFactory.addBeanPostProcessor(new LifecycleBean.PostProcessor());
break;
case "constructor":
rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen");
rbd.getConstructorArgumentValues().addGenericArgumentValue("99");
break;
case "constructorArgument":
rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse"));
this.beanFactory.registerBeanDefinition("test", rbd);
this.beanFactory.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
break;
case "properties":
rbd.getPropertyValues().add("name", "juergen");
rbd.getPropertyValues().add("age", "99");
break;
case "resolvedProperties":
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse"));
this.beanFactory.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
break;
}
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
this.beanFactory.registerBeanDefinition("test", rbd);
this.beanFactory.freezeConfiguration();
}
}
@Benchmark
public Object prototypeCreation(PrototypeCreationState state) {
return state.beanFactory.getBean("test");
}
@State(Scope.Benchmark)
public static class SingletonLookupState extends Shared {
@Setup
public void setup() {
this.beanFactory = new DefaultListableBeanFactory();
this.beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
this.beanFactory.freezeConfiguration();
}
}
@Benchmark
public Object singletLookup(SingletonLookupState state) {
return state.beanFactory.getBean("test");
}
@Benchmark
public Object singletLookupByType(SingletonLookupState state) {
return state.beanFactory.getBean(TestBean.class);
}
@State(Scope.Benchmark)
public static class SingletonLookupManyBeansState extends Shared {
@Setup
public void setup() {
this.beanFactory = new DefaultListableBeanFactory();
this.beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
for (int i = 0; i < 1000; i++) {
this.beanFactory.registerBeanDefinition("a" + i, new RootBeanDefinition(A.class));
}
this.beanFactory.freezeConfiguration();
}
}
// See SPR-6870
@Benchmark
public Object singletLookupByTypeManyBeans(SingletonLookupState state) {
return state.beanFactory.getBean(B.class);
}
static class A {
}
static class B {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 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.
@@ -305,8 +305,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(tokens.actualName, newArray);
propValue = getPropertyValue(tokens.actualName);
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
String propName = tokens.canonicalName.substring(0, lastKeyIndex);
setPropertyValue(propName, newArray);
propValue = getPropertyValue(propName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
@@ -16,7 +16,6 @@
package org.springframework.beans;
import java.beans.ConstructorProperties;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.Constructor;
@@ -44,15 +43,11 @@ import kotlin.reflect.jvm.ReflectJvmMapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -77,9 +72,6 @@ public abstract class BeanUtils {
private static final Log logger = LogFactory.getLog(BeanUtils.class);
private static final ParameterNameDiscoverer parameterNameDiscoverer =
new DefaultParameterNameDiscoverer();
private static final Set<Class<?>> unknownEditorTypes =
Collections.newSetFromMap(new ConcurrentReferenceHashMap<>(64));
@@ -226,35 +218,6 @@ public abstract class BeanUtils {
}
}
/**
* Return a resolvable constructor for the provided class, either a primary constructor
* or single public constructor or simply a default constructor. Callers have to be
* prepared to resolve arguments for the returned constructor's parameters, if any.
* @param clazz the class to check
* @since 5.3
* @see #findPrimaryConstructor
*/
@SuppressWarnings("unchecked")
public static <T> Constructor<T> getResolvableConstructor(Class<T> clazz) {
Constructor<T> ctor = findPrimaryConstructor(clazz);
if (ctor == null) {
Constructor<?>[] ctors = clazz.getConstructors();
if (ctors.length == 1) {
ctor = (Constructor<T>) ctors[0];
}
else {
try {
ctor = clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("No primary or single public constructor found for " +
clazz + " - and no default constructor found either");
}
}
}
return ctor;
}
/**
* Return the primary constructor of the provided class. For Kotlin classes, this
* returns the Java constructor corresponding to the Kotlin primary constructor
@@ -543,6 +506,7 @@ public abstract class BeanUtils {
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
return null;
}
ClassLoader cl = targetType.getClassLoader();
if (cl == null) {
try {
@@ -559,28 +523,34 @@ public abstract class BeanUtils {
return null;
}
}
String targetTypeName = targetType.getName();
String editorName = targetTypeName + "Editor";
try {
Class<?> editorClass = cl.loadClass(editorName);
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
if (logger.isInfoEnabled()) {
logger.info("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
if (editorClass != null) {
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
if (logger.isInfoEnabled()) {
logger.info("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
}
unknownEditorTypes.add(targetType);
return null;
}
unknownEditorTypes.add(targetType);
return null;
return (PropertyEditor) instantiateClass(editorClass);
}
return (PropertyEditor) instantiateClass(editorClass);
// Misbehaving ClassLoader returned null instead of ClassNotFoundException
// - fall back to unknown editor type registration below
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("No property editor [" + editorName + "] found for type " +
targetTypeName + " according to 'Editor' suffix convention");
}
unknownEditorTypes.add(targetType);
return null;
// Ignore - fall back to unknown editor type registration below
}
if (logger.isTraceEnabled()) {
logger.trace("No property editor [" + editorName + "] found for type " +
targetTypeName + " according to 'Editor' suffix convention");
}
unknownEditorTypes.add(targetType);
return null;
}
/**
@@ -619,26 +589,6 @@ public abstract class BeanUtils {
}
}
/**
* Determine required parameter names for the given constructor,
* considering the JavaBeans {@link ConstructorProperties} annotation
* as well as Spring's {@link DefaultParameterNameDiscoverer}.
* @param ctor the constructor to find parameter names for
* @return the parameter names (matching the constructor's parameter count)
* @throws IllegalStateException if the parameter names are not resolvable
* @since 5.3
* @see ConstructorProperties
* @see DefaultParameterNameDiscoverer
*/
public static String[] getParameterNames(Constructor<?> ctor) {
ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
Assert.state(paramNames.length == ctor.getParameterCount(),
() -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);
return paramNames;
}
/**
* Check if the given type represents a "simple" property: a simple value
* type or an array of simple value types.
@@ -737,8 +687,6 @@ public abstract class BeanUtils {
* <p>Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
* <p>As of Spring Framework 5.3, this method honors generic type information
* when matching properties in the source and target objects.
* @param source the source bean
* @param target the target bean
* @param editable the class (or interface) to restrict property setting to
@@ -769,24 +717,21 @@ public abstract class BeanUtils {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null) {
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
if (targetResolvableType.isAssignableFrom(sourceResolvableType)) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
if (readMethod != null &&
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
@@ -844,7 +789,7 @@ public abstract class BeanUtils {
}
List<KParameter> parameters = kotlinConstructor.getParameters();
Map<KParameter, Object> argParameters = CollectionUtils.newHashMap(parameters.size());
Map<KParameter, Object> argParameters = new HashMap<>(parameters.size());
Assert.isTrue(args.length <= parameters.size(),
"Number of provided arguments should be less of equals than number of constructor parameters");
for (int i = 0 ; i < args.length ; i++) {
@@ -20,10 +20,7 @@ import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -281,8 +278,6 @@ public final class CachedIntrospectionResults {
}
this.propertyDescriptors = new LinkedHashMap<>();
Set<String> readMethodNames = new HashSet<>();
// This call is slow so we do it once.
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
@@ -299,25 +294,16 @@ public final class CachedIntrospectionResults {
}
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptors.put(pd.getName(), pd);
Method readMethod = pd.getReadMethod();
if (readMethod != null) {
readMethodNames.add(readMethod.getName());
}
}
// Explicitly check implemented interfaces for setter/getter methods as well,
// in particular for Java 8 default methods...
Class<?> currClass = beanClass;
while (currClass != null && currClass != Object.class) {
introspectInterfaces(beanClass, currClass, readMethodNames);
introspectInterfaces(beanClass, currClass);
currClass = currClass.getSuperclass();
}
// Check for record-style accessors without prefix: e.g. "lastName()"
// - accessor method directly referring to instance field of same name
// - same convention for component accessors of Java 15 record classes
introspectPlainAccessors(beanClass, readMethodNames);
this.typeDescriptorCache = new ConcurrentReferenceHashMap<>();
}
catch (IntrospectionException ex) {
@@ -325,9 +311,7 @@ public final class CachedIntrospectionResults {
}
}
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass, Set<String> readMethodNames)
throws IntrospectionException {
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws IntrospectionException {
for (Class<?> ifc : currClass.getInterfaces()) {
if (!ClassUtils.isJavaLanguageInterface(ifc)) {
for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
@@ -338,45 +322,13 @@ public final class CachedIntrospectionResults {
// against a declared read method, so we prefer read method descriptors here.
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptors.put(pd.getName(), pd);
Method readMethod = pd.getReadMethod();
if (readMethod != null) {
readMethodNames.add(readMethod.getName());
}
}
}
introspectInterfaces(ifc, ifc, readMethodNames);
introspectInterfaces(ifc, ifc);
}
}
}
private void introspectPlainAccessors(Class<?> beanClass, Set<String> readMethodNames)
throws IntrospectionException {
for (Method method : beanClass.getMethods()) {
if (!this.propertyDescriptors.containsKey(method.getName()) &&
!readMethodNames.contains((method.getName())) && isPlainAccessor(method)) {
this.propertyDescriptors.put(method.getName(),
new GenericTypeAwarePropertyDescriptor(beanClass, method.getName(), method, null, null));
readMethodNames.add(method.getName());
}
}
}
private boolean isPlainAccessor(Method method) {
if (method.getParameterCount() > 0 || method.getReturnType() == void.class ||
method.getDeclaringClass() == Object.class || Modifier.isStatic(method.getModifiers())) {
return false;
}
try {
// Accessor method referring to instance field of same name?
method.getDeclaringClass().getDeclaredField(method.getName());
return true;
}
catch (Exception ex) {
return false;
}
}
BeanInfo getBeanInfo() {
return this.beanInfo;

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