Compare commits

..
245 Commits
Author SHA1 Message Date
Spring Builds 8f4c172734 Release v5.2.22.RELEASE 2022-05-11 07:20:17 +00:00
Juergen Hoeller 9f238c997d Polishing 2022-05-11 08:47:46 +02:00
Juergen Hoeller 50177b1ad3 Refine CachedIntrospectionResults property introspection
Closes gh-28445
2022-05-11 08:42:43 +02:00
rstoyanchev 159a99bbaf Ignore invalid STOMP frame
Closes gh-28444
2022-05-11 07:26:26 +01:00
Spring Builds 41e158c93d Next development version (v5.2.22.BUILD-SNAPSHOT) 2022-04-13 10:32:09 +00:00
Sam Brannen 833e750175 Improve documentation and matching algorithm in data binders 2022-04-13 10:20:41 +02:00
Juergen Hoeller d70054d686 Upgrade to Log4j2 2.17.2 2022-04-08 14:00:06 +02:00
Juergen Hoeller 36e4951b5e Polishing 2022-04-08 13:58:10 +02:00
Juergen Hoeller 87b5080586 Consistent use of getLocalAddr() without DNS lookups in request adapters
Closes gh-28280
2022-04-08 13:57:09 +02:00
Juergen Hoeller 5cbf85a6f8 Avoid return value reference in potentially cached MethodParameter instance
Closes gh-28232

(cherry picked from commit eefdd2c768)
2022-04-08 13:32:12 +02:00
Juergen Hoeller 69c7eb9418 Restore ability to configure setClassLoader methods
Closes gh-28269

(cherry picked from commit 9f91168396)
2022-04-08 13:31:34 +02:00
Juergen Hoeller fb763dd0f4 Consistent fallback in case of fast-class generation failure
Closes gh-28138

(cherry picked from commit 7aed6279a2)
2022-04-08 13:29:07 +02:00
Spring Builds 1b75f393a9 Next development version (v5.2.21.BUILD-SNAPSHOT) 2022-03-31 10:01:20 +00:00
Brian Clozel 996f701a19 Refine PropertyDescriptor filtering
Restrict property paths under `Class` and properties of types
`ClassLoader` or `ProtectionDomain`.
2022-03-31 10:32:41 +02:00
Sam Brannen 90cfde985e Improve diagnostics in SpEL for large array creation
Attempting to create a large array in a SpEL expression can result in
an OutOfMemoryError. Although the JVM recovers from that, the error
message is not very helpful to the user.

This commit improves the diagnostics in SpEL for large array creation
by throwing a SpelEvaluationException with a meaningful error message
in order to improve diagnostics for the user.

Closes gh-28257
2022-03-31 10:25:27 +02:00
Stephane Nicoll 94f52bc94f Upgrade to Artifactory Resource 0.0.17 2022-03-30 13:13:31 +02:00
Stephane Nicoll d4478bafa4 Upgrade Java versions in CI image 2022-03-30 13:12:08 +02:00
Stephane Nicoll 136e6db822 Upgrade Ubuntu version in CI images 2022-03-30 13:11:18 +02:00
Stephane Nicoll 8f1f68377d Upgrade Java versions in CI image 2022-01-27 09:54:40 +01:00
Sam Brannen ce2367a76f Upgrade to Log4j2 2.17.1 2022-01-03 11:33:22 +01:00
Spring Builds acf782347f Next development version (v5.2.20.BUILD-SNAPSHOT) 2021-12-16 09:38:42 +00:00
Stephane Nicoll 1a03ffef62 Upgrade to Log4j2 2.16.0 2021-12-15 09:49:30 +01:00
Juergen Hoeller e954d7fc20 Upgrade to AspectJ 1.9.7, Groovy 2.5.15, BlockHound 1.0.6, SLF4J 1.7.32 2021-12-14 18:19:49 +01:00
Juergen Hoeller ec13a3f1ba Backported clarifications for SchedulerFactoryBean and cache annotations
See gh-27709
See gh-27726
2021-12-14 18:19:17 +01:00
Juergen Hoeller 842f5b354d Declare serialVersionUID on DefaultAopProxyFactory
Closes gh-27784
2021-12-14 18:17:03 +01:00
Juergen Hoeller 67a4b63d42 Avoid NPE against null value from toString call
Closes gh-27782
2021-12-14 18:16:52 +01:00
Juergen Hoeller 354dad615b Avoid early initialization of empty interceptor names
Closes gh-12238
2021-12-14 18:16:35 +01:00
Stephane Nicoll 0668323176 Upgrade to Log4j2 2.15.0 2021-12-10 15:12:57 +01:00
Sam Brannen e03e62c76a Test status quo for null in varargs in SpEL expressions
This commit also points out that `null` supplied as a single value for
a varargs array of type Optional will be kept as `null` instead of being
converted to Optional.empty(); whereas, if more than one value is passed
to such a varargs array a null value will be properly converted to
Optional.empty().

See gh-27719
2021-12-10 11:18:10 +01:00
Rossen Stoyanchev 96a7fc693b Apply LogFormatUtils in more places 2021-12-09 16:07:20 +00:00
Rossen Stoyanchev 50f6db2704 Replace both EOL and control characters 2021-12-08 13:41:45 +00:00
Arjen Poutsma 24ebb5ecd5 Use ByteArrayDecoder in DefaultClientResponse::createException
This commit changes DefaultClientResponse::createException to use
the ByteArrayDecoder, instead of converting to DataBuffers and
turning these into a byte array.

Closes gh-27666
2021-11-10 17:09:55 +01:00
Juergen Hoeller a439a83f34 Polishing 2021-11-09 23:01:46 +01:00
Juergen Hoeller f0de3a9924 Recommend ObjectProvider as alternative to @Lazy for optional dependencies
Closes gh-27649
2021-11-09 23:01:31 +01:00
Stephane Nicoll 17c3976bca Upgrade to Reactor Dysprosium-SR25
Closes gh-27635
2021-11-09 19:40:59 +01:00
Sam Brannen 9c4a33e64c Increase the likelihood that timed tests pass on CI server 2021-11-05 13:29:06 +01:00
Stephane Nicoll dd3ae4e63d Start building against Reactor Dysprosium-SR25 snapshots
See gh-27635
2021-11-04 14:51:52 +01:00
Sam Brannen dfc435d045 Return previous value in UndertowHeadersAdapter's remove() method
Prior to this commit, UndertowHeadersAdapter's remove() method violated
the java.util.Map contract by always returning null.

This commit fixes this by returning the previous list stored under the
specified key, and otherwise returning null if no previous value was
present.

Closes gh-27592
2021-10-22 14:59:57 +02:00
Sam Brannen 78a24c0dd1 Update "Reporting a Vulnerability" link 2021-10-20 14:50:19 +02:00
Sam Brannen 2bec54e7b3 Fix Javadoc in [NamedParameter]JdbcOperations.queryForObject methods
This commit fixes the Javadoc in all queryForObject(...) methods in
JdbcOperations and NamedParameterJdbcOperations regarding what kinds of
exceptions are thrown under which conditions.

Closes gh-27559

(cherry picked from commit 0853baaa3f)
2021-10-19 18:38:17 +02:00
Rossen Stoyanchev 52e2953de9 Fix checkstyle warning
See gh-27569
2021-10-18 17:09:46 +01:00
Rossen Stoyanchev 7b149a68c6 Fix assertion message in DefaultDataBuffer
Closes gh-27567
2021-10-18 16:57:12 +01:00
Smile d1b3b8eaf6 Update Javadoc in DefaultResponseErrorHandler
Closes gh-27569
2021-10-18 16:28:19 +01:00
Spring Builds f94794e5c0 Next development version (v5.2.19.BUILD-SNAPSHOT) 2021-10-14 10:25:19 +00:00
Rossen Stoyanchev 26af506441 DefaultResponseErrorHandler shows full error details
Closes gh-27552
2021-10-13 21:21:38 +01:00
Juergen Hoeller b14a940716 Polishing 2021-10-13 13:00:53 +02:00
Juergen Hoeller 4ecbf6511d Remove dead fallback code 2021-10-13 12:52:38 +02:00
Juergen Hoeller 5b6a32d1b9 Polishing 2021-10-12 16:18:41 +02:00
Juergen Hoeller 263244f637 Avoid expensive isReadable() check during classpath scan
Closes gh-27541
See gh-21372
2021-10-12 16:18:21 +02:00
Juergen Hoeller 3a166ea742 Add efficient existence check to ClassPathResource.isReadable()
Includes reduced isReadable() check in PathResourceLookupFunction, aligned with PathResourceResolver.

Closes gh-27538
See gh-21372
2021-10-12 16:18:09 +02:00
Sam Brannen 6d4dfed772 Introduce test for gh-27499 and polish contribution 2021-10-12 13:19:13 +02:00
Nick 09ef597836 Avoid duplicate JCacheOperationSource bean registration in <cache:annotation-driven />
In our application we use XML context and <cache:annotation-driven />
declaration. Also we disable bean definition duplication by setting
GenericApplicationContext.setAllowBeanDefinitionOverriding(false) in an
ApplicationContextInitializer. This combination leads to a
BeanDefinitionOverrideException because the
DefaultJCacheOperationSource bean is registered twice.

 - once for: parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
 - once for: parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));

This commit refactors JCacheCachingConfigurer.registerCacheAspect(...)
so that the JCacheOperationSource bean is registered only once.

Closes gh-27499
2021-10-12 13:19:13 +02:00
Sam Brannen 50920e1a96 Upgrade to Reactor Dysprosium-SR24
Closes gh-27526
2021-10-12 13:19:13 +02:00
Stephane Nicoll 8c4d1d4d29 Upgrade CI to github-release resource 1.5.5
Closes gh-27460
2021-10-11 16:20:35 +02:00
Rossen Stoyanchev 82f8d0dfd7 Apply value formatting to resolved exceptions 2021-10-11 11:15:59 +01:00
Stephane Nicoll 38f616a8e8 Start building against Reactor Dysprosium-SR23 snapshots
See gh-27526
2021-10-07 08:52:40 +02:00
Rossen Stoyanchev 441c4d5d5c Generalize formatValue
Provide an overload for additional control and compact output.
2021-10-06 21:31:02 +01:00
Sam Brannen 66f4d20fd4 Comment out unused fudgeFactor 2021-10-05 14:22:51 +02:00
Rossen Stoyanchev 2fa44d62b9 ResponseStatusExceptionHandler logs exception message only
No need to log the full exception for a resolved exception, and as the
comment suggests that it mirrors Spring MVC equivalent, which also
logs the message only.
2021-10-05 12:13:39 +01:00
Stephane Nicoll c86ac97267 Upgrade to GitHub Changelog Generator 0.0.7 in CI
Closes gh-27513
2021-10-03 07:10:06 +02:00
Juergen Hoeller fd916baf79 Skip all flaky StopWatch time assertions 2021-10-02 12:09:01 +02:00
Juergen Hoeller 790d56dd18 Backported tests for bean-derived (Auto)Closeable.close() method
See gh-27504
2021-10-01 13:47:58 +02:00
Sam Brannen 5a5f118efc Escape closing curly braces in regular expressions for Android support
PR gh-24470 introduced a regression for Android users by no longer
escaping closing curly braces in regular expressions.

This commit therefore partially reverts the changes made in 273812f9c5
for closing curly braces (`}`).

Closes gh27467
2021-10-01 10:56:00 +02:00
Juergen Hoeller edf664c1cf Defensively handle fast class generation failure for individual methods
Includes rethrowing of last actual defineClass exception encountered.

Closes gh-27490
2021-09-30 18:00:10 +02:00
Juergen Hoeller 137bca129f Skip flaky StopWatch time assertions 2021-09-27 17:43:25 +02:00
Juergen Hoeller b01a3aeb6b Fix invalid characters in source files
Closes gh-27475
2021-09-27 17:42:27 +02:00
Juergen Hoeller 195d375964 Polishing 2021-09-24 13:49:48 +02:00
Juergen Hoeller ebd351753f Fix contract violations in ConcurrentReferenceHashMap's EntrySet/Iterator
Closes gh-27454

(cherry picked from commit 208fafa4a3)
2021-09-24 13:41:35 +02:00
Juergen Hoeller 9524ecd5b0 Log rejected listener container tasks at warn level
Closes gh-27451
2021-09-24 13:30:50 +02:00
Spring Builds 9053613a65 Next development version (v5.2.18.BUILD-SNAPSHOT) 2021-09-15 08:10:53 +00:00
Stephane Nicoll 0aa7ba80e1 Migrate to Spring Builds account 2021-09-15 09:07:14 +02:00
Stephane Nicoll 9a05a8846b Fix GitHub credentials to use token rather than password
Closes gh-27403
2021-09-15 08:42:30 +02:00
Juergen Hoeller fb97a126a5 Defensive handling of dimensions nullability 2021-09-14 21:54:42 +02:00
Sam Brannen 1ad5b4fbd6 Support char primitive default values in BeanUtils.instantiateClass()
Closes gh-27390
2021-09-14 16:17:46 +02:00
Sam Brannen 4d1cdf6379 Introduce test for gh-27390 2021-09-14 16:17:36 +02:00
takeaction21 e1ba3e7dbb Support float and double primitive default values in BeanUtils.instantiateClass()
See gh-27390
2021-09-14 16:13:36 +02:00
Rossen Stoyanchev 2b55b9ccd5 Do not log request parameters for multipart requests
Closes gh-27350
2021-09-14 13:41:15 +01:00
Brian Clozel 90bcb2e375 Upgrade to Reactor Dysprosium-SR23
Closes gh-27378
2021-09-14 13:49:51 +02:00
Juergen Hoeller 9ad3464c80 Reduce log statement for non-unique JavaBean property to debug level
Closes gh-27372

(cherry picked from commit 6c17e9375b)
2021-09-13 18:47:27 +02:00
Stephane Nicoll 1954a22c23 Fix bug fix icon in changelog configuration
Closes gh-27385
2021-09-11 00:01:46 +02:00
Brian Clozel bd90c4d0f0 Switch to Reactor Dysprosium SNAPSHOTs
See gh-27378
2021-09-09 19:06:25 +02:00
Juergen Hoeller e31d66cd2b Polishing (backported from 5.3.x) 2021-09-02 23:18:36 +02:00
Juergen Hoeller eb349be1fc Fix Kotlin example for filtering handler functions
Closes gh-27337
2021-09-02 23:08:27 +02:00
Juergen Hoeller 4b3e8619ec Polishing 2021-09-02 22:53:30 +02:00
Juergen Hoeller 50d597eb41 Avoid unnecessary cause initialization in ResponseStatusException
Closes gh-27196
2021-09-02 22:52:14 +02:00
Juergen Hoeller 9c931f669c Convenient configuration of type permissions for XStream 1.4.18
Closes gh-27343

(cherry picked from commit 837301fdb3)
2021-09-02 22:49:09 +02:00
Sam Brannen b7e6169e12 Update copyright date 2021-08-31 09:46:29 +02:00
Inmord 9c204dc475 Polish AbstractAspectJAdvisorFactory
Closes gh-27340
2021-08-31 09:40:28 +02:00
Sam Brannen 21c0e50b33 Document when prepareTestInstance() is invoked by the SpringMethodRule
Closes gh-27305
2021-08-22 16:02:57 +02:00
Sam Brannen cecd2ee2e6 Polishing 2021-08-22 14:40:55 +02:00
Sam Brannen 97a89d6db9 Polish contribution
See gh-27303
2021-08-22 14:39:24 +02:00
Erik van Paassen 10a90d3204 Fix UrlPathHelper#shouldRemoveSemicolonContent() (#27303)
The checkReadOnly() method should only be called from
methods that modify properties to prevent modification
of read-only instances.

Fixes #27256
2021-08-22 14:30:46 +02:00
Sam Brannen ab2a861163 Fix and document CompositeUriComponentsContributor#hasContributors()
Prior to this commit, the hasContributors() method incorrectly returned
false if contributors had been configured.

This commit fixes the logic in hasContributors() and documents it.

Closes #27271
2021-08-18 17:35:50 +02:00
Sam Brannen f56d6ea1fb Avoid StringIndexOutOfBoundsException in WebSocketMessageBrokerStats
Prior to this commit, if the TaskExecutor configured in
WebSocketMessageBrokerStats for the inboundChannelExecutor or
outboundChannelExecutor was not a ThreadPoolTaskExecutor, a
StringIndexOutOfBoundsException was thrown when attempting to parse the
results of invoking toString() on the executor.

The reason is that ThreadPoolTaskExecutor delegates to a
ThreadPoolExecutor whose toString() implementation generates text
containing "pool size = ...", and WebSocketMessageBrokerStats'
getExecutorStatsInfo() method relied on the presence of "pool" in the
text returned from toString().

This commit fixes this bug by ensuring that the text returned from
toString() contains "pool" before parsing the text. If "pool" is not
present in the text, getExecutorStatsInfo() now returns "unknown"
instead of throwing a StringIndexOutOfBoundsException.

Closes gh-27209
2021-07-26 11:50:27 +02:00
Spring Buildmaster 420aa9bef0 Next development version (v5.2.17.BUILD-SNAPSHOT) 2021-07-14 08:00:09 +00:00
Stephane Nicoll 14adefa867 Remove coroutines links until the javadoc publication is fixed
See gh-27169
2021-07-14 07:48:42 +02:00
Juergen Hoeller fe3357d6b9 Polishing (backported) 2021-07-13 19:07:15 +02:00
Juergen Hoeller 11c51d8633 Upgrade to Reactor Dysprosium-SR21
Closes gh-27163
2021-07-13 19:06:22 +02:00
Juergen Hoeller bdbd999619 Make proxyTargetClass=true with introduction advice work for JDK proxy targets
Closes gh-27044

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

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

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

instead of:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This commit fixes this issue.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Closes: gh-25992
2020-10-29 13:36:26 +01:00
11421 changed files with 350522 additions and 689328 deletions
+17
View File
@@ -0,0 +1,17 @@
<!--
!!! For Security Vulnerabilities, please go to https://pivotal.io/security !!!
-->
**Affects:** \<Spring Framework version>
---
<!--
Thanks for taking the time to create an issue. Please read the following:
- Questions should be asked on Stack Overflow.
- For bugs, specify affected versions and explain what you are trying to do.
- For enhancements, provide context and describe the problem.
Issue or Pull Request? Create only one, not both. GitHub treats them as the same.
If unsure, start with an issue, and if you submit a pull request later, the
issue will be closed as superseded.
-->
-6
View File
@@ -1,6 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Community Support
url: https://stackoverflow.com/tags/spring
about: Please ask and answer questions on StackOverflow with the tag `spring`.
-23
View File
@@ -1,23 +0,0 @@
---
name: General
about: Bugs, enhancements, documentation, tasks.
title: ''
labels: ''
assignees: ''
---
<!--
Have you considered asking for help on stackoverflow.com?
** Bug Reports **
Please submit issues against OSS supported versions, see https://spring.io/projects/spring-framework#support
Please provide a minimal sample application that reproduces the problem for faster issue triage.
** Enhancements requests **
Before explaining how you would like things to work,
please describe a concrete use case for this feature and how you have tried to solve this so far.
-->
-83
View File
@@ -1,83 +0,0 @@
name: 'Build'
description: 'Builds the project, optionally publishing it to a local deployment repository'
inputs:
commercial-release-repository-url:
description: 'URL of the release repository'
required: false
commercial-repository-password:
description: 'Password for authentication with the commercial repository'
required: false
commercial-repository-username:
description: 'Username for authentication with the commercial repository'
required: false
commercial-snapshot-repository-url:
description: 'URL of the snapshot repository'
required: false
develocity-access-key:
description: 'Access key for authentication with ge.spring.io'
required: false
java-distribution:
description: 'Java distribution to use'
required: false
default: 'liberica'
java-early-access:
description: 'Whether the Java version is in early access'
required: false
default: 'false'
java-toolchain:
description: 'Whether a Java toolchain should be used'
required: false
default: 'false'
java-version:
description: 'Java version to compile and test with'
required: false
default: '25'
publish:
description: 'Whether to publish artifacts ready for deployment to Artifactory'
required: false
default: 'false'
outputs:
build-scan-url:
description: 'URL, if any, of the build scan produced by the build'
value: ${{ (inputs.publish == 'true' && steps.publish.outputs.build-scan-url) || steps.build.outputs.build-scan-url }}
version:
description: 'Version that was built'
value: ${{ steps.read-version.outputs.version }}
runs:
using: composite
steps:
- name: Prepare Gradle Build
uses: ./.github/actions/prepare-gradle-build
with:
develocity-access-key: ${{ inputs.develocity-access-key }}
java-distribution: ${{ inputs.java-distribution }}
java-early-access: ${{ inputs.java-early-access }}
java-toolchain: ${{ inputs.java-toolchain }}
java-version: ${{ inputs.java-version }}
- name: Build
id: build
if: ${{ inputs.publish == 'false' }}
shell: bash
env:
COMMERCIAL_RELEASE_REPO_URL: ${{ inputs.commercial-release-repository-url }}
COMMERCIAL_REPO_PASSWORD: ${{ inputs.commercial-repository-password }}
COMMERCIAL_REPO_USERNAME: ${{ inputs.commercial-repository-username }}
COMMERCIAL_SNAPSHOT_REPO_URL: ${{ inputs.commercial-snapshot-repository-url }}
run: ./gradlew check antora
- name: Publish
id: publish
if: ${{ inputs.publish == 'true' }}
shell: bash
env:
COMMERCIAL_RELEASE_REPO_URL: ${{ inputs.commercial-release-repository-url }}
COMMERCIAL_REPO_PASSWORD: ${{ inputs.commercial-repository-password }}
COMMERCIAL_REPO_USERNAME: ${{ inputs.commercial-repository-username }}
COMMERCIAL_SNAPSHOT_REPO_URL: ${{ inputs.commercial-snapshot-repository-url }}
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository build publishAllPublicationsToDeploymentRepository
- name: Read Version From gradle.properties
id: read-version
shell: bash
run: |
version=$(sed -n 's/version=\(.*\)/\1/p' gradle.properties)
echo "Version is $version"
echo "version=$version" >> $GITHUB_OUTPUT
@@ -1,34 +0,0 @@
name: Create GitHub Release
description: 'Create the release on GitHub with a changelog'
inputs:
commercial:
description: 'Whether to generate the changelog for the commercial release'
required: true
latest:
description: 'Whether the release is the latest release'
required: false
default: 'false'
milestone:
description: 'Name of the GitHub milestone for which a release will be created'
required: true
pre-release:
description: 'Whether the release is a pre-release (a milestone or release candidate)'
required: false
default: 'false'
token:
description: 'Token to use for authentication with GitHub'
required: true
runs:
using: composite
steps:
- name: Generate Changelog
uses: spring-io/github-changelog-generator@f7d7a87a3e7c627ecb8c26cf086c38ac5a939721 #v0.0.14
with:
config-file: ${{ inputs.commercial && '.github/actions/create-github-release/changelog-generator-commercial.yml' || '.github/actions/create-github-release/changelog-generator-oss.yml' }}
milestone: ${{ inputs.milestone }}
token: ${{ inputs.token }}
- name: Create GitHub Release
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || format('--latest={0}', inputs.latest) }}
@@ -1,33 +0,0 @@
changelog:
repository: spring-projects/spring-framework-commercial
sections:
- title: ":warning: Attention Required"
labels:
- "for: upgrade-attention"
summary:
mode: "member-comment"
config:
prefix: "Attention Required:"
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
contributors:
exclude:
names:
- "bclozel"
- "jhoeller"
- "rstoyanchev"
- "sbrannen"
- "sdeleuze"
- "snicoll"
@@ -1,33 +0,0 @@
changelog:
repository: spring-projects/spring-framework
sections:
- title: ":warning: Attention Required"
labels:
- "for: upgrade-attention"
summary:
mode: "member-comment"
config:
prefix: "Attention Required:"
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
contributors:
exclude:
names:
- "bclozel"
- "jhoeller"
- "rstoyanchev"
- "sbrannen"
- "sdeleuze"
- "snicoll"
@@ -1,53 +0,0 @@
name: Prepare Gradle Build
description: 'Prepares a Gradle build. Sets up Java and Gradle and configures Gradle properties'
inputs:
develocity-access-key:
description: 'Access key for authentication with ge.spring.io'
required: false
java-distribution:
description: 'Java distribution to use'
required: false
default: 'liberica'
java-early-access:
description: 'Whether the Java version is in early access. When true, forces java-distribution to temurin'
required: false
default: 'false'
java-toolchain:
description: 'Whether a Java toolchain should be used'
required: false
default: 'false'
java-version:
description: 'Java version to use for the build'
required: false
default: '25'
runs:
using: composite
steps:
- name: Set Up Java
uses: actions/setup-java@v5
with:
distribution: ${{ inputs.java-early-access == 'true' && 'temurin' || (inputs.java-distribution || 'liberica') }}
java-version: |
${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '25' || '' }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # 6.2.0
with:
cache-provider: basic
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
develocity-token-expiry: 4
- name: Configure Gradle Properties
shell: bash
run: |
echo 'systemProp.user.name=spring-builds+github' >> $GRADLE_USER_HOME/gradle.properties
echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $GRADLE_USER_HOME/gradle.properties
echo 'org.gradle.daemon=false' >> $GRADLE_USER_HOME/gradle.properties
- name: Configure Toolchain Properties
if: ${{ inputs.java-toolchain == 'true' }}
shell: bash
run: |
echo toolchainVersion=${{ inputs.java-version }} >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.auto-detect=false >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.auto-download=false >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.paths=${{ format('$JAVA_HOME_{0}_X64', inputs.java-version) }} >> $GRADLE_USER_HOME/gradle.properties
@@ -1,17 +0,0 @@
name: Print JVM thread dumps
description: 'Prints a thread dump for all running JVMs'
runs:
using: composite
steps:
- if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
for jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem); do
jcmd $jvm_pid Thread.print
done
- if: ${{ runner.os == 'Windows' }}
shell: powershell
run: |
foreach ($jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem)) {
jcmd $jvm_pid Thread.print
}
@@ -1,7 +0,0 @@
name: Build Release
runs:
using: composite
steps:
- name: Build Release
shell: bash
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository publishAllPublicationsToDeploymentRepository
@@ -1,16 +0,0 @@
artifactory:
artifacts:
- pattern: "/**/framework-api-*.zip"
properties:
zip.deployed: "false"
zip.name: "spring-framework"
- pattern: "/**/framework-api-*-docs.zip"
properties:
zip.type: "docs"
- pattern: "/**/framework-api-*-schema.zip"
properties:
zip.type: "schema"
maven-central:
excludes:
- "org/springframework/framework-api/**"
- "org/springframework/framework-docs/**"
@@ -1,7 +0,0 @@
name: Test Release
runs:
using: composite
steps:
- name: Test Release
shell: bash
run: ./gradlew check
@@ -1,39 +0,0 @@
name: Send Notification
description: 'Sends a Google Chat message as a notification of the job''s outcome'
inputs:
build-scan-url:
description: 'URL of the build scan to include in the notification'
required: false
run-name:
description: 'Name of the run to include in the notification'
required: false
default: ${{ format('{0} {1}', github.ref_name, github.job) }}
status:
description: 'Status of the job'
required: true
webhook-url:
description: 'Google Chat Webhook URL'
required: true
runs:
using: composite
steps:
- name: Prepare Variables
shell: bash
run: |
echo "BUILD_SCAN=${{ inputs.build-scan-url == '' && ' [build scan unavailable]' || format(' [<{0}|Build Scan>]', inputs.build-scan-url) }}" >> "$GITHUB_ENV"
echo "RUN_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> "$GITHUB_ENV"
- name: Success Notification
if: ${{ inputs.status == 'success' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was successful ${{ env.BUILD_SCAN }}"}' || true
- name: Failure Notification
if: ${{ inputs.status == 'failure' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<users/all> *<${{ env.RUN_URL }}|${{ inputs.run-name }}> failed* ${{ env.BUILD_SCAN }}"}' || true
- name: Cancel Notification
if: ${{ inputs.status == 'cancelled' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was cancelled"}' || true
-3
View File
@@ -1,3 +0,0 @@
require:
members: false
-18
View File
@@ -1,18 +0,0 @@
workflow:
generator:
project:
java:
versions:
primary: 25
workflows:
release-train:
build:
env:
COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL
test:
env:
COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL
-21
View File
@@ -1,21 +0,0 @@
name: Backport Bot
on:
issues:
types: [labeled]
pull_request:
types: [labeled]
push:
branches:
- '*.x'
jobs:
backport-issue:
permissions:
contents: read
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Create Backport Issue
uses: spring-io/backport-bot@v0.0.3
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,77 +0,0 @@
name: Build and Deploy Snapshot
on:
push:
branches:
- 'main'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-deploy-snapshot:
name: Build and Deploy Snapshot
if: ${{ github.repository == 'spring-projects/spring-framework' || github.repository == 'spring-projects/spring-framework-commercial' }}
runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}
timeout-minutes: 60
steps:
- name: Check Out Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
with:
commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}
commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}
commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}
commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
publish: true
- name: Deploy
uses: spring-io/artifactory-deploy-action@aba148f1541e09adcf5735af90029fac9a6d3083 # v0.0.5
with:
artifact-properties: |
/**/framework-api-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-api-*-docs.zip::zip.type=docs
/**/framework-api-*-schema.zip::zip.type=schema
build-name: ${{ vars.COMMERCIAL && format('spring-framework-commercial-{0}', '7.1.x') || format('spring-framework-{0}', '7.1.x') }}
folder: 'deployment-repository'
project: ${{ vars.COMMERCIAL && 'spring' }}
repository: ${{ vars.COMMERCIAL && 'spring-enterprise-maven-dev-local' || 'libs-snapshot-local' }}
uri: ${{ vars.COMMERCIAL_DEPLOY_REPO_URL || 'https://repo.spring.io' }}
username: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_USERNAME }}
password: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_PASSWORD }}
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Send Notification
if: always()
uses: ./.github/actions/send-notification
with:
build-scan-url: ${{ steps.build-and-publish.outputs.build-scan-url }}
run-name: ${{ format('{0} | Linux | Java 25', github.ref_name) }}
status: ${{ job.status }}
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
trigger-docs-build:
name: Trigger Docs Build
needs: build-and-deploy-snapshot
if: ${{ !vars.COMMERCIAL }} # remove when commercial support
permissions:
actions: write
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Run Deploy Docs Workflow
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }}
verify:
name: Verify
needs: build-and-deploy-snapshot
uses: ./.github/workflows/verify.yml
secrets:
commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}
commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}
google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
with:
version: ${{ needs.build-and-deploy-snapshot.outputs.version }}
-24
View File
@@ -1,24 +0,0 @@
name: Build Pull Request
on: pull_request
permissions:
contents: read
jobs:
build:
name: Build Pull Request
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build
id: build
uses: ./.github/actions/build
- name: Print JVM Thread Dumps When Cancelled
if: cancelled()
uses: ./.github/actions/print-jvm-thread-dumps
- name: Upload Build Reports
if: failure()
uses: actions/upload-artifact@v7
with:
name: build-reports
path: '**/build/reports/'
-61
View File
@@ -1,61 +0,0 @@
name: CI
on:
schedule:
- cron: '30 9 * * *'
permissions:
contents: read
jobs:
ci:
name: '${{ matrix.os.name}} | Java ${{ matrix.java.version}}'
if: ${{ github.repository == 'spring-projects/spring-framework' || github.repository == 'spring-projects/spring-framework-commercial' }}
runs-on: ${{ matrix.os.id }}
timeout-minutes: 60
strategy:
matrix:
os:
- id: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}
name: Linux
java:
- version: 17
toolchain: true
- version: 21
toolchain: true
- version: 25
toolchain: false
- version: 27
toolchain: true
exclude:
- os:
name: Linux
java:
version: 25
steps:
- name: Prepare Windows runner
if: ${{ runner.os == 'Windows' }}
run: |
git config --global core.autocrlf true
git config --global core.longPaths true
Stop-Service -name Docker
- name: Check Out Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build
id: build
uses: ./.github/actions/build
with:
commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}
commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}
commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}
commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
java-early-access: ${{ matrix.java.early-access || 'false' }}
java-distribution: ${{ matrix.java.distribution }}
java-toolchain: ${{ matrix.java.toolchain }}
java-version: ${{ matrix.java.version }}
- name: Send Notification
if: always()
uses: ./.github/actions/send-notification
with:
build-scan-url: ${{ steps.build.outputs.build-scan-url }}
run-name: ${{ format('{0} | {1} | Java {2}', github.ref_name, matrix.os.name, matrix.java.version) }}
status: ${{ job.status }}
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
@@ -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
-39
View File
@@ -1,39 +0,0 @@
name: Release Milestone
on:
push:
tags:
- v7.1.0-M[1-9]
- v7.1.0-RC[1-9]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
trigger-docs-build:
name: Trigger Docs Build
permissions:
actions: write
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Determine Version
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Run Deploy Docs Workflow
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }}
create-github-release:
name: Create GitHub Release
needs:
- trigger-docs-build
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
commercial: ${{ vars.COMMERCIAL }}
milestone: ${{ needs.trigger-docs-build.outputs.version }}
pre-release: true
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
-38
View File
@@ -1,38 +0,0 @@
name: Release
on:
push:
tags:
- v7.1.[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
trigger-docs-build:
name: Trigger Docs Build
permissions:
actions: write
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Determine Version
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Run Deploy Docs Workflow
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }}
create-github-release:
name: Create GitHub Release
needs:
- trigger-docs-build
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
commercial: ${{ vars.COMMERCIAL }}
latest: true
milestone: ${{ needs.trigger-docs-build.outputs.version }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
-93
View File
@@ -1,93 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Build"
run-name: "${{ inputs.callback-ref }} Build"
"on":
workflow_dispatch:
inputs:
callback:
description: "Repository to which a callback should be made upon completion"
required: true
type: "string"
callback-ref:
description: "Ref in the callback repository to which a callback should be made upon completion"
required: true
type: "string"
release-train-maven-repository-url:
description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train"
required: true
type: "string"
permissions:
contents: "read"
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
jobs:
build-release:
name: "Build Release"
runs-on: "ubuntu22-2-8"
steps:
- name: "Prevent Re-runs"
id: "prevent-re-runs"
run: |-
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
echo "Re-runs are prohibited. Use the 'Release Train  Retry' workflow to retry build failures"
exit 1
fi
- name: "Set up Java"
id: "set-up-java"
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
with:
distribution: "liberica"
java-version: "25"
- name: "Check Out Code"
id: "check-out-code"
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
- name: "Build Release"
id: "build-release"
uses: "./.github/actions/release-train-build"
env:
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
- name: "Upload Deployment Repository"
id: "upload-deployment-repository"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
name: "deployment-repository"
path: "deployment-repository/**"
- name: "Upload Deployment Spec"
id: "upload-deployment-spec"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
archive: "false"
if-no-files-found: "ignore"
name: "deployment-spec"
path: ".github/actions/release-train-build/deployment-spec.yml"
- name: "Save Build System Caches"
id: "save-build-system-caches"
uses: "actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
with:
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
path: |-
~/.gradle/caches
~/.gradle/wrapper
- name: "Send Callback"
id: "send-callback"
if: "${{ !cancelled() }}"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run callback \
--repo ${{ inputs.callback }} \
--ref ${{ inputs.callback-ref }} \
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
--field deployment-repository-artifact-identifier=${{ steps.upload-deployment-repository.outputs.artifact-id }} \
--field deployment-spec-artifact-identifier=${{ steps.upload-deployment-spec.outputs.artifact-id }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }} \
--field result=${{ job.status == 'success' && 'built' || 'build-failed' }} \
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
-55
View File
@@ -1,55 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Join"
run-name: "${{ inputs.release-train }} Join"
"on":
workflow_dispatch:
inputs:
deployment-destination:
description: "Destination to which the release should be deployed"
options:
- "Maven Central"
- "Spring Enterprise"
required: true
type: "choice"
release-train:
description: "Release train"
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
description: "Release train repository"
required: true
type: "string"
permissions:
contents: "none"
jobs:
join-release-train:
name: "Join Release Train"
runs-on: "ubuntu-latest"
steps:
- name: "Join Release Train"
id: "join-release-train"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run join \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field commit-hash=${{ github.sha }} \
--field deployment-destination=${{ inputs.deployment-destination == 'Maven Central' && 'maven-central' || 'spring-enterprise' }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
-46
View File
@@ -1,46 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Leave"
run-name: "${{ inputs.release-train }} Leave"
"on":
workflow_dispatch:
inputs:
release-train:
description: "Release train"
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
description: "Release train repository"
required: true
type: "string"
permissions:
contents: "none"
jobs:
leave:
name: "Leave"
runs-on: "ubuntu-latest"
steps:
- name: "Leave"
id: "leave"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run leave \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
-47
View File
@@ -1,47 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Ready"
run-name: "${{ inputs.release-train }} Ready"
"on":
workflow_dispatch:
inputs:
release-train:
description: "Release train"
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
description: "Release train repository"
required: true
type: "string"
permissions:
contents: "none"
jobs:
ready:
name: "Ready"
runs-on: "ubuntu-latest"
steps:
- name: "Ready"
id: "ready"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run ready \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field commit-hash=${{ github.sha }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
-34
View File
@@ -1,34 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Retry"
run-name: "${{ inputs.release-train }} Retry"
"on":
workflow_dispatch:
inputs:
release-train:
description: "Release train"
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
description: "Release train repository"
required: true
type: "string"
permissions:
contents: "none"
jobs:
trigger-retry:
name: "Trigger Retry"
runs-on: "ubuntu-latest"
steps:
- name: "Trigger Retry"
id: "trigger-retry"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run retry \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
-84
View File
@@ -1,84 +0,0 @@
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train Test"
run-name: "${{ inputs.callback-ref }} Test"
"on":
workflow_dispatch:
inputs:
callback:
description: "Repository to which a callback should be made upon completion"
required: true
type: "string"
callback-ref:
description: "Ref in the callback repository to which a callback should be made upon completion"
required: true
type: "string"
release-train-maven-repository-url:
description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train"
required: true
type: "string"
permissions:
contents: "read"
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
jobs:
test-release:
name: "Test Release"
runs-on: "ubuntu22-2-8"
steps:
- name: "Prevent Re-runs"
id: "prevent-re-runs"
run: |-
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
echo "Re-runs are prohibited. Use the 'Release Train  Retry' workflow to retry test failures"
exit 1
fi
- name: "Set up Java"
id: "set-up-java"
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
with:
distribution: "liberica"
java-version: "25"
- name: "Check Out Code"
id: "check-out-code"
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
- name: "Restore Build System Caches"
id: "restore-build-system-caches"
uses: "actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
with:
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
path: |-
~/.gradle/caches
~/.gradle/wrapper
- name: "Test Release"
id: "test-release"
uses: "./.github/actions/release-train-test"
env:
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
- name: "Send Callback"
id: "send-callback"
if: "${{ !cancelled() }}"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run callback \
--repo ${{ inputs.callback }} \
--ref ${{ inputs.callback-ref }} \
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }} \
--field result=${{ job.status == 'success' && 'tested' || 'test-failed' }} \
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: "Upload Build System Reports"
id: "upload-build-system-reports"
if: "${{ failure() }}"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
name: "build-system-reports"
path: "**/build/reports"
@@ -1,37 +0,0 @@
name: Update Antora UI Spring
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions:
pull-requests: write
issues: write
contents: write
jobs:
update-antora-ui-spring:
name: Update on Supported Branches
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
strategy:
matrix:
branch: [ '6.2.x', '7.0.x', 'main' ]
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@5a57bcc6a0da2a1474136cf29571b277850432bc
name: Update
with:
docs-branch: ${{ matrix.branch }}
token: ${{ secrets.GITHUB_TOKEN }}
antora-file-path: 'framework-docs/antora-playbook.yml'
update-antora-ui-spring-docs-build:
name: Update on docs-build
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@5a57bcc6a0da2a1474136cf29571b277850432bc
name: Update
with:
docs-branch: 'docs-build'
token: ${{ secrets.GITHUB_TOKEN }}
-88
View File
@@ -1,88 +0,0 @@
name: Verify
on:
workflow_call:
inputs:
staging:
description: 'Whether the release to verify is in the staging repository'
required: false
default: false
type: boolean
version:
description: 'Version to verify'
required: true
type: string
secrets:
commercial-repository-password:
description: 'Password for authentication with the commercial repository'
required: false
commercial-repository-username:
description: 'Username for authentication with the commercial repository'
required: false
google-chat-webhook-url:
description: 'Google Chat Webhook URL'
required: true
opensource-repository-password:
description: 'Password for authentication with the open-source repository'
required: false
opensource-repository-username:
description: 'Username for authentication with the open-source repository'
required: false
token:
description: 'Token to use for authentication with GitHub'
required: true
permissions:
contents: read
jobs:
verify:
name: Verify
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Check Out Release Verification Tests
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: 'v0.0.3'
repository: spring-projects/spring-framework-release-verification
token: ${{ secrets.token }}
- name: Check Out Send Notification Action
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: send-notification
sparse-checkout: .github/actions/send-notification
- name: Set Up Java
uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: 17
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
with:
cache-provider: basic
cache-read-only: false
- name: Configure Gradle Properties
shell: bash
run: |
mkdir -p $HOME/.gradle
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
- name: Run Release Verification Tests
env:
RVT_COMMERCIAL_REPOSITORY_PASSWORD: ${{ secrets.commercial-repository-password }}
RVT_COMMERCIAL_REPOSITORY_USERNAME: ${{ secrets.commercial-repository-username }}
RVT_OSS_REPOSITORY_PASSWORD: ${{ secrets.opensource-repository-password }}
RVT_OSS_REPOSITORY_USERNAME: ${{ secrets.opensource-repository-username }}
RVT_RELEASE_TYPE: ${{ vars.COMMERCIAL && 'commercial' || 'oss' }}
RVT_STAGING: ${{ inputs.staging }}
RVT_VERSION: ${{ inputs.version }}
run: ./gradlew spring-framework-release-verification-tests:test
- name: Upload Build Reports on Failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: build-reports
path: '**/build/reports/'
- name: Send Notification
if: failure()
uses: ./send-notification/.github/actions/send-notification
with:
run-name: ${{ format('{0} | Verification | {1}', github.ref_name, inputs.version) }}
status: ${{ job.status }}
webhook-url: ${{ secrets.google-chat-webhook-url }}
+15 -33
View File
@@ -1,61 +1,43 @@
# Miscellaneous
*.java.hsp
*.sonarj
*.sw*
.DS_Store
.settings
.springBeans
bin
build.sh
integration-repo
ivy-cache
argfile*
activemq-data/
classes/
.cursor/
# Log files
jxl.log
jmx.log
derby.log
# Gradle artifacts
spring-test/test-output/
.gradle
.gradletasknamecache
argfile*
pom.xml
activemq-data/
classes/
/build
buildSrc/build
/spring-*/build
/framework-*/build
/spring-core/kotlin-coroutines/build
/framework-bom/build
/integration-tests/build
/src/asciidoc/build
spring-test/test-output/
# Maven artifacts
pom.xml
/target/
target/
# Eclipse artifacts, including WTP generated manifests
bin
.classpath
.project
.settings
.springBeans
spring-*/src/main/java/META-INF/MANIFEST.MF
# IntelliJ IDEA artifacts and output dirs
# IDEA artifacts and output dirs
*.iml
*.ipr
*.iws
.idea/*
!.idea/icon.svg
.idea
out
test-output
atlassian-ide-plugin.xml
# VS Code
.vscode/
# Claude artifacts
.claude/*
cached-antora-playbook.yml
node_modules
/.kotlin/
.gradletasknamecache
-52
View File
@@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 510 510" style="enable-background:new 0 0 510 510;" xml:space="preserve">
<style type="text/css">
.st0{fill:#6DB33F;}
</style>
<title>icon-framework</title>
<g id="Layer_2_1_">
<g id="Layer_1-2">
<path class="st0" d="M479.2,162.5c-5.6-34.3-20.5-64.4-43.9-87.8S382,36.5,347.6,30.9C320.1,11.2,288.5,0,255,0
s-65.1,11.2-92.6,30.9C128,36.5,98,51.3,74.7,74.7C50.9,98.4,36.5,128.7,31,162.2C11.2,189.8,0,221.4,0,255s11.2,65.2,31,92.8
c5.5,33.5,19.9,63.8,43.7,87.5c23.3,23.3,53.3,38.2,87.7,43.8C190,498.8,221.5,510,255,510s65-11.2,92.6-30.9
c34.4-5.6,64.4-20.5,87.7-43.8c23.8-23.8,38.1-54.1,43.7-87.5c19.8-27.6,31-59.2,31-92.8S498.8,190,479.2,162.5z M473,224.2
c-0.8,6-1.9,11.9-3.2,17.9c-7.2-22.4-17.1-43.8-29.4-63.8c-5.5-22.8-13.6-44.9-24.4-65.8c22.9,14.8,42.2,32.6,56.7,52.6
C475.7,184.6,475.8,204.6,473,224.2z M444.7,199.6c9.3,17.7,16.6,36.3,21.9,55.6c-5.3,19.3-12.7,37.9-22,55.6
C450.9,274,451,236.4,444.7,199.6L444.7,199.6z M175.4,341.1c6.5-4.5,13.7-7.8,21.3-9.8c32.2-7.5,46.7-9.9,66.3-18.4
c36.8-15.9,74.8-53.3,84.6-94c-16.1,38.8-59.5,70.2-97.9,81.6c-26.2,7.8-79.8,13.6-80.1,13.6l-1.4-1.2
c-30.6-17.4-27-85.8,31.8-104.1c25.7-8,55.9-0.7,83.5-5.4c29.4-5,64.4-24.5,79.9-52c12.3,46.4,26.1,118.5-9.7,160.2
C309.4,363,211.8,318,175.4,341.1z M310.8,444.6c-17.7,9.4-36.5,16.8-55.8,22.1c-19.4-5.3-38.1-12.7-55.8-22.1
C236.1,450.9,273.9,450.9,310.8,444.6z M117.6,392.4c13.1,13.1,27.3,25.1,42.3,35.8c-19-5.9-37.2-13.8-54.5-23.7
c-9.9-17.3-17.8-35.7-23.7-54.7C92.4,365.1,104.5,379.3,117.6,392.4z M81.7,160.1c5.9-19,13.9-37.4,23.7-54.7
c17.3-9.8,35.5-17.8,54.5-23.7c-15.1,10.8-29.2,22.7-42.3,35.8C104.5,130.7,92.4,144.9,81.7,160.1z M149.1,346.4
c-8.5,0.2-15.5-6.5-15.7-15c-0.2-8.5,6.5-15.5,15-15.7c8.5-0.2,15.5,6.5,15.7,15c0,0,0,0.1,0,0.1
C164.2,339.3,157.5,346.2,149.1,346.4L149.1,346.4z M199.2,65.4c17.7-9.4,36.5-16.8,55.8-22.1c19.4,5.3,38.1,12.7,55.8,22.1
C273.9,59.1,236.1,59.1,199.2,65.4L199.2,65.4z M392.4,392.4c13.1-13.1,25.1-27.3,35.9-42.4c-5.9,19-13.9,37.3-23.7,54.5
c-17.3,9.8-35.5,17.7-54.5,23.7C365.2,417.5,379.3,405.5,392.4,392.4L392.4,392.4z M392.4,117.6c-13.1-13.1-27.2-25.1-42.3-35.8
c19,5.9,37.2,13.9,54.5,23.7c9.8,17.3,17.8,35.6,23.7,54.7C417.6,144.9,405.5,130.7,392.4,117.6L392.4,117.6z M430.5,79.5
c19.4,19.3,32.6,43.6,39.3,71.1c-16.2-19.2-36.6-36.2-60.4-50c-13.8-23.8-30.8-44.2-50-60.4C387.1,46.9,411.2,60.1,430.5,79.5
L430.5,79.5z M397.6,94c-20.8-10.7-42.8-18.8-65.6-24.2c-20-12.4-41.5-22.4-63.9-29.6c15.5-3.4,31.3-5.1,47.2-5.2
c10,0,19.9,0.8,29.7,2.3C365.1,51.8,382.8,71.1,397.6,94z M255,6.8c27.6,0,53.8,8,77.4,22.2c-5.6-0.5-11.3-0.7-17.1-0.7
c-20.4,0.1-40.6,2.8-60.3,8.1c-19.7-5.3-39.9-8-60.3-8.1c-5.8,0-11.5,0.2-17.1,0.7C201.2,14.7,227.4,6.8,255,6.8z M165,37.3
c9.8-1.5,19.8-2.3,29.7-2.3c15.9,0.1,31.7,1.8,47.2,5.2C219.5,47.4,198,57.3,178,69.8c-22.7,5.4-44.8,13.6-65.6,24.2
C127.2,71.1,144.9,51.8,165,37.3z M79.5,79.5c19.3-19.3,43.5-32.6,71.1-39.3c-19.2,16.2-36.2,36.6-50,60.4
c-23.7,13.8-44,30.6-60.2,49.8C47,123.4,59.8,99.1,79.5,79.5z M37.4,164.9c14.6-20,33.8-37.7,56.6-52.4
c-10.7,20.9-18.8,43-24.3,65.8c-12.3,20-22.2,41.4-29.4,63.8C34.6,215.4,33.5,189.3,37.4,164.9z M65.4,310.4
c-9.3-17.6-16.6-36.2-21.9-55.4c5.3-19.2,12.6-37.8,21.9-55.4C59.1,236.3,59.1,273.7,65.4,310.4L65.4,310.4z M29.2,332.8
c-14.4-23.7-22.4-50-22.4-77.8s8.1-54.1,22.4-77.8c-2.1,25,0.4,51.3,7.4,77.8C29.5,281.5,27,307.8,29.2,332.8z M40.3,268
c7.2,22.3,17.1,43.7,29.4,63.7c5.5,22.8,13.6,44.9,24.3,65.8c-22.8-14.7-42-32.5-56.6-52.4C33.5,320.7,34.6,294.6,40.3,268z
M79.5,430.5c-19.6-19.6-32.5-43.9-39.1-70.9c16.1,19.1,36.5,36,60.2,49.8c13.8,23.7,30.8,44.2,50,60.4
C122.9,463.1,98.8,449.9,79.5,430.5z M112.5,416c20.8,10.7,42.8,18.8,65.5,24.2c20,12.4,41.5,22.4,63.9,29.6
c-15.5,3.4-31.3,5.1-47.2,5.1c-10,0-19.9-0.8-29.7-2.3C144.9,458.1,127.2,438.9,112.5,416L112.5,416z M255,503.2
c-27.6,0-53.8-8-77.4-22.2c5.6,0.5,11.3,0.7,17.1,0.7c20.4-0.1,40.6-2.8,60.3-8.1c19.7,5.3,39.9,8,60.3,8.1
c5.8,0,11.5-0.2,17.1-0.7C308.8,495.3,282.6,503.2,255,503.2z M345,472.7c-9.8,1.5-19.8,2.3-29.7,2.3c-15.9-0.1-31.7-1.8-47.2-5.1
c22.4-7.2,43.9-17.2,63.9-29.6c22.7-5.4,44.8-13.6,65.6-24.2C382.8,438.9,365.1,458.1,345,472.7z M430.5,430.5
c-19.3,19.3-43.5,32.6-71.1,39.3c19.2-16.2,36.2-36.6,50-60.4c23.7-13.8,44-30.6,60.2-49.8C463.1,386.6,450.1,410.9,430.5,430.5
L430.5,430.5z M472.6,345.1c-14.6,20-33.8,37.7-56.6,52.4c10.7-20.8,18.8-42.8,24.3-65.6c12.3-20,22.2-41.3,29.5-63.7
C475.4,294.7,476.5,320.8,472.6,345.1L472.6,345.1z M473.5,255.3c2.6-9.9,4.7-20,6.1-30.1c2.2-15.7,2.7-31.7,1.4-47.5
c14.2,23.6,22.2,49.8,22.2,77.4s-8.1,54.1-22.4,77.8C482.9,307.9,480.5,281.6,473.5,255.3L473.5,255.3z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

+23
View File
@@ -0,0 +1,23 @@
Juergen Hoeller <jhoeller@pivotal.io> jhoeller <jhoeller@vmware.com>
<jhoeller@pivotal.io> <jhoeller@vmware.com>
<jhoeller@pivotal.io> <jhoeller@gopivotal.com>
<rstoyanchev@pivotal.io> <rstoyanchev@vmware.com>
<rstoyanchev@pivotal.io> <rstoyanchev@gopivotal.com>
<pwebb@pivotal.io> <pwebb@vmware.com>
<pwebb@pivotal.io> <pwebb@gopivotal.com>
<cbeams@pivotal.io> <cbeams@vmware.com>
<cbeams@pivotal.io> <cbeams@gopivotal.com>
<cbeams@pivotal.io> <cbeams@gmail.com>
<apoutsma@pivotal.io> <apoutsma@vmware.com>
<apoutsma@pivotal.io> <apoutsma@gopivotal.com>
<apoutsma@pivotal.io> <poutsma@mac.com>
<ogierke@pivotal.io> <ogierke@vmware.com>
<ogierke@pivotal.io> <ogierke@gopivotal.com>
<dsyer@pivotal.io> <dsyer@vmware.com>
<dsyer@pivotal.io> <dsyer@gopivotal.com>
<dsyer@pivotal.io> <david_syer@hotmail.com>
<aclement@pivotal.io> <aclement@vmware.com>
<aclement@pivotal.io> <aclement@gopivotal.com>
<aclement@pivotal.io> <andrew.clement@gmail.com>
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
-3
View File
@@ -1,3 +0,0 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=25-librca
+44
View File
@@ -0,0 +1,44 @@
= Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open
and welcoming community, we pledge to respect all people who contribute through reporting
issues, posting feature requests, updating documentation, submitting pull requests or
patches, and other activities.
We are committed to making participation in this project a harassment-free experience for
everyone, regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses,
without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
consistently applying these principles to every aspect of managing this project. Project
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
be reviewed and investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
+28 -30
View File
@@ -1,4 +1,4 @@
# Contributing to the Spring Framework
# Contributing to the Spring Framework
First off, thank you for taking the time to contribute! :+1: :tada:
@@ -6,7 +6,7 @@ First off, thank you for taking the time to contribute! :+1: :tada:
* [Code of Conduct](#code-of-conduct)
* [How to Contribute](#how-to-contribute)
* [Ask questions](#ask-questions)
* [Discuss](#discuss)
* [Create an Issue](#create-an-issue)
* [Issue Lifecycle](#issue-lifecycle)
* [Submit a Pull Request](#submit-a-pull-request)
@@ -16,16 +16,17 @@ First off, thank you for taking the time to contribute! :+1: :tada:
### Code of Conduct
This project is governed by the [Spring Code of Conduct](https://github.com/spring-projects/spring-framework#coc-ov-file).
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc).
By participating you are expected to uphold this code.
Please report unacceptable behavior to spring-code-of-conduct@spring.io.
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
### How to Contribute
#### Ask questions
#### Discuss
If you have a question, check Stack Overflow using
[this list of tags](https://stackoverflow.com/questions/tagged/spring+or+spring-mvc+or+spring-aop+or+spring-jdbc+or+spring-transactions+or+spring-annotations+or+spring-jms+or+spring-el+or+spring-test+or+spring+or+spring-remoting+or+spring-orm+or+spring-jmx+or+spring-cache+or+spring-webflux?tab=Newest). Find an existing discussion, or start a new one if necessary.
[this list of tags](https://stackoverflow.com/questions/tagged/spring+or+spring-mvc+or+spring-aop+or+spring-jdbc+or+spring-transactions+or+spring-annotations+or+spring-jms+or+spring-el+or+spring-test+or+spring+or+spring-remoting+or+spring-orm+or+spring-jmx+or+spring-cache+or+spring-webflux?tab=Newest).
Find an existing discussion, or start a new one if necessary.
If you believe there is an issue, search through
[existing issues](https://github.com/spring-projects/spring-framework/issues) trying a
@@ -38,18 +39,14 @@ decision.
Reporting an issue or making a feature request is a great way to contribute. Your feedback
and the conversations that result from it provide a continuous flow of ideas. However,
before creating a ticket, please take the time to [ask and research](#ask-questions) first.
before creating a ticket, please take the time to [discuss and research](#discuss) first.
If you create an issue after a discussion on Stack Overflow, please provide a description
If creating an issue after a discussion on Stack Overflow, please provide a description
in the issue instead of simply referring to Stack Overflow. The issue tracker is an
important place of record for design discussions and should be self-sufficient.
Once you're ready, create an issue on [GitHub](https://github.com/spring-projects/spring-framework/issues).
Many issues are caused by subtle behavior, typos, and unintended configuration.
Creating a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)
(starting with https://start.spring.io for example) of the problem helps the team
quickly triage your issue and get to the core of the problem.
Once you're ready, create an issue on
[GitHub](https://github.com/spring-projects/spring-framework/issues).
#### Issue Lifecycle
@@ -65,13 +62,17 @@ follow-up reports will need to be created as new issues with a fresh description
#### Submit a Pull Request
1. If you have not previously done so, please sign the
[Contributor License Agreement](https://cla.pivotal.io/sign/spring). You will be reminded
automatically when you submit the PR.
1. Should you create an issue first? No, just create the pull request and use the
description to provide context and motivation, as you would for an issue. If you want
to start a discussion first or have already created an issue, once a pull request is
created, we will close the issue as superseded by the pull request, and the discussion
about the issue will continue under the pull request.
1. Always check out the `main` branch and submit pull requests against it
1. Always check out the `master` branch and submit pull requests against it
(for target version see [settings.gradle](settings.gradle)).
Backports to prior versions will be considered on a case-by-case basis and reflected as
the fix version in the issue tracker.
@@ -81,13 +82,8 @@ multiple edits or corrections of the same logical change. See
[Rewriting History section of Pro Git](https://git-scm.com/book/en/Git-Tools-Rewriting-History)
for an overview of streamlining the commit history.
1. All commits must include a _Signed-off-by_ trailer at the end of each commit message
to indicate that the contributor agrees to the Developer Certificate of Origin.
For additional details, please refer to the blog post
[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring](https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring).
1. Format commit messages using 55 characters for the subject line, 72 characters per line
for the description, followed by the issue fixed, for example, `Closes gh-22276`. See the
for the description, followed by the issue fixed, e.g. `Closes gh-22276`. See the
[Commit Guidelines section of Pro Git](https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines)
for best practices around commit messages, and use `git log` to see some examples.
@@ -120,17 +116,19 @@ source code into your IDE.
The wiki pages
[Code Style](https://github.com/spring-projects/spring-framework/wiki/Code-Style) and
[IntelliJ IDEA Editor Settings](https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings)
define the source file coding standards we use along with some IntelliJ editor settings we customize.
define the source file coding standards we use along with some IDEA editor settings we customize.
### Reference Docs
The reference documentation is authored in [Asciidoctor](https://asciidoctor.org/) format
using [Antora](https://docs.antora.org/antora/latest/). The source files for the documentation
reside in the [framework-docs/modules/ROOT](framework-docs/modules/ROOT) directory. For
trivial changes, you may be able to browse, edit source files, and submit directly from GitHub.
The reference documentation is in the [src/docs/asciidoc](src/docs/asciidoc) directory, in
[Asciidoctor](https://asciidoctor.org/) format. For trivial changes, you may be able to browse,
edit source files, and submit directly from GitHub.
When making changes locally, execute `./gradlew antora` and then browse the results under
`framework-docs/build/site/index.html`.
When making changes locally, execute `./gradlew asciidoctor` and then browse the result under
`build/asciidoc/html5/index.html`.
Asciidoctor also supports live editing. For more details see
[AsciiDoc Tooling](https://docs.asciidoctor.org/asciidoctor/latest/tooling/).
Asciidoctor also supports live editing. For more details read
[Editing AsciiDoc with Live Preview](https://asciidoctor.org/docs/editing-asciidoc-with-live-preview/).
Note that if you choose the
[System Monitor](https://asciidoctor.org/docs/editing-asciidoc-with-live-preview/#using-a-system-monitor)
option, you can find a Guardfile under `src/docs/asciidoc`.
+6 -14
View File
@@ -1,12 +1,12 @@
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=main)](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3Amain) [![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.spring.io/scans?search.rootProjectNames=spring)
# <img src="src/docs/asciidoc/images/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-5.2.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x?groups=Build")
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
Spring provides everything required beyond the Java programming language for creating enterprise applications for a wide range of scenarios and architectures. Please read the [Overview](https://docs.spring.io/spring-framework/reference/overview.html) section of the reference documentation for a more complete introduction.
Spring provides everything required beyond the Java programming language for creating enterprise applications for a wide range of scenarios and architectures. Please read the [Overview](https://docs.spring.io/spring/docs/current/spring-framework-reference/overview.html#spring-introduction) section as reference for a more complete introduction.
## Code of Conduct
This project is governed by the [Spring Code of Conduct](https://github.com/spring-projects/spring-framework/?tab=coc-ov-file#contributor-code-of-conduct). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@spring.io.
This project is governed by the [Spring Code of Conduct](CODE_OF_CONDUCT.adoc). By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
## Access to Binaries
@@ -14,24 +14,16 @@ For access to artifacts or a distribution zip, see the [Spring Framework Artifac
## Documentation
The Spring Framework maintains reference documentation ([published](https://docs.spring.io/spring-framework/reference/) and [source](framework-docs/modules/ROOT)), GitHub [wiki pages](https://github.com/spring-projects/spring-framework/wiki), and an
The Spring Framework maintains reference documentation ([published](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/) and [source](src/docs/asciidoc)), Github [wiki pages](https://github.com/spring-projects/spring-framework/wiki), and an
[API reference](https://docs.spring.io/spring-framework/docs/current/javadoc-api/). There are also [guides and tutorials](https://spring.io/guides) across Spring projects.
## Micro-Benchmarks
See the [Micro-Benchmarks](https://github.com/spring-projects/spring-framework/wiki/Micro-Benchmarks) wiki page.
## Build from Source
See the [Build from Source](https://github.com/spring-projects/spring-framework/wiki/Build-from-Source) wiki page and the [CONTRIBUTING.md](CONTRIBUTING.md) file.
## Continuous Integration Builds
CI builds are defined with [GitHub Actions workflows](.github/workflows).
See the [Build from Source](https://github.com/spring-projects/spring-framework/wiki/Build-from-Source) Wiki page and the [CONTRIBUTING.md](CONTRIBUTING.md) file.
## Stay in Touch
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on 𝕏. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [releases feed](https://spring.io/blog/category/releases).
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on Twitter. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [news feed](https://spring.io/blog/category/news).
## License
+7 -6
View File
@@ -1,10 +1,11 @@
# Reporting a Vulnerability
# Security Policy
Please, [open a draft security advisory](https://github.com/spring-projects/security-advisories/security/advisories/new) if you need to disclose and discuss a security issue in private with the Spring Framework team. Note that we only accept reports against [supported versions](https://spring.io/projects/spring-framework#support).
## Supported Versions
For more details, check out our [security policy](https://spring.io/security-policy).
Please see the
[Spring Framework Versions](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions)
wiki page.
## JAR signing
## Reporting a Vulnerability
Spring Framework JARs released on Maven Central are signed.
You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt
Please see https://spring.io/security-policy.
+380 -51
View File
@@ -1,25 +1,286 @@
plugins {
id 'io.freefair.aspectj' version '8.13.1' apply false
// kotlinVersion is managed in gradle.properties
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka'
id 'com.github.bjornvester.xjc' version '1.9.1' apply false
id 'com.gradleup.shadow' version "9.2.2" apply false
id 'me.champeau.jmh' version '0.7.2' apply false
id 'io.spring.nullability' version '0.0.15' apply false
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.ge.conventions' version '0.0.7'
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id "io.freefair.aspectj" version '4.1.6' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false
id 'org.asciidoctor.jvm.convert' version '2.4.0'
id 'org.asciidoctor.jvm.pdf' version '2.4.0'
id "com.github.ben-manes.versions" version '0.28.0'
id 'com.gradle.build-scan' version '3.2'
id 'de.undercouch.download' version '4.1.1'
}
apply from: "$rootDir/gradle/build-scan-user-data.gradle"
ext {
moduleProjects = subprojects.findAll { it.name.startsWith("spring-") }
javaProjects = subprojects.findAll { !it.name.startsWith("framework-") }
javaProjects = subprojects - project(":framework-bom")
withoutJclOverSlf4j = {
exclude group: "org.slf4j", name: "jcl-over-slf4j"
}
}
description = "Spring Framework"
configure(allprojects) { project ->
apply plugin: "org.springframework.build.localdev"
apply plugin: "org.springframework.build.repositories"
group = "org.springframework"
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.5"
mavenBom "io.netty:netty-bom:4.1.51.Final"
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR25"
mavenBom "io.rsocket:rsocket-bom:1.0.4"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.31.v20200723"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.72"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.5"
mavenBom "org.junit:junit-bom:5.6.3"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.17.2') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
entry 'log4j-slf4j-impl'
}
dependency "org.slf4j:slf4j-api:1.7.32"
dependency "com.google.code.findbugs:jsr305:3.0.2"
dependencySet(group: 'org.aspectj', version: '1.9.7') {
entry 'aspectjrt'
entry 'aspectjtools'
entry 'aspectjweaver'
}
dependencySet(group: 'org.codehaus.groovy', version: '2.5.15') {
entry 'groovy'
entry 'groovy-jsr223'
entry 'groovy-templates'
entry 'groovy-test'
entry 'groovy-xml'
}
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
dependency "com.caucho:hessian:4.0.63"
dependency "com.fasterxml:aalto-xml:1.2.2"
dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") {
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
dependency "com.google.protobuf:protobuf-java-util:3.11.4"
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
dependency("com.thoughtworks.xstream:xstream:1.4.11.1") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
dependency("org.codehaus.jettison:jettison:1.3.8") {
exclude group: "stax", name: "stax-api"
}
dependencySet(group: 'org.jibx', version: '1.3.3') {
entry 'jibx-bind'
entry 'jibx-run'
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.27"
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.8"
dependency "com.github.librepdf:openpdf:1.3.25"
dependency "com.rometools:rome:1.12.2"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.3"
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
dependencySet(group: 'org.apache.activemq', version: '5.8.0') {
entry 'activemq-broker'
entry('activemq-kahadb-store') {
exclude group: "org.springframework", name: "spring-context"
}
entry 'activemq-stomp'
}
dependency "org.apache.bcel:bcel:6.0"
dependency "org.apache.commons:commons-pool2:2.8.1"
dependencySet(group: 'org.apache.derby', version: '10.14.2.0') {
entry 'derby'
entry 'derbyclient'
}
dependency "org.apache.poi:poi-ooxml:4.1.2"
dependency "org.apache-extras.beanshell:bsh:2.0b6"
dependency "org.freemarker:freemarker:2.3.30"
dependency "org.hsqldb:hsqldb:2.5.1"
dependency "org.quartz-scheduler:quartz:2.3.2"
dependency "org.codehaus.fabric3.api:commonj:1.1.0"
dependency "net.sf.ehcache:ehcache:2.10.6"
dependency "org.ehcache:jcache:1.0.1"
dependency "org.ehcache:ehcache:3.4.0"
dependency "org.hibernate:hibernate-core:5.4.28.Final"
dependency "org.hibernate:hibernate-validator:6.1.7.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.37') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.37') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.0.32.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
}
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_3.1_spec"
exclude group: "org.jboss.spec.javax.annotation", name: "jboss-annotations-api_1.2_spec"
}
}
dependencySet(group: 'com.squareup.okhttp3', version: '3.14.9') {
entry 'okhttp'
entry 'mockwebserver'
}
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
dependency "org.jruby:jruby:9.2.11.1"
dependency "org.python:jython-standalone:2.7.1"
dependency "org.mozilla:rhino:1.7.11"
dependency "commons-fileupload:commons-fileupload:1.4"
dependency "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
dependency("dom4j:dom4j:1.6.1") {
exclude group: "xml-apis", name: "xml-apis"
}
dependency("jaxen:jaxen:1.1.1") {
exclude group: "xml-apis", name: "xml-apis"
exclude group: "xom", name: "xom"
exclude group: "xerces", name: "xercesImpl"
}
dependency("junit:junit:4.12") {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
dependency("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1") {
exclude group: "junit", name: "junit"
}
dependency "org.testng:testng:6.14.3"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.18.1"
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.3.3') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
entry 'mockito-junit-jupiter'
}
dependency "io.mockk:mockk:1.10.2"
dependency("net.sourceforge.htmlunit:htmlunit:2.43.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.43.1") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
exclude group: "commons-logging", name: "commons-logging"
exclude group: "io.netty", name: "netty"
}
dependency "org.skyscreamer:jsonassert:1.5.0"
dependency "com.jayway.jsonpath:json-path:2.4.0"
dependencySet(group: 'org.apache.tiles', version: '3.0.8') {
entry 'tiles-api'
entry('tiles-core', withoutJclOverSlf4j)
entry('tiles-servlet', withoutJclOverSlf4j)
entry('tiles-jsp', withoutJclOverSlf4j)
entry('tiles-el', withoutJclOverSlf4j)
entry('tiles-extras') {
exclude group: "org.springframework", name: "spring-web"
exclude group: "org.slf4j", name: "jcl-over-slf4j"
}
}
dependency("org.apache.taglibs:taglibs-standard-jstlel:1.2.5") {
exclude group: "org.apache.taglibs", name: "taglibs-standard-spec"
}
dependency "com.ibm.websphere:uow:6.0.2.17"
dependency "com.jamonapi:jamon:2.82"
dependency "joda-time:joda-time:2.10.10"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
dependency "org.javamoney:moneta:1.3"
dependency "com.sun.activation:javax.activation:1.2.0"
dependency "com.sun.mail:javax.mail:1.6.2"
dependencySet(group: 'com.sun.xml.bind', version: '2.3.0.1') {
entry 'jaxb-core'
entry 'jaxb-impl'
entry 'jaxb-xjc'
}
dependency "javax.activation:javax.activation-api:1.2.0"
dependency "javax.annotation:javax.annotation-api:1.3.2"
dependency "javax.cache:cache-api:1.1.0"
dependency "javax.ejb:javax.ejb-api:3.2"
dependency "javax.el:javax.el-api:3.0.1-b04"
dependency "javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0"
dependency "javax.faces:javax.faces-api:2.2"
dependency "javax.inject:javax.inject:1"
dependency "javax.inject:javax.inject-tck:1"
dependency "javax.interceptor:javax.interceptor-api:1.2.2"
dependency "javax.jms:javax.jms-api:2.0.1"
dependency "javax.json:javax.json-api:1.1.4"
dependency "javax.json.bind:javax.json.bind-api:1.0"
dependency "javax.mail:javax.mail-api:1.6.2"
dependency "javax.money:money-api:1.0.3"
dependency "javax.resource:javax.resource-api:1.7.1"
dependency "javax.servlet:javax.servlet-api:4.0.1"
dependency "javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02"
dependency "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1"
dependency "javax.transaction:javax.transaction-api:1.3"
dependency "javax.validation:validation-api:2.0.1.Final"
dependency "javax.websocket:javax.websocket-api:1.1"
dependency "javax.xml.bind:jaxb-api:2.3.1"
dependency "javax.xml.ws:jaxws-api:2.3.1"
dependency "org.eclipse.persistence:javax.persistence:2.2.0"
// Substitute for "javax.management:jmxremote_optional:1.0.1_04" which
// is not available on Maven Central
dependency "org.glassfish.external:opendmk_jmxremote_optional_jar:1.0-b01-ea"
dependency "org.glassfish:javax.el:3.0.1-b08"
dependency "org.glassfish.main:javax.jws:4.0-b33"
dependency "org.glassfish.tyrus:tyrus-container-servlet:1.13.1"
}
generatedPomCustomization {
enabled = false
}
resolutionStrategy {
cacheChangingModulesFor 0, "seconds"
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/libs-spring-framework-build" }
}
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor 0, "seconds"
@@ -28,55 +289,123 @@ configure(allprojects) { project ->
}
}
configure(allprojects - project(":framework-platform")) {
configurations {
dependencyManagement {
canBeConsumed = false
canBeResolved = false
visible = false
}
matching { it.name.endsWith("Classpath") }.all { it.extendsFrom(dependencyManagement) }
}
dependencies {
dependencyManagement(enforcedPlatform(dependencies.project(path: ":framework-platform")))
}
}
configure([rootProject] + javaProjects) { project ->
group = "org.springframework"
apply plugin: "java"
apply plugin: "java-test-fixtures"
apply plugin: 'org.springframework.build.conventions'
apply plugin: "checkstyle"
apply plugin: 'org.springframework.build.compile'
apply from: "${rootDir}/gradle/custom-java-home.gradle"
apply from: "${rootDir}/gradle/ide.gradle"
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.junit.platform:junit-platform-suite")
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testImplementation("io.mockk:mockk") {
exclude group: 'junit', module: 'junit'
pluginManager.withPlugin("kotlin") {
apply plugin: "org.jetbrains.dokka"
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = ["-Xjsr305=strict"]
allWarningsAsErrors = true
}
}
testImplementation("org.assertj:assertj-core")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("org.apache.logging.log4j:log4j-core")
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = ["-Xjsr305=strict"]
}
}
}
test {
useJUnitPlatform()
include(["**/*Tests.class", "**/*Test.class"])
systemProperty("java.awt.headless", "true")
systemProperty("testGroups", project.properties.get("testGroups"))
systemProperty("io.netty.leakDetection.level", "paranoid")
}
checkstyle {
toolVersion = "8.38"
configDir = rootProject.file("src/checkstyle")
}
dependencies {
testCompile("org.junit.jupiter:junit-jupiter-api")
testCompile("org.junit.jupiter:junit-jupiter-params")
testCompile("org.mockito:mockito-core")
testCompile("org.mockito:mockito-junit-jupiter")
testCompile("io.mockk:mockk")
testCompile("org.assertj:assertj-core")
// Pull in the latest JUnit 5 Launcher API to ensure proper support in IDEs.
testRuntime("org.junit.platform:junit-platform-launcher")
testRuntime("org.junit.jupiter:junit-jupiter-engine")
testRuntime("org.apache.logging.log4j:log4j-core")
testRuntime("org.apache.logging.log4j:log4j-slf4j-impl")
testRuntime("org.apache.logging.log4j:log4j-jul")
// JSR-305 only used for non-required meta-annotations
compileOnly("com.google.code.findbugs:jsr305")
testCompileOnly("com.google.code.findbugs:jsr305")
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.15")
}
ext.javadocLinks = [
"https://docs.oracle.com/en/java/javase/17/docs/api/",
//"https://jakarta.ee/specifications/platform/11/apidocs/",
"https://docs.hibernate.org/orm/7.2/javadocs/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://hc.apache.org/httpcomponents-client-5.6.x/5.6/httpclient5/apidocs/",
"https://projectreactor.io/docs/core/release/api/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
"https://docs.junit.org/6.1.2/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.4-javadoc/",
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
"https://jspecify.dev/docs/api/"
"https://docs.oracle.com/javase/8/docs/api/",
"https://docs.oracle.com/javaee/7/api/",
"https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"https://www.ibm.com/support/knowledgecenter/SS7JFU_8.5.5/com.ibm.websphere.javadoc.doc/web/apidocs/",
"https://glassfish.java.net/nonav/docs/v3/api/",
"https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"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.quartz-scheduler.org/api/2.3.0/",
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
"https://junit.org/junit4/javadoc/4.12/",
"https://junit.org/junit5/docs/5.6.3/api/"
] as String[]
}
configure(moduleProjects) { project ->
apply from: "${rootDir}/gradle/spring-module.gradle"
}
configure(rootProject) {
description = "Spring Framework"
apply plugin: "groovy"
apply plugin: "kotlin"
apply plugin: "io.spring.nohttp"
apply plugin: 'org.springframework.build.api-diff'
apply from: "${rootDir}/gradle/publications.gradle"
apply from: "${rootDir}/gradle/docs.gradle"
nohttp {
source.exclude "**/test-output/**"
allowlistFile = project.file("src/nohttp/allowlist.lines")
def rootPath = file(rootDir).toPath()
def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/buildSrc"
projectDirs.forEach { dir ->
[ 'bin', 'build', 'out', '.settings' ]
.collect { rootPath.relativize(new File(dir, it).toPath()) }
.forEach { source.exclude "$it/**" }
[ '.classpath', '.project' ]
.collect { rootPath.relativize(new File(dir, it).toPath()) }
.forEach { source.exclude "$it" }
}
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact docsZip
artifact schemaZip
artifact distZip
}
}
}
}
+17 -66
View File
@@ -5,27 +5,19 @@ They are declared in the `build.gradle` file in this folder.
## Build Conventions
The `org.springframework.build.conventions` plugin applies all conventions to the Framework build:
### Compiler conventions
* Configuring the Java compiler, see `JavaConventions`
* Configuring the Kotlin compiler, see `KotlinConventions`
* Configuring testing in the build with `TestConventions`
* Configuring the ArchUnit rules for the project, see `org.springframework.build.architecture.ArchitectureRules`
The `org.springframework.build.compile` plugin applies the Java compiler conventions to the build.
By default, the build compiles sources with Java `1.8` source and target compatibility.
You can test a different source compatibility version on the CLI with a project property like:
This plugin also provides a DSL extension to optionally enable Java preview features for
compiling and testing sources in a module. This can be applied with the following in a
module build file:
```groovy
springFramework {
enableJavaPreviewFeatures = true
}
```
./gradlew test -PjavaSourceVersion=11
```
## Build Plugins
### Optional dependencies
## Optional dependencies
The `org.springframework.build.optional-dependencies` plugin creates a new `optional`
Gradle configuration - it adds the dependencies to the project's compile and runtime classpath
@@ -33,58 +25,17 @@ but doesn't affect the classpath of dependent projects.
This plugin does not provide a `provided` configuration, as the native `compileOnly` and `testCompileOnly`
configurations are preferred.
### MultiRelease Jar
## API Diff
The `org.springframework.build.multiReleaseJar` plugin configures the project with MultiRelease JAR support.
It creates a new SourceSet and dedicated tasks for each Java variant considered.
This can be configured with the DSL, by setting a list of Java variants to configure:
This plugin uses the [Gradle JApiCmp](https://github.com/melix/japicmp-gradle-plugin) plugin
to generate API Diff reports for each Spring Framework module. This plugin is applied once on the root
project and creates tasks in each framework module. Unlike previous versions of this part of the build,
there is no need for checking out a specific tag. The plugin will fetch the JARs we want to compare the
current working version with. You can generate the reports for all modules or a single module:
```groovy
plugins {
id 'org.springframework.build.multiReleaseJar'
}
multiRelease {
releaseVersions 21, 24
}
```
./gradlew apiDiff -PbaselineVersion=5.1.0.RELEASE
./gradlew :spring-core:apiDiff -PbaselineVersion=5.1.0.RELEASE
```
Note, Java classes will be compiled with the toolchain pre-configured by the project, assuming that its
Java language version is equal or higher than all variants we consider. Each compilation task will only
set the "-release" compilation option accordingly to produce the expected bytecode version.
### RuntimeHints Java Agent
The `spring-core-test` project module contributes the `RuntimeHintsAgent` Java agent.
The `RuntimeHintsAgentPlugin` Gradle plugin creates a dedicated `"runtimeHintsTest"` test task for each project.
This task will detect and execute [tests tagged](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-gradle)
with the `"RuntimeHintsTests"` [JUnit tag](https://junit.org/junit5/docs/current/user-guide/#running-tests-tags).
In the Spring Framework test suite, those are usually annotated with the `@EnabledIfRuntimeHintsAgent` annotation.
By default, the agent will instrument all classes located in the `"org.springframework"` package, as they are loaded.
The `RuntimeHintsAgentExtension` allows to customize this using a DSL:
```groovy
// this applies the `RuntimeHintsAgentPlugin` to the project
plugins {
id 'org.springframework.build.runtimehints-agent'
}
// You can configure the agent to include and exclude packages from the instrumentation process.
runtimeHintsAgent {
includedPackages = ["org.springframework", "io.spring"]
excludedPackages = ["org.example"]
}
dependencies {
// to use the test infrastructure, the project should also depend on the "spring-core-test" module
testImplementation(project(":spring-core-test"))
}
```
With this configuration, `./gradlew runtimeHintsTest` will run all tests instrumented by this java agent.
The global `./gradlew check` task depends on `runtimeHintsTest`.
NOTE: the "spring-core-test" module doesn't shade "spring-core" by design, so the agent should never instrument
code that doesn't have "spring-core" on its classpath.
The reports are located under `build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/`.
+8 -50
View File
@@ -1,6 +1,5 @@
plugins {
id 'java-gradle-plugin'
id 'checkstyle'
}
repositories {
@@ -8,65 +7,24 @@ repositories {
gradlePluginPortal()
}
ext {
def propertiesFile = new File(new File("$projectDir").parentFile, "gradle.properties")
propertiesFile.withInputStream {
def properties = new Properties()
properties.load(it)
set("kotlinVersion", properties["kotlinVersion"])
}
}
dependencies {
checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}"
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
implementation "org.jetbrains.dokka:dokka-gradle-plugin:2.2.0"
implementation "com.tngtech.archunit:archunit:1.4.1"
implementation "org.gradle:test-retry-gradle-plugin:1.6.2"
implementation "io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}"
implementation "io.spring.nohttp:nohttp-gradle:0.0.11"
testImplementation("org.assertj:assertj-core:${assertjVersion}")
testImplementation(platform("org.junit:junit-bom:${junitVersion}"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation "me.champeau.gradle:japicmp-gradle-plugin:0.2.8"
implementation "com.google.guava:guava:28.2-jre" // required by japicmp-gradle-plugin
}
gradlePlugin {
plugins {
architecturePlugin {
id = "org.springframework.architecture"
implementationClass = "org.springframework.build.architecture.ArchitecturePlugin"
apiDiffPlugin {
id = "org.springframework.build.api-diff"
implementationClass = "org.springframework.build.api.ApiDiffPlugin"
}
conventionsPlugin {
id = "org.springframework.build.conventions"
implementationClass = "org.springframework.build.ConventionsPlugin"
compileConventionsPlugin {
id = "org.springframework.build.compile"
implementationClass = "org.springframework.build.compile.CompilerConventionsPlugin"
}
localDevPlugin {
id = "org.springframework.build.localdev"
implementationClass = "org.springframework.build.dev.LocalDevelopmentPlugin"
}
multiReleasePlugin {
id = "org.springframework.build.multiReleaseJar"
implementationClass = "org.springframework.build.multirelease.MultiReleaseJarPlugin"
}
repositoriesPlugin {
id = "org.springframework.build.repositories"
implementationClass = "org.springframework.build.RepositoriesPlugin"
}
optionalDependenciesPlugin {
id = "org.springframework.build.optional-dependencies"
implementationClass = "org.springframework.build.optional.OptionalDependenciesPlugin"
}
runtimeHintsAgentPlugin {
id = "org.springframework.build.runtimehints-agent"
implementationClass = "org.springframework.build.hint.RuntimeHintsAgentPlugin"
}
}
}
test {
useJUnitPlatform()
}
jar.dependsOn check
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- Root Checks -->
<module name="io.spring.javaformat.checkstyle.check.SpringHeaderCheck">
<property name="fileExtensions" value="java"/>
<property name="headerType" value="apache2"/>
<property name="headerCopyrightPattern" value="20\d\d-present"/>
<property name="packageInfoHeaderType" value="none"/>
</module>
<module name="com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck"/>
<!-- TreeWalker Checks -->
<module name="TreeWalker">
<!-- Imports -->
<module name="AvoidStarImport"/>
<module name="UnusedImports"/>
<module name="RedundantImport"/>
<!-- Modifiers -->
<module name="com.puppycrawl.tools.checkstyle.checks.modifier.ModifierOrderCheck"/>
</module>
</module>
-3
View File
@@ -1,4 +1 @@
org.gradle.caching=true
assertjVersion=3.27.3
javaFormatVersion=0.0.43
junitVersion=5.12.2
+1
View File
@@ -0,0 +1 @@
apply from: "../gradle/build-cache-settings.gradle"
@@ -1,130 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import io.spring.javaformat.gradle.SpringJavaFormatPlugin;
import io.spring.nohttp.gradle.NoHttpExtension;
import io.spring.nohttp.gradle.NoHttpPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.quality.Checkstyle;
import org.gradle.api.plugins.quality.CheckstyleExtension;
import org.gradle.api.plugins.quality.CheckstylePlugin;
/**
* {@link Plugin} that applies conventions for checkstyle.
*
* @author Brian Clozel
* @author Sam Brannen
*/
public class CheckstyleConventions {
/**
* Applies the Spring Java Format and Checkstyle plugins with the project conventions.
* @param project the current project
*/
public void apply(Project project) {
project.getPlugins().withType(JavaBasePlugin.class, (java) -> {
if (project.getRootProject() == project) {
configureNoHttpPlugin(project);
}
project.getPlugins().apply(CheckstylePlugin.class);
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize()
.set("checkstyleNohttp".equals(checkstyle.getName()) ? "1536m" : "1g"));
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.setToolVersion("14.1.0");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
checkstyleDependencies.add(
project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
});
}
private static void configureNoHttpPlugin(Project project) {
project.getPlugins().apply(NoHttpPlugin.class);
NoHttpExtension noHttp = project.getExtensions().getByType(NoHttpExtension.class);
noHttp.setAllowlistFile(project.file("src/nohttp/allowlist.lines"));
noHttp.getSource().exclude("**/test-output/**", "**/.settings/**", "**/.classpath",
"**/.project", "**/.gradle/**", "**/node_modules/**", "**/spring-jcl/**", "buildSrc/build/**",
".claude/**");
excludeGitIgnoredPaths(project, noHttp);
List<String> buildFolders = List.of("bin", "build", "out");
project.allprojects(subproject -> {
Path rootPath = project.getRootDir().toPath();
Path projectPath = rootPath.relativize(subproject.getProjectDir().toPath());
for (String buildFolder : buildFolders) {
Path innerBuildDir = projectPath.resolve(buildFolder);
noHttp.getSource().exclude(innerBuildDir + File.separator + "**");
}
});
}
/**
* Additionally exclude everything matched by the root {@code .gitignore} file,
* so that new ignored paths (build output, IDE metadata, local git worktrees,
* etc.) are automatically kept out of nohttp scanning without having to
* remember to mirror every {@code .gitignore} change here as well.
* <p>Negated patterns (lines starting with {@code !}) are not supported and are
* simply skipped, since there is no useful Ant-glob equivalent for them here.
*/
private static void excludeGitIgnoredPaths(Project project, NoHttpExtension noHttp) {
File gitignore = project.getRootProject().file(".gitignore");
if (!gitignore.exists()) {
return;
}
try {
for (String line : Files.readAllLines(gitignore.toPath())) {
String pattern = line.strip();
if (pattern.isEmpty() || pattern.startsWith("#") || pattern.startsWith("!")) {
continue;
}
boolean directoryOnly = pattern.endsWith("/");
if (directoryOnly) {
pattern = pattern.substring(0, pattern.length() - 1);
}
// A '/' anywhere but a (now removed) trailing position anchors the
// pattern to the repository root; otherwise it matches at any depth.
boolean anchored = pattern.contains("/");
if (pattern.startsWith("/")) {
pattern = pattern.substring(1);
}
String rootPattern = anchored ? pattern : "**/" + pattern;
if (directoryOnly) {
noHttp.getSource().exclude(rootPattern + "/**");
}
else {
// The pattern may match either a file or a directory, so exclude both.
noHttp.getSource().exclude(rootPattern, rootPattern + "/**");
}
}
}
catch (IOException ex) {
throw new UncheckedIOException("Failed to read .gitignore for nohttp exclusions", ex);
}
}
}
@@ -1,50 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin;
import org.springframework.build.architecture.ArchitecturePlugin;
/**
* Plugin to apply conventions to projects that are part of Spring Framework's build.
* Conventions are applied in response to various plugins being applied.
*
* <p>When the {@link JavaBasePlugin} is applied, the conventions in {@link CheckstyleConventions},
* {@link TestConventions} and {@link JavaConventions} are applied.
* The {@link ArchitecturePlugin} plugin is also applied.
* When the {@link KotlinBasePlugin} is applied, the conventions in {@link KotlinConventions}
* are applied.
*
* @author Brian Clozel
*/
public class ConventionsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getExtensions().create("springFramework", SpringFrameworkExtension.class);
new ArchitecturePlugin().apply(project);
new CheckstyleConventions().apply(project);
new JavaConventions().apply(project);
new KotlinConventions().apply(project);
new TestConventions().apply(project);
}
}
@@ -1,135 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.jvm.toolchain.JavaLanguageVersion;
/**
* {@link Plugin} that applies conventions for compiling Java sources in Spring Framework.
*
* @author Brian Clozel
* @author Sam Brannen
* @author Sebastien Deleuze
*/
public class JavaConventions {
private static final List<String> COMPILER_ARGS;
private static final List<String> TEST_COMPILER_ARGS;
/**
* The Java version we should use as the JVM baseline for building the project.
* <p>NOTE: If you update this value, you should also update the value used in
* the {@code javadoc} task in {@code framework-api.gradle}.
*/
private static final JavaLanguageVersion DEFAULT_LANGUAGE_VERSION = JavaLanguageVersion.of(25);
/**
* The Java version we should use as the baseline for the compiled bytecode
* (the "-release" compiler argument).
*/
private static final JavaLanguageVersion DEFAULT_RELEASE_VERSION = JavaLanguageVersion.of(17);
static {
List<String> commonCompilerArgs = List.of(
"-Xlint:serial", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann",
"-Xlint:divzero", "-Xlint:empty", "-Xlint:finally", "-Xlint:overrides",
"-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try", "-Xlint:-options",
"-parameters"
);
COMPILER_ARGS = new ArrayList<>();
COMPILER_ARGS.addAll(commonCompilerArgs);
COMPILER_ARGS.addAll(List.of(
"-Xlint:varargs", "-Xlint:fallthrough", "-Xlint:rawtypes", "-Xlint:deprecation",
"-Xlint:unchecked", "-Werror"
));
TEST_COMPILER_ARGS = new ArrayList<>();
TEST_COMPILER_ARGS.addAll(commonCompilerArgs);
TEST_COMPILER_ARGS.addAll(List.of("-Xlint:-varargs", "-Xlint:-fallthrough", "-Xlint:-rawtypes",
"-Xlint:-deprecation", "-Xlint:-unchecked"));
}
public void apply(Project project) {
project.getPlugins().withType(JavaBasePlugin.class, javaPlugin -> {
applyToolchainConventions(project);
applyJavaCompileConventions(project);
});
}
/**
* Configure the Toolchain support for the project.
* @param project the current project
*/
private static void applyToolchainConventions(Project project) {
project.getExtensions().getByType(JavaPluginExtension.class).toolchain(toolchain -> {
toolchain.getLanguageVersion().set(DEFAULT_LANGUAGE_VERSION);
});
}
/**
* Apply the common Java compiler options for main sources, test fixture sources, and
* test sources.
* @param project the current project
*/
private void applyJavaCompileConventions(Project project) {
project.afterEvaluate(p -> {
p.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_JAVA_TASK_NAME))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
setJavaRelease(compileTask);
});
p.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME)
|| compileTask.getName().equals("compileTestFixturesJava"))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
setJavaRelease(compileTask);
});
});
}
/**
* We should pick the {@link #DEFAULT_RELEASE_VERSION} for all compiled classes,
* unless the current task is compiling multi-release JAR code with a higher version.
*/
private void setJavaRelease(JavaCompile task) {
int defaultVersion = DEFAULT_RELEASE_VERSION.asInt();
int releaseVersion = defaultVersion;
int compilerVersion = task.getJavaCompiler().get().getMetadata().getLanguageVersion().asInt();
for (int version = defaultVersion ; version <= compilerVersion ; version++) {
if (task.getName().contains("Java" + version)) {
releaseVersion = version;
break;
}
}
task.getOptions().getRelease().set(releaseVersion);
}
}
@@ -1,94 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.jetbrains.dokka.gradle.DokkaExtension;
import org.jetbrains.dokka.gradle.DokkaPlugin;
import org.jetbrains.kotlin.gradle.dsl.JvmTarget;
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion;
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile;
/**
* @author Brian Clozel
* @author Sebastien Deleuze
*/
public class KotlinConventions {
void apply(Project project) {
project.getPlugins().withId("org.jetbrains.kotlin.jvm", plugin -> {
project.getTasks().withType(KotlinCompile.class, this::configure);
if (project.getLayout().getProjectDirectory().dir("src/main/kotlin").getAsFile().exists()) {
project.getPlugins().apply(DokkaPlugin.class);
project.getExtensions().configure(DokkaExtension.class, dokka -> configure(project, dokka));
project.project(":framework-api").getDependencies()
.add("dokka", project.getDependencyFactory().createProjectDependency());
}
});
}
private void configure(KotlinCompile compile) {
compile.compilerOptions(options -> {
options.getApiVersion().set(KotlinVersion.KOTLIN_2_2);
options.getLanguageVersion().set(KotlinVersion.KOTLIN_2_2);
options.getJvmTarget().set(JvmTarget.JVM_17);
options.getJavaParameters().set(true);
options.getAllWarningsAsErrors().set(true);
options.getFreeCompilerArgs().addAll(
"-Xsuppress-version-warnings",
"-Xjsr305=strict", // For dependencies using JSR 305
"-opt-in=kotlin.RequiresOptIn",
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
"-Xannotation-default-target=param-property" // Preferred behavior, default with Kotlin language version set to 2.4+, see https://youtrack.jetbrains.com/issue/KT-73255
);
});
}
private void configure(Project project, DokkaExtension dokka) {
dokka.getDokkaSourceSets().forEach(sourceSet -> {
sourceSet.getSourceRoots().setFrom(project.file("src/main/kotlin"));
sourceSet.getClasspath()
.from(project.getExtensions()
.getByType(SourceSetContainer.class)
.getByName(SourceSet.MAIN_SOURCE_SET_NAME)
.getOutput());
var externalDocumentationLinks = sourceSet.getExternalDocumentationLinks();
var springVersion = project.getVersion();
externalDocumentationLinks.register("spring-framework", spec -> {
spec.url("https://docs.spring.io/spring-framework/docs/" + springVersion + "/javadoc-api/");
spec.packageListUrl("https://docs.spring.io/spring-framework/docs/" + springVersion + "/javadoc-api/element-list");
});
externalDocumentationLinks.register("reactor-core", spec ->
spec.url("https://projectreactor.io/docs/core/release/api/"));
externalDocumentationLinks.register("reactive-streams", spec ->
spec.url("https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/"));
externalDocumentationLinks.register("kotlinx-coroutines", spec ->
spec.url("https://kotlinlang.org/api/kotlinx.coroutines/"));
externalDocumentationLinks.register("hamcrest", spec ->
spec.url("https://javadoc.io/doc/org.hamcrest/hamcrest/2.1/"));
externalDocumentationLinks.register("jakarta-servlet", spec -> {
spec.url("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/");
spec.packageListUrl("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/element-list");
});
externalDocumentationLinks.register("rsocket-core", spec ->
spec.url("https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/"));
});
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* Plugin that configures the OSS, commercial and release train repositories in the build.
*
* @author Brian Clozel
*/
public class RepositoriesPlugin implements Plugin <Project> {
@Override
public void apply(Project project) {
configureOssRepositories(project);
configureCommercialRepositories(project);
configureReleaseTrainRepository(project);
}
private void configureOssRepositories(Project project) {
project.getRepositories().mavenCentral();
if (project.getVersion().toString().contains("-")) {
project.getRepositories().maven(repository -> {
repository.setName("spring-oss-milestone");
repository.setUrl("https://repo.spring.io/milestone/");
});
}
if (project.getVersion().toString().endsWith("-SNAPSHOT")) {
project.getRepositories().maven(repository -> {
repository.setName("spring-oss-snapshot");
repository.setUrl("https://repo.spring.io/snapshot/");
});
}
}
private void configureCommercialRepositories(Project project) {
String releaseRepositoryUrl = getEnv("COMMERCIAL_RELEASE_REPO_URL");
if (releaseRepositoryUrl != null) {
project.getRepositories().maven((repository) -> {
repository.setName("spring-commercial-release");
repository.setUrl(releaseRepositoryUrl);
repository.credentials((creds) -> {
creds.setUsername(System.getenv("COMMERCIAL_REPO_USERNAME"));
creds.setPassword(System.getenv("COMMERCIAL_REPO_PASSWORD"));
});
});
}
String snapshotRepositoryUrl = getEnv("COMMERCIAL_SNAPSHOT_REPO_URL");
if (snapshotRepositoryUrl != null && project.getVersion().toString().endsWith("-SNAPSHOT")) {
project.getRepositories().maven((repository) -> {
repository.setName("spring-commercial-snapshot");
repository.setUrl(snapshotRepositoryUrl);
repository.credentials((creds) -> {
creds.setUsername(System.getenv("COMMERCIAL_REPO_USERNAME"));
creds.setPassword(System.getenv("COMMERCIAL_REPO_PASSWORD"));
});
});
}
}
private void configureReleaseTrainRepository(Project project) {
String releaseTrainRepositoryUrl = getEnv("RELEASE_TRAIN_MAVEN_REPOSITORY_URL");
if (releaseTrainRepositoryUrl != null) {
project.getRepositories().maven(repository -> {
repository.setName("spring-release-train");
repository.setUrl(releaseTrainRepositoryUrl);
repository.credentials((creds) -> {
creds.setUsername(System.getenv("RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME"));
creds.setPassword(System.getenv("RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD"));
});
});
}
}
/**
* Returns the environment variable's value, or {@code null} if it is unset or blank.
*/
private static String getEnv(String name) {
String value = System.getenv(name);
return (value != null && !value.isBlank()) ? value : null;
}
}
@@ -1,53 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import java.util.Collections;
import java.util.List;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.process.CommandLineArgumentProvider;
public class SpringFrameworkExtension {
private final Property<Boolean> enableJavaPreviewFeatures;
public SpringFrameworkExtension(Project project) {
this.enableJavaPreviewFeatures = project.getObjects().property(Boolean.class);
project.getTasks().withType(JavaCompile.class).configureEach(javaCompile ->
javaCompile.getOptions().getCompilerArgumentProviders().add(asArgumentProvider()));
project.getTasks().withType(Test.class).configureEach(test ->
test.getJvmArgumentProviders().add(asArgumentProvider()));
}
public Property<Boolean> getEnableJavaPreviewFeatures() {
return this.enableJavaPreviewFeatures;
}
private CommandLineArgumentProvider asArgumentProvider() {
return () -> {
if (getEnableJavaPreviewFeatures().getOrElse(false)) {
return List.of("--enable-preview");
}
return Collections.emptyList();
};
}
}
@@ -1,109 +0,0 @@
/*
* Copyright 2002-present the original author 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.build;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.testing.Test;
import org.gradle.api.tasks.testing.TestFrameworkOptions;
import org.gradle.api.tasks.testing.junitplatform.JUnitPlatformOptions;
import org.gradle.testretry.TestRetryPlugin;
import org.gradle.testretry.TestRetryTaskExtension;
import java.util.Map;
/**
* Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the
* plugin is applied:
* <ul>
* <li>The {@link TestRetryPlugin Test Retry} plugin is applied so that flaky tests
* are retried 3 times when running on the CI server.
* <li>Common test properties are configured
* <li>The ByteBuddy Java agent is configured on test tasks.
* </ul>
*
* @author Brian Clozel
* @author Andy Wilkinson
* @author Sam Brannen
*/
class TestConventions {
void apply(Project project) {
project.getPlugins().withType(JavaBasePlugin.class, (java) -> configureTestConventions(project));
}
private void configureTestConventions(Project project) {
configureByteBuddyAgent(project);
project.getTasks().withType(Test.class,
test -> {
configureTests(project, test);
configureTestRetryPlugin(project, test);
});
}
private void configureTests(Project project, Test test) {
TestFrameworkOptions existingOptions = test.getOptions();
test.useJUnitPlatform(options -> {
if (existingOptions instanceof JUnitPlatformOptions junitPlatformOptions) {
options.copyFrom(junitPlatformOptions);
}
});
test.include("**/*Tests.class", "**/*Test.class");
test.setSystemProperties(Map.of(
"java.awt.headless", "true",
"io.netty.leakDetection.level", "paranoid",
"junit.platform.discovery.issue.severity.critical", "INFO"
));
if (project.hasProperty("testGroups")) {
test.systemProperty("testGroups", project.findProperty("testGroups"));
}
test.jvmArgs(
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"-Xshare:off"
);
}
private void configureByteBuddyAgent(Project project) {
if (project.hasProperty("byteBuddyVersion")) {
String byteBuddyVersion = (String) project.findProperty("byteBuddyVersion");
Configuration byteBuddyAgentConfig = project.getConfigurations().create("byteBuddyAgentConfig");
byteBuddyAgentConfig.setTransitive(false);
Dependency byteBuddyAgent = project.getDependencies().create("net.bytebuddy:byte-buddy-agent:" + byteBuddyVersion);
byteBuddyAgentConfig.getDependencies().add(byteBuddyAgent);
project.afterEvaluate(p -> {
p.getTasks().withType(Test.class, test -> test
.jvmArgs("-javaagent:" + byteBuddyAgentConfig.getAsPath()));
});
}
}
private void configureTestRetryPlugin(Project project, Test test) {
project.getPlugins().withType(TestRetryPlugin.class, testRetryPlugin -> {
TestRetryTaskExtension testRetry = test.getExtensions().getByType(TestRetryTaskExtension.class);
testRetry.getFailOnPassedAfterRetry().set(true);
testRetry.getMaxRetries().set(isCi() ? 3 : 0);
});
}
private boolean isCi() {
return Boolean.parseBoolean(System.getenv("CI"));
}
}
@@ -0,0 +1,115 @@
/*
* 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.build.api;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import me.champeau.gradle.japicmp.JapicmpPlugin;
import me.champeau.gradle.japicmp.JapicmpTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.jvm.tasks.Jar;
/**
* {@link Plugin} that applies the {@code "japicmp-gradle-plugin"}
* and create tasks for all subprojects, diffing the public API one by one
* and creating the reports in {@code "build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/"}.
* <p>{@code "./gradlew apiDiff -PbaselineVersion=5.1.0.RELEASE"} will output the
* reports for the API diff between the baseline version and the current one for all modules.
* You can limit the report to a single module with
* {@code "./gradlew :spring-core:apiDiff -PbaselineVersion=5.1.0.RELEASE"}.
*
* @author Brian Clozel
*/
public class ApiDiffPlugin implements Plugin<Project> {
public static final String TASK_NAME = "apiDiff";
private static final String BASELINE_VERSION_PROPERTY = "baselineVersion";
private static final List<String> PACKAGE_INCLUDES = Collections.singletonList("org.springframework.*");
@Override
public void apply(Project project) {
if (project.hasProperty(BASELINE_VERSION_PROPERTY) && project.equals(project.getRootProject())) {
project.getPluginManager().apply(JapicmpPlugin.class);
project.getPlugins().withType(JapicmpPlugin.class,
plugin -> applyApiDiffConventions(project));
}
}
private void applyApiDiffConventions(Project project) {
String baselineVersion = project.property(BASELINE_VERSION_PROPERTY).toString();
project.subprojects(subProject -> createApiDiffTask(baselineVersion, subProject));
}
private void createApiDiffTask(String baselineVersion, Project project) {
if (isProjectEligible(project)) {
JapicmpTask apiDiff = project.getTasks().create(TASK_NAME, JapicmpTask.class);
apiDiff.setDescription("Generates an API diff report with japicmp");
apiDiff.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP);
apiDiff.setOldClasspath(project.files(createBaselineConfiguration(baselineVersion, project)));
TaskProvider<Jar> jar = project.getTasks().withType(Jar.class).named("jar");
apiDiff.setNewArchives(project.getLayout().files(jar.get().getArchiveFile().get().getAsFile()));
apiDiff.setNewClasspath(getRuntimeClassPath(project));
apiDiff.setPackageIncludes(PACKAGE_INCLUDES);
apiDiff.setOnlyModified(true);
apiDiff.setIgnoreMissingClasses(true);
// Ignore Kotlin metadata annotations since they contain
// illegal HTML characters and fail the report generation
apiDiff.setAnnotationExcludes(Collections.singletonList("@kotlin.Metadata"));
apiDiff.setHtmlOutputFile(getOutputFile(baselineVersion, project));
apiDiff.dependsOn(project.getTasks().getByName("jar"));
}
}
private boolean isProjectEligible(Project project) {
return project.getPlugins().hasPlugin(JavaPlugin.class)
&& project.getPlugins().hasPlugin(MavenPublishPlugin.class);
}
private Configuration createBaselineConfiguration(String baselineVersion, Project project) {
String baseline = String.join(":",
project.getGroup().toString(), project.getName(), baselineVersion);
Dependency baselineDependency = project.getDependencies().create(baseline + "@jar");
return project.getRootProject().getConfigurations().detachedConfiguration(baselineDependency);
}
private Configuration getRuntimeClassPath(Project project) {
return project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
}
private File getOutputFile(String baseLineVersion, Project project) {
Path outDir = Paths.get(project.getRootProject().getBuildDir().getAbsolutePath(),
"reports", "api-diff",
baseLineVersion + "_to_" + project.getRootProject().getVersion());
return project.file(outDir.resolve(project.getName() + ".html").toString());
}
}
@@ -1,123 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.EvaluationResult;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.List;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
/**
* {@link Task} that checks for architecture problems.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
public abstract class ArchitectureCheck extends DefaultTask {
private FileCollection classes;
public ArchitectureCheck() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
getProhibitObjectsRequireNonNull().convention(true);
getRules().addAll(ArchitectureRules.CLASSES_SHOULD_NOT_IMPORT_FORBIDDEN_TYPES,
ArchitectureRules.JAVA_CLASSES_SHOULD_NOT_IMPORT_KOTLIN_ANNOTATIONS,
ArchitectureRules.ALL_PACKAGES_SHOULD_BE_FREE_OF_TANGLES,
ArchitectureRules.NO_CLASSES_SHOULD_CALL_STRING_TO_LOWER_CASE_WITHOUT_LOCALE,
ArchitectureRules.NO_CLASSES_SHOULD_CALL_STRING_TO_UPPER_CASE_WITHOUT_LOCALE);
}
@TaskAction
void checkArchitecture() throws IOException {
JavaClasses javaClasses = new ClassFileImporter()
.importPaths(this.classes.getFiles().stream().map(File::toPath).toList());
List<EvaluationResult> violations = getRules().get()
.stream()
.map(ArchitectureRules::archRule)
.map((rule) -> rule.evaluate(javaClasses))
.filter(EvaluationResult::hasViolation)
.toList();
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
outputFile.getParentFile().mkdirs();
if (!violations.isEmpty()) {
StringBuilder report = new StringBuilder();
for (EvaluationResult violation : violations) {
report.append(violation.getFailureReport());
report.append(String.format("%n"));
}
Files.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
throw new GradleException("Architecture check failed. See '" + outputFile + "' for details.");
}
else {
outputFile.createNewFile();
}
}
public void setClasses(FileCollection classes) {
this.classes = classes;
}
@Internal
public FileCollection getClasses() {
return this.classes;
}
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
final FileTree getInputClasses() {
return this.classes.getAsFileTree();
}
@Optional
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public abstract DirectoryProperty getResourcesDirectory();
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@Input
public abstract ListProperty<ArchitectureRules> getRules();
@Internal
public abstract Property<Boolean> getProhibitObjectsRequireNonNull();
}
@@ -1,74 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* {@link Plugin} for verifying a project's architecture.
*
* @author Andy Wilkinson
*/
public class ArchitecturePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerTasks(project));
}
private void registerTasks(Project project) {
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
List<TaskProvider<ArchitectureCheck>> architectureChecks = new ArrayList<>();
for (SourceSet sourceSet : javaPluginExtension.getSourceSets()) {
if (sourceSet.getName().contains("test")) {
// skip test source sets.
continue;
}
TaskProvider<ArchitectureCheck> checkArchitecture = project.getTasks()
.register(taskName(sourceSet), ArchitectureCheck.class,
(task) -> {
task.setClasses(sourceSet.getOutput().getClassesDirs());
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
task.dependsOn(sourceSet.getProcessResourcesTaskName());
task.setDescription("Checks the architecture of the classes of the " + sourceSet.getName()
+ " source set.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
});
architectureChecks.add(checkArchitecture);
}
if (!architectureChecks.isEmpty()) {
TaskProvider<Task> checkTask = project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME);
checkTask.configure((check) -> check.dependsOn(architectureChecks));
}
}
private static String taskName(SourceSet sourceSet) {
return "checkArchitecture"
+ sourceSet.getName().substring(0, 1).toUpperCase()
+ sourceSet.getName().substring(1);
}
}
@@ -1,117 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import com.tngtech.archunit.library.dependencies.SliceAssignment;
import com.tngtech.archunit.library.dependencies.SliceIdentifier;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
import java.util.List;
public enum ArchitectureRules {
ALL_PACKAGES_SHOULD_BE_FREE_OF_TANGLES(allPackagesShouldBeFreeOfTangles()),
NO_CLASSES_SHOULD_CALL_STRING_TO_LOWER_CASE_WITHOUT_LOCALE(noClassesShouldCallStringToLowerCaseWithoutLocale()),
NO_CLASSES_SHOULD_CALL_STRING_TO_UPPER_CASE_WITHOUT_LOCALE(noClassesShouldCallStringToUpperCaseWithoutLocale()),
CLASSES_SHOULD_NOT_IMPORT_FORBIDDEN_TYPES(classesShouldNotImportForbiddenTypes()),
JAVA_CLASSES_SHOULD_NOT_IMPORT_KOTLIN_ANNOTATIONS(javaClassesShouldNotImportKotlinAnnotations())
;
private final ArchRule archRule;
public ArchRule archRule() {
return this.archRule;
}
private ArchitectureRules(ArchRule archRule) {
this.archRule = archRule;
}
static ArchRule allPackagesShouldBeFreeOfTangles() {
return SlicesRuleDefinition.slices()
.assignedFrom(new SpringSlices()).should().beFreeOfCycles();
}
static ArchRule noClassesShouldCallStringToLowerCaseWithoutLocale() {
return ArchRuleDefinition.noClasses()
.should()
.callMethod(String.class, "toLowerCase")
.because("String.toLowerCase(Locale.ROOT) should be used instead");
}
static ArchRule noClassesShouldCallStringToUpperCaseWithoutLocale() {
return ArchRuleDefinition.noClasses()
.should()
.callMethod(String.class, "toUpperCase")
.because("String.toUpperCase(Locale.ROOT) should be used instead");
}
static ArchRule classesShouldNotImportForbiddenTypes() {
return ArchRuleDefinition.noClasses()
.should().dependOnClassesThat()
.haveFullyQualifiedName("reactor.core.support.Assert")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.slf4j.LoggerFactory")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.springframework.lang.NonNull")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.springframework.lang.Nullable");
}
static ArchRule javaClassesShouldNotImportKotlinAnnotations() {
return ArchRuleDefinition.noClasses()
.that(new DescribedPredicate<JavaClass>("is not a Kotlin class") {
@Override
public boolean test(JavaClass javaClass) {
return javaClass.getSourceCodeLocation()
.getSourceFileName().endsWith(".java");
}
}
)
.should().dependOnClassesThat()
.resideInAnyPackage("org.jetbrains.annotations..")
.allowEmptyShould(true);
}
static class SpringSlices implements SliceAssignment {
private final List<String> ignoredPackages = List.of("org.springframework.asm",
"org.springframework.cglib",
"org.springframework.javapoet",
"org.springframework.objenesis");
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
String packageName = javaClass.getPackageName();
for (String ignoredPackage : ignoredPackages) {
if (packageName.startsWith(ignoredPackage)) {
return SliceIdentifier.ignore();
}
}
return SliceIdentifier.of("spring framework");
}
@Override
public String getDescription() {
return "Spring Framework Slices";
}
}
}
@@ -0,0 +1,106 @@
/*
* 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.build.compile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.gradle.api.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.compile.JavaCompile;
/**
* {@link Plugin} that applies conventions for compiling Java sources in Spring Framework.
* <p>One can override the default Java source compatibility version
* with a dedicated property on the CLI: {@code "./gradlew test -PjavaSourceVersion=11"}.
*
* @author Brian Clozel
* @author Sam Brannen
*/
public class CompilerConventionsPlugin implements Plugin<Project> {
/**
* The project property that can be used to switch the Java source
* compatibility version for building source and test classes.
*/
public static final String JAVA_SOURCE_VERSION_PROPERTY = "javaSourceVersion";
public static final JavaVersion DEFAULT_COMPILER_VERSION = JavaVersion.VERSION_1_8;
private static final List<String> COMPILER_ARGS;
private static final List<String> TEST_COMPILER_ARGS;
static {
List<String> commonCompilerArgs = Arrays.asList(
"-Xlint:serial", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann",
"-Xlint:divzero", "-Xlint:empty", "-Xlint:finally", "-Xlint:overrides",
"-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try", "-Xlint:-options"
);
COMPILER_ARGS = new ArrayList<>();
COMPILER_ARGS.addAll(commonCompilerArgs);
COMPILER_ARGS.addAll(Arrays.asList(
"-Xlint:varargs", "-Xlint:fallthrough", "-Xlint:rawtypes", "-Xlint:deprecation",
"-Xlint:unchecked", "-Werror"
));
TEST_COMPILER_ARGS = new ArrayList<>();
TEST_COMPILER_ARGS.addAll(commonCompilerArgs);
TEST_COMPILER_ARGS.addAll(Arrays.asList("-Xlint:-varargs", "-Xlint:-fallthrough", "-Xlint:-rawtypes",
"-Xlint:-deprecation", "-Xlint:-unchecked", "-parameters"));
}
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> applyJavaCompileConventions(project));
}
/**
* Applies the common Java compiler options for main sources, test fixture sources, and
* test sources.
* @param project the current project
*/
private void applyJavaCompileConventions(Project project) {
JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class);
if (project.hasProperty(JAVA_SOURCE_VERSION_PROPERTY)) {
JavaVersion javaSourceVersion = JavaVersion.toVersion(project.property(JAVA_SOURCE_VERSION_PROPERTY));
java.setSourceCompatibility(javaSourceVersion);
}
else {
java.setSourceCompatibility(DEFAULT_COMPILER_VERSION);
}
java.setTargetCompatibility(DEFAULT_COMPILER_VERSION);
project.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
});
project.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME)
|| compileTask.getName().equals("compileTestFixturesJava"))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
});
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.dev;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
/**
* {@link Plugin} that skips documentation tasks when the {@code "-PskipDocs"} property is defined.
*
* @author Brian Clozel
*/
public class LocalDevelopmentPlugin implements Plugin<Project> {
private static final String SKIP_DOCS_PROPERTY = "skipDocs";
@Override
public void apply(Project target) {
if (target.hasProperty(SKIP_DOCS_PROPERTY)) {
skipDocumentationTasks(target);
target.subprojects(this::skipDocumentationTasks);
}
}
private void skipDocumentationTasks(Project project) {
project.afterEvaluate(p -> {
p.getTasks().matching(task -> {
return JavaBasePlugin.DOCUMENTATION_GROUP.equals(task.getGroup())
|| "distribution".equals(task.getGroup());
})
.forEach(task -> task.setEnabled(false));
});
}
}
@@ -1,48 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.hint;
import java.util.Collections;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
import org.gradle.process.CommandLineArgumentProvider;
/**
* Argument provider for registering the runtime hints agent with a Java process.
*/
public interface RuntimeHintsAgentArgumentProvider extends CommandLineArgumentProvider {
@Classpath
ConfigurableFileCollection getAgentJar();
@Input
SetProperty<String> getIncludedPackages();
@Input
SetProperty<String> getExcludedPackages();
@Override
default Iterable<String> asArguments() {
StringBuilder packages = new StringBuilder();
getIncludedPackages().get().forEach(packageName -> packages.append('+').append(packageName).append(','));
getExcludedPackages().get().forEach(packageName -> packages.append('-').append(packageName).append(','));
return Collections.singleton("-javaagent:" + getAgentJar().getSingleFile() + "=" + packages);
}
}
@@ -1,30 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.hint;
import org.gradle.api.provider.SetProperty;
/**
* Entry point to the DSL extension for the {@link RuntimeHintsAgentPlugin} Gradle plugin.
* @author Brian Clozel
*/
public interface RuntimeHintsAgentExtension {
SetProperty<String> getIncludedPackages();
SetProperty<String> getExcludedPackages();
}
@@ -1,102 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.hint;
import org.gradle.api.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.attributes.Bundling;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.LibraryElements;
import org.gradle.api.attributes.Usage;
import org.gradle.api.attributes.java.TargetJvmVersion;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.jvm.JvmTestSuite;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.testing.Test;
import org.gradle.testing.base.TestingExtension;
import java.util.Collections;
/**
* {@link Plugin} that configures the {@code RuntimeHints} Java agent to test tasks.
*
* @author Brian Clozel
* @author Sebastien Deleuze
*/
public class RuntimeHintsAgentPlugin implements Plugin<Project> {
public static final String RUNTIMEHINTS_TEST_TASK = "runtimeHintsTest";
private static final String EXTENSION_NAME = "runtimeHintsAgent";
private static final String CONFIGURATION_NAME = "testRuntimeHintsAgentJar";
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
TestingExtension testing = project.getExtensions().getByType(TestingExtension.class);
JvmTestSuite jvmTestSuite = (JvmTestSuite) testing.getSuites().getByName("test");
RuntimeHintsAgentExtension agentExtension = createRuntimeHintsAgentExtension(project);
TaskProvider<Test> agentTest = project.getTasks().register(RUNTIMEHINTS_TEST_TASK, Test.class, test -> {
test.useJUnitPlatform(options -> {
options.includeTags("RuntimeHintsTests");
});
test.include("**/*Tests.class", "**/*Test.class");
test.systemProperty("java.awt.headless", "true");
test.systemProperty("org.graalvm.nativeimage.imagecode", "runtime");
test.setTestClassesDirs(jvmTestSuite.getSources().getOutput().getClassesDirs());
test.setClasspath(jvmTestSuite.getSources().getRuntimeClasspath());
test.getJvmArgumentProviders().add(createRuntimeHintsAgentArgumentProvider(project, agentExtension));
});
project.getTasks().named("check", task -> task.dependsOn(agentTest));
project.getDependencies().add(CONFIGURATION_NAME,
project.getDependencyFactory().createProjectDependency(":spring-core-test"));
});
}
private static RuntimeHintsAgentExtension createRuntimeHintsAgentExtension(Project project) {
RuntimeHintsAgentExtension agentExtension = project.getExtensions().create(EXTENSION_NAME, RuntimeHintsAgentExtension.class);
agentExtension.getIncludedPackages().convention(Collections.singleton("org.springframework"));
agentExtension.getExcludedPackages().convention(Collections.emptySet());
return agentExtension;
}
private static RuntimeHintsAgentArgumentProvider createRuntimeHintsAgentArgumentProvider(
Project project, RuntimeHintsAgentExtension agentExtension) {
RuntimeHintsAgentArgumentProvider agentArgumentProvider = project.getObjects().newInstance(RuntimeHintsAgentArgumentProvider.class);
agentArgumentProvider.getAgentJar().from(createRuntimeHintsAgentConfiguration(project));
agentArgumentProvider.getIncludedPackages().set(agentExtension.getIncludedPackages());
agentArgumentProvider.getExcludedPackages().set(agentExtension.getExcludedPackages());
return agentArgumentProvider;
}
private static Configuration createRuntimeHintsAgentConfiguration(Project project) {
return project.getConfigurations().create(CONFIGURATION_NAME, configuration -> {
configuration.setCanBeConsumed(false);
configuration.setTransitive(false); // Only the built artifact is required
configuration.attributes(attributes -> {
attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.EXTERNAL));
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, Category.LIBRARY));
attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.getObjects().named(LibraryElements.class, LibraryElements.JAR));
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, Integer.valueOf(JavaVersion.current().getMajorVersion()));
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
});
});
}
}
@@ -1,139 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import javax.inject.Inject;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.attributes.LibraryElements;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.java.archives.Attributes;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* @author Cedric Champeau
* @author Brian Clozel
*/
public abstract class MultiReleaseExtension {
private final TaskContainer tasks;
private final SourceSetContainer sourceSets;
private final DependencyHandler dependencies;
private final ObjectFactory objects;
private final ConfigurationContainer configurations;
@Inject
public MultiReleaseExtension(SourceSetContainer sourceSets,
ConfigurationContainer configurations,
TaskContainer tasks,
DependencyHandler dependencies,
ObjectFactory objectFactory) {
this.sourceSets = sourceSets;
this.configurations = configurations;
this.tasks = tasks;
this.dependencies = dependencies;
this.objects = objectFactory;
}
public void releaseVersions(int... javaVersions) {
releaseVersions("src/main/", "src/test/", javaVersions);
}
private void releaseVersions(String mainSourceDirectory, String testSourceDirectory, int... javaVersions) {
for (int javaVersion : javaVersions) {
addLanguageVersion(javaVersion, mainSourceDirectory, testSourceDirectory);
}
}
private void addLanguageVersion(int javaVersion, String mainSourceDirectory, String testSourceDirectory) {
String javaN = "java" + javaVersion;
SourceSet langSourceSet = sourceSets.create(javaN, srcSet -> srcSet.getJava().srcDir(mainSourceDirectory + javaN));
SourceSet testSourceSet = sourceSets.create(javaN + "Test", srcSet -> srcSet.getJava().srcDir(testSourceDirectory + javaN));
SourceSet sharedSourceSet = sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME);
SourceSet sharedTestSourceSet = sourceSets.findByName(SourceSet.TEST_SOURCE_SET_NAME);
FileCollection mainClasses = objects.fileCollection().from(sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput().getClassesDirs());
dependencies.add(javaN + "Implementation", mainClasses);
tasks.named(langSourceSet.getCompileJavaTaskName(), JavaCompile.class, task ->
task.getOptions().getRelease().set(javaVersion)
);
tasks.named(testSourceSet.getCompileJavaTaskName(), JavaCompile.class, task ->
task.getOptions().getRelease().set(javaVersion)
);
TaskProvider<Test> testTask = createTestTask(javaVersion, testSourceSet, sharedTestSourceSet, langSourceSet, sharedSourceSet);
tasks.named("check", task -> task.dependsOn(testTask));
configureMultiReleaseJar(javaVersion, langSourceSet);
}
private TaskProvider<Test> createTestTask(int javaVersion, SourceSet testSourceSet, SourceSet sharedTestSourceSet, SourceSet langSourceSet, SourceSet sharedSourceSet) {
Configuration testImplementation = configurations.getByName(testSourceSet.getImplementationConfigurationName());
testImplementation.extendsFrom(configurations.getByName(sharedTestSourceSet.getImplementationConfigurationName()));
Configuration testCompileOnly = configurations.getByName(testSourceSet.getCompileOnlyConfigurationName());
testCompileOnly.extendsFrom(configurations.getByName(sharedTestSourceSet.getCompileOnlyConfigurationName()));
testCompileOnly.getDependencies().add(dependencies.create(langSourceSet.getOutput().getClassesDirs()));
testCompileOnly.getDependencies().add(dependencies.create(sharedSourceSet.getOutput().getClassesDirs()));
Configuration testRuntimeClasspath = configurations.getByName(testSourceSet.getRuntimeClasspathConfigurationName());
// so here's the deal. MRjars are JARs! Which means that to execute tests, we need
// the JAR on classpath, not just classes + resources as Gradle usually does
testRuntimeClasspath.getAttributes()
.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR));
TaskProvider<Test> testTask = tasks.register("java" + javaVersion + "Test", Test.class, test -> {
test.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
ConfigurableFileCollection testClassesDirs = objects.fileCollection();
testClassesDirs.from(testSourceSet.getOutput());
testClassesDirs.from(sharedTestSourceSet.getOutput());
test.setTestClassesDirs(testClassesDirs);
ConfigurableFileCollection classpath = objects.fileCollection();
// must put the MRJar first on classpath
classpath.from(tasks.named("jar"));
// then we put the specific test sourceset tests, so that we can override
// the shared versions
classpath.from(testSourceSet.getOutput());
// then we add the shared tests
classpath.from(sharedTestSourceSet.getRuntimeClasspath());
test.setClasspath(classpath);
});
return testTask;
}
private void configureMultiReleaseJar(int version, SourceSet languageSourceSet) {
tasks.named("jar", Jar.class, jar -> {
jar.into("META-INF/versions/" + version, s -> s.from(languageSourceSet.getOutput()));
Attributes attributes = jar.getManifest().getAttributes();
attributes.put("Multi-Release", "true");
});
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import javax.inject.Inject;
import org.gradle.api.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.ExtensionContainer;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.jvm.tasks.Jar;
import org.gradle.jvm.toolchain.JavaLanguageVersion;
import org.gradle.jvm.toolchain.JavaToolchainService;
/**
* A plugin which adds support for building multi-release jars
* with Gradle.
* @author Cedric Champeau
* @author Brian Clozel
* @see <a href="https://github.com/melix/mrjar-gradle-plugin">original project</a>
*/
public class MultiReleaseJarPlugin implements Plugin<Project> {
public static String VALIDATE_JAR_TASK_NAME = "validateMultiReleaseJar";
@Inject
protected JavaToolchainService getToolchains() {
throw new UnsupportedOperationException();
}
public void apply(Project project) {
project.getPlugins().apply(JavaPlugin.class);
ExtensionContainer extensions = project.getExtensions();
JavaPluginExtension javaPluginExtension = extensions.getByType(JavaPluginExtension.class);
ConfigurationContainer configurations = project.getConfigurations();
TaskContainer tasks = project.getTasks();
DependencyHandler dependencies = project.getDependencies();
ObjectFactory objects = project.getObjects();
extensions.create("multiRelease", MultiReleaseExtension.class,
javaPluginExtension.getSourceSets(),
configurations,
tasks,
dependencies,
objects);
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_25)) {
TaskProvider<MultiReleaseJarValidateTask> validateJarTask = tasks.register(VALIDATE_JAR_TASK_NAME, MultiReleaseJarValidateTask.class, (task) -> {
task.getJar().set(tasks.named("jar", Jar.class).flatMap(AbstractArchiveTask::getArchiveFile));
task.getJavaLauncher().set(task.getJavaToolchainService().launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.of(25))));
});
tasks.named("check", task -> task.dependsOn(validateJarTask));
}
}
}
@@ -1,47 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.jvm.toolchain.JavaToolchainService;
import java.util.List;
import javax.inject.Inject;
@CacheableTask
public abstract class MultiReleaseJarValidateTask extends JavaExec {
public MultiReleaseJarValidateTask() {
getMainModule().set("jdk.jartool");
getArgumentProviders().add(() -> List.of("--validate", "--file", getJar().get().getAsFile().getAbsolutePath()));
}
@Inject
protected abstract JavaToolchainService getJavaToolchainService();
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
public abstract RegularFileProperty getJar();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-present 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.
@@ -19,14 +19,16 @@ package org.springframework.build.optional;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.plugins.ide.eclipse.EclipsePlugin;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
/**
* A {@code Plugin} that adds support for Maven-style optional dependencies. Creates a new
* {@code optional} configuration. The {@code optional} configuration is part of the
* project's compile and runtime classpaths but does not affect the classpath of
* project's compile and runtime classpath's but does not affect the classpath of
* dependent projects.
*
* @author Andy Wilkinson
@@ -40,17 +42,23 @@ public class OptionalDependenciesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
Configuration optional = project.getConfigurations().create(OPTIONAL_CONFIGURATION_NAME);
optional.setCanBeConsumed(false);
optional.setCanBeResolved(false);
project.getPlugins().withType(JavaBasePlugin.class, (javaBasePlugin) -> {
SourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class)
.getSourceSets();
Configuration optional = project.getConfigurations().create("optional");
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
SourceSetContainer sourceSets = project.getConvention()
.getPlugin(JavaPluginConvention.class).getSourceSets();
sourceSets.all((sourceSet) -> {
project.getConfigurations().getByName(sourceSet.getCompileClasspathConfigurationName()).extendsFrom(optional);
project.getConfigurations().getByName(sourceSet.getRuntimeClasspathConfigurationName()).extendsFrom(optional);
sourceSet.setCompileClasspath(
sourceSet.getCompileClasspath().plus(optional));
sourceSet.setRuntimeClasspath(
sourceSet.getRuntimeClasspath().plus(optional));
});
});
project.getPlugins().withType(EclipsePlugin.class, (eclipePlugin) -> {
project.getExtensions().getByType(EclipseModel.class)
.classpath((classpath) -> {
classpath.getPlusConfigurations().add(optional);
});
});
}
}
}
@@ -1,191 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.shadow;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.gradle.api.DefaultTask;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.component.ModuleComponentSelector;
import org.gradle.api.artifacts.query.ArtifactResolutionQuery;
import org.gradle.api.artifacts.result.ArtifactResolutionResult;
import org.gradle.api.artifacts.result.ComponentArtifactsResult;
import org.gradle.api.artifacts.result.DependencyResult;
import org.gradle.api.artifacts.result.ResolutionResult;
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCopyDetails;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
import org.gradle.jvm.JvmLibrary;
import org.gradle.language.base.artifact.SourcesArtifact;
/**
* Gradle task to add source from shadowed jars into our own source jars.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class ShadowSource extends DefaultTask {
private final DirectoryProperty outputDirectory = getProject().getObjects().directoryProperty();
private List<Configuration> configurations = new ArrayList<>();
private final List<Relocation> relocations = new ArrayList<>();
@Classpath
@Optional
public List<Configuration> getConfigurations() {
return this.configurations;
}
public void setConfigurations(List<Configuration> configurations) {
this.configurations = configurations;
}
@Nested
public List<Relocation> getRelocations() {
return this.relocations;
}
public void relocate(String pattern, String destination) {
this.relocations.add(new Relocation(pattern, destination));
}
@OutputDirectory
public DirectoryProperty getOutputDirectory() {
return this.outputDirectory;
}
@TaskAction
void syncSourceJarFiles() {
sync(getSourceJarFiles());
}
private List<File> getSourceJarFiles() {
List<File> sourceJarFiles = new ArrayList<>();
for (Configuration configuration : this.configurations) {
ResolutionResult resolutionResult = configuration.getIncoming().getResolutionResult();
resolutionResult.getRootComponent().get().getDependencies().forEach(dependency -> {
Set<ComponentArtifactsResult> artifactsResults = resolveSourceArtifacts(dependency);
for (ComponentArtifactsResult artifactResult : artifactsResults) {
artifactResult.getArtifacts(SourcesArtifact.class).forEach(sourceArtifact -> {
sourceJarFiles.add(((ResolvedArtifactResult) sourceArtifact).getFile());
});
}
});
}
return Collections.unmodifiableList(sourceJarFiles);
}
private Set<ComponentArtifactsResult> resolveSourceArtifacts(DependencyResult dependency) {
ModuleComponentSelector componentSelector = (ModuleComponentSelector) dependency.getRequested();
ArtifactResolutionQuery query = getProject().getDependencies().createArtifactResolutionQuery()
.forModule(componentSelector.getGroup(), componentSelector.getModule(), componentSelector.getVersion());
return executeQuery(query).getResolvedComponents();
}
@SuppressWarnings("unchecked")
private ArtifactResolutionResult executeQuery(ArtifactResolutionQuery query) {
return query.withArtifacts(JvmLibrary.class, SourcesArtifact.class).execute();
}
private void sync(List<File> sourceJarFiles) {
getProject().sync(spec -> {
spec.into(this.outputDirectory);
spec.eachFile(this::relocateFile);
spec.filter(this::transformContent);
spec.exclude("META-INF/**");
spec.setIncludeEmptyDirs(false);
sourceJarFiles.forEach(sourceJar -> spec.from(zipTree(sourceJar)));
});
}
private void relocateFile(FileCopyDetails details) {
String path = details.getPath();
for (Relocation relocation : this.relocations) {
path = relocation.relocatePath(path);
}
details.setPath(path);
}
private String transformContent(String content) {
for (Relocation relocation : this.relocations) {
content = relocation.transformContent(content);
}
return content;
}
private FileTree zipTree(File sourceJar) {
return getProject().zipTree(sourceJar);
}
/**
* A single relocation.
*/
static class Relocation {
private final String pattern;
private final String pathPattern;
private final String destination;
private final String pathDestination;
Relocation(String pattern, String destination) {
this.pattern = pattern;
this.pathPattern = pattern.replace('.', '/');
this.destination = destination;
this.pathDestination = destination.replace('.', '/');
}
@Input
public String getPattern() {
return this.pattern;
}
@Input
public String getDestination() {
return this.destination;
}
String relocatePath(String path) {
return path.replace(this.pathPattern, this.pathDestination);
}
public String transformContent(String content) {
return content.replaceAll("\\b" + this.pattern, this.destination);
}
}
}
@@ -1,182 +0,0 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.UnexpectedBuildFailure;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.io.TempDir;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link MultiReleaseJarPlugin}
*/
public class MultiReleaseJarPluginTests {
private File projectDir;
private File buildFile;
private File propertiesFile;
@BeforeEach
void setup(@TempDir File projectDir) {
this.projectDir = projectDir;
this.buildFile = new File(this.projectDir, "build.gradle");
this.propertiesFile = new File(this.projectDir, "gradle.properties");
}
@Test
void configureSourceSets() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
multiRelease { releaseVersions 21, 24 }
task printSourceSets {
doLast {
sourceSets.all { println it.name }
}
}
""");
BuildResult buildResult = runGradle("printSourceSets");
assertThat(buildResult.getOutput()).contains("main", "test", "java21", "java21Test", "java24", "java24Test");
}
@Test
void configureToolchainReleaseVersion() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
multiRelease { releaseVersions 21 }
task printReleaseVersion {
doLast {
tasks.all { println it.name }
tasks.named("compileJava21Java") {
println "compileJava21Java releaseVersion: ${it.options.release.get()}"
}
tasks.named("compileJava21TestJava") {
println "compileJava21TestJava releaseVersion: ${it.options.release.get()}"
}
}
}
""");
BuildResult buildResult = runGradle("printReleaseVersion");
assertThat(buildResult.getOutput()).contains("compileJava21Java releaseVersion: 21")
.contains("compileJava21TestJava releaseVersion: 21");
}
@Test
void packageInJar() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
version = '1.2.3'
multiRelease { releaseVersions 17 }
""");
writeClass("src/main/java17", "Main.java", """
public class Main {}
""");
BuildResult buildResult = runGradle("assemble");
File file = new File(this.projectDir, "/build/libs/" + this.projectDir.getName() + "-1.2.3.jar");
assertThat(file).exists();
try (JarFile jar = new JarFile(file)) {
Attributes mainAttributes = jar.getManifest().getMainAttributes();
assertThat(mainAttributes.getValue("Multi-Release")).isEqualTo("true");
assertThat(jar.entries().asIterator()).toIterable()
.anyMatch(entry -> entry.getName().equals("META-INF/versions/17/Main.class"));
}
}
@Test
@DisabledForJreRange(max = JRE.JAVA_24, disabledReason = "'jar --validate' is available as of Java 25")
void validateJar() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
version = '1.2.3'
tasks.withType(JavaCompile).configureEach {
options.release = 11
}
multiRelease { releaseVersions 17 }
""");
writeGradleProperties("""
org.gradle.jvmargs=-Duser.language=en
""");
writeClass("src/main/java17", "Main.java", """
public class Main {
public void method() {}
}
""");
writeClass("src/main/java", "Main.java", """
public class Main {}
""");
assertThatThrownBy(() ->runGradle("validateMultiReleaseJar"))
.isInstanceOf(UnexpectedBuildFailure.class)
.hasMessageContaining("entry: META-INF/versions/17/Main.class, contains a class with different api from earlier version");
}
private void writeBuildFile(String buildContent) throws IOException {
try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {
out.print(buildContent);
}
}
private void writeGradleProperties(String properties) throws IOException {
try (PrintWriter out = new PrintWriter(new FileWriter(this.propertiesFile))) {
out.print(properties);
}
}
private void writeClass(String path, String fileName, String fileContent) throws IOException {
Path folder = this.projectDir.toPath().resolve(path);
Files.createDirectories(folder);
Path filePath = folder.resolve(fileName);
Files.createFile(filePath);
Files.writeString(filePath, fileContent);
}
private BuildResult runGradle(String... args) {
return GradleRunner.create().withProjectDir(this.projectDir).withArguments(args).withPluginClasspath().build();
}
}
+57
View File
@@ -0,0 +1,57 @@
== Spring Framework Concourse pipeline
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x[Spring Framework 5.2.x].
=== Setting up your development environment
If you're part of the Spring Framework project on GitHub, you can get access to CI management features.
First, you need to go to https://ci.spring.io and install the client CLI for your platform (see bottom right of the screen).
You can then login with the instance using:
[source]
----
$ fly -t spring login -n spring-framework -c https://ci.spring.io
----
Once logged in, you should get something like:
[source]
----
$ fly ts
name url team expiry
spring https://ci.spring.io spring-framework Wed, 25 Mar 2020 17:45:26 UTC
----
=== Pipeline configuration and structure
The build pipelines are described in `pipeline.yml` file.
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
You'll find in this folder the following resources:
* `pipeline.yml` the build pipeline
* `parameters.yml` the build parameters used for the pipeline
* `images/` holds the container images definitions used in this pipeline
* `scripts/` holds the build scripts that ship within the CI container images
* `tasks` contains the task definitions used in the main `pipeline.yml`
=== Updating the build pipeline
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
The pipeline can be deployed using the following command:
[source]
----
$ fly -t spring set-pipeline -p spring-framework-5.2.x -c ci/pipeline.yml -l ci/parameters.yml
----
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
+17
View File
@@ -0,0 +1,17 @@
changelog:
repository: spring-projects/spring-framework
sections:
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
+10
View File
@@ -0,0 +1,10 @@
logging:
level:
io.spring.concourse: DEBUG
spring:
main:
banner-mode: off
sonatype:
exclude:
- 'build-info\.json'
- '.*\.zip'
+21
View File
@@ -0,0 +1,21 @@
== CI Images
These images are used by CI to run the actual builds.
To build the image locally run the following from this directory:
----
$ docker build --no-cache -f <image-folder>/Dockerfile .
----
For example
----
$ docker build --no-cache -f spring-framework-ci-image/Dockerfile .
----
To test run:
----
$ docker run -it --entrypoint /bin/bash <SHA>
----
+8
View File
@@ -0,0 +1,8 @@
FROM ubuntu:focal-20220302
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java11
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
+8
View File
@@ -0,0 +1,8 @@
FROM ubuntu:focal-20220302
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java8
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
set -e
case "$1" in
java8)
echo "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u322-b06/OpenJDK8U-jdk_x64_linux_hotspot_8u322b06.tar.gz"
;;
java11)
echo "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.14.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.14.1_1.tar.gz"
;;
*)
echo $"Unknown java version"
exit 1
esac
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
set -ex
###########################################################
# UTILS
###########################################################
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
dpkg-reconfigure --frontend noninteractive tzdata
rm -rf /var/lib/apt/lists/*
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
###########################################################
# JAVA
###########################################################
JDK_URL=$( ./get-jdk-url.sh $1 )
mkdir -p /opt/openjdk
cd /opt/openjdk
curl -L ${JDK_URL} | tar zx --strip-components=1
test -f /opt/openjdk/bin/java
test -f /opt/openjdk/bin/javac
###########################################################
# GRADLE ENTERPRISE
###########################################################
cd /
mkdir ~/.gradle
echo 'systemProp.user.name=concourse' > ~/.gradle/gradle.properties
+13
View File
@@ -0,0 +1,13 @@
email-server: "smtp.svc.pivotal.io"
email-from: "ci@spring.io"
email-to: ["spring-framework-dev@pivotal.io"]
github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "5.2.x"
milestone: "5.2.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
task-timeout: 1h00m
+391
View File
@@ -0,0 +1,391 @@
anchors:
git-repo-resource-source: &git-repo-resource-source
uri: ((github-repo))
username: ((github-username))
password: ((github-ci-release-token))
branch: ((branch))
gradle-enterprise-task-params: &gradle-enterprise-task-params
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
sonatype-task-params: &sonatype-task-params
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
build-project-task-params: &build-project-task-params
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
[$TEXT_FILE_CONTENT]
text_file: git-repo/build/build-scan-uri.txt
silent: true
icon_emoji: ":concourse:"
username: concourse-ci
changelog-task-params: &changelog-task-params
name: generated-changelog/tag
tag: generated-changelog/tag
body: generated-changelog/changelog.md
github-task-params: &github-task-params
GITHUB_USERNAME: ((github-username))
GITHUB_TOKEN: ((github-ci-release-token))
resource_types:
- name: artifactory-resource
type: registry-image
source:
repository: springio/artifactory-resource
tag: 0.0.17
- name: github-release
type: registry-image
source:
repository: concourse/github-release-resource
tag: 1.5.5
- name: github-status-resource
type: registry-image
source:
repository: dpb587/github-status-resource
tag: master
- name: slack-notification
type: registry-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
- name: git-repo
type: git
icon: github
source:
<<: *git-repo-resource-source
- name: every-morning
type: time
icon: alarm
source:
start: 8:00 AM
stop: 9:00 AM
location: Europe/Vienna
- name: ci-images-git-repo
type: git
icon: github
source:
uri: ((github-repo))
branch: ((branch))
paths: ["ci/images/*"]
- name: ci-image
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
- name: ci-image-jdk11
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci-jdk11
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
source:
uri: ((artifactory-server))
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: build
- name: repo-status-jdk11-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk11-build
- name: slack-alert
type: slack-notification
icon: slack
source:
url: ((slack-webhook-url))
- name: github-pre-release
type: github-release
icon: briefcase-download-outline
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: true
release: false
- name: github-release
type: github-release
icon: briefcase-download
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: false
jobs:
- name: build-ci-images
plan:
- get: ci-images-git-repo
trigger: true
- in_parallel:
- put: ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
- put: ci-image-jdk11
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/ci-image-jdk11/Dockerfile
- name: build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
trigger: true
- put: repo-status-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
image: ci-image
file: git-repo/ci/tasks/build-project.yml
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-build
params: { state: "success", commit: "git-repo" }
- put: artifactory-repo
params: &artifactory-params
signing_key: ((signing-key))
signing_passphrase: ((signing-passphrase))
repo: libs-snapshot-local
folder: distribution-repository
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}"
disable_checksum_uploads: true
threads: 8
artifact_set:
- include:
- "/**/spring-*.zip"
properties:
"zip.name": "spring-framework"
"zip.displayname": "Spring Framework"
"zip.deployed": "false"
- include:
- "/**/spring-*-docs.zip"
properties:
"zip.type": "docs"
- include:
- "/**/spring-*-dist.zip"
properties:
"zip.type": "dist"
- include:
- "/**/spring-*-schema.zip"
properties:
"zip.type": "schema"
get_params:
threads: 8
- name: jdk11-build
serial: true
public: true
plan:
- get: ci-image-jdk11
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk11-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
image: ci-image-jdk11
file: git-repo/ci/tasks/check-project.yml
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk11-build
params: { state: "success", commit: "git-repo" }
- name: stage-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: M
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-milestone]
params:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: M
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: M
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RC
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-rc]
params:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RC
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RC
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-release]
params:
download_artifacts: true
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *artifactory-task-params
<<: *sonatype-task-params
- name: create-github-release
serial: true
plan:
- get: ci-image
- get: git-repo
- get: artifactory-repo
trigger: true
passed: [promote-release]
params:
download_artifacts: false
save_build_info: true
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RELEASE
<<: *github-task-params
- put: github-release
params:
<<: *changelog-task-params
groups:
- name: "builds"
jobs: ["build", "jdk11-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
popd > /dev/null
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
popd > /dev/null
+2
View File
@@ -0,0 +1,2 @@
source /opt/concourse-java.sh
setup_symlinks
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
set -e
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
milestone=${version}
if [[ $RELEASE_TYPE = "RELEASE" ]]; then
milestone=${version%.RELEASE}
fi
java -jar /github-changelog-generator.jar \
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
${milestone} generated-changelog/changelog.md
echo ${version} > generated-changelog/version
echo v${version} > generated-changelog/tag
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
source $(dirname $0)/common.sh
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
echo "Promotion complete"
echo $version > version/version
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
git fetch --tags --all > /dev/null
popd > /dev/null
git clone git-repo stage-git-repo > /dev/null
pushd stage-git-repo > /dev/null
snapshotVersion=$( awk -F '=' '$1 == "version" { print $2 }' gradle.properties )
if [[ $RELEASE_TYPE = "M" ]]; then
stageVersion=$( get_next_milestone_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RC" ]]; then
stageVersion=$( get_next_rc_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RELEASE" ]]; then
stageVersion=$( get_next_release $snapshotVersion "RELEASE")
nextVersion=$( bump_version_number $snapshotVersion)
else
echo "Unknown release type $RELEASE_TYPE" >&2; exit 1;
fi
echo "Staging $stageVersion (next version will be $nextVersion)"
sed -i "s/version=$snapshotVersion/version=$stageVersion/" gradle.properties
git config user.name "Spring Builds" > /dev/null
git config user.email "spring-builds@users.noreply.github.com" > /dev/null
git add gradle.properties > /dev/null
git commit -m"Release v$stageVersion" > /dev/null
git tag -a "v$stageVersion" -m"Release v$stageVersion" > /dev/null
./gradlew --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
git reset --hard HEAD^ > /dev/null
if [[ $nextVersion != $snapshotVersion ]]; then
echo "Setting next development version (v$nextVersion)"
sed -i "s/version=$snapshotVersion/version=$nextVersion/" gradle.properties
git add gradle.properties > /dev/null
git commit -m"Next development version (v$nextVersion)" > /dev/null
fi;
echo "Staging Complete"
popd > /dev/null
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; }
echo "Sync complete"
echo $version > version/version
+22
View File
@@ -0,0 +1,22 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/build-project.sh
+22
View File
@@ -0,0 +1,22 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/check-project.sh
+20
View File
@@ -0,0 +1,20 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: springio/github-changelog-generator
tag: '0.0.7'
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: generated-changelog
params:
GITHUB_ORGANIZATION:
GITHUB_REPO:
GITHUB_USERNAME:
GITHUB_TOKEN:
RELEASE_TYPE:
run:
path: git-repo/ci/scripts/generate-changelog.sh
+18
View File
@@ -0,0 +1,18 @@
---
platform: linux
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: version
params:
RELEASE_TYPE:
ARTIFACTORY_SERVER:
ARTIFACTORY_USERNAME:
ARTIFACTORY_PASSWORD:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE_ID:
run:
path: git-repo/ci/scripts/promote-version.sh
+17
View File
@@ -0,0 +1,17 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: stage-git-repo
- name: distribution-repository
params:
RELEASE_TYPE:
CI: true
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
caches:
- path: gradle
run:
path: git-repo/ci/scripts/stage-version.sh
-127
View File
@@ -1,127 +0,0 @@
plugins {
id 'java-platform'
id 'io.freefair.aggregate-javadoc' version '8.13.1'
id 'org.jetbrains.dokka'
}
description = "Spring Framework API Docs"
apply from: "${rootDir}/gradle/publications.gradle"
repositories {
maven {
url = "https://repo.spring.io/release"
}
}
dependencies {
rootProject.ext.moduleProjects.each { moduleProject ->
javadoc project(moduleProject.path)
}
}
def springAspectsOutput = project(":spring-aspects").sourceSets.main.output
javadoc {
javadocTool.set(javaToolchains.javadocToolFor({
languageVersion = JavaLanguageVersion.of(25)
}))
title = "${rootProject.description} ${version} API"
failOnError = true
options {
encoding = "UTF-8"
memberLevel = JavadocMemberLevel.PROTECTED
author = true
header = rootProject.description
use = true
overview = project.relativePath("$rootProject.rootDir/framework-docs/src/docs/api/overview.html")
destinationDir = project.java.docsDir.dir("javadoc-api").get().asFile
splitIndex = true
links(rootProject.ext.javadocLinks)
// Check for 'syntax' and 'reference' during linting.
addBooleanOption('Xdoclint:syntax,reference', true)
// Change modularity mismatch from warn to info.
// See https://github.com/spring-projects/spring-framework/issues/27497
addStringOption("-link-modularity-mismatch", "info")
// Fail build on Javadoc warnings.
addBooleanOption('Werror', true)
}
maxMemory = "1024m"
doFirst {
classpath += files(
// ensure the javadoc process can resolve types compiled from .aj sources
springAspectsOutput
)
classpath += files(rootProject.ext.moduleProjects.collect { it.sourceSets.main.compileClasspath })
}
}
dokka {
moduleName = "spring-framework"
dokkaPublications.html {
outputDirectory = project.java.docsDir.dir("kdoc-api")
includes.from("$rootProject.rootDir/framework-docs/src/docs/api/dokka-overview.md")
}
}
/**
* Zip all Java docs (javadoc & kdoc) into a single archive
*/
tasks.register('docsZip', Zip) {
dependsOn = ['javadoc', 'dokkaGenerate']
group = "distribution"
description = "Builds -${archiveClassifier} archive containing api and reference " +
"for deployment at https://docs.spring.io/spring-framework/docs/."
archiveBaseName.set("spring-framework")
archiveClassifier.set("docs")
from("src/dist") {
include "changelog.txt"
}
from(javadoc) {
into "javadoc-api"
}
from(project.java.docsDir.dir("kdoc-api")) {
into "kdoc-api"
}
}
/**
* Zip all Spring Framework schemas into a single archive
*/
tasks.register('schemaZip', Zip) {
group = "distribution"
archiveBaseName.set("spring-framework")
archiveClassifier.set("schema")
description = "Builds -${archiveClassifier} archive containing all " +
"XSDs for deployment at https://springframework.org/schema."
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
rootProject.ext.moduleProjects.each { module ->
def Properties schemas = new Properties();
module.sourceSets.main.resources.find {
(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 = module.sourceSets.main.resources.find {
(it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/', '\\\\')))
}
assert xsdFile != null
into(shortName) {
from xsdFile.path
}
}
}
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact docsZip
artifact schemaZip
}
}
}
+7 -1
View File
@@ -8,7 +8,7 @@ group = "org.springframework"
dependencies {
constraints {
parent.moduleProjects.sort { "$it.name" }.each {
api project(it.path)
api it
}
}
}
@@ -18,6 +18,12 @@ publishing {
mavenJava(MavenPublication) {
artifactId = 'spring-framework-bom'
from components.javaPlatform
// remove scope information from published BOM
pom.withXml {
asNode().dependencyManagement.first().dependencies.first().each {
it.remove(it.scope.first())
}
}
}
}
}
-41
View File
@@ -1,41 +0,0 @@
antora:
extensions:
- require: '@springio/antora-extensions'
root_component_name: 'framework'
site:
title: Spring Framework
url: https://docs.spring.io/spring-framework/reference
robots: allow
git:
ensure_git_suffix: false
content:
sources:
- url: https://github.com/spring-projects/spring-framework
# Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
# branches: We include snapshots for main, 6.2.x, and 7.0.x to 9.*.x.
branches: ['main', '6.2.x', '{7..9}.+({0..9}).x']
# tags: include all releases from 6.2.0 to 9.*.*.
tags: ['v6.2.+({0..9})', 'v{7..9}.+({0..9}).+({0..9})?(-{RC,M}*)']
start_path: framework-docs
asciidoc:
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@springio/asciidoctor-extensions/include-code-extension'
attributes:
page-stackoverflow-url: https://stackoverflow.com/questions/tagged/spring
page-pagination: ''
hide-uri-scheme: '@'
tabs-sync-option: '@'
include-java: 'example$docs-src/main/java/org/springframework/docs'
urls:
latest_version_segment_strategy: redirect:to
latest_version_segment: ''
redirect_facility: httpd
runtime:
log:
failure_level: warn
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.26/ui-bundle.zip
-97
View File
@@ -1,97 +0,0 @@
name: framework
version: true
title: Spring Framework
nav:
- modules/ROOT/nav.adoc
ext:
collector:
run:
command: gradlew -q -PbuildSrc.skipTests=true "-Dorg.gradle.jvmargs=-Xmx3g" :framework-docs:generateAntoraResources
local: true
scan:
dir: ./build/generated-antora-resources
asciidoc:
attributes:
attribute-missing: 'warn'
# FIXME: the copyright is not removed
# FIXME: The package is not renamed
chomp: 'all'
fold: 'all'
table-stripes: 'odd'
include-java: 'example$docs-src/main/java/org/springframework/docs'
include-kotlin: 'example$docs-src/main/kotlin/org/springframework/docs'
include-xml: 'example$docs-src/main/resources/org/springframework/docs'
spring-site: 'https://spring.io'
spring-site-blog: '{spring-site}/blog'
spring-site-cve: "{spring-site}/security"
spring-site-guides: '{spring-site}/guides'
spring-site-projects: '{spring-site}/projects'
spring-site-tools: "{spring-site}/tools"
spring-org: 'spring-projects'
spring-github-org: "https://github.com/{spring-org}"
spring-framework-github: "https://github.com/{spring-org}/spring-framework"
spring-framework-code: '{spring-framework-github}/tree/main'
spring-framework-issues: '{spring-framework-github}/issues'
spring-framework-wiki: '{spring-framework-github}/wiki'
# Docs
docs-site: 'https://docs.spring.io'
spring-framework-docs-root: '{docs-site}/spring-framework/docs'
spring-framework-api: '{spring-framework-docs-root}/{spring-version}/javadoc-api/org/springframework'
spring-framework-api-kdoc: '{spring-framework-docs-root}/{spring-version}/kdoc-api'
spring-framework-reference: '{spring-framework-docs-root}/{spring-version}/reference'
#
# Other Spring portfolio projects
spring-boot-docs: '{docs-site}/spring-boot'
spring-boot-docs-ref: '{spring-boot-docs}/reference'
spring-boot-issues: '{spring-github-org}/spring-boot/issues'
# TODO add more projects / links or just build up on {docs-site}?
# TODO rename the below using new conventions
docs-spring-gemfire: '{docs-site}/spring-gemfire/docs/current/reference'
docs-spring-security: '{docs-site}/spring-security/reference'
docs-spring-session: '{docs-site}/spring-session/reference'
#
# External projects URLs and related attributes
aspectj-site: 'https://www.eclipse.org/aspectj'
aspectj-docs: "{aspectj-site}/doc/released"
aspectj-api: "{aspectj-docs}/runtime-api"
aspectj-docs-devguide: "{aspectj-docs}/devguide"
aspectj-docs-progguide: "{aspectj-docs}/progguide"
assertj-docs: 'https://assertj.github.io/doc'
baeldung-blog: 'https://www.baeldung.com'
bean-validation-site: 'https://beanvalidation.org'
graalvm-docs: 'https://www.graalvm.org/22.3/reference-manual'
hibernate-validator-site: 'https://hibernate.org/validator/'
jackson-docs: 'https://fasterxml.github.io'
jackson-github-org: 'https://github.com/FasterXML'
java-api: 'https://docs.oracle.com/en/java/javase/17/docs/api'
java-tutorial: 'https://docs.oracle.com/javase/tutorial'
JSR: 'https://www.jcp.org/en/jsr/detail?id='
kotlin-site: 'https://kotlinlang.org'
kotlin-docs: '{kotlin-site}/docs'
kotlin-api: '{kotlin-site}/api/latest'
kotlin-coroutines-api: '{kotlin-site}/api/kotlinx.coroutines'
kotlin-github-org: 'https://github.com/Kotlin'
kotlin-issues: 'https://youtrack.jetbrains.com/issue'
micrometer-docs: 'https://docs.micrometer.io/micrometer/reference'
micrometer-context-propagation-docs: 'https://docs.micrometer.io/context-propagation/reference'
petclinic-github-org: 'https://github.com/spring-petclinic'
reactive-streams-site: 'https://www.reactive-streams.org'
reactive-streams-spec: 'https://github.com/reactive-streams/reactive-streams-jvm/blob/master/README.md#specification'
reactor-github-org: 'https://github.com/reactor'
reactor-site: 'https://projectreactor.io'
rsocket-github-org: 'https://github.com/rsocket'
rsocket-java: '{rsocket-github-org}/rsocket-java'
rsocket-java-code: '{rsocket-java}/tree/master/'
rsocket-protocol-extensions: '{rsocket-github-org}/rsocket/tree/master/Extensions'
rsocket-site: 'https://rsocket.io'
rfc-site: 'https://datatracker.ietf.org/doc/html'
sockjs-client: 'https://github.com/sockjs/sockjs-client'
sockjs-protocol: 'https://github.com/sockjs/sockjs-protocol'
sockjs-protocol-site: "https://sockjs.github.io/sockjs-protocol"
stackoverflow-site: 'https://stackoverflow.com'
stackoverflow-questions: '{stackoverflow-site}/questions'
stackoverflow-spring-tag: "{stackoverflow-questions}/tagged/spring"
stackoverflow-spring-kotlin-tags: "{stackoverflow-spring-tag}+kotlin"
testcontainers-site: 'https://www.testcontainers.org'
vavr-docs: 'https://vavr-io.github.io/vavr-docs'
-98
View File
@@ -1,98 +0,0 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
plugins {
id 'kotlin'
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
id 'org.antora' version '1.0.0'
}
description = "Spring Framework Docs"
apply from: "${rootDir}/gradle/ide.gradle"
apply from: "${rootDir}/gradle/publications.gradle"
antora {
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
environment = [
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
]
}
node {
version = '24.15.0'
}
tasks.named("generateAntoraYml") {
asciidocAttributes = project.provider( {
return ["spring-version": project.version ]
} )
}
tasks.register("generateAntoraResources") {
dependsOn 'generateAntoraYml'
}
jar {
enabled = false
}
javadoc {
enabled = false
}
repositories {
maven {
url = "https://repo.spring.io/release"
}
}
// To avoid a redeclaration error with Kotlin compiler and set the JVM target
tasks.withType(KotlinCompilationTask.class).configureEach {
javaSources.from = []
compilerOptions.jvmTarget = JvmTarget.JVM_17
compilerOptions.freeCompilerArgs.addAll(
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
"-Xannotation-default-target=param-property" // Upcoming default, see https://youtrack.jetbrains.com/issue/KT-73255
)
}
dependencies {
implementation(project(":spring-aspects"))
implementation(project(":spring-context"))
implementation(project(":spring-context-support"))
implementation(project(":spring-core-test"))
implementation(project(":spring-jdbc"))
implementation(project(":spring-jms"))
implementation(project(":spring-test"))
implementation(project(":spring-web"))
implementation(project(":spring-webflux"))
implementation(project(":spring-webmvc"))
implementation(project(":spring-websocket"))
implementation("com.github.ben-manes.caffeine:caffeine")
implementation("com.mchange:c3p0:0.9.5.5")
implementation("com.oracle.database.jdbc:ojdbc11")
implementation("io.micrometer:context-propagation")
implementation("io.projectreactor.netty:reactor-netty-http")
implementation("jakarta.jms:jakarta.jms-api")
implementation("jakarta.servlet:jakarta.servlet-api")
implementation("jakarta.resource:jakarta.resource-api")
implementation("jakarta.validation:jakarta.validation-api")
implementation("jakarta.websocket:jakarta.websocket-client-api")
implementation("javax.cache:cache-api")
implementation("org.apache.activemq:activemq-ra:6.1.2")
implementation("org.apache.commons:commons-dbcp2:2.11.0")
implementation("org.apache.groovy:groovy-templates")
implementation("org.aspectj:aspectjweaver")
implementation("org.assertj:assertj-core")
implementation("org.eclipse.jetty.websocket:jetty-websocket-jetty-api")
implementation("org.freemarker:freemarker")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
implementation("org.junit.jupiter:junit-jupiter-api")
implementation("tools.jackson.core:jackson-databind")
implementation("tools.jackson.dataformat:jackson-dataformat-xml")
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

@@ -1,625 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 spring-overview.svg Page-1 -->
<svg
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6.4728541in"
height="5.9522467in"
viewBox="0 0 466.04561 428.56238"
xml:space="preserve"
class="st5"
id="svg5499"
version="1.1"
font-family="Helvetica, Arial, sans-serif"
inkscape:version="0.91 r13725"
sodipodi:docname="mvc-splitted-contexts.svg"
style="font-size:12px;overflow:visible;color-interpolation-filters:sRGB;fill:none;fill-rule:evenodd;stroke-linecap:square;stroke-miterlimit:3"
inkscape:export-filename="/Users/seb/Workspace/spring-framework/src/asciidoc/images/mvc-splitted-contexts.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><metadata
id="metadata5713"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="https://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs5711"><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker9162"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path9164" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8834"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8836" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8518"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8520" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8214"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8216" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7922"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7924" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7641"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7644" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7373"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7375" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7117"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7119" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6873"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6875" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6641"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6643" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6421"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6423" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6213"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6215" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker6017"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6019" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5833"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5835" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5661"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5663" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5501"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5503" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5353"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5355" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5217"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5219" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5093"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5095" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4981"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path4983" /></marker><marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mend"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always"><path
id="path7394"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8121"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path8123"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8033"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path8035"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker7957"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7959"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7376"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7388"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7370"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" /></marker></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="1005"
id="namedview5709"
showgrid="false"
inkscape:zoom="1.1640492"
inkscape:cx="134.86698"
inkscape:cy="203.59898"
inkscape:window-x="84"
inkscape:window-y="176"
inkscape:window-maximized="0"
inkscape:current-layer="g5503"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" /><v:documentProperties
v:langID="1033"
v:viewMarkup="false" /><style
type="text/css"
id="style5501"><![CDATA[
.st1 {fill:#969696;stroke:#333333;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#F8F9FA;stroke:#333333;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st3 {fill:#333333;font-family:Helvetica, Arial, sans-serif;font-size:2.50001em;font-weight:bold}
.st4 {font-size:0.333333em;font-weight:normal}
.st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]></style><g
v:mID="0"
v:index="1"
v:groupContext="foregroundPage"
id="g5503"
transform="matrix(0.99998201,0,0,1.0824094,-40.812382,-98.908648)"><rect
style="fill:#F8F9FA;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6599"
width="382.68423"
height="146.09897"
x="87.884865"
y="148.26482"
rx="8" /><v:userDefs><v:ud
v:nameU="SchemeName"
v:val="VT4(Default)" /></v:userDefs><rect
style="fill:none;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5725"
width="464.31128"
height="374.11411"
x="41.684383"
y="112.3262"
rx="8" /><title
id="title5505">Page-1</title><v:pageProperties
v:drawingScale="0.0393701"
v:pageScale="0.0393701"
v:drawingUnits="24"
v:shadowOffsetX="8.50394"
v:shadowOffsetY="-8.50394" /><v:layer
v:name="Connector"
v:index="0" /><rect
style="fill:#F8F9FA;fill-opacity:1;fill-rule:evenodd;stroke:#6db33f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5715"
width="322.8194"
height="43.63184"
x="119.95335"
y="-135.66222"
transform="scale(1,-1)"
rx="8" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="168.843"
y="124.32391"
id="text5717"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan5719"
x="172.843"
y="124.32391"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333">DispatcherServlet</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="89.770851"
y="181.20923"
id="text6589"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6591"
x="106.770851"
y="181.20923"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333">Servlet WebApplicationContext</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="260.00443"
y="198.41273"
id="text6593"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6595"
x="260.00443"
y="198.41273"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555">(containing controllers, view resolvers,</tspan><tspan
sodipodi:role="line"
x="260.00443"
y="212.83057"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
id="tspan6597">and other web-related beans)</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6620"
width="82.040657"
height="36.72575"
x="114.52653"
y="-259.43161"
transform="scale(1,-1)"
rx="4" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6622"
width="87.843979"
height="36.697304"
x="223.39864"
y="-287.19809"
transform="scale(1,-1)"
rx="4" /><rect
transform="scale(1,-1)"
y="-264.81918"
x="117.92834"
height="36.72575"
width="82.040657"
id="rect6614"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="121.24728"
y="260.14957"
id="text6616"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6618"
x="124.24728"
y="260.14957"
style="font-size:11.53426838px;fill:#333333">Controllers</tspan></text>
<text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6624"
y="282.70709"
x="219.61203"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px;fill:#333333"
y="282.70709"
x="221.61203"
id="tspan6626"
sodipodi:role="line">ViewResolver</tspan></text>
<rect
transform="scale(1,-1)"
y="-259.30249"
x="332.5405"
height="36.577778"
width="114.4539"
id="rect6628"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="327.51276"
y="255.28464"
id="text6630"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6632"
x="332.51276"
y="255.28464"
style="font-size:11.53426838px;fill:#333333">HandlerMapping</tspan></text>
<rect
y="338.69724"
x="87.803261"
height="121.5683"
width="382.84744"
id="rect6634"
style="fill:#F8F9FA;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="8" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6636"
y="376.61673"
x="108.61351"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333"
y="376.61673"
x="113.61351"
id="tspan6638"
sodipodi:role="line">Root WebApplicationContext</tspan></text>
<text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6640"
y="395.35812"
x="260.93863"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan6644"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
y="395.35812"
x="260.93863"
sodipodi:role="line">(containing middle-tier services, datasources, etc.)</tspan></text>
<rect
transform="scale(1,-1)"
y="-440.06805"
x="164.32933"
height="36.72575"
width="82.040657"
id="rect6648"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6650"
width="82.040657"
height="36.72575"
x="167.73116"
y="-445.45563"
transform="scale(1,-1)"
rx="4" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6652"
y="448.55054"
x="175.87148"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px;fill:#333333"
y="448.55054"
x="178.87148"
id="tspan6654"
sodipodi:role="line">Services</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6656"
width="86.393044"
height="36.704323"
x="306.86328"
y="-439.60837"
transform="scale(1,-1)"
rx="4" /><rect
transform="scale(1,-1)"
y="-444.99475"
x="310.26624"
height="36.701977"
width="86.876686"
id="rect6658"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="305.30771"
y="448.55054"
id="text6660"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6662"
x="308.30771"
y="448.55054"
style="font-size:11.53426838px;fill:#333333">Repositories</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#333333;stroke-width:0.76895118px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 265.33234,295.60379 c 0,42.65169 0,42.65169 0,0 z"
id="path7643"
inkscape:connector-curvature="0" /><path
style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:#333333;stroke-width:3.46028023;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
d="m 270.43505,294.70585 c 0,39.4721 0,39.87903 0,39.87903"
id="path7645"
inkscape:connector-curvature="0" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="352.55331"
y="333.03622"
id="text4963"
sodipodi:linespacing="125%"
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
x="352.55331"
y="333.03622"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
id="tspan4965">Delegates if no bean found</tspan></text>
</g></svg>

Before

Width:  |  Height:  |  Size: 31 KiB

@@ -1 +0,0 @@
../../../src
-465
View File
@@ -1,465 +0,0 @@
* xref:overview.adoc[Overview]
* xref:core.adoc[]
** xref:core/beans.adoc[]
*** xref:core/beans/introduction.adoc[]
*** xref:core/beans/basics.adoc[]
*** xref:core/beans/definition.adoc[]
*** xref:core/beans/dependencies.adoc[]
**** xref:core/beans/dependencies/factory-collaborators.adoc[]
**** xref:core/beans/dependencies/factory-properties-detailed.adoc[]
**** xref:core/beans/dependencies/factory-dependson.adoc[]
**** xref:core/beans/dependencies/factory-lazy-init.adoc[]
**** xref:core/beans/dependencies/factory-autowire.adoc[]
**** xref:core/beans/dependencies/factory-method-injection.adoc[]
*** xref:core/beans/factory-scopes.adoc[]
*** xref:core/beans/factory-nature.adoc[]
*** xref:core/beans/child-bean-definitions.adoc[]
*** xref:core/beans/factory-extension.adoc[]
*** xref:core/beans/annotation-config.adoc[]
**** xref:core/beans/annotation-config/autowired.adoc[]
**** xref:core/beans/annotation-config/autowired-primary.adoc[]
**** xref:core/beans/annotation-config/autowired-qualifiers.adoc[]
**** xref:core/beans/annotation-config/generics-as-qualifiers.adoc[]
**** xref:core/beans/annotation-config/custom-autowire-configurer.adoc[]
**** xref:core/beans/annotation-config/resource.adoc[]
**** xref:core/beans/annotation-config/value-annotations.adoc[]
**** xref:core/beans/annotation-config/postconstruct-and-predestroy-annotations.adoc[]
*** xref:core/beans/classpath-scanning.adoc[]
*** xref:core/beans/standard-annotations.adoc[]
*** xref:core/beans/java.adoc[]
**** xref:core/beans/java/basic-concepts.adoc[]
**** xref:core/beans/java/instantiating-container.adoc[]
**** xref:core/beans/java/bean-annotation.adoc[]
**** xref:core/beans/java/configuration-annotation.adoc[]
**** xref:core/beans/java/composing-configuration-classes.adoc[]
**** xref:core/beans/java/programmatic-bean-registration.adoc[]
*** xref:core/beans/environment.adoc[]
*** xref:core/beans/context-load-time-weaver.adoc[]
*** xref:core/beans/context-introduction.adoc[]
*** xref:core/beans/beanfactory.adoc[]
** xref:core/resources.adoc[]
** xref:core/validation.adoc[]
*** xref:core/validation/validator.adoc[]
*** xref:core/validation/data-binding.adoc[]
*** xref:core/validation/error-code-resolution.adoc[]
*** xref:core/validation/convert.adoc[]
*** xref:core/validation/format.adoc[]
*** xref:core/validation/format-configuring-formatting-globaldatetimeformat.adoc[]
*** xref:core/validation/beanvalidation.adoc[]
** xref:core/expressions.adoc[]
*** xref:core/expressions/evaluation.adoc[]
*** xref:core/expressions/beandef.adoc[]
*** xref:core/expressions/language-ref.adoc[]
**** xref:core/expressions/language-ref/literal.adoc[]
**** xref:core/expressions/language-ref/properties-arrays.adoc[]
**** xref:core/expressions/language-ref/inline-lists.adoc[]
**** xref:core/expressions/language-ref/inline-maps.adoc[]
**** xref:core/expressions/language-ref/array-construction.adoc[]
**** xref:core/expressions/language-ref/methods.adoc[]
**** xref:core/expressions/language-ref/operators.adoc[]
**** xref:core/expressions/language-ref/types.adoc[]
**** xref:core/expressions/language-ref/constructors.adoc[]
**** xref:core/expressions/language-ref/variables.adoc[]
**** xref:core/expressions/language-ref/functions.adoc[]
**** xref:core/expressions/language-ref/varargs.adoc[]
**** xref:core/expressions/language-ref/bean-references.adoc[]
**** xref:core/expressions/language-ref/operator-ternary.adoc[]
**** xref:core/expressions/language-ref/operator-elvis.adoc[]
**** xref:core/expressions/language-ref/operator-safe-navigation.adoc[]
**** xref:core/expressions/language-ref/collection-selection.adoc[]
**** xref:core/expressions/language-ref/collection-projection.adoc[]
**** xref:core/expressions/language-ref/templating.adoc[]
*** xref:core/expressions/example-classes.adoc[]
** xref:core/aop.adoc[]
*** xref:core/aop/introduction-defn.adoc[]
*** xref:core/aop/introduction-spring-defn.adoc[]
*** xref:core/aop/introduction-proxies.adoc[]
*** xref:core/aop/ataspectj.adoc[]
**** xref:core/aop/ataspectj/aspectj-support.adoc[]
**** xref:core/aop/ataspectj/at-aspectj.adoc[]
**** xref:core/aop/ataspectj/pointcuts.adoc[]
**** xref:core/aop/ataspectj/advice.adoc[]
**** xref:core/aop/ataspectj/introductions.adoc[]
**** xref:core/aop/ataspectj/instantiation-models.adoc[]
**** xref:core/aop/ataspectj/example.adoc[]
*** xref:core/aop/schema.adoc[]
*** xref:core/aop/choosing.adoc[]
*** xref:core/aop/mixing-styles.adoc[]
*** xref:core/aop/proxying.adoc[]
*** xref:core/aop/aspectj-programmatic.adoc[]
*** xref:core/aop/using-aspectj.adoc[]
*** xref:core/aop/resources.adoc[]
** xref:core/aop-api.adoc[]
*** xref:core/aop-api/pointcuts.adoc[]
*** xref:core/aop-api/advice.adoc[]
*** xref:core/aop-api/advisor.adoc[]
*** xref:core/aop-api/pfb.adoc[]
*** xref:core/aop-api/concise-proxy.adoc[]
*** xref:core/aop-api/prog.adoc[]
*** xref:core/aop-api/advised.adoc[]
*** xref:core/aop-api/autoproxy.adoc[]
*** xref:core/aop-api/targetsource.adoc[]
*** xref:core/aop-api/extensibility.adoc[]
** xref:core/resilience.adoc[]
** xref:core/null-safety.adoc[]
** xref:core/databuffer-codec.adoc[]
** xref:core/aot.adoc[]
** xref:core/appendix.adoc[]
*** xref:core/appendix/xsd-schemas.adoc[]
*** xref:core/appendix/xml-custom.adoc[]
*** xref:core/appendix/application-startup-steps.adoc[]
* xref:data-access.adoc[]
** xref:data-access/transaction.adoc[]
*** xref:data-access/transaction/motivation.adoc[]
*** xref:data-access/transaction/strategies.adoc[]
*** xref:data-access/transaction/tx-resource-synchronization.adoc[]
*** xref:data-access/transaction/declarative.adoc[]
**** xref:data-access/transaction/declarative/tx-decl-explained.adoc[]
**** xref:data-access/transaction/declarative/first-example.adoc[]
**** xref:data-access/transaction/declarative/rolling-back.adoc[]
**** xref:data-access/transaction/declarative/diff-tx.adoc[]
**** xref:data-access/transaction/declarative/txadvice-settings.adoc[]
**** xref:data-access/transaction/declarative/annotations.adoc[]
**** xref:data-access/transaction/declarative/tx-propagation.adoc[]
**** xref:data-access/transaction/declarative/applying-more-than-just-tx-advice.adoc[]
**** xref:data-access/transaction/declarative/aspectj.adoc[]
*** xref:data-access/transaction/programmatic.adoc[]
*** xref:data-access/transaction/tx-decl-vs-prog.adoc[]
*** xref:data-access/transaction/event.adoc[]
*** xref:data-access/transaction/application-server-integration.adoc[]
*** xref:data-access/transaction/solutions-to-common-problems.adoc[]
*** xref:data-access/transaction/resources.adoc[]
** xref:data-access/dao.adoc[]
** xref:data-access/jdbc.adoc[]
*** xref:data-access/jdbc/choose-style.adoc[]
*** xref:data-access/jdbc/packages.adoc[]
*** xref:data-access/jdbc/core.adoc[]
*** xref:data-access/jdbc/connections.adoc[]
*** xref:data-access/jdbc/advanced.adoc[]
*** xref:data-access/jdbc/simple.adoc[]
*** xref:data-access/jdbc/object.adoc[]
*** xref:data-access/jdbc/parameter-handling.adoc[]
*** xref:data-access/jdbc/embedded-database-support.adoc[]
*** xref:data-access/jdbc/initializing-datasource.adoc[]
** xref:data-access/r2dbc.adoc[]
** xref:data-access/orm.adoc[]
*** xref:data-access/orm/introduction.adoc[]
*** xref:data-access/orm/general.adoc[]
*** xref:data-access/orm/hibernate.adoc[]
*** xref:data-access/orm/jpa.adoc[]
** xref:data-access/oxm.adoc[]
** xref:data-access/appendix.adoc[]
* xref:web.adoc[]
** xref:web/webmvc.adoc[]
*** xref:web/webmvc/mvc-servlet.adoc[]
**** xref:web/webmvc/mvc-servlet/context-hierarchy.adoc[]
**** xref:web/webmvc/mvc-servlet/special-bean-types.adoc[]
**** xref:web/webmvc/mvc-servlet/config.adoc[]
**** xref:web/webmvc/mvc-servlet/container-config.adoc[]
**** xref:web/webmvc/mvc-servlet/sequence.adoc[]
**** xref:web/webmvc/mvc-servlet/handlermapping-path.adoc[]
**** xref:web/webmvc/mvc-servlet/handlermapping-interceptor.adoc[]
**** xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[]
**** xref:web/webmvc/mvc-servlet/viewresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/localeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/multipart.adoc[]
**** xref:web/webmvc/mvc-servlet/logging.adoc[]
*** xref:web/webmvc/filters.adoc[]
*** xref:web/webmvc/message-converters.adoc[]
*** xref:web/webmvc/mvc-controller.adoc[]
**** xref:web/webmvc/mvc-controller/ann.adoc[]
**** xref:web/webmvc/mvc-controller/ann-requestmapping.adoc[]
**** xref:web/webmvc/mvc-controller/ann-methods.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/arguments.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/return-types.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/matrix-variables.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestparam.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestheader.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/cookievalue.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/sessionattributes.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/sessionattribute.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestattrib.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/redirecting-passing-data.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/flash-attributes.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/multipart-forms.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/requestbody.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/httpentity.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/responsebody.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/responseentity.adoc[]
***** xref:web/webmvc/mvc-controller/ann-methods/jackson.adoc[]
**** xref:web/webmvc/mvc-controller/ann-modelattrib-methods.adoc[]
**** xref:web/webmvc/mvc-controller/ann-initbinder.adoc[]
**** xref:web/webmvc/mvc-controller/ann-validation.adoc[]
**** xref:web/webmvc/mvc-controller/ann-exceptionhandler.adoc[]
**** xref:web/webmvc/mvc-controller/ann-advice.adoc[]
*** xref:web/webmvc-functional.adoc[]
*** xref:web/webmvc/mvc-uri-building.adoc[]
*** xref:web/webmvc/mvc-ann-async.adoc[]
*** xref:web/webmvc/mvc-range.adoc[]
*** xref:web/webmvc/mvc-data-binding.adoc[]
*** xref:web/webmvc-cors.adoc[]
*** xref:web/webmvc-versioning.adoc[]
*** xref:web/webmvc/mvc-ann-rest-exceptions.adoc[]
*** xref:web/webmvc/mvc-security.adoc[]
*** xref:web/webmvc/mvc-caching.adoc[]
*** xref:web/webmvc-view.adoc[]
**** xref:web/webmvc-view/mvc-thymeleaf.adoc[]
**** xref:web/webmvc-view/mvc-freemarker.adoc[]
**** xref:web/webmvc-view/mvc-groovymarkup.adoc[]
**** xref:web/webmvc-view/mvc-script.adoc[]
**** xref:web/webmvc-view/mvc-fragments.adoc[]
**** xref:web/webmvc-view/mvc-jsp.adoc[]
**** xref:web/webmvc-view/mvc-feeds.adoc[]
**** xref:web/webmvc-view/mvc-document.adoc[]
**** xref:web/webmvc-view/mvc-jackson.adoc[]
**** xref:web/webmvc-view/mvc-xml-marshalling.adoc[]
**** xref:web/webmvc-view/mvc-xslt.adoc[]
*** xref:web/webmvc/mvc-config.adoc[]
**** xref:web/webmvc/mvc-config/enable.adoc[]
**** xref:web/webmvc/mvc-config/customize.adoc[]
**** xref:web/webmvc/mvc-config/conversion.adoc[]
**** xref:web/webmvc/mvc-config/validation.adoc[]
**** xref:web/webmvc/mvc-config/interceptors.adoc[]
**** xref:web/webmvc/mvc-config/content-negotiation.adoc[]
**** xref:web/webmvc/mvc-config/message-converters.adoc[]
**** xref:web/webmvc/mvc-config/view-controller.adoc[]
**** xref:web/webmvc/mvc-config/view-resolvers.adoc[]
**** xref:web/webmvc/mvc-config/static-resources.adoc[]
**** xref:web/webmvc/mvc-config/default-servlet-handler.adoc[]
**** xref:web/webmvc/mvc-config/path-matching.adoc[]
**** xref:web/webmvc/mvc-config/api-version.adoc[]
**** xref:web/webmvc/mvc-config/advanced-java.adoc[]
**** xref:web/webmvc/mvc-config/advanced-xml.adoc[]
*** xref:web/webmvc/mvc-http2.adoc[]
** xref:web/webmvc-client.adoc[]
** xref:web/webmvc-test.adoc[]
** xref:web/websocket.adoc[]
*** xref:web/websocket/server.adoc[]
*** xref:web/websocket/fallback.adoc[]
*** xref:web/websocket/stomp.adoc[]
**** xref:web/websocket/stomp/overview.adoc[]
**** xref:web/websocket/stomp/benefits.adoc[]
**** xref:web/websocket/stomp/enable.adoc[]
**** xref:web/websocket/stomp/server-config.adoc[]
**** xref:web/websocket/stomp/message-flow.adoc[]
**** xref:web/websocket/stomp/handle-annotations.adoc[]
**** xref:web/websocket/stomp/handle-send.adoc[]
**** xref:web/websocket/stomp/handle-simple-broker.adoc[]
**** xref:web/websocket/stomp/handle-broker-relay.adoc[]
**** xref:web/websocket/stomp/handle-broker-relay-configure.adoc[]
**** xref:web/websocket/stomp/destination-separator.adoc[]
**** xref:web/websocket/stomp/authentication.adoc[]
**** xref:web/websocket/stomp/authentication-token-based.adoc[]
**** xref:web/websocket/stomp/authorization.adoc[]
**** xref:web/websocket/stomp/user-destination.adoc[]
**** xref:web/websocket/stomp/ordered-messages.adoc[]
**** xref:web/websocket/stomp/application-context-events.adoc[]
**** xref:web/websocket/stomp/interceptors.adoc[]
**** xref:web/websocket/stomp/client.adoc[]
**** xref:web/websocket/stomp/scope.adoc[]
**** xref:web/websocket/stomp/configuration-performance.adoc[]
**** xref:web/websocket/stomp/stats.adoc[]
**** xref:web/websocket/stomp/testing.adoc[]
* xref:web-reactive.adoc[]
** xref:web/webflux.adoc[]
*** xref:web/webflux/new-framework.adoc[]
*** xref:web/webflux/reactive-spring.adoc[]
*** xref:web/webflux/dispatcher-handler.adoc[]
*** xref:web/webflux/controller.adoc[]
**** xref:web/webflux/controller/ann.adoc[]
**** xref:web/webflux/controller/ann-requestmapping.adoc[]
**** xref:web/webflux/controller/ann-methods.adoc[]
***** xref:web/webflux/controller/ann-methods/arguments.adoc[]
***** xref:web/webflux/controller/ann-methods/return-types.adoc[]
***** xref:web/webflux/controller/ann-methods/typeconversion.adoc[]
***** xref:web/webflux/controller/ann-methods/matrix-variables.adoc[]
***** xref:web/webflux/controller/ann-methods/requestparam.adoc[]
***** xref:web/webflux/controller/ann-methods/requestheader.adoc[]
***** xref:web/webflux/controller/ann-methods/cookievalue.adoc[]
***** xref:web/webflux/controller/ann-methods/modelattrib-method-args.adoc[]
***** xref:web/webflux/controller/ann-methods/sessionattributes.adoc[]
***** xref:web/webflux/controller/ann-methods/sessionattribute.adoc[]
***** xref:web/webflux/controller/ann-methods/requestattrib.adoc[]
***** xref:web/webflux/controller/ann-methods/multipart-forms.adoc[]
***** xref:web/webflux/controller/ann-methods/requestbody.adoc[]
***** xref:web/webflux/controller/ann-methods/httpentity.adoc[]
***** xref:web/webflux/controller/ann-methods/responsebody.adoc[]
***** xref:web/webflux/controller/ann-methods/responseentity.adoc[]
***** xref:web/webflux/controller/ann-methods/jackson.adoc[]
**** xref:web/webflux/controller/ann-modelattrib-methods.adoc[]
**** xref:web/webflux/controller/ann-initbinder.adoc[]
**** xref:web/webflux/controller/ann-validation.adoc[]
**** xref:web/webflux/controller/ann-exceptions.adoc[]
**** xref:web/webflux/controller/ann-advice.adoc[]
*** xref:web/webflux-functional.adoc[]
*** xref:web/webflux/uri-building.adoc[]
*** xref:web/webflux/range.adoc[]
*** xref:web/webflux/data-binding.adoc[]
*** xref:web/webflux-cors.adoc[]
*** xref:web/webflux-versioning.adoc[]
*** xref:web/webflux/ann-rest-exceptions.adoc[]
*** xref:web/webflux/security.adoc[]
*** xref:web/webflux/caching.adoc[]
*** xref:web/webflux-view.adoc[]
*** xref:web/webflux/config.adoc[]
*** xref:web/webflux/http2.adoc[]
** xref:web/webflux-webclient.adoc[]
*** xref:web/webflux-webclient/client-builder.adoc[]
*** xref:web/webflux-webclient/client-retrieve.adoc[]
*** xref:web/webflux-webclient/client-exchange.adoc[]
*** xref:web/webflux-webclient/client-body.adoc[]
*** xref:web/webflux-webclient/client-filter.adoc[]
*** xref:web/webflux-webclient/client-attributes.adoc[]
*** xref:web/webflux-webclient/client-context.adoc[]
*** xref:web/webflux-webclient/client-synchronous.adoc[]
*** xref:web/webflux-webclient/client-testing.adoc[]
** xref:web/webflux-http-service-client.adoc[]
** xref:web/webflux-websocket.adoc[]
** xref:web/webflux-test.adoc[]
** xref:rsocket.adoc[]
** xref:web/webflux-reactive-libraries.adoc[]
* xref:testing.adoc[]
** xref:testing/introduction.adoc[]
** xref:testing/unit.adoc[]
** xref:testing/integration.adoc[]
** xref:testing/support-jdbc.adoc[]
** xref:testing/testcontext-framework.adoc[]
*** xref:testing/testcontext-framework/key-abstractions.adoc[]
*** xref:testing/testcontext-framework/bootstrapping.adoc[]
*** xref:testing/testcontext-framework/tel-config.adoc[]
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/default-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/inheritance.adoc[]
**** xref:testing/testcontext-framework/ctx-management/env-profiles.adoc[]
**** xref:testing/testcontext-framework/ctx-management/property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web-mocks.adoc[]
**** xref:testing/testcontext-framework/ctx-management/caching.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-pausing.adoc[]
**** xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[]
**** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[]
*** xref:testing/testcontext-framework/fixture-di.adoc[]
*** xref:testing/testcontext-framework/bean-overriding.adoc[]
*** xref:testing/testcontext-framework/web-scoped-beans.adoc[]
*** xref:testing/testcontext-framework/tx.adoc[]
*** xref:testing/testcontext-framework/executing-sql.adoc[]
*** xref:testing/testcontext-framework/parallel-test-execution.adoc[]
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/resttestclient.adoc[]
** xref:testing/mockmvc.adoc[]
*** xref:testing/mockmvc/overview.adoc[]
*** xref:testing/mockmvc/setup-options.adoc[]
*** xref:testing/mockmvc/hamcrest.adoc[]
**** xref:testing/mockmvc/hamcrest/static-imports.adoc[]
**** xref:testing/mockmvc/hamcrest/setup.adoc[]
**** xref:testing/mockmvc/hamcrest/setup-steps.adoc[]
**** xref:testing/mockmvc/hamcrest/requests.adoc[]
**** xref:testing/mockmvc/hamcrest/expectations.adoc[]
**** xref:testing/mockmvc/hamcrest/async-requests.adoc[]
**** xref:testing/mockmvc/hamcrest/vs-streaming-response.adoc[]
**** xref:testing/mockmvc/hamcrest/filters.adoc[]
*** xref:testing/mockmvc/assertj.adoc[]
**** xref:testing/mockmvc/assertj/setup.adoc[]
**** xref:testing/mockmvc/assertj/requests.adoc[]
**** xref:testing/mockmvc/assertj/assertions.adoc[]
**** xref:testing/mockmvc/assertj/integration.adoc[]
*** xref:testing/mockmvc/htmlunit.adoc[]
**** xref:testing/mockmvc/htmlunit/why.adoc[]
**** xref:testing/mockmvc/htmlunit/mah.adoc[]
**** xref:testing/mockmvc/htmlunit/webdriver.adoc[]
**** xref:testing/mockmvc/htmlunit/geb.adoc[]
*** xref:testing/mockmvc/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/mockmvc/resources.adoc[]
** xref:testing/spring-mvc-test-client.adoc[]
** xref:testing/appendix.adoc[]
*** xref:testing/annotations.adoc[]
**** xref:testing/annotations/integration-standard.adoc[]
**** xref:testing/annotations/integration-spring.adoc[]
***** xref:testing/annotations/integration-spring/annotation-bootstrapwith.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-webappconfiguration.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contexthierarchy.adoc[]
***** xref:testing/annotations/integration-spring/annotation-contextcustomizerfactories.adoc[]
***** xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testbean.adoc[]
***** xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[]
***** xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[]
***** xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[]
***** xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[]
***** xref:testing/annotations/integration-spring/annotation-commit.adoc[]
***** xref:testing/annotations/integration-spring/annotation-rollback.adoc[]
***** xref:testing/annotations/integration-spring/annotation-beforetransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-aftertransaction.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sql.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlconfig.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[]
***** xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[]
***** xref:testing/annotations/integration-spring/annotation-disabledinaotmode.adoc[]
**** xref:testing/annotations/integration-junit4.adoc[]
**** xref:testing/annotations/integration-junit-jupiter.adoc[]
**** xref:testing/annotations/integration-meta.adoc[]
*** xref:testing/resources.adoc[]
* xref:integration.adoc[]
** xref:integration/rest-clients.adoc[]
** xref:integration/jms.adoc[]
*** xref:integration/jms/using.adoc[]
*** xref:integration/jms/sending.adoc[]
*** xref:integration/jms/receiving.adoc[]
*** xref:integration/jms/jca-message-endpoint-manager.adoc[]
*** xref:integration/jms/annotated.adoc[]
*** xref:integration/jms/namespace.adoc[]
** xref:integration/jmx.adoc[]
*** xref:integration/jmx/exporting.adoc[]
*** xref:integration/jmx/interface.adoc[]
*** xref:integration/jmx/naming.adoc[]
*** xref:integration/jmx/jsr160.adoc[]
*** xref:integration/jmx/proxy.adoc[]
*** xref:integration/jmx/notifications.adoc[]
*** xref:integration/jmx/resources.adoc[]
** xref:integration/email.adoc[]
** xref:integration/scheduling.adoc[]
** xref:integration/cache.adoc[]
*** xref:integration/cache/strategies.adoc[]
*** xref:integration/cache/annotations.adoc[]
*** xref:integration/cache/jsr-107.adoc[]
*** xref:integration/cache/declarative-xml.adoc[]
*** xref:integration/cache/store-configuration.adoc[]
*** xref:integration/cache/plug.adoc[]
*** xref:integration/cache/specific-config.adoc[]
** xref:integration/observability.adoc[]
** xref:integration/aot-cache.adoc[]
** xref:integration/checkpoint-restore.adoc[]
** xref:integration/appendix.adoc[]
* xref:languages.adoc[]
** xref:languages/kotlin.adoc[]
*** xref:languages/kotlin/requirements.adoc[]
*** xref:languages/kotlin/extensions.adoc[]
*** xref:languages/kotlin/null-safety.adoc[]
*** xref:languages/kotlin/classes-interfaces.adoc[]
*** xref:languages/kotlin/annotations.adoc[]
*** xref:languages/kotlin/bean-registration-dsl.adoc[]
*** xref:languages/kotlin/web.adoc[]
*** xref:languages/kotlin/coroutines.adoc[]
*** xref:languages/kotlin/spring-projects-in.adoc[]
*** xref:languages/kotlin/getting-started.adoc[]
*** xref:languages/kotlin/resources.adoc[]
** xref:languages/groovy.adoc[]
* xref:appendix.adoc[]
* {spring-framework-docs-root}/{spring-version}/javadoc-api/[Java API,window=_blank, role=link-external]
* {spring-framework-api-kdoc}/[Kotlin API,window=_blank, role=link-external]
* {spring-framework-wiki}[Wiki, window=_blank, role=link-external]
@@ -1,162 +0,0 @@
[[appendix]]
= Appendix
This part of the reference documentation covers topics that apply to multiple modules
within the core Spring Framework.
[[appendix-spring-properties]]
== Spring Properties
{spring-framework-api}/core/SpringProperties.html[`SpringProperties`] is a static holder
for properties that control certain low-level aspects of the Spring Framework. Users can
configure these properties via JVM system properties or programmatically via the
`SpringProperties.setProperty(String key, String value)` method. The latter may be
necessary if the deployment environment disallows custom JVM system properties. As an
alternative, these properties may be configured in a `spring.properties` file in the root
of the classpath -- for example, deployed within the application's JAR file.
The following table lists all currently supported Spring properties.
.Supported Spring Properties
[cols="1,1"]
|===
| Name | Description
| `spring.aop.ajc.ignore`
| Instructs Spring to ignore ajc-compiled aspects for Spring AOP proxying, restoring traditional
Spring behavior for scenarios where both weaving and AspectJ auto-proxying are enabled. See
{spring-framework-api}++/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.html#IGNORE_AJC_PROPERTY_NAME++[`AbstractAspectJAdvisorFactory`]
for details.
| `spring.aot.enabled`
| Indicates the application should run with AOT generated artifacts. See
xref:core/aot.adoc[Ahead of Time Optimizations] and
{spring-framework-api}++/aot/AotDetector.html#AOT_ENABLED++[`AotDetector`]
for details.
| `spring.beaninfo.ignore`
| Instructs Spring to use the `Introspector.IGNORE_ALL_BEANINFO` mode when calling the
JavaBeans `Introspector`. See
{spring-framework-api}++/beans/StandardBeanInfoFactory.html#IGNORE_BEANINFO_PROPERTY_NAME++[`StandardBeanInfoFactory`]
for details.
| `spring.cache.reactivestreams.ignore`
| Instructs Spring's caching infrastructure to ignore the presence of Reactive Streams,
in particular Reactor's `Mono`/`Flux` in `@Cacheable` method return type declarations. See
{spring-framework-api}++/cache/interceptor/CacheAspectSupport.html#IGNORE_REACTIVESTREAMS_PROPERTY_NAME++[`CacheAspectSupport`]
for details.
| `spring.classformat.ignore`
| Instructs Spring to ignore class format exceptions during classpath scanning, in
particular for unsupported class file versions. See
{spring-framework-api}++/context/annotation/ClassPathScanningCandidateComponentProvider.html#IGNORE_CLASSFORMAT_PROPERTY_NAME++[`ClassPathScanningCandidateComponentProvider`]
for details.
| `spring.context.checkpoint`
| Property that specifies a common context checkpoint. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#CHECKPOINT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.exit`
| Property for terminating the JVM when the context reaches a specific phase. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#EXIT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.expression.maxLength`
| The maximum length for
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expressions used in XML bean definitions, `@Value`, etc.
| `spring.expression.compiler.mode`
| The mode to use when compiling expressions for the
xref:core/expressions/evaluation.adoc#expressions-compiler-configuration[Spring Expression Language].
| `spring.expression.maxBigPowerBits`
| The default maximum number of bits permitted in the result of a `BigDecimal` or
`BigInteger` power operation within a
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expression.
| `spring.expression.maxOperations`
| The default maximum number of operations permitted during
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expression evaluation.
| `spring.getenv.ignore`
| Instructs Spring to ignore operating system environment variables if a Spring
`Environment` property -- for example, a placeholder in a configuration String -- isn't
resolvable otherwise. See
{spring-framework-api}++/core/env/AbstractEnvironment.html#IGNORE_GETENV_PROPERTY_NAME++[`AbstractEnvironment`]
for details.
| `spring.http.response.flush.enabled`
| Configures the Spring MVC `ServletServerHttpResponse` to allow flushing on the `OutputStream`
returned by `ServletServerHttpResponse#getBody()`. By default, such flush calls are ignored and
only `ServletServerHttpResponse#flush()` will actually flush the response to the network.
| `spring.jdbc.getParameterType.ignore`
| Instructs Spring to ignore `java.sql.ParameterMetaData.getParameterType` completely.
See the note in xref:data-access/jdbc/advanced.adoc#jdbc-batch-list[Batch Operations with a List of Objects].
| `spring.jndi.ignore`
| Instructs Spring to ignore a default JNDI environment, as an optimization for scenarios
where nothing is ever to be found for such JNDI fallback searches to begin with, avoiding
the repeated JNDI lookup overhead. See
{spring-framework-api}++/jndi/JndiLocatorDelegate.html#IGNORE_JNDI_PROPERTY_NAME++[`JndiLocatorDelegate`]
for details.
| `spring.locking.strict`
| Instructs Spring to enforce strict locking during bean creation, rather than the mix of
strict and lenient locking that 6.2 applies by default. See
{spring-framework-api}++/beans/factory/support/DefaultListableBeanFactory.html#STRICT_LOCKING_PROPERTY_NAME++[`DefaultListableBeanFactory`]
for details.
| `spring.objenesis.ignore`
| Instructs Spring to ignore Objenesis, not even attempting to use it. See
{spring-framework-api}++/objenesis/SpringObjenesis.html#IGNORE_OBJENESIS_PROPERTY_NAME++[`SpringObjenesis`]
for details.
| `spring.placeholder.escapeCharacter.default`
| The default escape character for property placeholder support. If not set, `'\'` will
be used. Can be set to a custom escape character or an empty string to disable support
for an escape character. The default escape character be explicitly overridden in
`PropertySourcesPlaceholderConfigurer` and subclasses of `AbstractPropertyResolver`. See
{spring-framework-api}++/core/env/AbstractPropertyResolver.html#DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME++[`AbstractPropertyResolver`]
for details.
| `spring.test.aot.processing.failOnError`
| A boolean flag that controls whether errors encountered during AOT processing in the
_Spring TestContext Framework_ should result in an exception that fails the overall process.
See xref:testing/testcontext-framework/aot.adoc[Ahead of Time Support for Tests].
| `spring.test.constructor.autowire.mode`
| The default _test constructor autowire mode_ to use if `@TestConstructor` is not present
on a test class. See xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-testconstructor[Changing the default test constructor autowire mode].
| `spring.test.context.cache.maxSize`
| The maximum size of the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching].
| `spring.test.context.cache.pause`
| The pause mode for the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/context-pausing.adoc[Context Pausing].
| `spring.test.context.failure.threshold`
| The failure threshold for errors encountered while attempting to load an `ApplicationContext`
in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[Context Failure Threshold].
| `spring.test.extension.context.scope`
| The default _extension context scope_ used by the `SpringExtension` in `@Nested` test
class hierarchies. See
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-springextensionconfig[`@SpringExtensionConfig`].
| `spring.test.enclosing.configuration`
| The default _enclosing configuration inheritance mode_ to use if
`@NestedTestConfiguration` is not present on a test class. See
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-nestedtestconfiguration[Changing the default enclosing configuration inheritance mode].
|===
@@ -1,19 +0,0 @@
[[spring-core]]
= Core Technologies
This part of the reference documentation covers all the technologies that are
absolutely integral to the Spring Framework.
Foremost amongst these is the Spring Framework's Inversion of Control (IoC) container.
A thorough treatment of the Spring Framework's IoC container is closely followed by
comprehensive coverage of Spring's Aspect-Oriented Programming (AOP) technologies.
The Spring Framework has its own AOP framework, which is conceptually easy to
understand and which successfully addresses the 80% sweet spot of AOP requirements
in Java enterprise programming.
Coverage of Spring's integration with AspectJ (currently the richest -- in terms of
features -- and certainly most mature AOP implementation in the Java enterprise space)
is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically
used for native image deployment using GraalVM.
@@ -1,8 +0,0 @@
[[aop-api]]
= Spring AOP APIs
:page-section-summary-toc: 1
The previous chapter described the Spring's support for AOP with @AspectJ and schema-based
aspect definitions. In this chapter, we discuss the lower-level Spring AOP APIs. For common
applications, we recommend the use of Spring AOP with AspectJ pointcuts as described in the
previous chapter.

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