Compare commits

...

192 Commits

Author SHA1 Message Date
Spring Buildmaster 4ed9cc54fe Release version 5.1.16.RELEASE 2020-06-09 08:04:41 +00:00
Juergen Hoeller 4173ceefa5 Upgrade to Reactor Californium-SR19
Closes gh-25211
2020-06-08 23:35:40 +02:00
Juergen Hoeller 586235e9e4 Upgrade to Tomcat 9.0.36 2020-06-08 20:09:33 +02:00
Juergen Hoeller 4f81ab7e14 Polishing 2020-06-08 20:09:12 +02:00
Juergen Hoeller 7281d44178 Polishing 2020-06-06 19:14:34 +02:00
Juergen Hoeller f965c2f5af Avoid unnecessary creation of not-found entity in ResponseEntity#of
Closes gh-25183
2020-06-06 19:14:26 +02:00
Juergen Hoeller cf5bbce3f8 Avoid unnecessary copy of cookies map in DefaultWebClientBuilder
See gh-25034
2020-06-06 19:14:19 +02:00
Juergen Hoeller a80e36fd9f Upgrade to Checkstyle 8.33 2020-06-06 16:57:41 +02:00
Juergen Hoeller 840ae05942 Polishing 2020-06-06 16:57:28 +02:00
Juergen Hoeller b5928977d1 Extend readOnlyWebSocketHttpHeaders deprecation to 5.1.16 2020-06-06 16:57:17 +02:00
Juergen Hoeller 5cb950db3b Support for shared GroovyClassLoader in GroovyScriptFactory
Closes gh-25177
2020-06-06 16:56:47 +02:00
Juergen Hoeller 4b7890315f Restore original readOnlyHttpHeaders signature for binary compatibility
Closes gh-25034
2020-06-06 16:56:29 +02:00
Arjen Poutsma f81b1de2c0 Respect MimeType charset in Jackson codecs
Before this commit, Jackson2CodecSupport and subclasses
did not check media type encoding in the supportsMimeType
method (called from canEncode/canDecode).
As a result, the encoder reported that it can write
(for instance) "application/json;charset=ISO-8859-1", but in practice
wrote the default charset (UTF-8).

This commit fixes that bug.

Closes: gh-25076
2020-06-05 11:54:18 +02:00
Arjen Poutsma d9c98801bc Respect MediaType charset in Jackson converters
Before this commit, AbstractJackson2HttpMessageConverter and subclasses
did not check media type encoding in the canRead and canWrite
methods. As a result, the converter reported that it can write
(for instance) "application/json;charset=ISO-8859-1", but in practice
wrote the default charset (UTF-8).

This commit fixes that bug.

See: gh-25076
2020-06-05 11:14:43 +02:00
Sam Brannen 70a2219fac Configure Gradle wrapper validation action
This commit configures the Gradle Wrapper Validation Action
for GitHub actions.

See: https://github.com/gradle/wrapper-validation-action

Closes gh-25175
2020-06-02 14:45:04 +02:00
Juergen Hoeller 083dd0e19d Polishing 2020-05-29 16:31:11 +02:00
Juergen Hoeller e6553939b2 Consistent MultiValueMap behavior for empty list values
This commit extracts MultiValueMapAdapter from CollectionUtils and reuses its implementation as base class of LinkedMultiValueMap.

Closes gh-25140
2020-05-29 16:30:51 +02:00
Sam Brannen 008d011d37 Make use of custom types configurable in YamlProcessor
Prior to this commit, there was no easy way to restrict what types could
be loaded from a YAML document in subclasses of YamlProcessor such as
YamlPropertiesFactoryBean and YamlMapFactoryBean.

This commit introduces a setSupportedTypes(Class<?>...) method in
YamlProcessor in order to address this. If no supported types are
configured, all types encountered in YAML documents will be supported.
If an unsupported type is encountered, an IllegalStateException will be
thrown when the corresponding YAML node is processed.

Closes gh-25152
2020-05-29 14:03:51 +02:00
Sam Brannen 16ab43d957 Polish contribution
See gh-25149
2020-05-28 15:26:50 +02:00
dlsrb6342 6c5129b829 Fix BaseCodecConfigurer clone bug
Prior to this commit, ExchangeStrategies custom codec's reader and
writer were not registered due to a bug in BaseCodecConfigurer.

This commit fixes this by correcting the implementation of the
DefaultCustomCodecs constructor used within BaseCodecConfigurer.

Closes gh-25149
2020-05-28 15:06:34 +02:00
Rossen Stoyanchev e25e6a68cf Fix race condition in WriteResultPublisher
between subscription and error from the Publish

Closes gh-25096
2020-05-28 06:53:30 +01:00
Juergen Hoeller bb96bd4f48 Polishing 2020-05-26 23:55:56 +02:00
Juergen Hoeller 370bf184af WebSphereUowTransactionManager sets timeout for actual transaction only
Closes gh-25132
2020-05-26 23:55:29 +02:00
Juergen Hoeller cbcd8fdeba Upgrade to Jetty 9.4.29 2020-05-22 17:35:15 +02:00
Juergen Hoeller 9bb534e74c Polishing 2020-05-22 17:34:55 +02:00
Juergen Hoeller ec915bfd5d Avoid ClassCastException on IllegalArgumentException from sync invocation
Closes gh-25110
2020-05-22 17:18:56 +02:00
Sam Brannen 5c04c96d0e Honor attributes configured in ServerRequest.from() builder
Prior to this commit, if attributes were configured in the builder
returned by `ServerRequest.from(...)`, those attributes were not
available in the `ServerRequest` built by the builder. In addition, any
attributes in the original `ServerRequest` supplied to
`ServerRequest.from(...)` were also ignored.

This commit addresses this issue by ensuring that the attributes
configured via DefaultServerRequestBuilder are used as the attributes
in the resulting `ServerRequest`.

This commit also polishes the Javadoc in `ServerRequest` and
`ClientResponse` and avoids the use of lambda expressions in the
constructors for `DefaultServerRequestBuilder` and
`DefaultClientResponseBuilder`.

Closes gh-25106
2020-05-21 10:09:16 +02:00
Juergen Hoeller 7d39fbea16 Upgrade to Checkstyle 8.32, Tomcat 9.0.35, Netty 4.1.50, Hibernate ORM 5.3.17, Hibernate Validator 6.0.20 2020-05-18 15:16:11 +02:00
Juergen Hoeller 4ad7deda4c Polishing 2020-05-18 15:15:46 +02:00
Juergen Hoeller 4ec02a7e53 Consistent not-null assertions for configured interceptors
Closes gh-25089
2020-05-18 14:54:01 +02:00
Juergen Hoeller 2785ef0887 Avoid full synchronization in refreshable getBeanFactory() implementation
Closes gh-25081
2020-05-18 14:37:12 +02:00
Rossen Stoyanchev b22e670668 HttpHeaders#equals handles wrapping correctly
Closes gh-25034
2020-05-08 09:47:10 +01:00
Sam Brannen 436e9d8cdc Use SingletonSupplier for XStream instance in XStreamMarshaller
Closes gh-25017
2020-05-07 12:51:29 +02:00
Sam Brannen f474595dee Fix concurrency issues in XStreamMarshaller
Prior to this commit, if an instance of XStreamMarshaller was used
concurrently from multiple threads without having first invoked the
afterPropertiesSet() method, the private `xstream` field could be
initialized multiple times resulting in a ConcurrentModificationException
in XStream's internal DefaultConverterLookup.

This commit fixes these concurrency issues by making the `xstream` field
volatile and by implementing a double-checked locking algorithm in
getXStream() to avoid concurrent instance creation.

Closes gh-25017
2020-05-07 12:50:44 +02:00
Rossen Stoyanchev 42f60fe490 Fix race condition in WriteResultPublisher
Backport of c35b3e5c82

Closes gh-24989
2020-05-04 11:13:06 +01:00
Rossen Stoyanchev ce76a9b5de Error handling improvement in AbstractSockJsSession
Backport of e17736dd0a.

Closes gh-24986
2020-05-04 11:12:08 +01:00
Spring Buildmaster 6d26b962a9 Next Development Version 2020-04-28 07:29:39 +00:00
Juergen Hoeller a4cc16051c Polishing 2020-04-27 14:29:56 +02:00
Juergen Hoeller c8b49346b1 Store source in index-derived ScannedGenericBeanDefinition as well
Includes consistent constructor-level storage of derived resource in ScannedGenericBeanDefinition and ConfigurationClassBeanDefinition.

See gh-24978
2020-04-27 14:29:41 +02:00
Rossen Stoyanchev 34b9ca310d Ugrade to Reactor Californium-SR18
Closes gh-24893
2020-04-27 13:07:18 +01:00
Juergen Hoeller ea7b0103c5 Upgrade to Tomcat 9.0.34, Jetty 9.4.28, Netty 4.1.49, BeanShell 2.0b6, Checkstyle 8.31 2020-04-25 17:15:03 +02:00
Juergen Hoeller e3175a2dc9 Polishing 2020-04-25 17:13:44 +02:00
Juergen Hoeller 91316dc11b Caching of autowire candidate metadata for injection point matching
Closes gh-24904
2020-04-25 17:01:22 +02:00
Juergen Hoeller ac8d1df3ab Enforce limit for storing suppressed exceptions
Closes gh-24902
2020-04-25 17:01:09 +02:00
Sébastien Deleuze f023df703a Remove potentially confusing kotlin-reflect related log message
Closes gh-24939
2020-04-20 10:39:57 +02:00
Sam Brannen 9ab7cde00e Retain brackets for IPV6 address in MockHttpServletRequest
According to the Javadoc for ServletRequest's getServerName() method,
when the `Host` header is set, the server name is "the value of the
part before ':' in the Host header value ...". For a value representing
an IPV6 address such as `[::ffff:abcd:abcd]`, the enclosing square
brackets should therefore not be stripped from the enclosed IPV6
address.

However, the changes made in conjunction with gh-16704 introduced a
regression in Spring Framework 4.1 for the getServerName() method in
MockHttpServletRequest by stripping the enclosing brackets from the
IPV6 address in the `Host` header. Similarly, the changes made in
conjunction with gh-20686 introduced a regression in Spring Framework
4.3.13 and 5.0.2 in the getRequestURL() method in
MockHttpServletRequest by delegating to the getServerName() method
which strips the enclosing brackets.

This commit fixes the implementation of getServerName() so that the
enclosing brackets are no longer stripped from an IPV6 address in the
`Host` header. The implementation of getRequestURL() is therefore also
fixed.

In addition, in order to avoid a NullPointerException, the
implementations of getServerName() and getServerPort() now assert that
an IPV6 address present in the `Host` header correctly contains an
opening and closing bracket and throw an IllegalStateException if that
is not the case.

Closes gh-24916
2020-04-17 16:22:51 +02:00
Stephane Nicoll fad9b509ab Polish 2020-04-10 17:19:40 +02:00
Stephane Nicoll 5ddbefecea Start building against Reactor Californium-SR18 snapshots
See gh-24893
2020-04-10 17:18:51 +02:00
Juergen Hoeller a4bba6aff2 Honor overridden AcceptHeaderLocaleContextResolver.getDefaultLocale()
Closes gh-24871
2020-04-09 12:03:29 +02:00
Juergen Hoeller 906583c40a Upgrade to Tomcat 9.0.33, Hibernate ORM 5.3.16, Hibernate Validator 6.0.19 2020-04-03 21:50:28 +02:00
Juergen Hoeller 3689b3fdd5 Recursively copy directory with symbolic link
Closes gh-24823
2020-04-03 21:46:07 +02:00
Juergen Hoeller 4a5bac97b5 Close-suppressing Connection proxy exposes target isClosed() state
Closes gh-24853
2020-04-03 21:43:25 +02:00
Juergen Hoeller 45a270b71f Clear by-type cache in case of no pre-existing bean definition as well
Closes gh-24852
2020-04-03 21:43:18 +02:00
Rossen Stoyanchev ef013f7158 UriComponentsBuilder.cloneBuilder copies uriVariables
Closes gh-24772
2020-03-26 16:41:21 +00:00
Juergen Hoeller 818d18aa09 Expose context class for interface-based CGLIB proxies as well
Closes gh-24657
2020-03-26 17:31:31 +01:00
Juergen Hoeller 4715ad242e Upgrade to Netty 4.1.48 and Checkstyle 8.30 2020-03-24 01:00:41 +01:00
Juergen Hoeller e51f660286 Polishing 2020-03-24 00:56:36 +01:00
Juergen Hoeller 9f71c98871 Expose parameter annotations from interfaces across entire class hierarchy
Closes gh-24127
2020-03-24 00:53:40 +01:00
Juergen Hoeller dbb09334f3 Thread-safe access to WebSocketServerFactory and WebSocketExtensions
Closes gh-24745
2020-03-24 00:53:32 +01:00
Juergen Hoeller 5953d99d1c Mark MediaTypeNotSupportedStatusException as deprecated
Closes gh-24743
2020-03-24 00:25:53 +01:00
Rossen Stoyanchev c9be4f6874 Upgrade to Reactor Californium-SR17
Closes gh-24726
2020-03-23 15:47:27 +00:00
Rossen Stoyanchev fbc63b0e32 Switch to Reactor Californium snapshots
See gh-24726
2020-03-18 17:30:27 +00:00
Juergen Hoeller 5f7df0d14f Latest dependency updates (RxJava 2.2.19, Undertow 2.0.30, Netty 4.1.47, Jetty 9.4.27, POI 4.1.2, OkHttp 3.14.7) 2020-03-13 23:42:30 +01:00
Juergen Hoeller ee832206dc Polishing 2020-03-13 23:41:42 +01:00
Juergen Hoeller 1e295c7bbb Create ScannedGenericBeanDefinitions for index-derived components as well
Closes gh-24638
2020-03-13 23:41:31 +01:00
Arjen Poutsma 4fbba931a5 Improve RouterFunction composition
This commit changes the way two RouterFunctions are composed in
WebFlux.fn. Prior to this commit, two were composed with
`switchIfEmpty()`, switching from the first to the second route if the
first did not provide an element.
After this commit, two router functions are compose using `concat`,
which results in a smaller stack trace.

See gh-24652
2020-03-13 16:26:15 +01:00
Spring Buildmaster 86f19f6cb6 Next Development Version 2020-02-25 16:23:19 +00:00
Juergen Hoeller df60919bb0 Polishing 2020-02-25 15:32:05 +01:00
Juergen Hoeller 2f1f36eeda Upgrade to Groovy 2.5.9, RxJava 2.2.18, Tomcat 9.0.31, Jetty 9.4.26, Netty 4.1.45, Checkstyle 8.29 2020-02-24 19:44:25 +01:00
Juergen Hoeller 1c0a4f8d78 Polishing 2020-02-24 19:34:15 +01:00
Juergen Hoeller cc376ac5ed Clarify setCacheMillis/setCacheSeconds vs java.util.ResourceBundle
Closes gh-24563
2020-02-24 19:10:25 +01:00
Rossen Stoyanchev 10c9d2fcec Upgrade to Reactor Calfiornium-SR16
Closes gh-24527
2020-02-24 14:57:34 +00:00
Arjen Poutsma 439ffe2e8a Convert non-UTF-8 JSON
Jackson's asynchronous parser does not support any encoding except UTF-8
(or ASCII). This commit converts non-UTF-8/ASCII encoded JSON to UTF-8.

Closes gh-24489
2020-02-20 11:21:00 +01:00
Rossen Stoyanchev 4e55262521 Upgrade to Reactor Californium snapshots
See gh-24527
2020-02-19 16:26:17 +00:00
Juergen Hoeller ebd2ec57fc Polishing 2020-02-12 17:58:26 +01:00
Rossen Stoyanchev f536819c5d Update advice on RestTemplate
Closes gh-24503
2020-02-12 17:19:57 +01:00
Juergen Hoeller af75c6db2f Consistent ROLE_INFRASTRUCTURE declarations for configuration classes
Closes gh-24509
2020-02-12 17:18:59 +01:00
Juergen Hoeller d12619cf1f Raise log level for exceptions from EntityManager close call
Closes gh-24501
2020-02-12 17:10:32 +01:00
Sam Brannen 4c1d227776 Polish documentation format
Closes gh-24462
2020-02-12 15:47:17 +01:00
Sam Brannen da02b7a141 Support SpEL compilation of interface methods again
Spring Framework 5.1.8 introduced a regression for the compilation of
SpEL expressions referencing a method declared in an interface. An
attempt to compile such an expression resulted in a
SpelEvaluationException caused by an IncompatibleClassChangeError.

This commit fixes this regression by adding explicit support in
ReflectivePropertyAccessor.OptimalPropertyAccessor.generateCode() for
methods declared in interfaces.

Closes gh-24357
2020-02-12 15:40:17 +01:00
Arjen Poutsma 17117bd21a Force TokenBuffer to use BigDecimal if necessary
This commit makes the Jackson2Tokenizer enable
TokenBuffer.forceUseOfBigDecimal if the element type given to the
Decoder is BigDecimal. Previous to this commit, values would be
converted to floats.

Closes gh-24479
2020-02-07 14:45:58 +01:00
Arjen Poutsma 0d7494ac52 Honour ObjectMapper feature in Jackson2Tokenizer
After this commit, Jackson2Tokenizer honours ObjectMapper's
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS feature when creating
TokenBuffers.

Closes gh-24479
2020-02-06 17:12:05 +01:00
Christoph Dreis a59a33846e Polish documentation format
See gh-24462
2020-01-31 08:57:30 +01:00
Juergen Hoeller 51b8ba334a Polishing 2020-01-28 21:40:16 +01:00
Juergen Hoeller abc2269d97 Use local LoggerContext in Log4jLog when static field not initialized yet
Closes gh-24440
2020-01-28 21:21:30 +01:00
Juergen Hoeller ff385aaf7b Add Informix to supported database products for procedure calls
Closes gh-24443
2020-01-28 21:20:46 +01:00
Juergen Hoeller 1b50ca6bd3 Solve ReflectPermission issue in sandbox security policy model for CGLIB
Closes gh-24420
2020-01-28 21:19:15 +01:00
Arjen Poutsma 6bae759349 Use Jackson SequenceWriter for streaming
Before this commit, the AbstractJackson2Encoder instantiated a
ObjectWriter per value. This is not an issue for single values or
non-streaming scenarios (which effectively are the same, because in the
latter values are collected into a list until offered to Jackson).
However, this does create a problem for SMILE, because it allows for
shared references that do not match up when writing each value with a
new ObjectWriter, resulting in errors parsing the result.

This commit uses Jackson's SequenceWriter for streaming scenarios,
allowing Jackson to reuse the same context for writing multiple values,
fixing the issue described above.

Closes gh-24198
2020-01-22 10:12:05 +01:00
Brian Clozel e1e8c165db Avoid setting special Content-* response headers for Tomcat
As of gh-21783, Spring WebFlux uses a `TomcatHeadersAdapter`
implementation to directly address the native headers used by the
server.

In the case of Tomcat, "Content-Length" and "Content-Type" headers are
processed separately and should not be added to the native headers map.

This commit improves the `HandlerAdapter` implementation for Tomcat and
removes those headers, if previously set in the map. The adapter
already has a section that handles the Tomcat-specific calls for such
headers.

Fixes gh-24387
2020-01-17 15:15:14 +01:00
Sam Brannen 6699833121 Introduce regression test for gh-24375 2020-01-16 16:34:21 +01:00
Sam Brannen 095acefd7e Include Objenesis NOTICE file contents in binary distributions
Closes gh-24326
2020-01-16 10:54:23 +01:00
Spring Buildmaster b62e066b7d Next Development Version 2020-01-14 07:37:59 +00:00
Rossen Stoyanchev 9969cb6d83 Improve limit handling in StringDecoder
The case of one data buffer containing multiple lines can could cause
a buffer leak due to a suspected issue in concatMapIterable. This
commit adds workarounds for that until the underlying issue is
addressed.

Closes gh-24346
2020-01-13 20:46:51 +00:00
Rossen Stoyanchev 04b3f5a247 Upgrade to Reactor Californium SR15
Closes gh-24345
2020-01-13 17:09:38 +00:00
Sam Brannen c91b47fded Document Objenesis license in license.txt
Closes gh-24340
2020-01-13 16:08:14 +01:00
Sam Brannen f2c364b491 Update ASM and CBLIB versions in license.txt 2020-01-13 13:22:19 +01:00
Juergen Hoeller 170adccf80 Upgrade to RxJava 2.2.17, OkHttp 3.14.6, Hibernate ORM 5.3.15 2020-01-13 10:58:51 +01:00
Brian Clozel 98390e1e5e Copy strategiesConfigurers when cloning WebClient.Builder
This commit fixes the missing `strategiesConfigurers` copy when the
`WebClient.Builder` is cloned.

Fixes gh-24330
See gh-24329
2020-01-10 16:08:04 +01:00
Juergen Hoeller 6df8c2678b Upgrade to SLF4J 1.7.30 and Checkstyle 8.28 2020-01-09 17:13:16 +01:00
Juergen Hoeller 7f49abb6d1 Upgrade to Netty 4.1.44, Jetty 9.4.25, Undertow 2.0.29, OkHttp 3.14.5 2020-01-09 16:17:33 +01:00
Juergen Hoeller b9bf56e41d Polishing 2020-01-09 16:16:36 +01:00
Juergen Hoeller d0e3e2acfc Thread-safe compiled expression evaluation in SpelExpression
Closes gh-24265
2020-01-09 16:16:01 +01:00
Rossen Stoyanchev 18d983c686 Multi-value headers in ResponseStatusException
Closes gh-24284
2020-01-06 22:05:29 +00:00
Rossen Stoyanchev d8abbc501e CorsInterceptor skips async dispatch
Closes gh-24223
2020-01-06 21:24:02 +00:00
Rossen Stoyanchev 6ce19ff861 Escape quotes in filename
Also sync up with master on refactorings in ContentDisposition and
ContentDispositionTests.

Closes gh-24224
2020-01-06 18:18:56 +00:00
Juergen Hoeller c8ef49cc8e Upgrade to RxJava 2.2.16 2019-12-16 17:06:08 +01:00
Juergen Hoeller f61983d908 Polishing 2019-12-16 17:05:48 +01:00
Juergen Hoeller 7615e0b036 Un-deprecate PathResource (for NIO Path resolution in createRelative)
Includes aligned createRelative signature and dedicated java.io.File test.

Closes gh-24211
2019-12-16 17:05:28 +01:00
Juergen Hoeller afe22b84c2 ConcurrentReferenceHashMap cache for getInterfaceMethodIfPossible results
Closes gh-24206
2019-12-16 16:55:10 +01:00
Rossen Stoyanchev 634aba4ab6 Fix cloning issue in CodecConfigurer for multipart writers
Backport of b23617637d

Closes gh-24194
2019-12-13 06:38:49 +00:00
Rossen Stoyanchev 26a2d3875f Expose ClientCodecConfigurer in WebClient.Builder
Using Consumer<ClientCodecConfigurer> instead of
Consumer<ExchangeStrategies> eliminates one level of nesting that is
also unnecessary since codecs are the only strategy at present.

Backport of dd9b6287b4

Closes gh-24201
2019-12-13 06:38:49 +00:00
Rossen Stoyanchev 802d083df7 Add register methods to CodecConfigurer.CustomCodecs
The new register methods replace the now deprecated
encoder, decoder, reader, and writer methods, and also offer a choice
to opt into default properties such maxInMemorySize, if configured.

Backport of 11e321b8e7

See gh-24201
2019-12-13 06:38:43 +00:00
Rossen Stoyanchev f5b43a264a CodecConfigurer implementation refactoring
Backport of 9d65830133

See gh-24201
2019-12-13 06:23:40 +00:00
Rossen Stoyanchev 59e4755562 Correct WebFlux docs on BindingResult with @RequestBody
Backport of 70a0c93d69

Closes gh-22997
2019-12-13 05:54:22 +00:00
Rossen Stoyanchev 2576aa4063 ContentDisposition trims charset in filename
Backport of c8bce9686f

Closes gh-24112
2019-12-13 05:46:09 +00:00
Juergen Hoeller 3fbe762832 Consistent use of annotation-api dependency instead of tomcat-embed-core 2019-12-12 17:12:27 +01:00
Juergen Hoeller 611bb0b92e Explicit test dependency on javax.annotation.Priority 2019-12-12 17:01:18 +01:00
Juergen Hoeller 32a8b9b25a Polishing 2019-12-12 16:48:25 +01:00
Juergen Hoeller 97cad6ca8e Upgrade to Tomcat 9.0.30 2019-12-12 16:48:11 +01:00
Juergen Hoeller 015f7d8ce1 Polishing 2019-12-11 17:13:02 +01:00
Juergen Hoeller da4e2710b4 Upgrade to Joda-Time 2.10.5 and Commons Pool 2.6.2 2019-12-10 00:38:21 +01:00
Juergen Hoeller a368040fd6 Polishing 2019-12-09 15:54:40 +01:00
Juergen Hoeller 5dbd3b0bbf Avoid ByteArrayOutputStream for source values without the need to be encoded
Closes gh-24154
2019-12-09 13:56:50 +01:00
Juergen Hoeller 197dbffe20 Support variable resolution of wildcard types
Includes cleanup of "varaible" typos in ResolvableTypeTests.

Closes gh-24150
2019-12-09 13:56:25 +01:00
Sam Brannen 5341e77796 Introduce regression tests for prototype/request-scoped @ControllerAdvice
See gh-24157
2019-12-07 19:02:06 +01:00
Sam Brannen f049a6ec16 Add integration test for gh-24110 2019-12-03 17:12:14 +01:00
Spring Buildmaster 7203da7133 Next Development Version 2019-12-03 08:06:03 +00:00
Brian Clozel a21df0cc6d Provide default codecs config callback to custom codecs
As a follow-up of gh-23961, this change provides a way for custom codecs
to align with the default codecs' behavior on common features like
buffer size limits and logging request details.

Closes gh-24119
Co-authored-by: Rossen Stoyanchev <rstoyanchev@pivotal.io>
2019-12-02 23:16:49 +01:00
Brian Clozel 83683a13bb Allow ExchangeStrategies customizations in WebClient
Backport of d4209392 and acfeb77d

Closes gh-23961
2019-12-02 17:10:29 +00:00
Juergen Hoeller 59165dd526 Upgrade to AspectJ 1.9.5 and Checkstyle 8.27 2019-12-02 13:10:07 +01:00
Brian Clozel 25554d0b21 Revert "Allow ExchangeStrategies customizations in WebClient"
This reverts commit 43e047c523.
2019-12-02 10:29:24 +01:00
Juergen Hoeller 4f86282b14 Polishing 2019-12-01 01:55:26 +01:00
Juergen Hoeller b3237f3eb6 Polishing 2019-12-01 00:41:53 +01:00
Juergen Hoeller fd68fb115d Backport of recent ExtendedBeanInfo refinements from master
Closes gh-24095
2019-12-01 00:40:57 +01:00
Brian Clozel 43e047c523 Allow ExchangeStrategies customizations in WebClient
Prior to this commit, developers could configure their WebClient to use
their custom `ExchangeStrategies`, by providing it in the
`WebClient.Builder` chain.
Once created, an `ExchangeStrategies` instance is not mutable, which
makes it hard for further customizations by other components. In the
case of the reported issue, other components would override the default
configuration for the codecs maxInMemorySize.

This commit makes the `ExchangeStrategies` mutable and uses that fact to
further customize them with a new `WebClient.Builder#exchangeStrategies`
`Consumer` variant. This commit is also deprecating those mutating
variants in favor of a new `WebClient.Builder#exchangeStrategies` that
takes a `ExchangeStrategies#Builder` directly and avoids mutation issues
altogether.

Closes gh-24106
2019-11-29 23:35:20 +01:00
Sam Brannen 7fdf775394 Test status quo for @Inherited annotations in AnnotationMetadata
See gh-24077
2019-11-28 18:19:44 +01:00
Sam Brannen 59084c6b73 Test status quo for AnnotatedTypeMetadata.getAnnotationAttributes()
See gh-24077
2019-11-28 13:46:35 +01:00
Stephane Nicoll 4fcc09a02c Upgrade to Reactor Californium-SR14
Closes gh-24038
2019-11-27 11:51:27 +01:00
Arjen Poutsma f5b082d3b3 Remove println 2019-11-25 18:27:13 +01:00
Arjen Poutsma c164759c41 Fix NullPointerException in Jackson2SmileDecoder
Fix uncommon case in Jackson2SmileDecoder, where a null token,
incicating a document separator in streaming mode, is followed by
NOT_AVAILABLE.

Closes gh-24009

(cherry picked from commit 5f3c7ca559)
2019-11-25 16:37:36 +01:00
Juergen Hoeller 2179b67706 Upgrade to Tomcat 9.0.29, Jetty 9.4.24, RxJava 2.2.15 2019-11-24 21:47:25 +01:00
Rossen Stoyanchev fbde98f36e Add missing verify() in Jackson2TokenizerTests
Closes gh-24056
2019-11-22 16:39:14 +00:00
Rossen Stoyanchev 529f8ba786 Extra isReady-onWritePossible after last write
Closes gh-24050
2019-11-22 15:58:25 +00:00
Juergen Hoeller f4676bb41c Restore short-circuiting in equals implementation
Closes gh-24048
2019-11-21 18:25:37 +01:00
Juergen Hoeller 262332a7c9 Upgrade to Jetty 9.4.23 and Woodstox 5.3 2019-11-21 13:48:55 +01:00
Juergen Hoeller 8b1709b8f3 Upgrade to Hibernate Validator 6.0.18 and Undertow 2.0.28 2019-11-20 17:45:18 +01:00
Juergen Hoeller aee33d8b4b Mark SqlRowSet accessor methods as nullable (for alignment with JDBC)
Closes gh-24042
2019-11-20 17:42:11 +01:00
Stephane Nicoll 83f03976ea Start building against Reactor Californium-SR14 snapshots
See gh-24038
2019-11-20 11:02:08 +01:00
Sam Brannen ffcd83e3a8 Ignore scoped proxy targets for @ControllerAdvice beans
Prior to this commit, methods in a @ControllerAdvice bean were
registered and invoked twice if the advice was a scoped bean (e.g.,
request or session scoped). In other words, both the proxy bean and the
target bean were wrapped in ControllerAdviceBean instances.

This commit fixes this bug by modifying the findAnnotatedBeans() method
in ControllerAdviceBean so that it filters out targets of scoped
proxies.

Closes gh-24017
2019-11-19 15:21:48 +01:00
Sam Brannen 9a522946a5 Backport tests for gh-23985 2019-11-19 15:21:48 +01:00
Juergen Hoeller 268d029584 Avoid substring allocation in StringUtils.replace
Closes gh-24023
2019-11-19 15:04:15 +01:00
Juergen Hoeller 85471d0587 Revise getElementTypeDescriptor javadoc (no IllegalStateException)
Closes gh-23996
2019-11-14 18:34:19 +01:00
Sam Brannen 96a1a0dec5 Convert InstantFormatterTests to JUnit 4
See gh-23895
2019-11-14 12:01:11 +01:00
Sam Brannen 40ac055d11 Polish contribution
See gh-23895
2019-11-14 12:01:11 +01:00
monosoul c9a6f4282a Inverse condition to fix ISO-formatted Instant parsing
Prior to this commit, InstantFormatter was able to properly serialize
an Instant that is far in the future (or in the past), but it could not
properly deserialize it, because in such scenarios an ISO-formatted
Instant starts with a +/- sign.

This commit fixes this issue, while maintaining the previous contract,
and also introduces tests for InstantFormatter.

Closes gh-23895
2019-11-14 10:10:43 +01:00
Juergen Hoeller 6ed6c08ace Polishing 2019-11-13 23:49:33 +01:00
Juergen Hoeller e4c57a9b61 Minor internal refinements (backported from master) 2019-11-13 16:53:23 +01:00
Juergen Hoeller b0d8a667a1 Upgrade to Hibernate ORM 5.3.14 2019-11-13 16:51:47 +01:00
Juergen Hoeller 9c9ee22c2b Note on injecting results from local @Bean methods (self references)
Closes gh-23934
2019-11-13 16:50:47 +01:00
Juergen Hoeller 639dce6282 Support for new MySQL 8 error code 3572
Closes gh-23972
2019-11-13 16:25:30 +01:00
YuDongYing 8e65834c44 Fix schemaZip Gradle task on MS Windows
Prior to this commit, the schemaZip Gradle task failed to find Spring
schema files on MS Windows due to path separators hard coded to forward
slashes that are not compatible with the Windows operating system.

Consequently, a full build failed on Windows since the distZip task was
not able to locate the zipped schema archive that the schemaZip task
failed to create.

This commit fixes this by updating the schemaZip task to search for
schema files using backslashes as well as forward slashes.

Closes gh-23933
2019-11-13 15:02:49 +01:00
Rossen Stoyanchev 64db939e4a Javadoc update for content negotiation
Closes gh-23409
2019-11-11 12:08:05 +00:00
Sam Brannen 3d83f869d9 Fix Javadoc for SmartLifecycle.DEFAULT_PHASE regarding ordering
Closes gh-23956
2019-11-09 18:03:43 +01:00
Juergen Hoeller 088a653318 Upgrade to RxJava 2.2.14, OkHttp 3.14.4, Awaitility 3.1.6 2019-11-07 22:35:30 +01:00
Juergen Hoeller bdb1a81a39 Use Method.getParameterCount() when full type array is never needed 2019-11-07 22:35:21 +01:00
Arjen Poutsma c2e7b6341c Polishing 2019-11-07 15:03:28 +01:00
Arjen Poutsma e75556bc7b Polishing 2019-11-07 15:02:34 +01:00
Arjen Poutsma d3d40983d6 Corrupt multipart should not hang SynchronossPartHttpMessageReader
This commit notifies the Synchronoss listener that the buffer stream
has ended.

Closes gh-23768

(cherry picked from commit bf36f49dc5)
2019-11-07 14:48:18 +01:00
Arjen Poutsma 32adf77b22 Corrupt multipart should not hang SynchronossPartHttpMessageReader
This commit notifies the Synchronoss listener that the buffer stream
has ended.

See gh-23768
2019-11-07 09:42:36 +01:00
Rossen Stoyanchev 1301c7e95d Update WebMvcConfigurer#addInterceptors Javadoc
Closes gh-23908
2019-11-06 21:38:32 +00:00
Rossen Stoyanchev 1a057654b2 Defer ExchangeFilterFunction to subscription time
Previously fixed in 5.2 via d46359. Now also backported to 5.1.x.

Closes gh-23909
2019-11-06 21:38:32 +00:00
Sam Brannen ca3440cb42 Re-enable support for invalid Expires attributes in MockCookie
Changes introduced in commit 9b2087618b
caused a regression for Cookie support in MockHttpServletResponse.
Specifically, an Expires attribute that cannot be parsed using
`ZonedDateTime.parse()` now results in an exception; whereas,
previously an entry such as `Expires=0` was allowed.

This commit fixes this issue in MockCookie by catching and ignoring any
DateTimeException thrown while attempting to parse an Expires attribute.

Closes gh-23911
2019-11-06 22:23:20 +01:00
Rossen Stoyanchev 48b22292ff Fix issue with path matching options
Closes gh-23907
2019-11-06 18:13:10 +00:00
Rossen Stoyanchev e0faaa4807 Relax domain name checks in ResponseCookie
Closes gh-23924
2019-11-06 18:05:44 +00:00
Rossen Stoyanchev 2e4944198d Fix condition in ServletInvocableHandlerMethod
Closes gh-23775
2019-11-06 18:02:28 +00:00
Spring Buildmaster 38a1caefb8 Next Development Version 2019-11-02 07:17:14 +00:00
Rossen Stoyanchev e731a0a164 Use int for maxParts instead of long 2019-10-31 14:16:48 +00:00
Brian Clozel 0f2efdbe97 Polish
See gh-23884
2019-10-30 19:58:06 +01:00
Brian Clozel feeeab1761 Reorder date formatting converter in registrar
Prior to this commit, the `DateFormatterRegistrar` would register the
annotation-based formatter before the pattern-based formatter. This
would create an issue when an application tries to convert a `String` to
an annotated `@DateTimeFormat Date`: since the converters are considered
in reversed order of registration in
`GenericConversionServicei#ConvertersForPair`, the pattern-based variant
would always be considered before the annotation-based variant,
overriding the developer's opinion.

This commit aligns the `DateFormatterRegistrar` with the
`DateTimeFormatterRegistrar` and registers the annotation-based variant
last.

Closes gh-23896
2019-10-30 17:34:49 +01:00
Juergen Hoeller b4cf471021 Polishing 2019-10-30 16:45:35 +01:00
Juergen Hoeller 82751141ac Revise concurrent JAXBContext creation towards computeIfAbsent
Closes gh-23879
2019-10-30 16:26:13 +01:00
Sam Brannen 9f43ee3304 Treat InvalidPathException like an IOException in MockServletContext
Prior to this commit, if MockServletContext was configured with a
FileSystemResourceLoader, invocations of the following methods on a
Microsoft Windows operating system resulted in an InvalidPathException
if the supplied path contained a colon (such as "C:\\temp"). This is
inconsistent with the behavior on non-Windows operating systems. In
addition, for comparable errors resulting in an IOException, those
methods (except getRealPath()) return null instead of throwing the
exception.

- getResourcePaths()
- getResource()
- getResourceAsStream()
- getRealPath()

This commit makes handling of InvalidPathException and IOException
consistent for these methods: both exceptions now result in null be
returned by these methods.

Closes gh-23717
2019-10-30 16:19:40 +01:00
Rossen Stoyanchev 614c7b0f8e ResponseStatusException associated headers
A ResponseStatus exception now exposes extra method to return headers
for the response. This is used in ResponseStatusExceptionHandler to
apply the headers to the response.

Closes gh-23741
2019-10-30 12:34:24 +00:00
Rossen Stoyanchev cc84533d85 Logging decorator for WebSocketStompClient handler
Closes gh-23793
2019-10-30 12:16:45 +00:00
Juergen Hoeller 6faf61ba40 Latest applicable dependency updates (Tomcat 9.0.27, Undertow 2.0.27, RxJava 2.2.13, Hibernate ORM 5.3.13, POI 4.1.1, Checkstyle 8.26) 2019-10-30 11:07:39 +01:00
Juergen Hoeller 80a5019534 Verify read-only propagation in DataSourceTransactionManagerTests
See gh-23747
2019-10-30 11:07:07 +01:00
Juergen Hoeller 03bd02a627 Expose primary flag on BeanDefinitionBuilder
Closes gh-23794
2019-10-30 10:30:43 +01:00
Juergen Hoeller f16aa4a9b5 Nullability refinements 2019-10-30 10:30:36 +01:00
Sam Brannen a3c9e8d4fc Polish contribution
See gh-23769
2019-10-29 13:50:38 +01:00
Vedran Pavic 3814f12b67 Preserve expires attribute in MockCookie
At present, MockCookie doesn't preserve expires attribute. This has a
consequence that a cookie value set using
MockHttpServletResponse#addHeader containing an expires attribute will
not match the cookie value obtained from
MockHttpServletResponse#getHeader, since the expires attribute will get
calculated based on current time.

This commit enhances MockCookie to preserve the expires attribute.

Closes gh-23769
2019-10-29 13:50:38 +01:00
Sam Brannen ceb881ab05 Ignore projects not in this branch 2019-10-29 13:50:38 +01:00
Rossen Stoyanchev 871464811c Limits on input stream in codecs
- Add maxInMemorySize property to Decoder and HttpMessageReader
  implementations that aggregate input to trigger
  DataBufferLimitException when reached.

- For codecs that call DataBufferUtils#join, there is now an overloaded
  variant with a maxInMemorySize extra argument. Internally, a custom
  LimitedDataBufferList is used to count and enforce the limit.

- Jackson2Tokenizer and XmlEventDecoder support those limits per
  streamed JSON object.

- Configurable limits for multipart requests with Synchronoss NIO.

- Centralized maxInMemorySize exposed via CodecConfigurer along with
  ability to plug in an instance of MultipartHttpMessageWrite.

Closes gh-23884
2019-10-29 12:36:36 +00:00
313 changed files with 6486 additions and 2297 deletions
@@ -0,0 +1,10 @@
name: "Validate Gradle Wrapper"
on: [push, pull_request]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
+4
View File
@@ -24,6 +24,10 @@ buildSrc/build
/src/asciidoc/build
target/
# Projects not in this branch
integration-tests/
spring-core/kotlin-coroutines/
# Eclipse artifacts, including WTP generated manifests
.classpath
.project
+12 -12
View File
@@ -28,24 +28,24 @@ ext {
!it.name.equals("spring-build-src") && !it.name.equals("spring-framework-bom")
}
aspectjVersion = "1.9.4"
aspectjVersion = "1.9.5"
freemarkerVersion = "2.3.28"
groovyVersion = "2.5.8"
groovyVersion = "2.5.9"
hsqldbVersion = "2.4.1"
jackson2Version = "2.9.9"
jettyVersion = "9.4.21.v20190926"
jettyVersion = "9.4.29.v20200521"
junit5Version = "5.3.2"
kotlinVersion = "1.2.71"
log4jVersion = "2.11.2"
nettyVersion = "4.1.43.Final"
reactorVersion = "Californium-SR13"
nettyVersion = "4.1.50.Final"
reactorVersion = "Californium-SR19"
rxjavaVersion = "1.3.8"
rxjavaAdapterVersion = "1.2.1"
rxjava2Version = "2.2.12"
slf4jVersion = "1.7.28" // spring-jcl + consistent 3rd party deps
rxjava2Version = "2.2.19"
slf4jVersion = "1.7.30" // spring-jcl + consistent 3rd party deps
tiles3Version = "3.0.8"
tomcatVersion = "9.0.26"
undertowVersion = "2.0.26.Final"
tomcatVersion = "9.0.36"
undertowVersion = "2.0.30.Final"
gradleScriptDir = "${rootProject.projectDir}/gradle"
withoutJclOverSlf4j = {
@@ -142,13 +142,13 @@ configure(allprojects) { project ->
}
checkstyle {
toolVersion = "8.24"
toolVersion = "8.33"
configDir = rootProject.file("src/checkstyle")
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/libs-release" }
mavenLocal()
}
dependencies {
@@ -184,7 +184,7 @@ configure(allprojects) { project ->
"https://tiles.apache.org/tiles-request/apidocs/",
"https://tiles.apache.org/framework/apidocs/",
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"https://www.ehcache.org/apidocs/2.10.4",
"https://www.ehcache.org/apidocs/2.10.4/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://fasterxml.github.io/jackson-core/javadoc/2.9/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.9/",
+1 -1
View File
@@ -1 +1 @@
version=5.1.11.BUILD-SNAPSHOT
version=5.1.16.RELEASE
+2 -2
View File
@@ -149,14 +149,14 @@ task schemaZip(type: Zip) {
def Properties schemas = new Properties();
subproject.sourceSets.main.resources.find {
it.path.endsWith("META-INF/spring.schemas")
(it.path.endsWith("META-INF/spring.schemas") || it.path.endsWith("META-INF\\spring.schemas"))
}?.withInputStream { schemas.load(it) }
for (def key : schemas.keySet()) {
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
assert shortName != key
File xsdFile = subproject.sourceSets.main.resources.find {
it.path.endsWith(schemas.get(key))
(it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/','\\\\')))
}
assert xsdFile != null
into (shortName) {
+1 -1
View File
@@ -4,6 +4,6 @@ dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.apache.commons:commons-pool2:2.6.0")
optional("org.apache.commons:commons-pool2:2.6.2")
optional("com.jamonapi:jamon:2.81")
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -76,9 +76,8 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> annotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (annotation != null ? annotation.getAnnotation() : null);
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
@@ -153,8 +152,10 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
methods.sort(METHOD_COMPARATOR);
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
@@ -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.
@@ -138,14 +138,8 @@ class AspectJPrecedenceComparator implements Comparator<Advisor> {
}
private int getAspectDeclarationOrder(Advisor anAdvisor) {
AspectJPrecedenceInformation precedenceInfo =
AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
if (precedenceInfo != null) {
return precedenceInfo.getDeclarationOrder();
}
else {
return 0;
}
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
return (precedenceInfo != null ? precedenceInfo.getDeclarationOrder() : 0);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 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.
@@ -61,12 +61,12 @@ public class AopNamespaceHandler extends NamespaceHandlerSupport {
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -258,15 +258,17 @@ class CglibAopProxy implements AopProxy, Serializable {
int mod = method.getModifiers();
if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) {
if (Modifier.isFinal(mod)) {
if (implementsInterface(method, ifcs)) {
if (logger.isInfoEnabled() && implementsInterface(method, ifcs)) {
logger.info("Unable to proxy interface-implementing method [" + method + "] because " +
"it is marked as final: Consider using interface-based JDK proxies instead!");
}
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
"Calls to this method will NOT be routed to the target instance and " +
"might lead to NPEs against uninitialized fields in the proxy instance.");
if (logger.isDebugEnabled()) {
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
"Calls to this method will NOT be routed to the target instance and " +
"might lead to NPEs against uninitialized fields in the proxy instance.");
}
}
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
else if (logger.isDebugEnabled() && !Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
logger.debug("Method [" + method + "] is package-visible across different ClassLoaders " +
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
@@ -526,7 +528,7 @@ class CglibAopProxy implements AopProxy, Serializable {
private static class StaticDispatcher implements Dispatcher, Serializable {
@Nullable
private Object target;
private final Object target;
public StaticDispatcher(@Nullable Object target) {
this.target = target;
@@ -552,7 +554,7 @@ class CglibAopProxy implements AopProxy, Serializable {
}
@Override
public Object loadObject() throws Exception {
public Object loadObject() {
return this.advised;
}
}
@@ -940,11 +942,11 @@ class CglibAopProxy implements AopProxy, Serializable {
return true;
}
private boolean equalsAdviceClasses(Advisor a, Advisor b) {
private static boolean equalsAdviceClasses(Advisor a, Advisor b) {
return (a.getAdvice().getClass() == b.getAdvice().getClass());
}
private boolean equalsPointcuts(Advisor a, Advisor b) {
private static boolean equalsPointcuts(Advisor a, Advisor b) {
// If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch.
// Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959).
return (!(a instanceof PointcutAdvisor) ||
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -21,9 +21,7 @@ import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.Interceptor;
@@ -342,11 +340,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// an independent instance of the configuration.
// In this case, no proxy will have an instance of this object's configuration,
// but will have an independent copy.
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
}
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
@@ -359,9 +354,6 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}
@@ -395,9 +387,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +
"is not an advisor class: treating it as a target or TargetSource");
}
String[] newNames = new String[this.interceptorNames.length - 1];
System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);
this.interceptorNames = newNames;
this.interceptorNames = Arrays.copyOf(this.interceptorNames, this.interceptorNames.length - 1);
}
}
}
@@ -449,16 +439,12 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
@@ -475,7 +461,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
addAdvisorOnChainCreation(advice);
}
}
}
@@ -498,11 +484,10 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
if (logger.isDebugEnabled()) {
logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
}
// Replace the placeholder with a fresh prototype instance resulting
// from a getBean() lookup
// Replace the placeholder with a fresh prototype instance resulting from a getBean lookup
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve prototype advisor '" + pa.getBeanName() + "'");
throw new IllegalStateException("No BeanFactory available anymore (probably due to " +
"serialization) - cannot resolve prototype advisor '" + pa.getBeanName() + "'");
}
Object bean = this.beanFactory.getBean(pa.getBeanName());
Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
@@ -519,28 +504,26 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
/**
* Add all global interceptors and pointcuts.
*/
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
private void addGlobalAdvisors(ListableBeanFactory beanFactory, String prefix) {
String[] globalAdvisorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
String[] globalInterceptorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
Map<Object, String> names = new HashMap<>(beans.size());
for (String name : globalAdvisorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
for (String name : globalInterceptorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
AnnotationAwareOrderComparator.sort(beans);
for (Object bean : beans) {
String name = names.get(bean);
if (name.startsWith(prefix)) {
addAdvisorOnChainCreation(bean, name);
if (globalAdvisorNames.length > 0 || globalInterceptorNames.length > 0) {
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
for (String name : globalAdvisorNames) {
if (name.startsWith(prefix)) {
beans.add(beanFactory.getBean(name));
}
}
for (String name : globalInterceptorNames) {
if (name.startsWith(prefix)) {
beans.add(beanFactory.getBean(name));
}
}
AnnotationAwareOrderComparator.sort(beans);
for (Object bean : beans) {
addAdvisorOnChainCreation(bean);
}
}
}
@@ -551,17 +534,11 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
* Because of these three possibilities, we can't type the signature
* more strongly.
* @param next advice, advisor or target object
* @param name bean name from which we obtained this object in our owning
* bean factory
*/
private void addAdvisorOnChainCreation(Object next, String name) {
private void addAdvisorOnChainCreation(Object next) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
addAdvisor(namedBeanToAdvisor(next));
}
/**
@@ -572,9 +549,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
*/
private TargetSource freshTargetSource() {
if (this.targetName == null) {
if (logger.isTraceEnabled()) {
logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
}
// Not refreshing target: bean name not specified in 'interceptorNames'
return this.targetSource;
}
else {
@@ -602,8 +577,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// We expected this to be an Advisor or Advice,
// but it wasn't. This is a configuration error.
throw new AopConfigException("Unknown advisor type " + next.getClass() +
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
"which may also be target or TargetSource", ex);
"; can only include Advisor or Advice type beans in interceptorNames chain " +
"except for last entry which may also be target instance or TargetSource", ex);
}
}
@@ -614,7 +589,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
protected void adviceChanged() {
super.adviceChanged();
if (this.singleton) {
logger.debug("Advice has changed; recaching singleton instance");
logger.debug("Advice has changed; re-caching singleton instance");
synchronized (this) {
this.singletonInstance = null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -37,6 +37,7 @@ import org.springframework.scheduling.config.TaskManagementConfigUtils;
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -36,6 +36,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
* @see TransactionManagementConfigurationSelector
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJJtaTransactionManagementConfiguration extends AspectJTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_BEAN_NAME)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -38,6 +38,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
* @see AspectJJtaTransactionManagementConfiguration
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)
+1 -1
View File
@@ -9,7 +9,7 @@ dependencies {
optional("org.codehaus.groovy:groovy-xml:${groovyVersion}")
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("javax.annotation:javax.annotation-api:1.3.2")
}
// This module does joint compilation for Java and Groovy code with the compileGroovy task.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -43,9 +43,9 @@ import org.springframework.util.StringUtils;
* Internal class that caches JavaBeans {@link java.beans.PropertyDescriptor}
* information for a Java class. Not intended for direct use by application code.
*
* <p>Necessary for own caching of descriptors within the application's
* ClassLoader, rather than rely on the JDK's system-wide BeanInfo cache
* (in order to avoid leaks on ClassLoader shutdown).
* <p>Necessary for Spring's own caching of bean descriptors within the application
* {@link ClassLoader}, rather than relying on the JDK's system-wide {@link BeanInfo}
* cache (in order to avoid leaks on individual application shutdown in a shared JVM).
*
* <p>Information is cached statically, so we don't need to create new
* objects of this class for every JavaBean we manipulate. Hence, this class
@@ -97,7 +97,7 @@ public final class CachedIntrospectionResults {
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
/** Stores the BeanInfoFactory instances. */
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
private static final List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
@@ -163,7 +163,6 @@ public final class CachedIntrospectionResults {
* @return the corresponding CachedIntrospectionResults
* @throws BeansException in case of introspection failure
*/
@SuppressWarnings("unchecked")
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
CachedIntrospectionResults results = strongClassCache.get(beanClass);
if (results != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -41,8 +41,8 @@ import org.springframework.util.ObjectUtils;
/**
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
* and/or non-void returning setter methods. For example:
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register
* static and/or non-void returning setter methods. For example:
*
* <pre class="code">
* public class Bean {
@@ -145,11 +145,10 @@ class ExtendedBeanInfo implements BeanInfo {
public static boolean isCandidateWriteMethod(Method method) {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
int nParams = parameterTypes.length;
int nParams = method.getParameterCount();
return (methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
(nParams == 1 || (nParams == 2 && int.class == parameterTypes[0])));
(nParams == 1 || (nParams == 2 && int.class == method.getParameterTypes()[0])));
}
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
@@ -209,7 +208,7 @@ class ExtendedBeanInfo implements BeanInfo {
}
private String propertyNameFor(Method method) {
return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
return Introspector.decapitalize(method.getName().substring(3));
}
@@ -488,7 +487,7 @@ class ExtendedBeanInfo implements BeanInfo {
}
/*
* See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
* See java.beans.IndexedPropertyDescriptor#equals
*/
@Override
public boolean equals(Object other) {
@@ -535,11 +534,13 @@ class ExtendedBeanInfo implements BeanInfo {
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
String left = desc1.getName();
String right = desc2.getName();
byte[] leftBytes = left.getBytes();
byte[] rightBytes = right.getBytes();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = left.getBytes()[i] - right.getBytes()[i];
int result = leftBytes[i] - rightBytes[i];
if (result != 0) {
return result;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -66,8 +66,7 @@ abstract class PropertyDescriptorUtils {
Class<?> propertyType = null;
if (readMethod != null) {
Class<?>[] params = readMethod.getParameterTypes();
if (params.length != 0) {
if (readMethod.getParameterCount() != 0) {
throw new IntrospectionException("Bad read method arg count: " + readMethod);
}
propertyType = readMethod.getReturnType();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -39,10 +39,16 @@ import org.springframework.lang.Nullable;
*
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
* the bootstrap process, even ahead of any post-processor setup. If you need access
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
* bootstrap process, even ahead of any post-processor setup. If you need access to
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
*
* <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
* instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
* a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
* will <i>not</i> be called automatically. Instead, a FactoryBean should implement
* {@link DisposableBean} and delegate any such close call to the underlying object.
*
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
* synchronization of bean creation. There is usually no need for internal
* synchronization other than for purposes of lazy initialization within the
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -41,12 +41,11 @@ import java.lang.annotation.Target;
* regular constructors: i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we cannot dynamically provide a subclass for them.
*
* <p><b>Concrete limitations in typical Spring configuration scenarios:</b>
* When used with component scanning or any other mechanism that filters out abstract
* beans, provide stub implementations of your lookup methods to be able to declare
* them as concrete classes. And please remember that lookup methods won't work on
* beans returned from {@code @Bean} methods in configuration classes; you'll have
* to resort to {@code @Inject Provider<TargetBean>} or the like instead.
* <p><b>Recommendations for typical Spring configuration scenarios:</b>
* When a concrete class may be needed in certain scenarios, consider providing stub
* implementations of your lookup methods. And please remember that lookup methods
* won't work on beans returned from {@code @Bean} methods in configuration classes;
* you'll have to resort to {@code @Inject Provider<TargetBean>} or the like instead.
*
* @author Juergen Hoeller
* @since 4.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -373,7 +373,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
/**
* Determine the name of the wrapped parameter/field.
* @return the declared name (never {@code null})
* @return the declared name (may be {@code null} if unresolvable)
*/
@Nullable
public String getDependencyName() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -25,17 +25,23 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.reader.UnicodeReader;
import org.yaml.snakeyaml.representer.Representer;
import org.springframework.core.CollectionFactory;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -45,6 +51,7 @@ import org.springframework.util.StringUtils;
*
* @author Dave Syer
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.1
*/
public abstract class YamlProcessor {
@@ -59,6 +66,8 @@ public abstract class YamlProcessor {
private boolean matchDefault = true;
private Set<String> supportedTypes = Collections.emptySet();
/**
* A map of document matchers allowing callers to selectively use only
@@ -117,6 +126,27 @@ public abstract class YamlProcessor {
this.resources = resources;
}
/**
* Set the supported types that can be loaded from YAML documents.
* <p>If no supported types are configured, all types encountered in YAML
* documents will be supported. If an unsupported type is encountered, an
* {@link IllegalStateException} will be thrown when the corresponding YAML
* node is processed.
* @param supportedTypes the supported types, or an empty array to clear the
* supported types
* @since 5.1.16
* @see #createYaml()
*/
public void setSupportedTypes(Class<?>... supportedTypes) {
if (ObjectUtils.isEmpty(supportedTypes)) {
this.supportedTypes = Collections.emptySet();
}
else {
Assert.noNullElements(supportedTypes, "'supportedTypes' must not contain null elements");
this.supportedTypes = Arrays.stream(supportedTypes).map(Class::getName)
.collect(Collectors.collectingAndThen(Collectors.toSet(), Collections::unmodifiableSet));
}
}
/**
* Provide an opportunity for subclasses to process the Yaml parsed from the supplied
@@ -142,12 +172,22 @@ public abstract class YamlProcessor {
* Create the {@link Yaml} instance to use.
* <p>The default implementation sets the "allowDuplicateKeys" flag to {@code false},
* enabling built-in duplicate key handling in SnakeYAML 1.18+.
* <p>As of Spring Framework 5.1.16, if custom {@linkplain #setSupportedTypes
* supported types} have been configured, the default implementation creates
* a {@code Yaml} instance that filters out unsupported types encountered in
* YAML documents. If an unsupported type is encountered, an
* {@link IllegalStateException} will be thrown when the node is processed.
* @see LoaderOptions#setAllowDuplicateKeys(boolean)
*/
protected Yaml createYaml() {
LoaderOptions options = new LoaderOptions();
options.setAllowDuplicateKeys(false);
return new Yaml(options);
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
if (!this.supportedTypes.isEmpty()) {
return new Yaml(new FilteringConstructor(), new Representer(),
new DumperOptions(), loaderOptions);
}
return new Yaml(loaderOptions);
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
@@ -388,4 +428,20 @@ public abstract class YamlProcessor {
FIRST_FOUND
}
/**
* {@link Constructor} that supports filtering of unsupported types.
* <p>If an unsupported type is encountered in a YAML document, an
* {@link IllegalStateException} will be thrown from {@link #getClassForName}.
*/
private class FilteringConstructor extends Constructor {
@Override
protected Class<?> getClassForName(String name) throws ClassNotFoundException {
Assert.state(YamlProcessor.this.supportedTypes.contains(name),
() -> "Unsupported type encountered in YAML document: " + name);
return super.getClassForName(name);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -182,10 +182,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
@Override
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
@Override
public MetaClass getMetaClass() {
return this.metaClass;
}
@@ -216,6 +218,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
@@ -240,10 +243,11 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
logger.trace("Loading Groovy bean definitions from " + encodedResource);
}
Closure beans = new Closure(this) {
@SuppressWarnings("serial")
Closure<Object> beans = new Closure<Object>(this) {
@Override
public Object call(Object[] args) {
invokeBeanDefiningClosure((Closure) args[0]);
public Object call(Object... args) {
invokeBeanDefiningClosure((Closure<?>) args[0]);
return null;
}
};
@@ -285,7 +289,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* @param closure the block or closure
* @return this {@code GroovyBeanDefinitionReader} instance
*/
public GroovyBeanDefinitionReader beans(Closure closure) {
public GroovyBeanDefinitionReader beans(Closure<?> closure) {
return invokeBeanDefiningClosure(closure);
}
@@ -309,25 +313,22 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
public AbstractBeanDefinition bean(Class<?> type, Object...args) {
GroovyBeanDefinitionWrapper current = this.currentBeanDefinition;
try {
Closure callable = null;
Collection constructorArgs = null;
Closure<?> callable = null;
Collection<Object> constructorArgs = null;
if (!ObjectUtils.isEmpty(args)) {
int index = args.length;
Object lastArg = args[index - 1];
if (lastArg instanceof Closure) {
callable = (Closure) lastArg;
if (lastArg instanceof Closure<?>) {
callable = (Closure<?>) lastArg;
index--;
}
if (index > -1) {
constructorArgs = resolveConstructorArguments(args, 0, index);
}
constructorArgs = resolveConstructorArguments(args, 0, index);
}
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(null, type, constructorArgs);
if (callable != null) {
callable.call(this.currentBeanDefinition);
}
return this.currentBeanDefinition.getBeanDefinition();
}
finally {
this.currentBeanDefinition = current;
@@ -373,10 +374,11 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* This method overrides method invocation to create beans for each method name that
* takes a class argument.
*/
@Override
public Object invokeMethod(String name, Object arg) {
Object[] args = (Object[])arg;
if ("beans".equals(name) && args.length == 1 && args[0] instanceof Closure) {
return beans((Closure) args[0]);
return beans((Closure<?>) args[0]);
}
else if ("ref".equals(name)) {
String refName;
@@ -429,10 +431,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
private void finalizeDeferredProperties() {
for (DeferredProperty dp : this.deferredProperties.values()) {
if (dp.value instanceof List) {
dp.value = manageListIfNecessary((List) dp.value);
dp.value = manageListIfNecessary((List<?>) dp.value);
}
else if (dp.value instanceof Map) {
dp.value = manageMapIfNecessary((Map) dp.value);
dp.value = manageMapIfNecessary((Map<?, ?>) dp.value);
}
dp.apply();
}
@@ -444,7 +446,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* @param callable the closure argument
* @return this {@code GroovyBeanDefinitionReader} instance
*/
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure<?> callable) {
callable.setDelegate(this);
callable.call();
finalizeDeferredProperties();
@@ -483,9 +485,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
else if (args[0] instanceof Map) {
// named constructor arguments
if (args.length > 1 && args[1] instanceof Class) {
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
Map namedArgs = (Map)args[0];
List<Object> constructorArgs =
resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class<?>) args[1], constructorArgs);
Map<?, ?> namedArgs = (Map<?, ?>) args[0];
for (Object o : namedArgs.keySet()) {
String propName = (String) o;
setProperty(propName, namedArgs.get(propName));
@@ -494,8 +497,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
// factory method syntax
else {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
//First arg is the map containing factoryBean : factoryMethod
Map.Entry factoryBeanEntry = (Map.Entry) ((Map) args[0]).entrySet().iterator().next();
// First arg is the map containing factoryBean : factoryMethod
Map.Entry<?, ?> factoryBeanEntry = ((Map<?, ?>) args[0]).entrySet().iterator().next();
// If we have a closure body, that will be the last argument.
// In between are the constructor args
int constructorArgsTest = (hasClosureArgument ? 2 : 1);
@@ -519,12 +522,13 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
}
else {
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
List<Object> constructorArgs =
resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
}
if (hasClosureArgument) {
Closure callable = (Closure) args[args.length - 1];
Closure<?> callable = (Closure<?>) args[args.length - 1];
callable.setDelegate(this);
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
callable.call(this.currentBeanDefinition);
@@ -544,10 +548,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
constructorArgs[i] = constructorArgs[i].toString();
}
else if (constructorArgs[i] instanceof List) {
constructorArgs[i] = manageListIfNecessary((List) constructorArgs[i]);
constructorArgs[i] = manageListIfNecessary((List<?>) constructorArgs[i]);
}
else if (constructorArgs[i] instanceof Map){
constructorArgs[i] = manageMapIfNecessary((Map) constructorArgs[i]);
constructorArgs[i] = manageMapIfNecessary((Map<?, ?>) constructorArgs[i]);
}
}
return Arrays.asList(constructorArgs);
@@ -601,6 +605,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* This method overrides property setting in the scope of the {@code GroovyBeanDefinitionReader}
* to set properties on the current bean definition.
*/
@Override
public void setProperty(String name, Object value) {
if (this.currentBeanDefinition != null) {
applyPropertyToBeanDefinition(name, value);
@@ -617,7 +622,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
else if (value instanceof Closure) {
GroovyBeanDefinitionWrapper current = this.currentBeanDefinition;
try {
Closure callable = (Closure) value;
Closure<?> callable = (Closure<?>) value;
Class<?> parameterType = callable.getParameterTypes()[0];
if (Object.class == parameterType) {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper("");
@@ -647,6 +652,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
* properties from the {@code GroovyBeanDefinitionReader} itself
* </ul>
*/
@Override
public Object getProperty(String name) {
Binding binding = getBinding();
if (binding != null && binding.hasVariable(name)) {
@@ -690,8 +696,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(new DescriptiveResource(
"Groovy"));
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(
new DescriptiveResource("Groovy"));
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
boolean decorating = (this.currentBeanDefinition != null);
if (!decorating) {
@@ -749,10 +755,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
this.metaClass = InvokerHelper.getMetaClass(this);
}
@Override
public MetaClass getMetaClass() {
return this.metaClass;
}
@Override
public Object getProperty(String property) {
if (property.equals("beanName")) {
return getBeanName();
@@ -769,14 +777,17 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
}
@Override
public Object invokeMethod(String name, Object args) {
return this.metaClass.invokeMethod(this, name, args);
}
@Override
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
@Override
public void setProperty(String property, Object newValue) {
if (!addDeferredProperty(property, newValue)) {
this.beanDefinition.getBeanDefinition().getPropertyValues().add(property, newValue);
@@ -785,7 +796,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Wraps a bean definition property an ensures that any RuntimeBeanReference
* Wraps a bean definition property and ensures that any RuntimeBeanReference
* additions to it are deferred for resolution later.
*/
private class GroovyPropertyValue extends GroovyObjectSupport {
@@ -799,18 +810,21 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
this.propertyValue = propertyValue;
}
@SuppressWarnings("unused")
public void leftShift(Object value) {
InvokerHelper.invokeMethod(this.propertyValue, "leftShift", value);
updateDeferredProperties(value);
}
@SuppressWarnings("unused")
public boolean add(Object value) {
boolean retVal = (Boolean) InvokerHelper.invokeMethod(this.propertyValue, "add", value);
updateDeferredProperties(value);
return retVal;
}
public boolean addAll(Collection values) {
@SuppressWarnings("unused")
public boolean addAll(Collection<?> values) {
boolean retVal = (Boolean) InvokerHelper.invokeMethod(this.propertyValue, "addAll", values);
for (Object value : values) {
updateDeferredProperties(value);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -196,7 +196,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
// constructorArgs
else if (CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) {
ConstructorArgumentValues cav = new ConstructorArgumentValues();
List args = (List) newValue;
List<?> args = (List<?>) newValue;
for (Object arg : args) {
cav.addGenericArgumentValue(arg);
}
@@ -645,7 +645,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
@Nullable
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
// eventual type after a before-instantiation shortcut.
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
@@ -1364,34 +1363,28 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
return;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
@@ -1495,7 +1488,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
@@ -1127,30 +1127,30 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
return false;
}
AbstractBeanDefinition that = (AbstractBeanDefinition) other;
boolean rtn = ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName());
rtn = rtn &= ObjectUtils.nullSafeEquals(this.scope, that.scope);
rtn = rtn &= this.abstractFlag == that.abstractFlag;
rtn = rtn &= this.lazyInit == that.lazyInit;
rtn = rtn &= this.autowireMode == that.autowireMode;
rtn = rtn &= this.dependencyCheck == that.dependencyCheck;
rtn = rtn &= Arrays.equals(this.dependsOn, that.dependsOn);
rtn = rtn &= this.autowireCandidate == that.autowireCandidate;
rtn = rtn &= ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers);
rtn = rtn &= this.primary == that.primary;
rtn = rtn &= this.nonPublicAccessAllowed == that.nonPublicAccessAllowed;
rtn = rtn &= this.lenientConstructorResolution == that.lenientConstructorResolution;
rtn = rtn &= ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues);
rtn = rtn &= ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues);
rtn = rtn &= ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides);
rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName);
rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName);
rtn = rtn &= ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName);
rtn = rtn &= this.enforceInitMethod == that.enforceInitMethod;
rtn = rtn &= ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName);
rtn = rtn &= this.enforceDestroyMethod == that.enforceDestroyMethod;
rtn = rtn &= this.synthetic == that.synthetic;
rtn = rtn &= this.role == that.role;
return rtn && super.equals(other);
return (ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName()) &&
ObjectUtils.nullSafeEquals(this.scope, that.scope) &&
this.abstractFlag == that.abstractFlag &&
this.lazyInit == that.lazyInit &&
this.autowireMode == that.autowireMode &&
this.dependencyCheck == that.dependencyCheck &&
Arrays.equals(this.dependsOn, that.dependsOn) &&
this.autowireCandidate == that.autowireCandidate &&
ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers) &&
this.primary == that.primary &&
this.nonPublicAccessAllowed == that.nonPublicAccessAllowed &&
this.lenientConstructorResolution == that.lenientConstructorResolution &&
ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues) &&
ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues) &&
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName) &&
this.enforceInitMethod == that.enforceInitMethod &&
ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName) &&
this.enforceDestroyMethod == that.enforceDestroyMethod &&
this.synthetic == that.synthetic &&
this.role == that.role &&
super.equals(other));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -887,7 +887,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
/**
* Return whether this factory holds a InstantiationAwareBeanPostProcessor
* that will get applied to singleton beans on shutdown.
* that will get applied to singleton beans on creation.
* @see #addBeanPostProcessor
* @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
*/
@@ -1283,7 +1283,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
@@ -1298,7 +1298,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
@@ -302,6 +302,15 @@ public final class BeanDefinitionBuilder {
return this;
}
/**
* Set whether this bean is a primary autowire candidate.
* @since 5.1.11
*/
public BeanDefinitionBuilder setPrimary(boolean primary) {
this.beanDefinition.setPrimary(primary);
return this;
}
/**
* Set the role of this definition.
*/
@@ -162,6 +162,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map from bean name to merged BeanDefinitionHolder. */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
@@ -759,8 +762,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
}
return resolver.isAutowireCandidate(
new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
BeanDefinitionHolder holder = (beanName.equals(beanDefinitionName) ?
this.mergedBeanDefinitionHolders.computeIfAbsent(beanName,
key -> new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName))) :
new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)));
return resolver.isAutowireCandidate(holder, descriptor);
}
@Override
@@ -783,9 +789,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return iterator;
}
@Override
protected void clearMergedBeanDefinition(String beanName) {
super.clearMergedBeanDefinition(beanName);
this.mergedBeanDefinitionHolders.remove(beanName);
}
@Override
public void clearMetadataCache() {
super.clearMetadataCache();
this.mergedBeanDefinitionHolders.clear();
clearByTypeCache();
}
@@ -942,6 +955,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -70,6 +70,10 @@ import org.springframework.util.StringUtils;
*/
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Maximum number of suppressed exceptions to preserve. */
private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
@@ -90,7 +94,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** List of suppressed Exceptions, available for associating related causes. */
/** Collection of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;
@@ -253,13 +257,17 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
/**
* Register an Exception that happened to get suppressed during the creation of a
* Register an exception that happened to get suppressed during the creation of a
* singleton bean instance, e.g. a temporary circular reference resolution problem.
* <p>The default implementation preserves any given exception in this registry's
* collection of suppressed exceptions, up to a limit of 100 exceptions, adding
* them as related causes to an eventual top-level {@link BeanCreationException}.
* @param ex the Exception to register
* @see BeanCreationException#getRelatedCauses()
*/
protected void onSuppressedException(Exception ex) {
synchronized (this.singletonObjects) {
if (this.suppressedExceptions != null) {
if (this.suppressedExceptions != null && this.suppressedExceptions.size() < SUPPRESSED_EXCEPTIONS_LIMIT) {
this.suppressedExceptions.add(ex);
}
}
@@ -612,6 +620,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* should <i>not</i> have their own mutexes involved in singleton creation,
* to avoid the potential for deadlocks in lazy-init situations.
*/
@Override
public final Object getSingletonMutex() {
return this.singletonObjects;
}
@@ -311,9 +311,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* assuming a "force" parameter), else logging an error.
*/
private void invokeCustomDestroyMethod(final Method destroyMethod) {
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
final Object[] args = new Object[paramTypes.length];
if (paramTypes.length == 1) {
int paramCount = destroyMethod.getParameterCount();
final Object[] args = new Object[paramCount];
if (paramCount == 1) {
args[0] = Boolean.TRUE;
}
if (logger.isTraceEnabled()) {
@@ -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.
@@ -40,6 +40,11 @@ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolve
return descriptor.isRequired();
}
@Override
public boolean hasQualifier(DependencyDescriptor descriptor) {
return false;
}
@Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
@@ -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.
@@ -146,8 +146,9 @@ public class ArgumentConvertingMethodInvoker extends MethodInvoker {
for (Method candidate : candidates) {
if (candidate.getName().equals(targetMethod)) {
// Check if the inspected method has the correct number of parameters.
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length == argCount) {
int parameterCount = candidate.getParameterCount();
if (parameterCount == argCount) {
Class<?>[] paramTypes = candidate.getParameterTypes();
Object[] convertedArguments = new Object[argCount];
boolean match = true;
for (int j = 0; j < argCount && match; j++) {
@@ -1399,6 +1399,39 @@ public class DefaultListableBeanFactoryTests {
lbf.getBean(TestBean.class);
}
@Test
public void testGetBeanByTypeWithLateRegistration() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
try {
lbf.getBean(TestBean.class);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName(), equalTo("bd1"));
}
@Test
public void testGetBeanByTypeWithLateRegistrationAgainstFrozen() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.freezeConfiguration();
try {
lbf.getBean(TestBean.class);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("bd1", bd1);
TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName(), equalTo("bd1"));
}
@Test
public void testGetBeanByTypeDefinedInParent() {
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -16,12 +16,15 @@
package org.springframework.beans.factory.config;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.yaml.snakeyaml.constructor.ConstructorException;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.scanner.ScannerException;
@@ -34,6 +37,7 @@ import static org.junit.Assert.*;
*
* @author Dave Syer
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class YamlProcessorTests {
@@ -45,7 +49,7 @@ public class YamlProcessorTests {
@Test
public void arrayConvertedToIndexedBeanReference() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar: [1,2,3]".getBytes()));
setYaml("foo: bar\nbar: [1,2,3]");
this.processor.process((properties, map) -> {
assertEquals(4, properties.size());
assertEquals("bar", properties.get("foo"));
@@ -61,13 +65,13 @@ public class YamlProcessorTests {
@Test
public void testStringResource() {
this.processor.setResources(new ByteArrayResource("foo # a document that is a literal".getBytes()));
setYaml("foo # a document that is a literal");
this.processor.process((properties, map) -> assertEquals("foo", map.get("document")));
}
@Test
public void testBadDocumentStart() {
this.processor.setResources(new ByteArrayResource("foo # a document\nbar: baz".getBytes()));
setYaml("foo # a document\nbar: baz");
this.exception.expect(ParserException.class);
this.exception.expectMessage("line 2, column 1");
this.processor.process((properties, map) -> {});
@@ -75,7 +79,7 @@ public class YamlProcessorTests {
@Test
public void testBadResource() {
this.processor.setResources(new ByteArrayResource("foo: bar\ncd\nspam:\n foo: baz".getBytes()));
setYaml("foo: bar\ncd\nspam:\n foo: baz");
this.exception.expect(ScannerException.class);
this.exception.expectMessage("line 3, column 1");
this.processor.process((properties, map) -> {});
@@ -83,7 +87,7 @@ public class YamlProcessorTests {
@Test
public void mapConvertedToIndexedBeanReference() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
setYaml("foo: bar\nbar:\n spam: bucket");
this.processor.process((properties, map) -> {
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
@@ -92,7 +96,7 @@ public class YamlProcessorTests {
@Test
public void integerKeyBehaves() {
this.processor.setResources(new ByteArrayResource("foo: bar\n1: bar".getBytes()));
setYaml("foo: bar\n1: bar");
this.processor.process((properties, map) -> {
assertEquals("bar", properties.get("[1]"));
assertEquals(2, properties.size());
@@ -101,7 +105,7 @@ public class YamlProcessorTests {
@Test
public void integerDeepKeyBehaves() {
this.processor.setResources(new ByteArrayResource("foo:\n 1: bar".getBytes()));
setYaml("foo:\n 1: bar");
this.processor.process((properties, map) -> {
assertEquals("bar", properties.get("foo[1]"));
assertEquals(1, properties.size());
@@ -111,7 +115,7 @@ public class YamlProcessorTests {
@Test
@SuppressWarnings("unchecked")
public void flattenedMapIsSameAsPropertiesButOrdered() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
setYaml("foo: bar\nbar:\n spam: bucket");
this.processor.process((properties, map) -> {
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
@@ -124,4 +128,47 @@ public class YamlProcessorTests {
});
}
@Test
public void customTypeSupportedByDefault() throws Exception {
URL url = new URL("https://localhost:9000/");
setYaml("value: !!java.net.URL [\"" + url + "\"]");
this.processor.process((properties, map) -> {
assertEquals(1, properties.size());
assertEquals(1, map.size());
assertEquals(url, properties.get("value"));
assertEquals(url, map.get("value"));
});
}
@Test
public void customTypesSupportedDueToExplicitConfiguration() throws Exception {
this.processor.setSupportedTypes(URL.class, String.class);
URL url = new URL("https://localhost:9000/");
setYaml("value: !!java.net.URL [!!java.lang.String [\"" + url + "\"]]");
this.processor.process((properties, map) -> {
assertEquals(1, properties.size());
assertEquals(1, map.size());
assertEquals(url, properties.get("value"));
assertEquals(url, map.get("value"));
});
}
@Test
public void customTypeNotSupportedDueToExplicitConfiguration() {
this.processor.setSupportedTypes(List.class);
setYaml("value: !!java.net.URL [\"https://localhost:9000/\"]");
this.exception.expect(ConstructorException.class);
this.exception.expectMessage("Unsupported type encountered in YAML document: java.net.URL");
this.processor.process((properties, map) -> {});
}
private void setYaml(String yaml) {
this.processor.setResources(new ByteArrayResource(yaml.getBytes()));
}
}
@@ -16,7 +16,7 @@ dependencies {
optional("org.freemarker:freemarker:${freemarkerVersion}")
testCompile(project(":spring-context"))
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
testCompile("org.hibernate:hibernate-validator:6.0.17.Final")
testCompile("org.hibernate:hibernate-validator:6.0.20.Final")
testCompile("javax.annotation:javax.annotation-api:1.3.2")
testRuntime("org.ehcache:jcache:1.0.1")
testRuntime("org.ehcache:ehcache:3.4.0")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -35,6 +35,7 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 4.3
* @see CaffeineCacheManager
*/
public class CaffeineCache extends AbstractValueAdaptingCache {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -34,6 +34,7 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
* @see EhCacheCacheManager
*/
public class EhCacheCache implements Cache {
@@ -95,7 +96,6 @@ public class EhCacheCache implements Cache {
this.cache.releaseWriteLockOnKey(key);
}
}
}
private <T> T loadValue(Object key, Callable<T> valueLoader) {
@@ -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.
@@ -34,6 +34,7 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
* @see EhCacheCache
*/
public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManager {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -36,6 +36,7 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.2
* @see JCacheCacheManager
*/
public class JCacheCache extends AbstractValueAdaptingCache {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -36,6 +36,7 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.2
* @see JCacheCache
*/
public class JCacheCacheManager extends AbstractTransactionSupportingCacheManager {
@@ -88,6 +88,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
return this.cacheOperationSource;
}
@Override
public void afterPropertiesSet() {
getCacheOperationSource();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -110,7 +110,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
public void shutdown() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
/* Quartz 2.2 initialize method */
@Override
public void initialize() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
@@ -138,7 +138,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
public void shutdown() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
/* Quartz 2.2 initialize method */
@Override
public void initialize() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 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.
@@ -82,6 +82,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper {
}
@SuppressWarnings("unchecked")
@Override
public <T> Class<? extends T> loadClass(String name, Class<T> clazz) throws ClassNotFoundException {
return (Class<? extends T>) loadClass(name);
}
+4 -4
View File
@@ -18,17 +18,17 @@ dependencies {
optional("javax.xml.ws:jaxws-api:2.3.1")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy:${groovyVersion}")
optional("org.beanshell:bsh:2.0b5")
optional("joda-time:joda-time:2.10.4")
optional("org.apache-extras.beanshell:bsh:2.0b6")
optional("joda-time:joda-time:2.10.5")
optional("org.hibernate:hibernate-validator:5.4.3.Final")
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
testCompile("org.codehaus.groovy:groovy-jsr223:${groovyVersion}")
testCompile("org.codehaus.groovy:groovy-test:${groovyVersion}")
testCompile("org.codehaus.groovy:groovy-xml:${groovyVersion}")
testCompile("org.apache.commons:commons-pool2:2.6.0")
testCompile("org.apache.commons:commons-pool2:2.6.2")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("org.awaitility:awaitility:3.1.3")
testCompile("org.awaitility:awaitility:3.1.6")
testRuntime("javax.xml.bind:jaxb-api:2.3.1")
testRuntime("org.glassfish:javax.el:3.0.1-b08")
testRuntime("org.javamoney:moneta:1.3")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -191,7 +191,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache {
}
private Object serializeValue(SerializationDelegate serialization, Object storeValue) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
try {
serialization.serialize(storeValue, out);
return out.toByteArray();
@@ -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.
@@ -190,9 +190,7 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
*/
protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256),
isAllowNullValues(), actualSerialization);
return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -52,6 +52,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.util.function.SupplierUtils;
@@ -381,9 +382,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
}
catch (Cache.ValueRetrievalException ex) {
// The invoker wraps any Throwable in a ThrowableWrapper instance so we
// can just make sure that one bubbles up the stack.
throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
// Directly propagate ThrowableWrapper from the invoker,
// or potentially also an IllegalArgumentException etc.
ReflectionUtils.rethrowRuntimeException(ex.getCause());
}
}
else {
@@ -32,7 +32,9 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial")
public class SimpleKey implements Serializable {
/** An empty key. */
/**
* An empty key.
*/
public static final SimpleKey EMPTY = new SimpleKey();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
* @author Costin Leau
* @author Stephane Nicoll
* @since 4.3.4
* @see NoOpCacheManager
*/
public class NoOpCache implements Cache {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -37,7 +37,7 @@ import org.springframework.lang.Nullable;
* @author Costin Leau
* @author Stephane Nicoll
* @since 3.1
* @see CompositeCacheManager
* @see NoOpCache
*/
public class NoOpCacheManager implements CacheManager {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -17,19 +17,21 @@
package org.springframework.context;
/**
* An extension of the {@link Lifecycle} interface for those objects that require to
* be started upon ApplicationContext refresh and/or shutdown in a particular order.
* The {@link #isAutoStartup()} return value indicates whether this object should
* An extension of the {@link Lifecycle} interface for those objects that require
* to be started upon {@code ApplicationContext} refresh and/or shutdown in a
* particular order.
*
* <p>The {@link #isAutoStartup()} return value indicates whether this object should
* be started at the time of a context refresh. The callback-accepting
* {@link #stop(Runnable)} method is useful for objects that have an asynchronous
* shutdown process. Any implementation of this interface <i>must</i> invoke the
* callback's {@code run()} method upon shutdown completion to avoid unnecessary
* delays in the overall ApplicationContext shutdown.
* delays in the overall {@code ApplicationContext} shutdown.
*
* <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's
* return value indicates the phase within which this Lifecycle component should
* be started and stopped. The startup process begins with the <i>lowest</i> phase
* value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
* return value indicates the phase within which this {@code Lifecycle} component
* should be started and stopped. The startup process begins with the <i>lowest</i>
* phase value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
* is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible).
* The shutdown process will apply the reverse order. Any components with the
* same value will be arbitrarily ordered within the same phase.
@@ -44,9 +46,11 @@ package org.springframework.context;
*
* <p>Any {@code Lifecycle} components within the context that do not also
* implement {@code SmartLifecycle} will be treated as if they have a phase
* value of 0. That way a {@code SmartLifecycle} implementation may start
* before those {@code Lifecycle} components if it has a negative phase value,
* or it may start after those components if it has a positive phase value.
* value of {@code 0}. This allows a {@code SmartLifecycle} component to start
* before those {@code Lifecycle} components if the {@code SmartLifecycle}
* component has a negative phase value, or the {@code SmartLifecycle} component
* may start after those {@code Lifecycle} components if the {@code SmartLifecycle}
* component has a positive phase value.
*
* <p>Note that, due to the auto-startup support in {@code SmartLifecycle}, a
* {@code SmartLifecycle} bean instance will usually get initialized on startup
@@ -55,6 +59,7 @@ package org.springframework.context;
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
* @see LifecycleProcessor
* @see ConfigurableApplicationContext
@@ -63,9 +68,10 @@ public interface SmartLifecycle extends Lifecycle, Phased {
/**
* The default phase for {@code SmartLifecycle}: {@code Integer.MAX_VALUE}.
* <p>This is different from the common phase 0 associated with regular
* <p>This is different from the common phase {@code 0} associated with regular
* {@link Lifecycle} implementations, putting the typically auto-started
* {@code SmartLifecycle} beans into a separate later shutdown phase.
* {@code SmartLifecycle} beans into a later startup phase and an earlier
* shutdown phase.
* @since 5.1
* @see #getPhase()
* @see org.springframework.context.support.DefaultLifecycleProcessor#getPhase(Lifecycle)
@@ -115,7 +121,8 @@ public interface SmartLifecycle extends Lifecycle, Phased {
/**
* Return the phase that this lifecycle object is supposed to run in.
* <p>The default implementation returns {@link #DEFAULT_PHASE} in order to
* let stop callbacks execute after regular {@code Lifecycle} implementations.
* let {@code stop()} callbacks execute after regular {@code Lifecycle}
* implementations.
* @see #isAutoStartup()
* @see #start()
* @see #stop(Runnable)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -33,7 +33,8 @@ import org.springframework.core.type.AnnotationMetadata;
*
* @author Chris Beams
* @since 3.1
* @see EnableAspectJAutoProxy
* @see org.springframework.cache.annotation.EnableCaching
* @see org.springframework.transaction.annotation.EnableTransactionManagement
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -29,7 +29,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -386,8 +385,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
for (String type : types) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
if (isCandidateComponent(metadataReader)) {
AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition(
metadataReader.getAnnotationMetadata());
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(metadataReader.getResource());
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Using candidate component class from index: " + type);
@@ -430,7 +429,6 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -344,9 +344,9 @@ import org.springframework.stereotype.Component;
*
* <p>By default, {@code @Bean} methods will be <em>eagerly instantiated</em> at container
* bootstrap time. To avoid this, {@code @Configuration} may be used in conjunction with
* the {@link Lazy @Lazy} annotation to indicate that all {@code @Bean} methods declared within
* the class are by default lazily initialized. Note that {@code @Lazy} may be used on
* individual {@code @Bean} methods as well.
* the {@link Lazy @Lazy} annotation to indicate that all {@code @Bean} methods declared
* within the class are by default lazily initialized. Note that {@code @Lazy} may be used
* on individual {@code @Bean} methods as well.
*
* <h2>Testing support for {@code @Configuration} classes</h2>
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -209,7 +209,6 @@ class ConfigurationClassBeanDefinitionReader {
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
@@ -381,6 +380,7 @@ class ConfigurationClassBeanDefinitionReader {
public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
setResource(configClass.getResource());
setLenientConstructorResolution(false);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -748,8 +748,7 @@ class ConfigurationClassParser {
* @param importSelector the selector to handle
*/
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
configClass, importSelector);
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
@@ -775,7 +774,6 @@ class ConfigurationClassParser {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
@@ -786,8 +784,7 @@ class ConfigurationClassParser {
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
public void register(DeferredImportSelectorHolder deferredImport) {
Class<? extends Group> group = deferredImport.getImportSelector()
.getImportGroup();
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
@@ -799,8 +796,7 @@ class ConfigurationClassParser {
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getMetadata());
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
@@ -818,8 +814,7 @@ class ConfigurationClassParser {
}
private Group createGroup(@Nullable Class<? extends Group> type) {
Class<? extends Group> effectiveType = (type != null ? type
: DefaultDeferredImportSelectorGroup.class);
Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);
Group group = BeanUtils.instantiateClass(effectiveType);
ParserStrategyUtils.invokeAwareMethods(group,
ConfigurationClassParser.this.environment,
@@ -827,7 +822,6 @@ class ConfigurationClassParser {
ConfigurationClassParser.this.registry);
return group;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import java.util.Objects;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
@@ -53,6 +51,7 @@ public interface DeferredImportSelector extends ImportSelector {
/**
* Interface used to group results from different import selectors.
* @since 5.0
*/
interface Group {
@@ -100,7 +99,7 @@ public interface DeferredImportSelector extends ImportSelector {
}
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
@@ -108,13 +107,17 @@ public interface DeferredImportSelector extends ImportSelector {
return false;
}
Entry entry = (Entry) other;
return (Objects.equals(this.metadata, entry.metadata) &&
Objects.equals(this.importClassName, entry.importClassName));
return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));
}
@Override
public int hashCode() {
return Objects.hash(this.metadata, this.importClassName);
return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());
}
@Override
public String toString() {
return this.importClassName;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@@ -50,6 +50,7 @@ public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
@@ -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.
@@ -42,6 +42,7 @@ import org.springframework.util.Assert;
* @see ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoaderAware {
@Nullable
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -50,6 +50,7 @@ import org.springframework.util.StringUtils;
* @see EnableMBeanExport
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, BeanFactoryAware {
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -170,8 +170,11 @@ import org.springframework.core.io.support.PropertySourceFactory;
public @interface PropertySource {
/**
* Indicate the name of this property source. If omitted, a name will
* be generated based on the description of the underlying resource.
* Indicate the name of this property source. If omitted, the {@link #factory()}
* will generate a name based on the underlying resource (in the case of
* {@link org.springframework.core.io.support.DefaultPropertySourceFactory}:
* derived from the resource description through a corresponding name-less
* {@link org.springframework.core.io.support.ResourcePropertySource} constructor).
* @see org.springframework.core.env.PropertySource#getName()
* @see org.springframework.core.io.Resource#getDescription()
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -60,6 +60,7 @@ public class ScannedGenericBeanDefinition extends GenericBeanDefinition implemen
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@@ -53,6 +53,6 @@ public enum ScopedProxyMode {
/**
* Create a class-based proxy (uses CGLIB).
*/
TARGET_CLASS;
TARGET_CLASS
}
@@ -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.
@@ -57,6 +57,19 @@ public class CandidateComponentsIndex {
this.index = parseIndex(content);
}
private static MultiValueMap<String, Entry> parseIndex(List<Properties> content) {
MultiValueMap<String, Entry> index = new LinkedMultiValueMap<>();
for (Properties entry : content) {
entry.forEach((type, values) -> {
String[] stereotypes = ((String) values).split(",");
for (String stereotype : stereotypes) {
index.add(stereotype, new Entry((String) type));
}
});
}
return index;
}
/**
* Return the candidate types that are associated with the specified stereotype.
@@ -76,21 +89,11 @@ public class CandidateComponentsIndex {
return Collections.emptySet();
}
private static MultiValueMap<String, Entry> parseIndex(List<Properties> content) {
MultiValueMap<String, Entry> index = new LinkedMultiValueMap<>();
for (Properties entry : content) {
entry.forEach((type, values) -> {
String[] stereotypes = ((String) values).split(",");
for (String stereotype : stereotypes) {
index.add(stereotype, new Entry((String) type));
}
});
}
return index;
}
private static class Entry {
private final String type;
private final String packageName;
Entry(String type) {
@@ -106,7 +109,6 @@ public class CandidateComponentsIndex {
return this.type.startsWith(basePackage);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -79,6 +79,7 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@@ -835,7 +836,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -72,10 +72,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
/** Bean factory for this context. */
@Nullable
private DefaultListableBeanFactory beanFactory;
/** Synchronization monitor for the internal BeanFactory. */
private final Object beanFactoryMonitor = new Object();
private volatile DefaultListableBeanFactory beanFactory;
/**
@@ -131,9 +128,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
@@ -142,21 +137,19 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
@Override
protected void cancelRefresh(BeansException ex) {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
}
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory != null) {
beanFactory.setSerializationId(null);
}
super.cancelRefresh(ex);
}
@Override
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
this.beanFactory = null;
}
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory != null) {
beanFactory.setSerializationId(null);
this.beanFactory = null;
}
}
@@ -165,20 +158,17 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
* i.e. has been refreshed at least once and not been closed yet.
*/
protected final boolean hasBeanFactory() {
synchronized (this.beanFactoryMonitor) {
return (this.beanFactory != null);
}
return (this.beanFactory != null);
}
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return this.beanFactory;
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return beanFactory;
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -160,8 +160,9 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
/**
* Set the number of seconds to cache loaded properties files.
* <ul>
* <li>Default is "-1", indicating to cache forever (just like
* {@code java.util.ResourceBundle}).
* <li>Default is "-1", indicating to cache forever (matching the default behavior
* of {@code java.util.ResourceBundle}). Note that this constant follows Spring
* conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
* <li>A positive number will cache loaded properties files for the given
* number of seconds. This is essentially the interval between refresh checks.
* Note that a refresh attempt will first check the last-modified timestamp
@@ -184,8 +185,9 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
* Set the number of milliseconds to cache loaded properties files.
* Note that it is common to set seconds instead: {@link #setCacheSeconds}.
* <ul>
* <li>Default is "-1", indicating to cache forever (just like
* {@code java.util.ResourceBundle}).
* <li>Default is "-1", indicating to cache forever (matching the default behavior
* of {@code java.util.ResourceBundle}). Note that this constant follows Spring
* conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
* <li>A positive number will cache loaded properties files for the given
* number of milliseconds. This is essentially the interval between refresh checks.
* Note that a refresh attempt will first check the last-modified timestamp
@@ -225,18 +225,22 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i
// Implementation of the GroovyObject interface
@Override
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
@Override
public MetaClass getMetaClass() {
return this.metaClass;
}
@Override
public Object invokeMethod(String name, Object args) {
return this.metaClass.invokeMethod(this, name, args);
}
@Override
public void setProperty(String property, Object newValue) {
if (newValue instanceof BeanDefinition) {
registerBeanDefinition(property, (BeanDefinition) newValue);
@@ -246,6 +250,7 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i
}
}
@Override
@Nullable
public Object getProperty(String property) {
if (containsBean(property)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -237,6 +237,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
if (mergedHolder != null) {
return mergedHolder;
}
Properties mergedProps = newProperties();
long latestTimestamp = -1;
String[] basenames = StringUtils.toStringArray(getBasenameSet());
@@ -253,6 +254,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
}
}
}
mergedHolder = new PropertiesHolder(mergedProps, latestTimestamp);
PropertiesHolder existing = this.cachedMergedProperties.putIfAbsent(locale, mergedHolder);
if (existing != null) {
@@ -279,18 +281,28 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
return filenames;
}
}
// Filenames for given Locale
List<String> filenames = new ArrayList<>(7);
filenames.addAll(calculateFilenamesForLocale(basename, locale));
if (isFallbackToSystemLocale() && !locale.equals(Locale.getDefault())) {
List<String> fallbackFilenames = calculateFilenamesForLocale(basename, Locale.getDefault());
for (String fallbackFilename : fallbackFilenames) {
if (!filenames.contains(fallbackFilename)) {
// Entry for fallback locale that isn't already in filenames list.
filenames.add(fallbackFilename);
// Filenames for default Locale, if any
if (isFallbackToSystemLocale()) {
Locale defaultLocale = Locale.getDefault();
if (!locale.equals(defaultLocale)) {
List<String> fallbackFilenames = calculateFilenamesForLocale(basename, defaultLocale);
for (String fallbackFilename : fallbackFilenames) {
if (!filenames.contains(fallbackFilename)) {
// Entry for fallback locale that isn't already in filenames list.
filenames.add(fallbackFilename);
}
}
}
}
// Filename for default bundle file
filenames.add(basename);
if (localeMap == null) {
localeMap = new ConcurrentHashMap<>();
Map<Locale, List<String>> existing = this.cachedFilenames.putIfAbsent(basename, localeMap);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -43,6 +43,7 @@ public class StaticMessageSource extends AbstractMessageSource {
@Override
@Nullable
protected String resolveCodeWithoutArguments(String code, Locale locale) {
return this.messages.get(code + '_' + locale.toString());
}
@@ -61,14 +61,13 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
@Override
public void registerFormatters(FormatterRegistry registry) {
addDateConverters(registry);
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
// In order to retain back compatibility we only register Date/Calendar
// types when a user defined formatter is specified (see SPR-10105)
if (this.dateFormatter != null) {
registry.addFormatter(this.dateFormatter);
registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
}
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -31,6 +31,7 @@ import org.springframework.format.Formatter;
* (which is commonly used for HTTP date header values), as of Spring 4.3.
*
* @author Juergen Hoeller
* @author Andrei Nevedomskii
* @since 4.0
* @see java.time.Instant#parse
* @see java.time.format.DateTimeFormatter#ISO_INSTANT
@@ -40,14 +41,14 @@ public class InstantFormatter implements Formatter<Instant> {
@Override
public Instant parse(String text, Locale locale) throws ParseException {
if (text.length() > 0 && Character.isDigit(text.charAt(0))) {
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
return Instant.parse(text);
}
else {
if (text.length() > 0 && Character.isAlphabetic(text.charAt(0))) {
// assuming RFC-1123 value a la "Tue, 3 Jun 2008 11:05:30 GMT"
return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(text));
}
else {
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
return Instant.parse(text);
}
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -207,7 +207,7 @@ public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanI
* configured interfaces and is public, otherwise {@code false}.
*/
private boolean isPublicInInterface(Method method, String beanKey) {
return ((method.getModifiers() & Modifier.PUBLIC) > 0) && isDeclaredInInterface(method, beanKey);
return Modifier.isPublic(method.getModifiers()) && isDeclaredInInterface(method, beanKey);
}
/**
@@ -231,6 +231,7 @@ public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanI
for (Class<?> ifc : ifaces) {
for (Method ifcMethod : ifc.getMethods()) {
if (ifcMethod.getName().equals(method.getName()) &&
ifcMethod.getParameterCount() == method.getParameterCount() &&
Arrays.equals(ifcMethod.getParameterTypes(), method.getParameterTypes())) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -42,6 +42,6 @@ public enum RegistrationPolicy {
* Registration should replace the affected MBean when attempting to register an MBean
* under a name that already exists.
*/
REPLACE_EXISTING;
REPLACE_EXISTING
}
@@ -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.
@@ -158,7 +158,14 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.groovyClassLoader = buildGroovyClassLoader(classLoader);
if (classLoader instanceof GroovyClassLoader &&
(this.compilerConfiguration == null ||
((GroovyClassLoader) classLoader).hasCompatibleConfiguration(this.compilerConfiguration))) {
this.groovyClassLoader = (GroovyClassLoader) classLoader;
}
else {
this.groovyClassLoader = buildGroovyClassLoader(classLoader);
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -50,7 +50,7 @@ import org.springframework.validation.annotation.Validated;
* at the type level of the containing target class, applying to all public service methods
* of that class. By default, JSR-303 will validate against its default group only.
*
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider.
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1+ provider.
*
* @author Juergen Hoeller
* @since 3.1
@@ -87,7 +87,6 @@ public class MethodValidationInterceptor implements MethodInterceptor {
@Override
@SuppressWarnings("unchecked")
public Object invoke(MethodInvocation invocation) throws Throwable {
// Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
@@ -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.
@@ -50,7 +50,7 @@ import org.springframework.validation.annotation.Validated;
* inline constraint annotations. Validation groups can be specified through {@code @Validated}
* as well. By default, JSR-303 will validate against its default group only.
*
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider.
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1+ provider.
*
* @author Juergen Hoeller
* @since 3.1
@@ -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.
@@ -60,7 +60,7 @@ public class CacheReproTests {
@Test
public void spr11124MultipleAnnotations() throws Exception {
public void spr11124MultipleAnnotations() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
Spr11124Service bean = context.getBean(Spr11124Service.class);
bean.single(2);
@@ -71,7 +71,7 @@ public class CacheReproTests {
}
@Test
public void spr11249PrimitiveVarargs() throws Exception {
public void spr11249PrimitiveVarargs() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11249Config.class);
Spr11249Service bean = context.getBean(Spr11249Service.class);
Object result = bean.doSomething("op", 2, 3);
@@ -397,7 +397,6 @@ public class CacheReproTests {
public TestBean insertItem(TestBean item) {
return item;
}
}
@@ -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.
@@ -35,8 +35,7 @@ import static org.junit.Assert.*;
* @author Juergen Hoeller
* @author Stephane Nicoll
*/
public class ConcurrentMapCacheTests
extends AbstractValueAdaptingCacheTests<ConcurrentMapCache> {
public class ConcurrentMapCacheTests extends AbstractValueAdaptingCacheTests<ConcurrentMapCache> {
protected ConcurrentMap<Object, Object> nativeCache;
@@ -48,12 +47,11 @@ public class ConcurrentMapCacheTests
@Before
public void setUp() throws Exception {
public void setup() {
this.nativeCache = new ConcurrentHashMap<>();
this.cache = new ConcurrentMapCache(CACHE_NAME, this.nativeCache, true);
this.nativeCacheNoNull = new ConcurrentHashMap<>();
this.cacheNoNull = new ConcurrentMapCache(CACHE_NAME_NO_NULL,
this.nativeCacheNoNull, false);
this.cacheNoNull = new ConcurrentMapCache(CACHE_NAME_NO_NULL, this.nativeCacheNoNull, false);
this.cache.clear();
}
@@ -72,6 +70,7 @@ public class ConcurrentMapCacheTests
return this.nativeCache;
}
@Test
public void testIsStoreByReferenceByDefault() {
assertFalse(this.cache.isStoreByValue());
@@ -44,7 +44,7 @@ public class SimpleKeyGeneratorTests {
}
@Test
public void singleValue(){
public void singleValue() {
Object k1 = generateKey(new Object[] { "a" });
Object k2 = generateKey(new Object[] { "a" });
Object k3 = generateKey(new Object[] { "different" });
@@ -56,7 +56,7 @@ public class SimpleKeyGeneratorTests {
}
@Test
public void multipleValues() {
public void multipleValues() {
Object k1 = generateKey(new Object[] { "a", 1, "b" });
Object k2 = generateKey(new Object[] { "a", 1, "b" });
Object k3 = generateKey(new Object[] { "b", 1, "a" });
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -28,16 +28,18 @@ import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation2.NamedStubDao2;
import org.springframework.context.index.CandidateComponentsTestClassLoader;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
@@ -102,10 +104,66 @@ public class ClassPathBeanDefinitionScannerTests {
@Test
public void testDoubleScan() {
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
int beanCount = scanner.scan(BASE_PACKAGE);
assertEquals(12, beanCount);
scanner.scan(BASE_PACKAGE);
ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) {
@Override
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
super.postProcessBeanDefinition(beanDefinition, beanName);
beanDefinition.setAttribute("someDifference", "someValue");
}
};
scanner2.scan(BASE_PACKAGE);
assertTrue(context.containsBean("serviceInvocationCounter"));
assertTrue(context.containsBean("fooServiceImpl"));
assertTrue(context.containsBean("stubFooDao"));
assertTrue(context.containsBean("myNamedComponent"));
assertTrue(context.containsBean("myNamedDao"));
assertTrue(context.containsBean("thoreau"));
}
@Test
public void testWithIndex() {
GenericApplicationContext context = new GenericApplicationContext();
context.setClassLoader(CandidateComponentsTestClassLoader.index(
ClassPathScanningCandidateComponentProviderTests.class.getClassLoader(),
new ClassPathResource("spring.components", FooServiceImpl.class)));
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
int beanCount = scanner.scan(BASE_PACKAGE);
assertEquals(12, beanCount);
assertTrue(context.containsBean("serviceInvocationCounter"));
assertTrue(context.containsBean("fooServiceImpl"));
assertTrue(context.containsBean("stubFooDao"));
assertTrue(context.containsBean("myNamedComponent"));
assertTrue(context.containsBean("myNamedDao"));
assertTrue(context.containsBean("thoreau"));
}
@Test
public void testDoubleScanWithIndex() {
GenericApplicationContext context = new GenericApplicationContext();
context.setClassLoader(CandidateComponentsTestClassLoader.index(
ClassPathScanningCandidateComponentProviderTests.class.getClassLoader(),
new ClassPathResource("spring.components", FooServiceImpl.class)));
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
int beanCount = scanner.scan(BASE_PACKAGE);
assertEquals(12, beanCount);
ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) {
@Override
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
super.postProcessBeanDefinition(beanDefinition, beanName);
beanDefinition.setAttribute("someDifference", "someValue");
}
};
scanner2.scan(BASE_PACKAGE);
assertTrue(context.containsBean("serviceInvocationCounter"));
assertTrue(context.containsBean("fooServiceImpl"));
@@ -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.
@@ -40,8 +40,8 @@ import example.scannable.sub.BarComponent;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Test;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.componentscan.gh24375.MyComponent;
import org.springframework.context.index.CandidateComponentsTestClassLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
@@ -80,18 +80,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
testDefault(provider, ScannedGenericBeanDefinition.class);
testDefault(provider);
}
@Test
public void defaultsWithIndex() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
testDefault(provider, AnnotatedGenericBeanDefinition.class);
testDefault(provider);
}
private void testDefault(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testDefault(ClassPathScanningCandidateComponentProvider provider) {
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertTrue(containsBeanClass(candidates, DefaultNamedComponent.class));
assertTrue(containsBeanClass(candidates, NamedComponent.class));
@@ -101,7 +100,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
assertTrue(containsBeanClass(candidates, BarComponent.class));
assertEquals(7, candidates.size());
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
assertBeanDefinitionType(candidates);
}
@Test
@@ -109,22 +108,21 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
testAntStyle(provider, ScannedGenericBeanDefinition.class);
testAntStyle(provider);
}
@Test
public void antStylePackageWithIndex() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
testAntStyle(provider, AnnotatedGenericBeanDefinition.class);
testAntStyle(provider);
}
private void testAntStyle(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testAntStyle(ClassPathScanningCandidateComponentProvider provider) {
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE + ".**.sub");
assertTrue(containsBeanClass(candidates, BarComponent.class));
assertEquals(1, candidates.size());
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
assertBeanDefinitionType(candidates);
}
@Test
@@ -151,7 +149,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
provider.resetFilters(true);
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertBeanDefinitionType(candidates, AnnotatedGenericBeanDefinition.class);
assertBeanDefinitionType(candidates);
}
@Test
@@ -159,20 +157,19 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
testCustomAnnotationTypeIncludeFilter(provider, ScannedGenericBeanDefinition.class);
testCustomAnnotationTypeIncludeFilter(provider);
}
@Test
public void customAnnotationTypeIncludeFilterWithIndex() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
testCustomAnnotationTypeIncludeFilter(provider, AnnotatedGenericBeanDefinition.class);
testCustomAnnotationTypeIncludeFilter(provider);
}
private void testCustomAnnotationTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testCustomAnnotationTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider) {
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
testDefault(provider, expectedBeanDefinitionType);
testDefault(provider);
}
@Test
@@ -180,18 +177,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
testCustomAssignableTypeIncludeFilter(provider, ScannedGenericBeanDefinition.class);
testCustomAssignableTypeIncludeFilter(provider);
}
@Test
public void customAssignableTypeIncludeFilterWithIndex() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
testCustomAssignableTypeIncludeFilter(provider, AnnotatedGenericBeanDefinition.class);
testCustomAssignableTypeIncludeFilter(provider);
}
private void testCustomAssignableTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testCustomAssignableTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider) {
provider.addIncludeFilter(new AssignableTypeFilter(FooService.class));
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
// Interfaces/Abstract class are filtered out automatically.
@@ -199,7 +195,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
assertTrue(containsBeanClass(candidates, FooServiceImpl.class));
assertTrue(containsBeanClass(candidates, ScopedProxyTestBean.class));
assertEquals(3, candidates.size());
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
assertBeanDefinitionType(candidates);
}
@Test
@@ -207,18 +203,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
testCustomSupportedIncludeAndExcludeFilter(provider, ScannedGenericBeanDefinition.class);
testCustomSupportedIncludeAndExcludeFilter(provider);
}
@Test
public void customSupportedIncludeAndExcludeFilterWithIndex() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
testCustomSupportedIncludeAndExcludeFilter(provider, AnnotatedGenericBeanDefinition.class);
testCustomSupportedIncludeAndExcludeFilter(provider);
}
private void testCustomSupportedIncludeAndExcludeFilter(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testCustomSupportedIncludeAndExcludeFilter(ClassPathScanningCandidateComponentProvider provider) {
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
provider.addExcludeFilter(new AnnotationTypeFilter(Service.class));
provider.addExcludeFilter(new AnnotationTypeFilter(Repository.class));
@@ -227,7 +222,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
assertTrue(containsBeanClass(candidates, BarComponent.class));
assertEquals(3, candidates.size());
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
assertBeanDefinitionType(candidates);
}
@Test
@@ -240,7 +235,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertTrue(containsBeanClass(candidates, DefaultNamedComponent.class));
assertEquals(1, candidates.size());
assertBeanDefinitionType(candidates, ScannedGenericBeanDefinition.class);
assertBeanDefinitionType(candidates);
}
@Test
@@ -251,7 +246,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertTrue(containsBeanClass(candidates, StubFooDao.class));
assertEquals(1, candidates.size());
assertBeanDefinitionType(candidates, ScannedGenericBeanDefinition.class);
assertBeanDefinitionType(candidates);
}
@Test
@@ -260,7 +255,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
provider.setResourceLoader(new DefaultResourceLoader(
CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader())));
provider.addExcludeFilter(new RegexPatternTypeFilter(Pattern.compile(TEST_BASE_PACKAGE + ".*Named.*")));
testExclude(provider, ScannedGenericBeanDefinition.class);
testExclude(provider);
}
@Test
@@ -268,18 +263,17 @@ public class ClassPathScanningCandidateComponentProviderTests {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER));
provider.addExcludeFilter(new RegexPatternTypeFilter(Pattern.compile(TEST_BASE_PACKAGE + ".*Named.*")));
testExclude(provider, AnnotatedGenericBeanDefinition.class);
testExclude(provider);
}
private void testExclude(ClassPathScanningCandidateComponentProvider provider,
Class<? extends BeanDefinition> expectedBeanDefinitionType) {
private void testExclude(ClassPathScanningCandidateComponentProvider provider) {
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertTrue(containsBeanClass(candidates, FooServiceImpl.class));
assertTrue(containsBeanClass(candidates, StubFooDao.class));
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
assertTrue(containsBeanClass(candidates, BarComponent.class));
assertEquals(4, candidates.size());
assertBeanDefinitionType(candidates, expectedBeanDefinitionType);
assertBeanDefinitionType(candidates);
}
@Test
@@ -307,7 +301,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
}
@Test
public void testWithAspectAnnotationOnly() throws Exception {
public void testWithAspectAnnotationOnly() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(Aspect.class));
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
@@ -501,6 +495,15 @@ public class ClassPathScanningCandidateComponentProviderTests {
}
}
@Test
public void gh24375() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
Set<BeanDefinition> components = provider.findCandidateComponents(MyComponent.class.getPackage().getName());
assertEquals(1, components.size());
assertEquals(MyComponent.class.getName(), components.iterator().next().getBeanClassName());
}
private boolean containsBeanClass(Set<BeanDefinition> candidates, Class<?> beanClass) {
for (BeanDefinition candidate : candidates) {
if (beanClass.getName().equals(candidate.getBeanClassName())) {
@@ -510,10 +513,9 @@ public class ClassPathScanningCandidateComponentProviderTests {
return false;
}
private void assertBeanDefinitionType(Set<BeanDefinition> candidates,
Class<? extends BeanDefinition> expectedType) {
private void assertBeanDefinitionType(Set<BeanDefinition> candidates) {
candidates.forEach(c -> {
assertThat(c, is(instanceOf(expectedType)));
assertThat(c, is(instanceOf(ScannedGenericBeanDefinition.class)));
});
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -530,9 +530,10 @@ public class ImportSelectorTests {
static Map<String, List<String>> allImports() {
return TestImportGroup.imports.entrySet()
.stream()
.collect(Collectors.toMap((entry) -> entry.getKey().getClassName(),
.collect(Collectors.toMap(entry -> entry.getKey().getClassName(),
Map.Entry::getValue));
}
private final List<Entry> instanceImports = new ArrayList<>();
@Override
@@ -0,0 +1,35 @@
/*
* 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.context.annotation.componentscan.gh24375;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface A {
@AliasFor("value")
B other() default @B;
@AliasFor("other")
B value() default @B;
}
@@ -0,0 +1,29 @@
/*
* 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.context.annotation.componentscan.gh24375;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface B {
String name() default "";
}
@@ -0,0 +1,24 @@
/*
* 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.context.annotation.componentscan.gh24375;
import org.springframework.stereotype.Component;
@Component
@A(other = @B)
public class MyComponent {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -794,6 +794,7 @@ public class AnnotationDrivenEventListenerTests {
@EventListener
@Async
@Override
public void handleAsync(AnotherTestEvent event) {
assertTrue(!Thread.currentThread().getName().equals(event.content));
this.eventCollector.addEvent(this, event);
@@ -820,6 +821,7 @@ public class AnnotationDrivenEventListenerTests {
@EventListener
@Async
@Override
public void handleAsync(AnotherTestEvent event) {
assertTrue(!Thread.currentThread().getName().equals(event.content));
this.eventCollector.addEvent(this, event);
@@ -902,7 +904,6 @@ public class AnnotationDrivenEventListenerTests {
}
@EventListener
@Retention(RetentionPolicy.RUNTIME)
public @interface ConditionalEvent {
@@ -934,18 +935,20 @@ public class AnnotationDrivenEventListenerTests {
super.handle(event);
}
@Override
@EventListener(condition = "#payload.startsWith('OK')")
@Override
public void handleString(String payload) {
super.handleString(payload);
}
@ConditionalEvent("#root.event.timestamp > #p0")
@Override
public void handleTimestamp(Long timestamp) {
collectEvent(timestamp);
}
@ConditionalEvent("@conditionEvaluator.valid(#p0)")
@Override
public void handleRatio(Double ratio) {
collectEvent(ratio);
}
@@ -92,7 +92,7 @@ public class CandidateComponentsIndexLoaderTests {
}
@Test
public void loadIndexNoEntry() throws IOException {
public void loadIndexNoEntry() {
CandidateComponentsIndex index = CandidateComponentsIndexLoader.loadIndex(
CandidateComponentsTestClassLoader.index(getClass().getClassLoader(),
new ClassPathResource("empty-spring.components", getClass())));
@@ -100,7 +100,7 @@ public class CandidateComponentsIndexLoaderTests {
}
@Test
public void loadIndexWithException() throws IOException {
public void loadIndexWithException() {
final IOException cause = new IOException("test exception");
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Unable to load indexes");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -62,7 +62,6 @@ public class StaticMessageSourceTests extends AbstractApplicationContextTests {
@Test
@Override
public void count() {
// These are only checked for current Ctx (not parent ctx)
assertCount(15);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -46,7 +46,7 @@ import static org.junit.Assert.*;
*/
public class DateFormattingTests {
private final FormattingConversionService conversionService = new FormattingConversionService();
private FormattingConversionService conversionService;
private DataBinder binder;
@@ -58,6 +58,7 @@ public class DateFormattingTests {
}
private void setup(DateFormatterRegistrar registrar) {
conversionService = new FormattingConversionService();
DefaultConversionService.addDefaultConverters(conversionService);
registrar.registerFormatters(conversionService);
@@ -148,6 +149,20 @@ public class DateFormattingTests {
assertEquals("10/31/09 1:05", binder.getBindingResult().getFieldValue("dateAnnotatedPattern"));
}
@Test
public void testBindDateAnnotatedPatternWithGlobalFormat() {
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
DateFormatter dateFormatter = new DateFormatter();
dateFormatter.setIso(ISO.DATE_TIME);
registrar.setFormatter(dateFormatter);
setup(registrar);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotatedPattern", "10/31/09 1:05");
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertEquals("10/31/09 1:05", binder.getBindingResult().getFieldValue("dateAnnotatedPattern"));
}
@Test
public void testBindDateTimeOverflow() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
@@ -0,0 +1,121 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.format.datetime.standard;
import java.text.ParseException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.stream.Stream;
import org.junit.Test;
import static java.time.Instant.MAX;
import static java.time.Instant.MIN;
import static java.time.ZoneId.systemDefault;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link InstantFormatter}.
*
* @author Andrei Nevedomskii
* @author Sam Brannen
* @since 5.1.12
*/
public class InstantFormatterTests {
private final InstantFormatter instantFormatter = new InstantFormatter();
@Test
public void should_parse_an_ISO_formatted_string_representation_of_an_Instant() {
new ISOSerializedInstantProvider().provideArguments().forEach(input -> {
try {
Instant expected = DateTimeFormatter.ISO_INSTANT.parse(input, Instant::from);
Instant actual = instantFormatter.parse(input, null);
assertEquals(expected, actual);
}
catch (ParseException ex) {
throw new RuntimeException(ex);
}
});
}
@Test
public void should_parse_an_RFC1123_formatted_string_representation_of_an_Instant() {
new RFC1123SerializedInstantProvider().provideArguments().forEach(input -> {
try {
Instant expected = DateTimeFormatter.RFC_1123_DATE_TIME.parse(input, Instant::from);
Instant actual = instantFormatter.parse(input, null);
assertEquals(expected, actual);
}
catch (ParseException ex) {
throw new RuntimeException(ex);
}
});
}
@Test
public void should_serialize_an_Instant_using_ISO_format_and_ignoring_Locale() {
new RandomInstantProvider().randomInstantStream(MIN, MAX).forEach(instant -> {
String expected = DateTimeFormatter.ISO_INSTANT.format(instant);
String actual = instantFormatter.print(instant, null);
assertEquals(expected, actual);
});
}
private static class RandomInstantProvider {
private static final long DATA_SET_SIZE = 10;
private static final Random random = new Random();
Stream<Instant> randomInstantStream(Instant min, Instant max) {
return Stream.concat(Stream.of(Instant.now()), // make sure that the data set includes current instant
random.longs(min.getEpochSecond(), max.getEpochSecond()).limit(DATA_SET_SIZE).mapToObj(Instant::ofEpochSecond));
}
}
private static class ISOSerializedInstantProvider extends RandomInstantProvider {
Stream<String> provideArguments() {
return randomInstantStream(MIN, MAX).map(DateTimeFormatter.ISO_INSTANT::format);
}
}
private static class RFC1123SerializedInstantProvider extends RandomInstantProvider {
// RFC-1123 supports only 4-digit years
private static final Instant min = Instant.parse("0000-01-01T00:00:00.00Z");
private static final Instant max = Instant.parse("9999-12-31T23:59:59.99Z");
Stream<String> provideArguments() {
return randomInstantStream(min, max)
.map(DateTimeFormatter.RFC_1123_DATE_TIME.withZone(systemDefault())::format);
}
}
}
+2 -2
View File
@@ -79,11 +79,11 @@ dependencies {
optional("io.reactivex.rxjava2:rxjava:${rxjava2Version}")
optional("io.netty:netty-buffer")
testCompile("io.projectreactor:reactor-test")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("javax.annotation:javax.annotation-api:1.3.2")
testCompile("com.google.code.findbugs:jsr305:3.0.2")
testCompile("org.xmlunit:xmlunit-matchers:2.6.2")
testCompile("javax.xml.bind:jaxb-api:2.3.1")
testCompile("com.fasterxml.woodstox:woodstox-core:5.2.0") {
testCompile("com.fasterxml.woodstox:woodstox-core:5.3.0") {
exclude group: "stax", module: "stax-api"
}
}
@@ -336,7 +336,15 @@ public class ReflectUtils {
public static Constructor getConstructor(Class type, Class[] parameterTypes) {
try {
Constructor constructor = type.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
constructor.setAccessible(true);
return null;
});
}
else {
constructor.setAccessible(true);
}
return constructor;
}
catch (NoSuchMethodException e) {
@@ -259,6 +259,9 @@ public class Enhancer extends AbstractClassGenerator {
public void setSuperclass(Class superclass) {
if (superclass != null && superclass.isInterface()) {
setInterfaces(new Class[]{superclass});
// SPRING PATCH BEGIN
setContextClass(superclass);
// SPRING PATCH END
}
else if (superclass != null && superclass.equals(Object.class)) {
// affects choice of ClassLoader
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -169,11 +169,12 @@ public final class GenericTypeResolver {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Class<?>[] generics = new Class<?>[parameterizedType.getActualTypeArguments().length];
Type[] typeArguments = parameterizedType.getActualTypeArguments();
ResolvableType contextType = ResolvableType.forClass(contextClass);
for (int i = 0; i < typeArguments.length; i++) {
Type typeArgument = typeArguments[i];
if (typeArgument instanceof TypeVariable) {
ResolvableType resolvedTypeArgument = resolveVariable(
(TypeVariable<?>) typeArgument, ResolvableType.forClass(contextClass));
(TypeVariable<?>) typeArgument, contextType);
if (resolvedTypeArgument != ResolvableType.NONE) {
generics[i] = resolvedTypeArgument.resolve();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@@ -18,9 +18,6 @@ package org.springframework.core;
import java.lang.annotation.Annotation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@@ -34,8 +31,6 @@ import org.springframework.util.ClassUtils;
@SuppressWarnings("unchecked")
public abstract class KotlinDetector {
private static final Log logger = LogFactory.getLog(KotlinDetector.class);
@Nullable
private static final Class<? extends Annotation> kotlinMetadata;
@@ -53,9 +48,6 @@ public abstract class KotlinDetector {
}
kotlinMetadata = (Class<? extends Annotation>) metadata;
kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
if (kotlinMetadata != null && !kotlinReflectPresent) {
logger.info("Kotlin reflection implementation not found at runtime, related features won't be available.");
}
}
@@ -872,6 +872,12 @@ public class ResolvableType implements Serializable {
return forType(ownerType, this.variableResolver).resolveVariable(variable);
}
}
if (this.type instanceof WildcardType) {
ResolvableType resolved = resolveType().resolveVariable(variable);
if (resolved != null) {
return resolved;
}
}
if (this.variableResolver != null) {
return this.variableResolver.resolveVariable(variable);
}
@@ -982,7 +988,7 @@ public class ResolvableType implements Serializable {
* using the full generic type information for assignability checks.
* For example: {@code ResolvableType.forClass(MyArrayList.class)}.
* @param clazz the class to introspect ({@code null} is semantically
* equivalent to {@code Object.class} for typical use cases here}
* equivalent to {@code Object.class} for typical use cases here)
* @return a {@link ResolvableType} for the specified class
* @see #forClass(Class, Class)
* @see #forClassWithGenerics(Class, Class...)
@@ -997,7 +1003,7 @@ public class ResolvableType implements Serializable {
* {@link Class#isAssignableFrom}, which this serves as a wrapper for.
* For example: {@code ResolvableType.forRawClass(List.class)}.
* @param clazz the class to introspect ({@code null} is semantically
* equivalent to {@code Object.class} for typical use cases here}
* equivalent to {@code Object.class} for typical use cases here)
* @return a {@link ResolvableType} for the specified class
* @since 4.2
* @see #forClass(Class)
@@ -1485,10 +1491,10 @@ public class ResolvableType implements Serializable {
@Override
@Nullable
public ResolvableType resolveVariable(TypeVariable<?> variable) {
TypeVariable<?> variableToCompare = SerializableTypeWrapper.unwrap(variable);
for (int i = 0; i < this.variables.length; i++) {
TypeVariable<?> v1 = SerializableTypeWrapper.unwrap(this.variables[i]);
TypeVariable<?> v2 = SerializableTypeWrapper.unwrap(variable);
if (ObjectUtils.nullSafeEquals(v1, v2)) {
TypeVariable<?> resolvedVariable = SerializableTypeWrapper.unwrap(this.variables[i]);
if (ObjectUtils.nullSafeEquals(resolvedVariable, variableToCompare)) {
return this.generics[i];
}
}
@@ -47,12 +47,40 @@ import org.springframework.util.MimeType;
*/
public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
private int maxInMemorySize = -1;
protected AbstractDataBufferDecoder(MimeType... supportedMimeTypes) {
super(supportedMimeTypes);
}
/**
* Configure a limit on the number of bytes that can be buffered whenever
* the input stream needs to be aggregated. This can be a result of
* decoding to a single {@code DataBuffer},
* {@link java.nio.ByteBuffer ByteBuffer}, {@code byte[]},
* {@link org.springframework.core.io.Resource Resource}, {@code String}, etc.
* It can also occur when splitting the input stream, e.g. delimited text,
* in which case the limit applies to data buffered between delimiters.
* <p>By default in 5.1 this is set to -1, unlimited. In 5.2 the default
* value for this limit is set to 256K.
* @param byteCount the max number of bytes to buffer, or -1 for unlimited
* @since 5.1.11
*/
public void setMaxInMemorySize(int byteCount) {
this.maxInMemorySize = byteCount;
}
/**
* Return the {@link #setMaxInMemorySize configured} byte count limit.
* @since 5.1.11
*/
public int getMaxInMemorySize() {
return this.maxInMemorySize;
}
@Override
public Flux<T> decode(Publisher<DataBuffer> input, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
@@ -64,7 +92,7 @@ public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
public Mono<T> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return DataBufferUtils.join(input)
return DataBufferUtils.join(input, this.maxInMemorySize)
.map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
@@ -25,14 +25,17 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferLimitException;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.core.io.buffer.LimitedDataBufferList;
import org.springframework.core.io.buffer.PooledDataBuffer;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.lang.Nullable;
@@ -92,11 +95,44 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
List<byte[]> delimiterBytes = getDelimiterBytes(mimeType);
Flux<DataBuffer> inputFlux = Flux.from(input)
.flatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes))
.bufferUntil(buffer -> buffer == END_FRAME)
.map(StringDecoder::joinUntilEndFrame)
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
Flux<DataBuffer> inputFlux = Flux.defer(() -> {
if (getMaxInMemorySize() != -1) {
// Passing limiter into endFrameAfterDelimiter helps to ensure that in case of one DataBuffer
// containing multiple lines, the limit is checked and raised immediately without accumulating
// subsequent lines. This is necessary because concatMapIterable doesn't respect doOnDiscard.
// When reactor-core#1925 is resolved, we could replace bufferUntil with:
// .windowUntil(buffer -> buffer instanceof EndFrameBuffer)
// .concatMap(fluxes -> fluxes.collect(() -> new LimitedDataBufferList(getMaxInMemorySize()), LimitedDataBufferList::add))
LimitedDataBufferList limiter = new LimitedDataBufferList(getMaxInMemorySize());
return Flux.from(input)
.concatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes, limiter))
.bufferUntil(buffer -> buffer == END_FRAME)
.map(StringDecoder::joinUntilEndFrame)
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
}
else {
// When the decoder is unlimited (-1), concatMapIterable will cache buffers that may not
// be released if cancel is signalled before they are turned into String lines
// (see test maxInMemoryLimitReleasesUnprocessedLinesWhenUnlimited).
// When reactor-core#1925 is resolved, the workaround can be removed and the entire
// else clause possibly dropped.
ConcatMapIterableDiscardWorkaroundCache cache = new ConcatMapIterableDiscardWorkaroundCache();
return Flux.from(input)
.concatMapIterable(buffer -> cache.addAll(splitOnDelimiter(buffer, delimiterBytes, null)))
.doOnNext(cache)
.doOnCancel(cache)
.bufferUntil(buffer -> buffer == END_FRAME)
.map(StringDecoder::joinUntilEndFrame)
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
}
});
return super.decode(inputFlux, elementType, mimeType, hints);
}
@@ -116,7 +152,9 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
* Split the given data buffer on delimiter boundaries.
* The returned Flux contains an {@link #END_FRAME} buffer after each delimiter.
*/
private List<DataBuffer> splitOnDelimiter(DataBuffer buffer, List<byte[]> delimiterBytes) {
private List<DataBuffer> splitOnDelimiter(
DataBuffer buffer, List<byte[]> delimiterBytes, @Nullable LimitedDataBufferList limiter) {
List<DataBuffer> frames = new ArrayList<>();
try {
do {
@@ -138,15 +176,28 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
buffer.readPosition(readPosition + length + matchingDelimiter.length);
frames.add(DataBufferUtils.retain(frame));
frames.add(END_FRAME);
if (limiter != null) {
limiter.add(frame); // enforce the limit
limiter.clear();
}
}
else {
frame = buffer.slice(readPosition, buffer.readableByteCount());
buffer.readPosition(readPosition + buffer.readableByteCount());
frames.add(DataBufferUtils.retain(frame));
if (limiter != null) {
limiter.add(frame);
}
}
}
while (buffer.readableByteCount() > 0);
}
catch (DataBufferLimitException ex) {
if (limiter != null) {
limiter.releaseAndClear();
}
throw ex;
}
catch (Throwable ex) {
for (DataBuffer frame : frames) {
DataBufferUtils.release(frame);
@@ -283,4 +334,33 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
new MimeType("text", "plain", DEFAULT_CHARSET), MimeTypeUtils.ALL);
}
private class ConcatMapIterableDiscardWorkaroundCache implements Consumer<DataBuffer>, Runnable {
private final List<DataBuffer> buffers = new ArrayList<>();
public List<DataBuffer> addAll(List<DataBuffer> buffersToAdd) {
this.buffers.addAll(buffersToAdd);
return buffersToAdd;
}
@Override
public void accept(DataBuffer dataBuffer) {
this.buffers.remove(dataBuffer);
}
@Override
public void run() {
this.buffers.forEach(buffer -> {
try {
DataBufferUtils.release(buffer);
}
catch (Throwable ex) {
// Keep going..
}
});
}
}
}

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