mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| debd312d50 |
+1
-2
@@ -42,8 +42,7 @@ spring-*/src/main/java/META-INF/MANIFEST.MF
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/*
|
||||
!.idea/icon.svg
|
||||
.idea
|
||||
out
|
||||
test-output
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
Generated
-52
@@ -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 |
+2
-2
@@ -9,7 +9,7 @@ plugins {
|
||||
id 'io.github.goooler.shadow' version '8.1.8' apply false
|
||||
id 'me.champeau.jmh' version '0.7.2' apply false
|
||||
id 'me.champeau.mrjar' version '0.1.1'
|
||||
id "net.ltgt.errorprone" version "4.1.0" apply false
|
||||
id "net.ltgt.errorprone" version "3.1.0" apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
@@ -102,7 +102,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
|
||||
// See https://github.com/spring-projects/spring-framework/issues/27497
|
||||
//
|
||||
// "https://junit.org/junit5/docs/5.12.0/api/",
|
||||
// "https://junit.org/junit5/docs/5.11.4/api/",
|
||||
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
|
||||
//"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/",
|
||||
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
|
||||
|
||||
@@ -50,7 +50,7 @@ public class CheckstyleConventions {
|
||||
project.getPlugins().apply(CheckstylePlugin.class);
|
||||
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g"));
|
||||
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
|
||||
checkstyle.setToolVersion("10.21.4");
|
||||
checkstyle.setToolVersion("10.21.2");
|
||||
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
|
||||
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
|
||||
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
|
||||
@@ -64,7 +64,7 @@ public class CheckstyleConventions {
|
||||
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/**", "buildSrc/build/**");
|
||||
"**/.classpath", "**/.project", "**/.gradle/**", "**/node_modules/**");
|
||||
List<String> buildFolders = List.of("bin", "build", "out");
|
||||
project.allprojects(subproject -> {
|
||||
Path rootPath = project.getRootDir().toPath();
|
||||
|
||||
@@ -444,9 +444,9 @@ through Java 8's `java.util.Optional`, as the following example shows:
|
||||
}
|
||||
----
|
||||
|
||||
You can also use a parameter-level `@Nullable` annotation (of any kind in any package --
|
||||
for example, `javax.annotation.Nullable` from JSR-305) or just leverage Kotlin built-in
|
||||
null-safety support:
|
||||
You can also use a `@Nullable` annotation (of any kind in any package -- for example,
|
||||
`javax.annotation.Nullable` from JSR-305) or just leverage Kotlin built-in null-safety
|
||||
support:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -477,13 +477,6 @@ Kotlin::
|
||||
----
|
||||
======
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
A type-level `@Nullable` annotation such as from JSpecify is not supported in Spring
|
||||
Framework 6.2 yet. You need to upgrade to Spring Framework 7.0 where the framework
|
||||
detects type-level annotations and consistently declares JSpecify in its own codebase.
|
||||
====
|
||||
|
||||
You can also use `@Autowired` for interfaces that are well-known resolvable
|
||||
dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`,
|
||||
`ApplicationEventPublisher`, and `MessageSource`. These interfaces and their extended
|
||||
|
||||
@@ -857,7 +857,7 @@ Start by creating the interface with `@HttpExchange` methods:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
public interface RepositoryService {
|
||||
interface RepositoryService {
|
||||
|
||||
@GetExchange("/repos/{owner}/{repo}")
|
||||
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
|
||||
@@ -908,7 +908,7 @@ For `RestTemplate`:
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
|
||||
public interface RepositoryService {
|
||||
interface RepositoryService {
|
||||
|
||||
@GetExchange
|
||||
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
|
||||
|
||||
@@ -7,17 +7,16 @@ by default, exactly in the following order:
|
||||
* `ServletTestExecutionListener`: Configures Servlet API mocks for a
|
||||
`WebApplicationContext`.
|
||||
* `DirtiesContextBeforeModesTestExecutionListener`: Handles the `@DirtiesContext`
|
||||
annotation for "before" modes.
|
||||
annotation for "`before`" modes.
|
||||
* `ApplicationEventsTestExecutionListener`: Provides support for
|
||||
xref:testing/testcontext-framework/application-events.adoc[`ApplicationEvents`].
|
||||
* `BeanOverrideTestExecutionListener`: Provides support for
|
||||
xref:testing/testcontext-framework/bean-overriding.adoc[].
|
||||
* `BeanOverrideTestExecutionListener`: Provides support for xref:testing/testcontext-framework/bean-overriding.adoc[] .
|
||||
* `DependencyInjectionTestExecutionListener`: Provides dependency injection for the test
|
||||
instance.
|
||||
* `MicrometerObservationRegistryTestExecutionListener`: Provides support for
|
||||
Micrometer's `ObservationRegistry`.
|
||||
* `DirtiesContextTestExecutionListener`: Handles the `@DirtiesContext` annotation for
|
||||
"after" modes.
|
||||
"`after`" modes.
|
||||
* `CommonCachesTestExecutionListener`: Clears resource caches in the test's
|
||||
`ApplicationContext` if necessary.
|
||||
* `TransactionalTestExecutionListener`: Provides transactional test execution with
|
||||
@@ -162,16 +161,15 @@ change from release to release -- for example, `SqlScriptsTestExecutionListener`
|
||||
introduced in Spring Framework 4.1, and `DirtiesContextBeforeModesTestExecutionListener`
|
||||
was introduced in Spring Framework 4.2. Furthermore, third-party frameworks like Spring
|
||||
Boot and Spring Security register their own default `TestExecutionListener`
|
||||
implementations by using the aforementioned
|
||||
xref:testing/testcontext-framework/tel-config.adoc#testcontext-tel-config-automatic-discovery[automatic discovery mechanism].
|
||||
implementations by using the aforementioned xref:testing/testcontext-framework/tel-config.adoc#testcontext-tel-config-automatic-discovery[automatic discovery mechanism]
|
||||
.
|
||||
|
||||
To avoid having to be aware of and re-declare all default listeners, you can set the
|
||||
`mergeMode` attribute of `@TestExecutionListeners` to `MergeMode.MERGE_WITH_DEFAULTS`.
|
||||
`MERGE_WITH_DEFAULTS` indicates that locally declared listeners should be merged with the
|
||||
default listeners. The merging algorithm ensures that duplicates are removed from the
|
||||
list and that the resulting set of merged listeners is sorted according to the semantics
|
||||
of `AnnotationAwareOrderComparator`, as described in
|
||||
xref:testing/testcontext-framework/tel-config.adoc#testcontext-tel-config-ordering[Ordering `TestExecutionListener` Implementations].
|
||||
of `AnnotationAwareOrderComparator`, as described in xref:testing/testcontext-framework/tel-config.adoc#testcontext-tel-config-ordering[Ordering `TestExecutionListener` Implementations].
|
||||
If a listener implements `Ordered` or is annotated with `@Order`, it can influence the
|
||||
position in which it is merged with the defaults. Otherwise, locally declared listeners
|
||||
are appended to the list of default listeners when merged.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[[webflux-view]]
|
||||
= View Technologies
|
||||
|
||||
[.small]#xref:web/webmvc-view.adoc[See equivalent in the Servlet stack]#
|
||||
|
||||
The rendering of views in Spring WebFlux is pluggable. Whether you decide to
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[[mvc-view]]
|
||||
= View Technologies
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
[.small]#xref:web/webflux-view.adoc[See equivalent in the Reactive stack]#
|
||||
|
||||
The rendering of views in Spring MVC is pluggable. Whether you decide to use
|
||||
|
||||
@@ -130,7 +130,6 @@ the `Configuration` object.
|
||||
|
||||
[[mvc-view-freemarker-forms]]
|
||||
== Form Handling
|
||||
[.small]#xref:web/webflux-view.adoc#webflux-view-freemarker-forms[See equivalent in the Reactive stack]#
|
||||
|
||||
Spring provides a tag library for use in JSPs that contains, among others, a
|
||||
`<spring:bind/>` element. This element primarily lets forms display values from
|
||||
|
||||
@@ -47,7 +47,7 @@ through https://www.webjars.org/[WebJars].
|
||||
|
||||
[[mvc-view-script-integrate]]
|
||||
== Script Templates
|
||||
[.small]#xref:web/webflux-view.adoc#webflux-view-script-integrate[See equivalent in the Reactive stack]#
|
||||
[.small]#xref:web/webflux-view.adoc#webflux-view-script[See equivalent in the Reactive stack]#
|
||||
|
||||
You can declare a `ScriptTemplateConfigurer` bean to specify the script engine to use,
|
||||
the script files to load, what function to call to render templates, and so on.
|
||||
|
||||
@@ -37,7 +37,7 @@ already set.
|
||||
"application/problem+json" over "application/json" when rendering a `ProblemDetail`,
|
||||
and also falls back on it if no compatible media type is found.
|
||||
|
||||
To enable RFC 9457 responses for Spring MVC exceptions and for any
|
||||
To enable RFC 9457 responses for Spring WebFlux exceptions and for any
|
||||
`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an
|
||||
xref:web/webmvc/mvc-controller/ann-advice.adoc[@ControllerAdvice] in Spring configuration. The handler
|
||||
has an `@ExceptionHandler` method that handles any `ErrorResponse` exception, which
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"@antora/collector-extension": "1.0.0-alpha.3",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.2",
|
||||
"fast-xml-parser": "4.5.2",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.10"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
public class CustomHttpServiceArgumentResolver {
|
||||
|
||||
// tag::httpinterface[]
|
||||
public interface RepositoryService {
|
||||
interface RepositoryService {
|
||||
|
||||
@GetExchange("/repos/search")
|
||||
List<Repository> searchRepository(Search search);
|
||||
|
||||
@@ -7,31 +7,31 @@ javaPlatform {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(platform("com.fasterxml.jackson:jackson-bom:2.18.3"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.14.5"))
|
||||
api(platform("io.netty:netty-bom:4.1.119.Final"))
|
||||
api(platform("com.fasterxml.jackson:jackson-bom:2.18.2"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.14.4"))
|
||||
api(platform("io.netty:netty-bom:4.1.118.Final"))
|
||||
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
|
||||
api(platform("io.projectreactor:reactor-bom:2024.0.4"))
|
||||
api(platform("io.projectreactor:reactor-bom:2024.0.3"))
|
||||
api(platform("io.rsocket:rsocket-bom:1.1.5"))
|
||||
api(platform("org.apache.groovy:groovy-bom:4.0.26"))
|
||||
api(platform("org.apache.groovy:groovy-bom:4.0.24"))
|
||||
api(platform("org.apache.logging.log4j:log4j-bom:2.21.1"))
|
||||
api(platform("org.assertj:assertj-bom:3.27.3"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:12.0.17"))
|
||||
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.17"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:12.0.16"))
|
||||
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.16"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3"))
|
||||
api(platform("org.junit:junit-bom:5.12.0"))
|
||||
api(platform("org.mockito:mockito-bom:5.16.0"))
|
||||
api(platform("org.junit:junit-bom:5.11.4"))
|
||||
api(platform("org.mockito:mockito-bom:5.15.2"))
|
||||
|
||||
constraints {
|
||||
api("com.fasterxml:aalto-xml:1.3.2")
|
||||
api("com.fasterxml.woodstox:woodstox-core:6.7.0")
|
||||
api("com.github.ben-manes.caffeine:caffeine:3.2.0")
|
||||
api("com.github.ben-manes.caffeine:caffeine:3.1.8")
|
||||
api("com.github.librepdf:openpdf:1.3.43")
|
||||
api("com.google.code.findbugs:findbugs:3.0.1")
|
||||
api("com.google.code.findbugs:jsr305:3.0.2")
|
||||
api("com.google.code.gson:gson:2.12.1")
|
||||
api("com.google.protobuf:protobuf-java-util:4.30.0")
|
||||
api("com.google.code.gson:gson:2.11.0")
|
||||
api("com.google.protobuf:protobuf-java-util:4.29.3")
|
||||
api("com.h2database:h2:2.3.232")
|
||||
api("com.jayway.jsonpath:json-path:2.9.0")
|
||||
api("com.oracle.database.jdbc:ojdbc11:21.9.0.0")
|
||||
@@ -43,7 +43,7 @@ dependencies {
|
||||
api("com.sun.xml.bind:jaxb-core:3.0.2")
|
||||
api("com.sun.xml.bind:jaxb-impl:3.0.2")
|
||||
api("com.sun.xml.bind:jaxb-xjc:3.0.2")
|
||||
api("com.thoughtworks.qdox:qdox:2.2.0")
|
||||
api("com.thoughtworks.qdox:qdox:2.1.0")
|
||||
api("com.thoughtworks.xstream:xstream:1.4.21")
|
||||
api("commons-io:commons-io:2.15.0")
|
||||
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2")
|
||||
@@ -100,8 +100,8 @@ dependencies {
|
||||
api("org.apache.derby:derby:10.16.1.1")
|
||||
api("org.apache.derby:derbyclient:10.16.1.1")
|
||||
api("org.apache.derby:derbytools:10.16.1.1")
|
||||
api("org.apache.httpcomponents.client5:httpclient5:5.4.2")
|
||||
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.3.3")
|
||||
api("org.apache.httpcomponents.client5:httpclient5:5.4.1")
|
||||
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.3.1")
|
||||
api("org.apache.poi:poi-ooxml:5.2.5")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.28")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.28")
|
||||
@@ -110,18 +110,18 @@ dependencies {
|
||||
api("org.aspectj:aspectjrt:1.9.22.1")
|
||||
api("org.aspectj:aspectjtools:1.9.22.1")
|
||||
api("org.aspectj:aspectjweaver:1.9.22.1")
|
||||
api("org.awaitility:awaitility:4.3.0")
|
||||
api("org.awaitility:awaitility:4.2.2")
|
||||
api("org.bouncycastle:bcpkix-jdk18on:1.72")
|
||||
api("org.codehaus.jettison:jettison:1.5.4")
|
||||
api("org.crac:crac:1.4.0")
|
||||
api("org.dom4j:dom4j:2.1.4")
|
||||
api("org.easymock:easymock:5.5.0")
|
||||
api("org.eclipse.jetty:jetty-reactive-httpclient:4.0.9")
|
||||
api("org.easymock:easymock:5.4.0")
|
||||
api("org.eclipse.jetty:jetty-reactive-httpclient:4.0.8")
|
||||
api("org.eclipse.persistence:org.eclipse.persistence.jpa:3.0.4")
|
||||
api("org.eclipse:yasson:2.0.4")
|
||||
api("org.ehcache:ehcache:3.10.8")
|
||||
api("org.ehcache:jcache:1.0.1")
|
||||
api("org.freemarker:freemarker:2.3.34")
|
||||
api("org.freemarker:freemarker:2.3.33")
|
||||
api("org.glassfish.external:opendmk_jmxremote_optional_jar:1.0-b01-ea")
|
||||
api("org.glassfish:jakarta.el:4.0.2")
|
||||
api("org.glassfish.tyrus:tyrus-container-servlet:2.1.3")
|
||||
@@ -130,24 +130,24 @@ dependencies {
|
||||
api("org.hibernate:hibernate-core-jakarta:5.6.15.Final")
|
||||
api("org.hibernate:hibernate-validator:7.0.5.Final")
|
||||
api("org.hsqldb:hsqldb:2.7.4")
|
||||
api("org.htmlunit:htmlunit:4.10.0")
|
||||
api("org.htmlunit:htmlunit:4.6.0")
|
||||
api("org.javamoney:moneta:1.4.4")
|
||||
api("org.jruby:jruby:9.4.12.0")
|
||||
api("org.jruby:jruby:9.4.9.0")
|
||||
api("org.junit.support:testng-engine:1.0.5")
|
||||
api("org.mozilla:rhino:1.7.15")
|
||||
api("org.ogce:xpp3:1.1.6")
|
||||
api("org.python:jython-standalone:2.7.4")
|
||||
api("org.python:jython-standalone:2.7.3")
|
||||
api("org.quartz-scheduler:quartz:2.3.2")
|
||||
api("org.seleniumhq.selenium:htmlunit3-driver:4.29.0")
|
||||
api("org.seleniumhq.selenium:selenium-java:4.29.0")
|
||||
api("org.seleniumhq.selenium:htmlunit3-driver:4.26.0")
|
||||
api("org.seleniumhq.selenium:selenium-java:4.26.0")
|
||||
api("org.skyscreamer:jsonassert:1.5.3")
|
||||
api("org.slf4j:slf4j-api:2.0.17")
|
||||
api("org.slf4j:slf4j-api:2.0.16")
|
||||
api("org.testng:testng:7.11.0")
|
||||
api("org.webjars:underscorejs:1.8.3")
|
||||
api("org.webjars:webjars-locator-core:0.59")
|
||||
api("org.webjars:webjars-locator-lite:1.1.0")
|
||||
api("org.webjars:webjars-locator-core:0.55")
|
||||
api("org.webjars:webjars-locator-lite:1.0.0")
|
||||
api("org.xmlunit:xmlunit-assertj:2.10.0")
|
||||
api("org.xmlunit:xmlunit-matchers:2.10.0")
|
||||
api("org.yaml:snakeyaml:2.4")
|
||||
api("org.yaml:snakeyaml:2.3")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=6.2.4
|
||||
version=6.2.3
|
||||
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -205,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
@@ -46,21 +46,6 @@ import org.springframework.lang.Nullable;
|
||||
* Alternatively, you may implement the specific methods that your callers expect,
|
||||
* for example, just {@link #getObject()} or {@link #getIfAvailable()}.
|
||||
*
|
||||
* <p>Note that {@link #getObject()} never returns {@code null} - it will throw a
|
||||
* {@link NoSuchBeanDefinitionException} instead -, whereas {@link #getIfAvailable()}
|
||||
* will return {@code null} if no matching bean is present at all. However, both
|
||||
* methods will throw a {@link NoUniqueBeanDefinitionException} if more than one
|
||||
* matching bean is found without a clear unique winner (see below). Last but not
|
||||
* least, {@link #getIfUnique()} will return {@code null} both when no matching bean
|
||||
* is found and when more than one matching bean is found without a unique winner.
|
||||
*
|
||||
* <p>Uniqueness is generally up to the container's candidate resolution algorithm
|
||||
* but always honors the "primary" flag (with only one of the candidate beans marked
|
||||
* as primary) and the "fallback" flag (with only one of the candidate beans not
|
||||
* marked as fallback). The default-candidate flag is consistently taken into
|
||||
* account as well, even for non-annotation-based injection points, with a single
|
||||
* default candidate winning in case of no clear primary/fallback indication.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.3
|
||||
* @param <T> the object type
|
||||
@@ -203,7 +188,7 @@ public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
|
||||
* if unique (not called otherwise)
|
||||
* @throws BeansException in case of creation errors
|
||||
* @since 5.0
|
||||
* @see #getIfUnique()
|
||||
* @see #getIfAvailable()
|
||||
*/
|
||||
default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
|
||||
T dependency = getIfUnique();
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -443,7 +443,6 @@ public class InstanceSupplierCodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
record ConstructorDescriptor(String beanName, Constructor<?> constructor, Class<?> publicType) {
|
||||
|
||||
Class<?> actualType() {
|
||||
|
||||
-20
@@ -35,7 +35,6 @@ import java.util.Set;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -280,25 +279,6 @@ abstract class AutowireUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the default-candidate status for the specified bean.
|
||||
* @param beanFactory the bean factory
|
||||
* @param beanName the name of the bean to check
|
||||
* @return whether the specified bean qualifies as a default candidate
|
||||
* @since 6.2.4
|
||||
* @see AbstractBeanDefinition#isDefaultCandidate()
|
||||
*/
|
||||
public static boolean isDefaultCandidate(ConfigurableBeanFactory beanFactory, String beanName) {
|
||||
try {
|
||||
BeanDefinition mbd = beanFactory.getMergedBeanDefinition(beanName);
|
||||
return (!(mbd instanceof AbstractBeanDefinition abd) || abd.isDefaultCandidate());
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// A manually registered singleton instance not backed by a BeanDefinition.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reflective {@link InvocationHandler} for lazy access to the current target object.
|
||||
|
||||
+1
-31
@@ -1497,9 +1497,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (candidateName == null) {
|
||||
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
|
||||
}
|
||||
if (candidateName == null) {
|
||||
candidateName = determineDefaultCandidate(candidates);
|
||||
}
|
||||
if (candidateName != null) {
|
||||
Object beanInstance = candidates.get(candidateName);
|
||||
if (beanInstance == null) {
|
||||
@@ -1970,12 +1967,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (priorityCandidate != null) {
|
||||
return priorityCandidate;
|
||||
}
|
||||
// Step 4: pick unique default-candidate
|
||||
String defaultCandidate = determineDefaultCandidate(candidates);
|
||||
if (defaultCandidate != null) {
|
||||
return defaultCandidate;
|
||||
}
|
||||
// Step 5: pick directly registered dependency
|
||||
// Step 4: pick directly registered dependency
|
||||
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
|
||||
String candidateName = entry.getKey();
|
||||
Object beanInstance = entry.getValue();
|
||||
@@ -2136,28 +2128,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a unique "default-candidate" among remaining non-default candidates.
|
||||
* @param candidates a Map of candidate names and candidate instances
|
||||
* (or candidate classes if not created yet) that match the required type
|
||||
* @return the name of the default candidate, or {@code null} if none found
|
||||
* @since 6.2.4
|
||||
* @see AbstractBeanDefinition#isDefaultCandidate()
|
||||
*/
|
||||
@Nullable
|
||||
private String determineDefaultCandidate(Map<String, Object> candidates) {
|
||||
String defaultBeanName = null;
|
||||
for (String candidateBeanName : candidates.keySet()) {
|
||||
if (AutowireUtils.isDefaultCandidate(this, candidateBeanName)) {
|
||||
if (defaultBeanName != null) {
|
||||
return null;
|
||||
}
|
||||
defaultBeanName = candidateBeanName;
|
||||
}
|
||||
}
|
||||
return defaultBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given candidate name matches the bean name or the aliases
|
||||
* stored in this bean definition.
|
||||
|
||||
+15
-25
@@ -253,6 +253,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
|
||||
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
|
||||
boolean locked = (acquireLock && this.singletonLock.tryLock());
|
||||
boolean lenient = false;
|
||||
try {
|
||||
Object singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject == null) {
|
||||
@@ -267,6 +268,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
Thread.currentThread().getName() + "\" while other thread holds " +
|
||||
"singleton lock for other beans " + this.singletonsCurrentlyInCreation);
|
||||
}
|
||||
lenient = true;
|
||||
this.lenientCreationLock.lock();
|
||||
try {
|
||||
this.singletonsInLenientCreation.add(beanName);
|
||||
@@ -327,7 +329,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
// Try late locking for waiting on specific bean to be finished.
|
||||
this.singletonLock.lock();
|
||||
locked = true;
|
||||
// Lock-created singleton object should have appeared in the meantime.
|
||||
// Singleton object should have appeared in the meantime.
|
||||
singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject != null) {
|
||||
return singletonObject;
|
||||
@@ -341,12 +343,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
this.suppressedExceptions = new LinkedHashSet<>();
|
||||
}
|
||||
try {
|
||||
// Leniently created singleton object could have appeared in the meantime.
|
||||
singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject == null) {
|
||||
singletonObject = singletonFactory.getObject();
|
||||
newSingleton = true;
|
||||
}
|
||||
singletonObject = singletonFactory.getObject();
|
||||
newSingleton = true;
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Has the singleton object implicitly appeared in the meantime ->
|
||||
@@ -370,18 +368,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
afterSingletonCreation(beanName);
|
||||
}
|
||||
|
||||
if (newSingleton) {
|
||||
try {
|
||||
addSingleton(beanName, singletonObject);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Leniently accept same instance if implicitly appeared.
|
||||
Object object = this.singletonObjects.get(beanName);
|
||||
if (singletonObject != object) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
addSingleton(beanName, singletonObject);
|
||||
}
|
||||
}
|
||||
return singletonObject;
|
||||
@@ -390,13 +378,15 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
if (locked) {
|
||||
this.singletonLock.unlock();
|
||||
}
|
||||
this.lenientCreationLock.lock();
|
||||
try {
|
||||
this.singletonsInLenientCreation.remove(beanName);
|
||||
this.lenientCreationFinished.signalAll();
|
||||
}
|
||||
finally {
|
||||
this.lenientCreationLock.unlock();
|
||||
if (lenient) {
|
||||
this.lenientCreationLock.lock();
|
||||
try {
|
||||
this.singletonsInLenientCreation.remove(beanName);
|
||||
this.lenientCreationFinished.signalAll();
|
||||
}
|
||||
finally {
|
||||
this.lenientCreationLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -66,15 +66,11 @@ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolve
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition#isAutowireCandidate()
|
||||
* @see AbstractBeanDefinition#isDefaultCandidate()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Map<String, T> resolveAutowireCandidates(ConfigurableListableBeanFactory lbf, Class<T> type) {
|
||||
Map<String, T> candidates = new LinkedHashMap<>();
|
||||
for (String beanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(lbf, type)) {
|
||||
if (AutowireUtils.isAutowireCandidate(lbf, beanName)) {
|
||||
Object beanInstance = lbf.getBean(beanName);
|
||||
if (!(beanInstance instanceof NullBean)) {
|
||||
candidates.put(beanName, (T) beanInstance);
|
||||
}
|
||||
candidates.put(beanName, lbf.getBean(beanName, type));
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
|
||||
-83
@@ -113,7 +113,6 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
class DefaultListableBeanFactoryTests {
|
||||
|
||||
@@ -1659,94 +1658,12 @@ class DefaultListableBeanFactoryTests {
|
||||
bd2.setPrimary(true);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
lbf.registerSingleton("bd3", new TestBean());
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isEqualTo("bd2");
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanByTypeWithUniqueNonFallbackDefinition() {
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setLazyInit(true);
|
||||
bd1.setFallback(true);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setFallback(true);
|
||||
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
lbf.registerBeanDefinition("bd3", bd3);
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isEqualTo("bd3");
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanByTypeWithPrimaryAndUniqueNonFallbackDefinition() {
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setLazyInit(true);
|
||||
bd1.setFallback(true);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setPrimary(true);
|
||||
bd2.setFallback(true);
|
||||
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
lbf.registerBeanDefinition("bd3", bd3);
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isEqualTo("bd2");
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanByTypeWithUniqueNonFallbackAndUniqueNonDefaultDefinition() {
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setLazyInit(true);
|
||||
bd1.setFallback(true);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setFallback(true);
|
||||
bd2.setDefaultCandidate(false);
|
||||
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
|
||||
bd3.setDefaultCandidate(false);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
lbf.registerBeanDefinition("bd3", bd3);
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isEqualTo("bd3");
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanByTypeWithUniqueNonDefaultDefinition() {
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDefaultCandidate(false);
|
||||
bd1.setLazyInit(true);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isEqualTo("bd2");
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanByTypeWithUniqueNonDefaultSingleton() {
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDefaultCandidate(false);
|
||||
bd1.setLazyInit(true);
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
lbf.registerSingleton("bd2", new TestBean());
|
||||
|
||||
TestBean bean = lbf.getBean(TestBean.class);
|
||||
assertThat(bean.getBeanName()).isNull();
|
||||
assertThat(lbf.containsSingleton("bd1")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void getFactoryBeanByTypeWithPrimary() {
|
||||
|
||||
+1
-5
@@ -1770,10 +1770,6 @@ class AutowiredAnnotationBeanPostProcessorTests {
|
||||
parent.registerBeanDefinition("testBean4", tb4);
|
||||
bf.setParentBeanFactory(parent);
|
||||
|
||||
RootBeanDefinition tb5 = new RootBeanDefinition(NullFactoryMethods.class);
|
||||
tb5.setFactoryMethodName("createTestBean");
|
||||
bf.registerBeanDefinition("testBean5", tb5);
|
||||
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThat(bean.streamTestBeans()).containsExactly(bf.getBean("testBean1", TestBean.class),
|
||||
bf.getBean("testBean2", TestBean.class));
|
||||
@@ -1793,7 +1789,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
|
||||
Map<String, TestBean> typeMatches = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, TestBean.class);
|
||||
assertThat(typeMatches.remove("testBean3")).isNotNull();
|
||||
Map<String, TestBean> candidates = SimpleAutowireCandidateResolver.resolveAutowireCandidates(bf, TestBean.class);
|
||||
assertThat(candidates).containsExactlyEntriesOf(typeMatches);
|
||||
assertThat(candidates).containsExactlyEntriesOf(candidates);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,15 +50,10 @@ class DefaultSingletonBeanRegistryTests {
|
||||
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
|
||||
assertThat(tb2Flag.get()).isTrue();
|
||||
|
||||
TestBean tb3 = (TestBean) beanRegistry.getSingleton("tb3", () -> {
|
||||
TestBean newTb = new TestBean();
|
||||
beanRegistry.registerSingleton("tb3", newTb);
|
||||
return newTb;
|
||||
});
|
||||
assertThat(beanRegistry.getSingleton("tb3")).isSameAs(tb3);
|
||||
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(3);
|
||||
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb", "tb2", "tb3");
|
||||
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
|
||||
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(2);
|
||||
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb", "tb2");
|
||||
|
||||
beanRegistry.destroySingletons();
|
||||
assertThat(beanRegistry.getSingletonCount()).isZero();
|
||||
|
||||
+3
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -203,15 +203,6 @@ final class ConfigurationClass {
|
||||
return this.beanMethods;
|
||||
}
|
||||
|
||||
boolean hasNonStaticBeanMethods() {
|
||||
for (BeanMethod beanMethod : this.beanMethods) {
|
||||
if (!beanMethod.getMetadata().isStatic()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
|
||||
this.importedResources.put(importedResource, readerClass);
|
||||
}
|
||||
@@ -232,9 +223,8 @@ final class ConfigurationClass {
|
||||
void validate(ProblemReporter problemReporter) {
|
||||
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
|
||||
|
||||
// A configuration class may not be final (CGLIB limitation) unless it does not have to proxy bean methods
|
||||
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods") && hasNonStaticBeanMethods() &&
|
||||
this.metadata.isFinal()) {
|
||||
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
|
||||
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods") && this.metadata.isFinal()) {
|
||||
problemReporter.error(new FinalConfigurationProblem());
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -112,11 +112,12 @@ class ConfigurationClassEnhancer {
|
||||
|
||||
try {
|
||||
// Use original ClassLoader if config class not locally loaded in overriding class loader
|
||||
boolean classLoaderMismatch = (classLoader != null && classLoader != configClass.getClassLoader());
|
||||
if (classLoaderMismatch && classLoader instanceof SmartClassLoader smartClassLoader) {
|
||||
if (classLoader instanceof SmartClassLoader smartClassLoader &&
|
||||
classLoader != configClass.getClassLoader()) {
|
||||
classLoader = smartClassLoader.getOriginalClassLoader();
|
||||
}
|
||||
Enhancer enhancer = newEnhancer(configClass, classLoader);
|
||||
boolean classLoaderMismatch = (classLoader != null && classLoader != configClass.getClassLoader());
|
||||
Class<?> enhancedClass = createClass(enhancer, classLoaderMismatch);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
|
||||
@@ -167,9 +168,9 @@ class ConfigurationClassEnhancer {
|
||||
try {
|
||||
subclass = enhancer.createClass();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (CodeGenerationException ex) {
|
||||
if (!fallback) {
|
||||
throw (ex instanceof CodeGenerationException cgex ? cgex : new CodeGenerationException(ex));
|
||||
throw ex;
|
||||
}
|
||||
// Possibly a package-visible @Bean method declaration not accessible
|
||||
// in the given ClassLoader -> retry with original ClassLoader
|
||||
@@ -187,7 +188,8 @@ class ConfigurationClassEnhancer {
|
||||
/**
|
||||
* Marker interface to be implemented by all @Configuration CGLIB subclasses.
|
||||
* Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance}
|
||||
* through checking to see if candidate classes are already assignable to it.
|
||||
* through checking to see if candidate classes are already assignable to it, for example,
|
||||
* have already been enhanced.
|
||||
* <p>Also extends {@link BeanFactoryAware}, as all enhanced {@code @Configuration}
|
||||
* classes require access to the {@link BeanFactory} that created them.
|
||||
* <p>Note that this interface is intended for framework-internal use only, however
|
||||
|
||||
+12
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -167,22 +167,14 @@ class ConfigurationClassParser {
|
||||
for (BeanDefinitionHolder holder : configCandidates) {
|
||||
BeanDefinition bd = holder.getBeanDefinition();
|
||||
try {
|
||||
ConfigurationClass configClass;
|
||||
if (bd instanceof AnnotatedBeanDefinition annotatedBeanDef) {
|
||||
configClass = parse(annotatedBeanDef, holder.getBeanName());
|
||||
parse(annotatedBeanDef, holder.getBeanName());
|
||||
}
|
||||
else if (bd instanceof AbstractBeanDefinition abstractBeanDef && abstractBeanDef.hasBeanClass()) {
|
||||
configClass = parse(abstractBeanDef.getBeanClass(), holder.getBeanName());
|
||||
parse(abstractBeanDef.getBeanClass(), holder.getBeanName());
|
||||
}
|
||||
else {
|
||||
configClass = parse(bd.getBeanClassName(), holder.getBeanName());
|
||||
}
|
||||
|
||||
// Downgrade to lite (no enhancement) in case of no instance-level @Bean methods.
|
||||
if (!configClass.hasNonStaticBeanMethods() && ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(
|
||||
bd.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE))) {
|
||||
bd.setAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE,
|
||||
ConfigurationClassUtils.CONFIGURATION_CLASS_LITE);
|
||||
parse(bd.getBeanClassName(), holder.getBeanName());
|
||||
}
|
||||
}
|
||||
catch (BeanDefinitionStoreException ex) {
|
||||
@@ -197,25 +189,20 @@ class ConfigurationClassParser {
|
||||
this.deferredImportSelectorHandler.process();
|
||||
}
|
||||
|
||||
private ConfigurationClass parse(AnnotatedBeanDefinition beanDef, String beanName) {
|
||||
ConfigurationClass configClass = new ConfigurationClass(
|
||||
beanDef.getMetadata(), beanName, (beanDef instanceof ScannedGenericBeanDefinition));
|
||||
processConfigurationClass(configClass, DEFAULT_EXCLUSION_FILTER);
|
||||
return configClass;
|
||||
private void parse(AnnotatedBeanDefinition beanDef, String beanName) {
|
||||
processConfigurationClass(
|
||||
new ConfigurationClass(beanDef.getMetadata(), beanName, (beanDef instanceof ScannedGenericBeanDefinition)),
|
||||
DEFAULT_EXCLUSION_FILTER);
|
||||
}
|
||||
|
||||
private ConfigurationClass parse(Class<?> clazz, String beanName) {
|
||||
ConfigurationClass configClass = new ConfigurationClass(clazz, beanName);
|
||||
processConfigurationClass(configClass, DEFAULT_EXCLUSION_FILTER);
|
||||
return configClass;
|
||||
private void parse(Class<?> clazz, String beanName) {
|
||||
processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
|
||||
}
|
||||
|
||||
final ConfigurationClass parse(@Nullable String className, String beanName) throws IOException {
|
||||
final void parse(@Nullable String className, String beanName) throws IOException {
|
||||
Assert.notNull(className, "No bean class name for configuration class bean definition");
|
||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
|
||||
ConfigurationClass configClass = new ConfigurationClass(reader, beanName);
|
||||
processConfigurationClass(configClass, DEFAULT_EXCLUSION_FILTER);
|
||||
return configClass;
|
||||
processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.scheduling.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
@@ -54,7 +53,6 @@ public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionPa
|
||||
if (StringUtils.hasText(poolSize)) {
|
||||
builder.addPropertyValue("poolSize", poolSize);
|
||||
}
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
+1
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.scheduling.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -42,7 +41,6 @@ public class SchedulerBeanDefinitionParser extends AbstractSingleBeanDefinitionP
|
||||
if (StringUtils.hasText(poolSize)) {
|
||||
builder.addPropertyValue("poolSize", poolSize);
|
||||
}
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@
|
||||
The bean name of the KeyGenerator that is to be used to retrieve the backing caches.
|
||||
|
||||
This attribute is not required, and only needs to be specified
|
||||
explicitly if the default strategy (SimpleKeyGenerator) is not sufficient.
|
||||
explicitly if the default strategy (DefaultKeyGenerator) is not sufficient.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
|
||||
-38
@@ -56,16 +56,6 @@ class BackgroundBootstrapTests {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(5)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void bootstrapWithCircularReference() {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CircularReferenceBeanConfig.class);
|
||||
ctx.getBean("testBean1", TestBean.class);
|
||||
ctx.getBean("testBean2", TestBean.class);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(5)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
@@ -148,34 +138,6 @@ class BackgroundBootstrapTests {
|
||||
}
|
||||
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CircularReferenceBeanConfig {
|
||||
|
||||
@Bean
|
||||
public TestBean testBean1(ObjectProvider<TestBean> testBean2) {
|
||||
new Thread(testBean2::getObject).start();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestBean testBean2(TestBean testBean1) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return new TestBean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomExecutorBeanConfig {
|
||||
|
||||
|
||||
+2
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,7 +67,6 @@ import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -105,7 +104,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).contains(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
@@ -120,7 +118,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).contains(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
@@ -135,7 +132,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).doesNotContain(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isNotSameAs(foo);
|
||||
@@ -147,7 +143,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).doesNotContain(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isNotSameAs(foo);
|
||||
@@ -159,7 +154,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).doesNotContain(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("foo")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("bar")).hasBeanClass()).isTrue();
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
@@ -173,7 +167,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).doesNotContain(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("foo")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("bar")).hasBeanClass()).isTrue();
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
@@ -181,15 +174,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
assertThat(bar.foo).isNotSameAs(foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void enhancementIsNotPresentWithEmptyConfig() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(EmptyConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).hasBeanClass()).isTrue();
|
||||
assertThat(((RootBeanDefinition) beanFactory.getBeanDefinition("config")).getBeanClass().getName()).doesNotContain(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationIntrospectionOfInnerClassesWorksWithDotNameSyntax() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(getClass().getName() + ".SingletonBeanConfig"));
|
||||
@@ -1182,7 +1166,7 @@ class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static final class StaticSingletonBeanConfig {
|
||||
static class StaticSingletonBeanConfig {
|
||||
|
||||
@Bean
|
||||
public static Foo foo() {
|
||||
@@ -1195,10 +1179,6 @@ class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static final class EmptyConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(2)
|
||||
static class OverridingSingletonBeanConfig {
|
||||
|
||||
+5
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,18 +37,16 @@ class InvalidConfigurationClassDefinitionTests {
|
||||
@Test
|
||||
void configurationClassesMayNotBeFinal() {
|
||||
@Configuration
|
||||
final class Config {
|
||||
@Bean String dummy() { return "dummy"; }
|
||||
}
|
||||
final class Config { }
|
||||
|
||||
BeanDefinition configBeanDef = rootBeanDefinition(Config.class).getBeanDefinition();
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerBeanDefinition("config", configBeanDef);
|
||||
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> pp.postProcessBeanFactory(beanFactory))
|
||||
.withMessageContaining("Remove the final modifier");
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(() ->
|
||||
pp.postProcessBeanFactory(beanFactory))
|
||||
.withMessageContaining("Remove the final modifier");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.context.testfixture.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@@ -32,10 +31,4 @@ public class ValueCglibConfiguration {
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String dummy() {
|
||||
return "dummy";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,7 +27,6 @@ import java.util.stream.Stream;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Gather the need for resources available at runtime.
|
||||
@@ -51,14 +50,14 @@ public class ResourceHints {
|
||||
this.resourceBundleHints = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the resources that should be made available at runtime.
|
||||
* @return a stream of {@link ResourcePatternHints}
|
||||
*/
|
||||
public Stream<ResourcePatternHints> resourcePatternHints() {
|
||||
Stream<ResourcePatternHints> patterns = this.resourcePatternHints.stream();
|
||||
return (this.types.isEmpty() ? patterns : Stream.concat(Stream.of(typesPatternResourceHint()), patterns));
|
||||
return (this.types.isEmpty() ? patterns
|
||||
: Stream.concat(Stream.of(typesPatternResourceHint()), patterns));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,18 +70,18 @@ public class ResourceHints {
|
||||
|
||||
/**
|
||||
* Register a pattern if the given {@code location} is available on the
|
||||
* classpath. This delegates to {@link ClassLoader#getResource(String)} which
|
||||
* validates directories as well. The location is not included in the hint.
|
||||
* @param classLoader the ClassLoader to use, or {@code null} for the default
|
||||
* classpath. This delegates to {@link ClassLoader#getResource(String)}
|
||||
* which validates directories as well. The location is not included in
|
||||
* the hint.
|
||||
* @param classLoader the classloader to use
|
||||
* @param location a '/'-separated path name that should exist
|
||||
* @param resourceHint a builder to customize the resource pattern
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ResourceHints registerPatternIfPresent(@Nullable ClassLoader classLoader, String location,
|
||||
Consumer<ResourcePatternHints.Builder> resourceHint) {
|
||||
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
if (classLoaderToUse != null && classLoaderToUse.getResource(location) != null) {
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : getClass().getClassLoader());
|
||||
if (classLoaderToUse.getResource(location) != null) {
|
||||
registerPattern(resourceHint);
|
||||
}
|
||||
return this;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,8 @@ public interface RuntimeHintsRegistrar {
|
||||
/**
|
||||
* Contribute hints to the given {@link RuntimeHints} instance.
|
||||
* @param hints the hints contributed so far for the deployment unit
|
||||
* @param classLoader the ClassLoader to use, or {@code null} for the default
|
||||
* @param classLoader the classloader, or {@code null} if even the system
|
||||
* ClassLoader is not accessible
|
||||
*/
|
||||
void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader);
|
||||
|
||||
|
||||
+13
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,7 +23,6 @@ import java.util.List;
|
||||
import org.springframework.aot.hint.ResourceHints;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
@@ -67,21 +66,19 @@ public class FilePatternResourceHintsRegistrar {
|
||||
|
||||
@Deprecated(since = "6.0.12", forRemoval = true)
|
||||
public void registerHints(ResourceHints hints, @Nullable ClassLoader classLoader) {
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
if (classLoaderToUse != null) {
|
||||
List<String> includes = new ArrayList<>();
|
||||
for (String location : this.classpathLocations) {
|
||||
if (classLoaderToUse.getResource(location) != null) {
|
||||
for (String filePrefix : this.filePrefixes) {
|
||||
for (String fileExtension : this.fileExtensions) {
|
||||
includes.add(location + filePrefix + "*" + fileExtension);
|
||||
}
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : getClass().getClassLoader());
|
||||
List<String> includes = new ArrayList<>();
|
||||
for (String location : this.classpathLocations) {
|
||||
if (classLoaderToUse.getResource(location) != null) {
|
||||
for (String filePrefix : this.filePrefixes) {
|
||||
for (String fileExtension : this.fileExtensions) {
|
||||
includes.add(location + filePrefix + "*" + fileExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!includes.isEmpty()) {
|
||||
hints.registerPattern(hint -> hint.includes(includes.toArray(String[]::new)));
|
||||
}
|
||||
}
|
||||
if (!includes.isEmpty()) {
|
||||
hints.registerPattern(hint -> hint.includes(includes.toArray(String[]::new)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +246,8 @@ public class FilePatternResourceHintsRegistrar {
|
||||
* classpath location that resolves against the {@code ClassLoader}, files
|
||||
* with the configured file prefixes and extensions are registered.
|
||||
* @param hints the hints contributed so far for the deployment unit
|
||||
* @param classLoader the ClassLoader to use, or {@code null} for the default
|
||||
* @param classLoader the classloader, or {@code null} if even the system
|
||||
* ClassLoader isn't accessible
|
||||
*/
|
||||
public void registerHints(ResourceHints hints, @Nullable ClassLoader classLoader) {
|
||||
build().registerHints(hints, classLoader);
|
||||
|
||||
+5
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,11 +48,10 @@ class SpringFactoriesLoaderRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
if (classLoaderToUse != null) {
|
||||
for (String resourceLocation : RESOURCE_LOCATIONS) {
|
||||
registerHints(hints, classLoaderToUse, resourceLocation);
|
||||
}
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader :
|
||||
SpringFactoriesLoaderRuntimeHints.class.getClassLoader());
|
||||
for (String resourceLocation : RESOURCE_LOCATIONS) {
|
||||
registerHints(hints, classLoaderToUse, resourceLocation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-9
@@ -123,17 +123,13 @@ abstract public class AbstractClassGenerator<T> implements ClassGenerator {
|
||||
}
|
||||
|
||||
public Object get(AbstractClassGenerator gen, boolean useCache) {
|
||||
// SPRING PATCH BEGIN
|
||||
Object value = null;
|
||||
if (useCache) {
|
||||
if (!useCache) {
|
||||
return gen.generate(ClassLoaderData.this);
|
||||
}
|
||||
else {
|
||||
Object cachedValue = generatedClasses.get(gen);
|
||||
value = gen.unwrapCachedValue(cachedValue);
|
||||
return gen.unwrapCachedValue(cachedValue);
|
||||
}
|
||||
if (value == null) { // fallback when cached WeakReference returns null
|
||||
value = gen.generate(ClassLoaderData.this);
|
||||
}
|
||||
return value;
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,9 +159,6 @@ public final class GenericTypeResolver {
|
||||
if (genericType instanceof TypeVariable<?> typeVariable) {
|
||||
ResolvableType resolvedTypeVariable = resolveVariable(
|
||||
typeVariable, ResolvableType.forClass(contextClass));
|
||||
if (resolvedTypeVariable == ResolvableType.NONE) {
|
||||
resolvedTypeVariable = ResolvableType.forVariableBounds(typeVariable);
|
||||
}
|
||||
if (resolvedTypeVariable != ResolvableType.NONE) {
|
||||
Class<?> resolved = resolvedTypeVariable.resolve();
|
||||
if (resolved != null) {
|
||||
@@ -179,9 +176,6 @@ public final class GenericTypeResolver {
|
||||
Type typeArgument = typeArguments[i];
|
||||
if (typeArgument instanceof TypeVariable<?> typeVariable) {
|
||||
ResolvableType resolvedTypeArgument = resolveVariable(typeVariable, contextType);
|
||||
if (resolvedTypeArgument == ResolvableType.NONE) {
|
||||
resolvedTypeArgument = ResolvableType.forVariableBounds(typeVariable);
|
||||
}
|
||||
if (resolvedTypeArgument != ResolvableType.NONE) {
|
||||
generics[i] = resolvedTypeArgument;
|
||||
}
|
||||
@@ -235,7 +229,7 @@ public final class GenericTypeResolver {
|
||||
return resolvedType;
|
||||
}
|
||||
}
|
||||
return ResolvableType.NONE;
|
||||
return ResolvableType.forVariableBounds(typeVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -343,7 +343,7 @@ public class ResolvableType implements Serializable {
|
||||
return otherBounds.isAssignableFrom(this, matchedBefore);
|
||||
}
|
||||
else if (!strict) {
|
||||
return (matchedBefore != null ? otherBounds.equalsType(this, matchedBefore) :
|
||||
return (matchedBefore != null ? otherBounds.equalsType(this) :
|
||||
otherBounds.isAssignableTo(this, matchedBefore));
|
||||
}
|
||||
else {
|
||||
@@ -1794,13 +1794,11 @@ public class ResolvableType implements Serializable {
|
||||
* Return {@code true} if these bounds are equal to the specified type.
|
||||
* @param type the type to test against
|
||||
* @return {@code true} if these bounds are equal to the type
|
||||
* @since 6.2.4
|
||||
* @since 6.2.3
|
||||
*/
|
||||
public boolean equalsType(ResolvableType type, @Nullable Map<Type, Type> matchedBefore) {
|
||||
public boolean equalsType(ResolvableType type) {
|
||||
for (ResolvableType bound : this.bounds) {
|
||||
if (this.kind == Kind.UPPER && bound.hasUnresolvableGenerics() ?
|
||||
!type.isAssignableFrom(bound, true, matchedBefore, false) :
|
||||
!type.equalsType(bound)) {
|
||||
if (!type.equalsType(bound)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,12 +36,8 @@ import org.springframework.util.MultiValueMap;
|
||||
*
|
||||
* <p>{@code AnnotatedElementUtils} defines the public API for Spring's
|
||||
* meta-annotation programming model with support for <em>annotation attribute
|
||||
* overrides</em> and {@link AliasFor @AliasFor}. Note, however, that
|
||||
* {@code AnnotatedElementUtils} is effectively a facade for the
|
||||
* {@link MergedAnnotations} API. For fine-grained support consider using the
|
||||
* {@code MergedAnnotations} API directly. If you do not need support for
|
||||
* annotation attribute overrides, {@code @AliasFor}, or merged annotations,
|
||||
* consider using {@link AnnotationUtils} instead.
|
||||
* overrides</em>. If you do not need support for annotation attribute
|
||||
* overrides, consider using {@link AnnotationUtils} instead.
|
||||
*
|
||||
* <p>Note that the features of this class are not provided by the JDK's
|
||||
* introspection facilities themselves.
|
||||
@@ -91,7 +87,6 @@ import org.springframework.util.MultiValueMap;
|
||||
* @since 4.0
|
||||
* @see AliasFor
|
||||
* @see AnnotationAttributes
|
||||
* @see MergedAnnotations
|
||||
* @see AnnotationUtils
|
||||
* @see BridgeMethodResolver
|
||||
*/
|
||||
|
||||
+19
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,7 +60,7 @@ import org.springframework.util.StringUtils;
|
||||
* <h3>Terminology</h3>
|
||||
* The terms <em>directly present</em>, <em>indirectly present</em>, and
|
||||
* <em>present</em> have the same meanings as defined in the class-level
|
||||
* javadoc for {@link AnnotatedElement}.
|
||||
* javadoc for {@link AnnotatedElement} (in Java 8).
|
||||
*
|
||||
* <p>An annotation is <em>meta-present</em> on an element if the annotation
|
||||
* is declared as a meta-annotation on some other annotation which is
|
||||
@@ -73,8 +73,7 @@ import org.springframework.util.StringUtils;
|
||||
* provide support for finding annotations used as meta-annotations. Consult the
|
||||
* javadoc for each method in this class for details. For fine-grained support for
|
||||
* meta-annotations with <em>attribute overrides</em> in <em>composed annotations</em>,
|
||||
* consider using the {@link MergedAnnotations} API directly or the more specific
|
||||
* methods in {@link AnnotatedElementUtils} instead.
|
||||
* consider using {@link AnnotatedElementUtils}'s more specific methods instead.
|
||||
*
|
||||
* <h3>Attribute Aliases</h3>
|
||||
* <p>All public methods in this class that return annotations, arrays of
|
||||
@@ -98,7 +97,6 @@ import org.springframework.util.StringUtils;
|
||||
* @since 2.0
|
||||
* @see AliasFor
|
||||
* @see AnnotationAttributes
|
||||
* @see MergedAnnotations
|
||||
* @see AnnotatedElementUtils
|
||||
* @see BridgeMethodResolver
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotations()
|
||||
@@ -309,11 +307,11 @@ public abstract class AnnotationUtils {
|
||||
* {@code annotationType} from the supplied {@link AnnotatedElement}, where
|
||||
* such annotations are either <em>present</em>, <em>indirectly present</em>,
|
||||
* or <em>meta-present</em> on the element.
|
||||
* <p>This method mimics the functionality of
|
||||
* <p>This method mimics the functionality of Java 8's
|
||||
* {@link java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)}
|
||||
* with support for automatic detection of a <em>container annotation</em>
|
||||
* declared via {@link java.lang.annotation.Repeatable @Repeatable} and with
|
||||
* additional support for meta-annotations.
|
||||
* declared via @{@link java.lang.annotation.Repeatable} (when running on
|
||||
* Java 8 or higher) and with additional support for meta-annotations.
|
||||
* <p>Handles both single annotations and annotations nested within a
|
||||
* <em>container annotation</em>.
|
||||
* <p>Correctly handles <em>bridge methods</em> generated by the
|
||||
@@ -344,7 +342,7 @@ public abstract class AnnotationUtils {
|
||||
* {@code annotationType} from the supplied {@link AnnotatedElement}, where
|
||||
* such annotations are either <em>present</em>, <em>indirectly present</em>,
|
||||
* or <em>meta-present</em> on the element.
|
||||
* <p>This method mimics the functionality
|
||||
* <p>This method mimics the functionality of Java 8's
|
||||
* {@link java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)}
|
||||
* with additional support for meta-annotations.
|
||||
* <p>Handles both single annotations and annotations nested within a
|
||||
@@ -355,9 +353,10 @@ public abstract class AnnotationUtils {
|
||||
* <em>present</em> on the supplied element.
|
||||
* @param annotatedElement the element to look for annotations on
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param containerAnnotationType the type of the container that holds the
|
||||
* annotations; may be {@code null} if a container is not supported or if it
|
||||
* should be looked up via {@link java.lang.annotation.Repeatable @Repeatable}
|
||||
* @param containerAnnotationType the type of the container that holds
|
||||
* the annotations; may be {@code null} if a container is not supported
|
||||
* or if it should be looked up via @{@link java.lang.annotation.Repeatable}
|
||||
* when running on Java 8 or higher
|
||||
* @return the annotations found or an empty set (never {@code null})
|
||||
* @since 4.2
|
||||
* @see #getRepeatableAnnotations(AnnotatedElement, Class)
|
||||
@@ -389,11 +388,11 @@ public abstract class AnnotationUtils {
|
||||
* of {@code annotationType} from the supplied {@link AnnotatedElement},
|
||||
* where such annotations are either <em>directly present</em>,
|
||||
* <em>indirectly present</em>, or <em>meta-present</em> on the element.
|
||||
* <p>This method mimics the functionality of
|
||||
* <p>This method mimics the functionality of Java 8's
|
||||
* {@link java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType(Class)}
|
||||
* with support for automatic detection of a <em>container annotation</em>
|
||||
* declared via {@link java.lang.annotation.Repeatable @Repeatable} and with
|
||||
* additional support for meta-annotations.
|
||||
* declared via @{@link java.lang.annotation.Repeatable} (when running on
|
||||
* Java 8 or higher) and with additional support for meta-annotations.
|
||||
* <p>Handles both single annotations and annotations nested within a
|
||||
* <em>container annotation</em>.
|
||||
* <p>Correctly handles <em>bridge methods</em> generated by the
|
||||
@@ -425,7 +424,7 @@ public abstract class AnnotationUtils {
|
||||
* of {@code annotationType} from the supplied {@link AnnotatedElement},
|
||||
* where such annotations are either <em>directly present</em>,
|
||||
* <em>indirectly present</em>, or <em>meta-present</em> on the element.
|
||||
* <p>This method mimics the functionality of
|
||||
* <p>This method mimics the functionality of Java 8's
|
||||
* {@link java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType(Class)}
|
||||
* with additional support for meta-annotations.
|
||||
* <p>Handles both single annotations and annotations nested within a
|
||||
@@ -436,9 +435,10 @@ public abstract class AnnotationUtils {
|
||||
* <em>present</em> on the supplied element.
|
||||
* @param annotatedElement the element to look for annotations on
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param containerAnnotationType the type of the container that holds the
|
||||
* annotations; may be {@code null} if a container is not supported or if it
|
||||
* should be looked up via {@link java.lang.annotation.Repeatable @Repeatable}
|
||||
* @param containerAnnotationType the type of the container that holds
|
||||
* the annotations; may be {@code null} if a container is not supported
|
||||
* or if it should be looked up via @{@link java.lang.annotation.Repeatable}
|
||||
* when running on Java 8 or higher
|
||||
* @return the annotations found or an empty set (never {@code null})
|
||||
* @since 4.2
|
||||
* @see #getRepeatableAnnotations(AnnotatedElement, Class)
|
||||
|
||||
+2
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ import org.springframework.util.Assert;
|
||||
* <ul>
|
||||
* <li>Explicit and Implicit {@link AliasFor @AliasFor} declarations on one or
|
||||
* more attributes within the annotation</li>
|
||||
* <li>Explicit {@code @AliasFor} declarations for a meta-annotation</li>
|
||||
* <li>Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation</li>
|
||||
* <li>Convention based attribute aliases for a meta-annotation</li>
|
||||
* <li>From a meta-annotation declaration</li>
|
||||
* </ul>
|
||||
@@ -140,9 +140,6 @@ import org.springframework.util.Assert;
|
||||
* @see MergedAnnotationCollectors
|
||||
* @see MergedAnnotationPredicates
|
||||
* @see MergedAnnotationSelectors
|
||||
* @see AliasFor
|
||||
* @see AnnotationUtils
|
||||
* @see AnnotatedElementUtils
|
||||
*/
|
||||
public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>> {
|
||||
|
||||
@@ -563,7 +560,6 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
||||
* @see #withRepeatableContainers(RepeatableContainers)
|
||||
* @see #withAnnotationFilter(AnnotationFilter)
|
||||
* @see #from(AnnotatedElement)
|
||||
* @see org.springframework.test.context.TestContextAnnotationUtils#searchEnclosingClass(Class)
|
||||
*/
|
||||
public Search withEnclosingClasses(Predicate<Class<?>> searchEnclosingClass) {
|
||||
Assert.notNull(searchEnclosingClass, "Predicate must not be null");
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ import org.springframework.util.ClassUtils;
|
||||
* applying the mapping and mirroring rules of an {@link AnnotationTypeMapping}.
|
||||
*
|
||||
* <p>Root attribute values are extracted from a source object using a supplied
|
||||
* {@link ValueExtractor}. This allows various different annotation models to be
|
||||
* {@code BiFunction}. This allows various different annotation models to be
|
||||
* supported by the same class. For example, the attributes source might be an
|
||||
* actual {@link Annotation} instance where methods on the annotation instance
|
||||
* are {@linkplain AnnotationUtils#invokeAnnotationMethod(Method, Object) invoked}
|
||||
|
||||
-15
@@ -348,13 +348,6 @@ public class GenericConversionService implements ConfigurableConversionService {
|
||||
conditionalConverter.matches(sourceType, targetType);
|
||||
}
|
||||
|
||||
public boolean matchesFallback(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return (this.typeInfo.getTargetType() == targetType.getObjectType() &&
|
||||
this.targetType.hasUnresolvableGenerics() &&
|
||||
(!(this.converter instanceof ConditionalConverter conditionalConverter) ||
|
||||
conditionalConverter.matches(sourceType, targetType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
@@ -629,20 +622,12 @@ public class GenericConversionService implements ConfigurableConversionService {
|
||||
|
||||
@Nullable
|
||||
public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
// Look for proper match among all converters (taking full generics into account)
|
||||
for (GenericConverter converter : this.converters) {
|
||||
if (!(converter instanceof ConditionalGenericConverter genericConverter) ||
|
||||
genericConverter.matches(sourceType, targetType)) {
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
// Fallback to pre-6.2.3 behavior: accept Class match for unresolvable generics
|
||||
for (GenericConverter converter : this.converters) {
|
||||
if (converter instanceof ConverterAdapter converterAdapter &&
|
||||
converterAdapter.matchesFallback(sourceType, targetType)) {
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -81,10 +81,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check content-length entry but not for JarURLConnection where
|
||||
// this would open the jar file but effectively never close it ->
|
||||
// for jar entries, always fall back to stream existence instead.
|
||||
if (!(con instanceof JarURLConnection) && con.getContentLengthLong() > 0) {
|
||||
if (con.getContentLengthLong() > 0) {
|
||||
return true;
|
||||
}
|
||||
if (httpCon != null) {
|
||||
|
||||
+1
-5
@@ -816,21 +816,17 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
|
||||
// Clean root entry path to match jar entries format without "!" separators
|
||||
rootEntryPath = rootEntryPath.replace(ResourceUtils.JAR_URL_SEPARATOR, "/");
|
||||
// Search sorted entries from first entry with rootEntryPath prefix
|
||||
boolean rootEntryPathFound = false;
|
||||
for (String entryPath : entriesCache.tailSet(rootEntryPath, false)) {
|
||||
if (!entryPath.startsWith(rootEntryPath)) {
|
||||
// We are beyond the potential matches in the current TreeSet.
|
||||
break;
|
||||
}
|
||||
rootEntryPathFound = true;
|
||||
String relativePath = entryPath.substring(rootEntryPath.length());
|
||||
if (getPathMatcher().match(subPattern, relativePath)) {
|
||||
result.add(rootDirResource.createRelative(relativePath));
|
||||
}
|
||||
}
|
||||
if (rootEntryPathFound) {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,13 +69,7 @@ public class TaskRejectedException extends RejectedExecutionException {
|
||||
|
||||
private static String executorDescription(Executor executor) {
|
||||
if (executor instanceof ExecutorService executorService) {
|
||||
try {
|
||||
return "ExecutorService in " + (executorService.isShutdown() ? "shutdown" : "active") + " state";
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// UnsupportedOperationException/IllegalStateException from ManagedExecutorService.isShutdown()
|
||||
// Falling back to toString() below.
|
||||
}
|
||||
return "ExecutorService in " + (executorService.isShutdown() ? "shutdown" : "active") + " state";
|
||||
}
|
||||
return executor.toString();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -787,9 +787,9 @@ public abstract class StringUtils {
|
||||
pathElements.addFirst(CURRENT_PATH);
|
||||
}
|
||||
|
||||
String joined = collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);
|
||||
// Avoid String concatenation with empty prefix
|
||||
return (prefix.isEmpty() ? joined : prefix + joined);
|
||||
final String joined = collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);
|
||||
// avoid string concatenation with empty prefix
|
||||
return prefix.isEmpty() ? joined : prefix + joined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -243,13 +243,6 @@ class GenericTypeResolverTests {
|
||||
assertThat(resolvedType.toString()).isEqualTo("java.util.List<E>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveTypeFromGenericDefaultMethod() {
|
||||
Type type = method(InterfaceWithDefaultMethod.class, "get", InheritsDefaultMethod.AbstractType.class).getGenericParameterTypes()[0];
|
||||
Type resolvedType = resolveType(type, InheritsDefaultMethod.class);
|
||||
assertThat(resolvedType).isEqualTo(InheritsDefaultMethod.ConcreteType.class);
|
||||
}
|
||||
|
||||
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
||||
Method method = findMethod(target, methodName, parameterTypes);
|
||||
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
||||
@@ -461,20 +454,4 @@ class GenericTypeResolverTests {
|
||||
}
|
||||
}
|
||||
|
||||
public interface InterfaceWithDefaultMethod<T extends InterfaceWithDefaultMethod.AbstractType> {
|
||||
|
||||
default String get(T input) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
interface AbstractType {
|
||||
}
|
||||
}
|
||||
|
||||
public static class InheritsDefaultMethod implements InterfaceWithDefaultMethod<InheritsDefaultMethod.ConcreteType> {
|
||||
|
||||
static class ConcreteType implements InterfaceWithDefaultMethod.AbstractType {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1527,12 +1527,6 @@ class ResolvableTypeTests {
|
||||
assertThat(repository3.isAssignableFromResolvedPart(repository2)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void gh34541() throws Exception {
|
||||
ResolvableType typeWithGenerics = ResolvableType.forField(getClass().getDeclaredField("paymentCreator"));
|
||||
assertThat(typeWithGenerics.isAssignableFrom(PaymentCreator.class)).isTrue();
|
||||
}
|
||||
|
||||
|
||||
private ResolvableType testSerialization(ResolvableType type) throws Exception {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
@@ -1934,18 +1928,6 @@ class ResolvableTypeTests {
|
||||
}
|
||||
|
||||
|
||||
PaymentCreator<? extends Payment, PaymentCreatorParameter<? extends Payment>> paymentCreator;
|
||||
|
||||
static class PaymentCreator<T extends Payment, P extends PaymentCreatorParameter<T>> {
|
||||
}
|
||||
|
||||
static class PaymentCreatorParameter<T extends Payment> {
|
||||
}
|
||||
|
||||
abstract static class Payment {
|
||||
}
|
||||
|
||||
|
||||
private static class ResolvableTypeAssert extends AbstractAssert<ResolvableTypeAssert, ResolvableType>{
|
||||
|
||||
public ResolvableTypeAssert(ResolvableType actual) {
|
||||
|
||||
-22
@@ -581,19 +581,6 @@ class GenericConversionServiceTests {
|
||||
assertThat(bList).allMatch(e -> e instanceof BRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void stringToListOfMapConverterWithFallbackMatch() {
|
||||
conversionService.addConverter(new StringToListOfMapConverter());
|
||||
|
||||
List<Map<String, Object>> result = (List<Map<String, Object>>) conversionService.convert("foo",
|
||||
TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Map.class))
|
||||
);
|
||||
|
||||
assertThat("foo").isEqualTo(result.get(0).get("bar"));
|
||||
}
|
||||
|
||||
|
||||
@ExampleAnnotation(active = true)
|
||||
public String annotatedString;
|
||||
@@ -984,13 +971,4 @@ class GenericConversionServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringToListOfMapConverter implements Converter<String, List<? extends Map<String, ?>>> {
|
||||
|
||||
@Override
|
||||
public List<? extends Map<String, ?>> convert(String source) {
|
||||
return List.of(Map.of("bar", source));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -439,11 +439,7 @@ public abstract class DataSourceUtils {
|
||||
public static Connection getTargetConnection(Connection con) {
|
||||
Connection conToUse = con;
|
||||
while (conToUse instanceof ConnectionProxy connectionProxy) {
|
||||
Connection targetCon = connectionProxy.getTargetConnection();
|
||||
if (targetCon == conToUse) {
|
||||
break;
|
||||
}
|
||||
conToUse = targetCon;
|
||||
conToUse = connectionProxy.getTargetConnection();
|
||||
}
|
||||
return conToUse;
|
||||
}
|
||||
|
||||
+3
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -210,23 +210,13 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
|
||||
sb.append('[').append(this.target).append(']');
|
||||
}
|
||||
else {
|
||||
sb.append("from DataSource [").append(this.targetDataSource).append(']');
|
||||
sb.append(" from DataSource [").append(this.targetDataSource).append(']');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
case "close" -> {
|
||||
// Handle close method: only close if not within a transaction.
|
||||
if (this.target != null) {
|
||||
ConnectionHolder conHolder = (ConnectionHolder)
|
||||
TransactionSynchronizationManager.getResource(this.targetDataSource);
|
||||
if (conHolder != null && conHolder.hasConnection() && conHolder.getConnection() == this.target) {
|
||||
// It's the transactional Connection: Don't close it.
|
||||
conHolder.released();
|
||||
}
|
||||
else {
|
||||
DataSourceUtils.doCloseConnection(this.target, this.targetDataSource);
|
||||
}
|
||||
}
|
||||
DataSourceUtils.doReleaseConnection(this.target, this.targetDataSource);
|
||||
this.closed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,6 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* @see #setSql
|
||||
* @see #compile
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public SqlFunction() {
|
||||
setRowsExpected(1);
|
||||
}
|
||||
@@ -74,7 +73,6 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* @param ds the DataSource to obtain connections from
|
||||
* @param sql the SQL to execute
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public SqlFunction(DataSource ds, String sql) {
|
||||
setRowsExpected(1);
|
||||
setDataSource(ds);
|
||||
@@ -89,7 +87,6 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* {@code java.sql.Types} class
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public SqlFunction(DataSource ds, String sql, int[] types) {
|
||||
setRowsExpected(1);
|
||||
setDataSource(ds);
|
||||
@@ -107,7 +104,6 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* @see #setResultType(Class)
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public SqlFunction(DataSource ds, String sql, int[] types, Class<T> resultType) {
|
||||
setRowsExpected(1);
|
||||
setDataSource(ds);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -84,20 +84,14 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Set the number of rows expected.
|
||||
* <p>This can be used to ensure efficient storage of results. The
|
||||
* default behavior is not to expect any specific number of rows.
|
||||
* @deprecated since 6.2.4 with no replacement since the property has never
|
||||
* had any affect on behavior; to be removed in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
public void setRowsExpected(int rowsExpected) {
|
||||
this.rowsExpected = rowsExpected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of rows expected.
|
||||
* @deprecated since 6.2.4 with no replacement since the property has never
|
||||
* had any affect on behavior; to be removed in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
public int getRowsExpected() {
|
||||
return this.rowsExpected;
|
||||
}
|
||||
|
||||
+6
-43
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -72,7 +72,7 @@ public class DataSourceTransactionManagerTests {
|
||||
|
||||
protected DataSource ds = mock();
|
||||
|
||||
protected ConnectionProxy con = mock();
|
||||
protected Connection con = mock();
|
||||
|
||||
protected DataSourceTransactionManager tm;
|
||||
|
||||
@@ -81,7 +81,6 @@ public class DataSourceTransactionManagerTests {
|
||||
void setup() throws Exception {
|
||||
tm = createTransactionManager(ds);
|
||||
given(ds.getConnection()).willReturn(con);
|
||||
given(con.getTargetConnection()).willThrow(new UnsupportedOperationException());
|
||||
}
|
||||
|
||||
protected DataSourceTransactionManager createTransactionManager(DataSource ds) {
|
||||
@@ -1074,9 +1073,9 @@ public class DataSourceTransactionManagerTests {
|
||||
Connection tCon = dsProxy.getConnection();
|
||||
tCon.getWarnings();
|
||||
tCon.clearWarnings();
|
||||
assertThat(((ConnectionProxy) tCon).getTargetConnection()).isEqualTo(con);
|
||||
assertThat(((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()).isEqualTo(con);
|
||||
// should be ignored
|
||||
tCon.close();
|
||||
dsProxy.getConnection().close();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new UncategorizedSQLException("", "", ex);
|
||||
@@ -1110,9 +1109,9 @@ public class DataSourceTransactionManagerTests {
|
||||
Connection tCon = dsProxy.getConnection();
|
||||
assertThatExceptionOfType(SQLException.class).isThrownBy(tCon::getWarnings);
|
||||
tCon.clearWarnings();
|
||||
assertThat(((ConnectionProxy) tCon).getTargetConnection()).isEqualTo(con);
|
||||
assertThat(((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()).isEqualTo(con);
|
||||
// should be ignored
|
||||
tCon.close();
|
||||
dsProxy.getConnection().close();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new UncategorizedSQLException("", "", ex);
|
||||
@@ -1128,42 +1127,6 @@ public class DataSourceTransactionManagerTests {
|
||||
verify(con).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTransactionAwareDataSourceProxyWithEarlyConnection() throws Exception {
|
||||
given(ds.getConnection()).willReturn(mock(Connection.class), con);
|
||||
given(con.getAutoCommit()).willReturn(true);
|
||||
given(con.getWarnings()).willThrow(new SQLException());
|
||||
|
||||
TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds);
|
||||
dsProxy.setLazyTransactionalConnections(false);
|
||||
Connection tCon = dsProxy.getConnection();
|
||||
|
||||
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
|
||||
tt.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
// something transactional
|
||||
assertThat(DataSourceUtils.getConnection(ds)).isEqualTo(con);
|
||||
try {
|
||||
// should close the early Connection obtained before the transaction
|
||||
tCon.close();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new UncategorizedSQLException("", "", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
|
||||
|
||||
InOrder ordered = inOrder(con);
|
||||
ordered.verify(con).setAutoCommit(false);
|
||||
ordered.verify(con).commit();
|
||||
ordered.verify(con).setAutoCommit(true);
|
||||
verify(con).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTransactionAwareDataSourceProxyWithSuspension() throws Exception {
|
||||
given(con.getAutoCommit()).willReturn(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -163,7 +163,6 @@ class SqlQueryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void testStringQueryWithResults() throws Exception {
|
||||
String[] dbResults = new String[] { "alpha", "beta", "charlie" };
|
||||
given(resultSet.next()).willReturn(true, true, true, false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -178,8 +178,7 @@ public class MockCookie extends Cookie {
|
||||
cookie.setComment(extractAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
else if (!attribute.isEmpty()) {
|
||||
String[] nameAndValue = extractOptionalAttributeNameAndValue(attribute, setCookieHeader);
|
||||
cookie.setAttribute(nameAndValue[0], nameAndValue[1]);
|
||||
cookie.setAttribute(attribute, extractOptionalAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
}
|
||||
return cookie;
|
||||
@@ -192,9 +191,9 @@ public class MockCookie extends Cookie {
|
||||
return nameAndValue[1];
|
||||
}
|
||||
|
||||
private static String[] extractOptionalAttributeNameAndValue(String attribute, String header) {
|
||||
private static String extractOptionalAttributeValue(String attribute, String header) {
|
||||
String[] nameAndValue = attribute.split("=");
|
||||
return (nameAndValue.length == 2 ? nameAndValue : new String[] {attribute, ""});
|
||||
return nameAndValue.length == 2 ? nameAndValue[1] : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -686,12 +686,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, @Nullable String value) {
|
||||
if (value == null) {
|
||||
this.headers.remove(name);
|
||||
}
|
||||
else {
|
||||
setHeaderValue(name, value);
|
||||
}
|
||||
setHeaderValue(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -743,17 +738,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
|
||||
}
|
||||
else if (HttpHeaders.CONTENT_LANGUAGE.equalsIgnoreCase(name)) {
|
||||
String contentLanguages = value.toString();
|
||||
// only set the locale if we replace the header or if there was none before
|
||||
if (replaceHeader || !this.headers.containsKey(HttpHeaders.CONTENT_LANGUAGE)) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(HttpHeaders.CONTENT_LANGUAGE, contentLanguages);
|
||||
Locale language = headers.getContentLanguage();
|
||||
this.locale = language != null ? language : Locale.getDefault();
|
||||
doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguages, replaceHeader);
|
||||
}
|
||||
else {
|
||||
doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguages, false);
|
||||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(HttpHeaders.CONTENT_LANGUAGE, contentLanguages);
|
||||
Locale language = headers.getContentLanguage();
|
||||
setLocale(language != null ? language : Locale.getDefault());
|
||||
// Since setLocale() sets the Content-Language header to the given
|
||||
// single Locale, we have to explicitly set the Content-Language header
|
||||
// to the user-provided value.
|
||||
doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguages, true);
|
||||
return true;
|
||||
}
|
||||
else if (HttpHeaders.SET_COOKIE.equalsIgnoreCase(name)) {
|
||||
|
||||
+11
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,20 +43,19 @@ import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@code TestContextAnnotationUtils} is a collection of utility methods that
|
||||
* complements the standard support already available in {@link MergedAnnotations},
|
||||
* {@link AnnotationUtils}, and {@link AnnotatedElementUtils}, while transparently
|
||||
* honoring {@link NestedTestConfiguration @NestedTestConfiguration} semantics.
|
||||
* complements the standard support already available in {@link AnnotationUtils}
|
||||
* and {@link AnnotatedElementUtils}, while transparently honoring
|
||||
* {@link NestedTestConfiguration @NestedTestConfiguration} semantics.
|
||||
*
|
||||
* <p>Mainly for internal use within the <em>Spring TestContext Framework</em>
|
||||
* but also supported for third-party integrations with the TestContext framework.
|
||||
*
|
||||
* <p>Whereas {@code MergedAnnotations}, {@code AnnotationUtils} and
|
||||
* {@code AnnotatedElementUtils} provide utilities for <em>getting</em> or
|
||||
* <em>finding</em> annotations, {@code TestContextAnnotationUtils} goes a step
|
||||
* further by providing support for determining the <em>root class</em> on which
|
||||
* an annotation is declared, either directly or indirectly via a
|
||||
* <em>composed annotation</em>. This additional information is encapsulated in
|
||||
* an {@link AnnotationDescriptor}.
|
||||
* <p>Whereas {@code AnnotationUtils} and {@code AnnotatedElementUtils} provide
|
||||
* utilities for <em>getting</em> or <em>finding</em> annotations,
|
||||
* {@code TestContextAnnotationUtils} goes a step further by providing support
|
||||
* for determining the <em>root class</em> on which an annotation is declared,
|
||||
* either directly or indirectly via a <em>composed annotation</em>. This
|
||||
* additional information is encapsulated in an {@link AnnotationDescriptor}.
|
||||
*
|
||||
* <p>The additional information provided by an {@code AnnotationDescriptor} is
|
||||
* required by the <em>Spring TestContext Framework</em> in order to be able to
|
||||
@@ -68,11 +67,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* example, {@link ContextConfiguration#inheritLocations}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 5.3
|
||||
* @see MergedAnnotations
|
||||
* @see MergedAnnotations.Search
|
||||
* @see MergedAnnotations.Search#withEnclosingClasses(Predicate)
|
||||
* @see #searchEnclosingClass(Class)
|
||||
* @since 5.3, though originally since 4.0 as {@code org.springframework.test.util.MetaAnnotationUtils}
|
||||
* @see AnnotationUtils
|
||||
* @see AnnotatedElementUtils
|
||||
* @see AnnotationDescriptor
|
||||
|
||||
+3
-47
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,9 +22,8 @@ package org.springframework.test.context;
|
||||
* the listener is registered.
|
||||
*
|
||||
* <p>Note that not all testing frameworks support all lifecycle callbacks defined
|
||||
* in this API. For example, the {@link #beforeTestExecution(TestContext)
|
||||
* beforeTestExecution} and {@link #afterTestExecution(TestContext)
|
||||
* afterTestExecution} callbacks are not supported in conjunction with JUnit 4 when
|
||||
* in this API. For example, {@link #beforeTestExecution} and
|
||||
* {@link #afterTestExecution} are not supported in conjunction with JUnit 4 when
|
||||
* using the {@link org.springframework.test.context.junit4.rules.SpringMethodRule
|
||||
* SpringMethodRule}.
|
||||
*
|
||||
@@ -42,35 +41,6 @@ package org.springframework.test.context;
|
||||
* {@link org.springframework.core.annotation.Order @Order} annotation. See
|
||||
* {@link TestContextBootstrapper#getTestExecutionListeners()} for details.
|
||||
*
|
||||
* <h3>Wrapping Behavior for Listeners</h3>
|
||||
*
|
||||
* <p>The {@link TestContextManager} guarantees <em>wrapping</em> behavior for
|
||||
* multiple registered listeners that implement lifecycle callbacks such as
|
||||
* {@link #beforeTestClass(TestContext) beforeTestClass},
|
||||
* {@link #afterTestClass(TestContext) afterTestClass},
|
||||
* {@link #beforeTestMethod(TestContext) beforeTestMethod},
|
||||
* {@link #afterTestMethod(TestContext) afterTestMethod},
|
||||
* {@link #beforeTestExecution(TestContext) beforeTestExecution}, and
|
||||
* {@link #afterTestExecution(TestContext) afterTestExecution}. This means that,
|
||||
* given two listeners {@code Listener1} and {@code Listener2} with {@code Listener1}
|
||||
* registered before {@code Listener2}, any <em>before</em> callbacks implemented
|
||||
* by {@code Listener1} are guaranteed to be invoked <strong>before</strong> any
|
||||
* <em>before</em> callbacks implemented by {@code Listener2}. Similarly, given
|
||||
* the same two listeners registered in the same order, any <em>after</em>
|
||||
* callbacks implemented by {@code Listener1} are guaranteed to be invoked
|
||||
* <strong>after</strong> any <em>after</em> callbacks implemented by
|
||||
* {@code Listener2}. {@code Listener1} is therefore said to <em>wrap</em>
|
||||
* {@code Listener2}.
|
||||
*
|
||||
* <p>For a concrete example, consider the relationship between the
|
||||
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* TransactionalTestExecutionListener} and the
|
||||
* {@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
|
||||
* SqlScriptsTestExecutionListener}. The {@code SqlScriptsTestExecutionListener}
|
||||
* is registered after the {@code TransactionalTestExecutionListener}, so that
|
||||
* SQL scripts are executed within a transaction managed by the
|
||||
* {@code TransactionalTestExecutionListener}.
|
||||
*
|
||||
* <h3>Registering TestExecutionListener Implementations</h3>
|
||||
*
|
||||
* <p>A {@code TestExecutionListener} can be registered explicitly for a test class,
|
||||
@@ -130,8 +100,6 @@ public interface TestExecutionListener {
|
||||
* the class.
|
||||
* <p>This method should be called immediately before framework-specific
|
||||
* <em>before class</em> lifecycle callbacks.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context for the test; never {@code null}
|
||||
@@ -150,8 +118,6 @@ public interface TestExecutionListener {
|
||||
* {@link org.springframework.test.context.junit4.rules.SpringMethodRule
|
||||
* SpringMethodRule}). In any case, this method must be called prior to any
|
||||
* framework-specific lifecycle callbacks.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for listeners.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context for the test; never {@code null}
|
||||
@@ -171,8 +137,6 @@ public interface TestExecutionListener {
|
||||
* this method might be something like {@code beforeTestSetUp} or
|
||||
* {@code beforeEach}; however, it is unfortunately impossible to rename
|
||||
* this method due to backward compatibility concerns.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context in which the test method will be
|
||||
@@ -192,8 +156,6 @@ public interface TestExecutionListener {
|
||||
* or logging purposes.
|
||||
* <p>This method <strong>must</strong> be called after framework-specific
|
||||
* <em>before</em> lifecycle callbacks.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context in which the test method will be
|
||||
@@ -214,8 +176,6 @@ public interface TestExecutionListener {
|
||||
* or logging purposes.
|
||||
* <p>This method <strong>must</strong> be called before framework-specific
|
||||
* <em>after</em> lifecycle callbacks.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context in which the test method will be
|
||||
@@ -240,8 +200,6 @@ public interface TestExecutionListener {
|
||||
* this method might be something like {@code afterTestTearDown} or
|
||||
* {@code afterEach}; however, it is unfortunately impossible to rename
|
||||
* this method due to backward compatibility concerns.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context in which the test method was
|
||||
@@ -259,8 +217,6 @@ public interface TestExecutionListener {
|
||||
* the class.
|
||||
* <p>This method should be called immediately after framework-specific
|
||||
* <em>after class</em> lifecycle callbacks.
|
||||
* <p>See the {@linkplain TestExecutionListener class-level documentation}
|
||||
* for details on wrapping behavior for lifecycle callbacks.
|
||||
* <p>The default implementation is <em>empty</em>. Can be overridden by
|
||||
* concrete classes as necessary.
|
||||
* @param testContext the test context for the test; never {@code null}
|
||||
|
||||
+6
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.test.context.aot;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -26,9 +25,9 @@ import org.springframework.test.context.SmartContextLoader;
|
||||
|
||||
/**
|
||||
* Strategy interface for loading an {@link ApplicationContext} for build-time
|
||||
* {@linkplain #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* AOT processing} as well as run-time {@linkplain #loadContextForAotRuntime
|
||||
* AOT execution} for an integration test managed by the Spring TestContext Framework.
|
||||
* {@linkplain #loadContextForAotProcessing AOT processing} as well as run-time
|
||||
* {@linkplain #loadContextForAotRuntime AOT execution} for an integration test
|
||||
* managed by the Spring TestContext Framework.
|
||||
*
|
||||
* <p>{@code AotContextLoader} is an extension of the {@link SmartContextLoader}
|
||||
* SPI that allows a context loader to optionally provide ahead-of-time (AOT)
|
||||
@@ -43,30 +42,6 @@ import org.springframework.test.context.SmartContextLoader;
|
||||
*/
|
||||
public interface AotContextLoader extends SmartContextLoader {
|
||||
|
||||
/**
|
||||
* Load a new {@link ApplicationContext} for AOT build-time processing based
|
||||
* on the supplied {@link MergedContextConfiguration}, configure the context,
|
||||
* and return the context.
|
||||
* <p>The default implementation of this method throws an
|
||||
* {@link UnsupportedOperationException}. Note, however, that the framework
|
||||
* invokes {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)}
|
||||
* as of Spring Framework 6.2.4.
|
||||
* @param mergedConfig the merged context configuration to use to load the
|
||||
* application context
|
||||
* @return a new {@code GenericApplicationContext}
|
||||
* @throws ContextLoadException if context loading failed
|
||||
* @see #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* @see #loadContextForAotRuntime(MergedContextConfiguration, ApplicationContextInitializer)
|
||||
* @deprecated as of Spring Framework 6.2.4, in favor of
|
||||
* {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)};
|
||||
* to be removed in Spring Framework 8.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
default ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
throw new UnsupportedOperationException(
|
||||
"Invoke loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a new {@link ApplicationContext} for AOT build-time processing based
|
||||
* on the supplied {@link MergedContextConfiguration}, configure the context,
|
||||
@@ -90,23 +65,13 @@ public interface AotContextLoader extends SmartContextLoader {
|
||||
* throw new ContextLoadException(context, ex);
|
||||
* }
|
||||
* </pre>
|
||||
* <p>For backward compatibility, the default implementation of this method
|
||||
* delegates to {@link #loadContextForAotProcessing(MergedContextConfiguration)}.
|
||||
* Note, however, that the framework only invokes this method as of Spring
|
||||
* Framework 6.2.4.
|
||||
* @param mergedConfig the merged context configuration to use to load the
|
||||
* application context
|
||||
* @param runtimeHints the runtime hints
|
||||
* @return a new {@code GenericApplicationContext}
|
||||
* @throws ContextLoadException if context loading failed
|
||||
* @since 6.2.4
|
||||
* @see #loadContextForAotRuntime(MergedContextConfiguration, ApplicationContextInitializer)
|
||||
*/
|
||||
default ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) throws Exception {
|
||||
|
||||
return loadContextForAotProcessing(mergedConfig);
|
||||
}
|
||||
ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception;
|
||||
|
||||
/**
|
||||
* Load a new {@link ApplicationContext} for AOT run-time execution based on
|
||||
@@ -133,7 +98,7 @@ public interface AotContextLoader extends SmartContextLoader {
|
||||
* be applied to the context in order to recreate bean definitions
|
||||
* @return a new {@code GenericApplicationContext}
|
||||
* @throws ContextLoadException if context loading failed
|
||||
* @see #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* @see #loadContextForAotProcessing(MergedContextConfiguration)
|
||||
*/
|
||||
ApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig,
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext> initializer) throws Exception;
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -331,7 +331,7 @@ public class TestContextAotGenerator {
|
||||
* create {@link GenericApplicationContext GenericApplicationContexts}.
|
||||
* @throws TestContextAotException if an error occurs while loading the application
|
||||
* context or if one of the prerequisites is not met
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
*/
|
||||
private GenericApplicationContext loadContextForAotProcessing(
|
||||
MergedContextConfiguration mergedConfig) throws TestContextAotException {
|
||||
@@ -345,7 +345,7 @@ public class TestContextAotGenerator {
|
||||
|
||||
if (contextLoader instanceof AotContextLoader aotContextLoader) {
|
||||
try {
|
||||
ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig, this.runtimeHints);
|
||||
ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig);
|
||||
if (context instanceof GenericApplicationContext gac) {
|
||||
return gac;
|
||||
}
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class MockitoResetTestExecutionListener extends AbstractTestExecutionList
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
return Ordered.LOWEST_PRECEDENCE - 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.test.context.support;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -226,13 +225,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
|
||||
* {@code ApplicationContext} from the supplied merged context configuration
|
||||
* @since 6.0
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
* @deprecated as of Spring Framework 6.2.4, in favor of
|
||||
* {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)};
|
||||
* to be removed in Spring Framework 8.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
AotContextLoader loader = getAotContextLoader(mergedConfig);
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -242,33 +236,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
|
||||
return loader.loadContextForAotProcessing(mergedConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||
* an {@link ApplicationContext} for AOT processing.
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||
* default loaders. See {@link #loadContext(MergedContextConfiguration)} for
|
||||
* details.
|
||||
* @param mergedConfig the merged context configuration to use to load the application context
|
||||
* @param runtimeHints the runtime hints
|
||||
* @return a new application context
|
||||
* @throws IllegalArgumentException if the supplied merged configuration is {@code null}
|
||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||
* {@code ApplicationContext} from the supplied merged context configuration
|
||||
* @since 6.2.4
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
*/
|
||||
@Override
|
||||
public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) throws Exception {
|
||||
|
||||
AotContextLoader loader = getAotContextLoader(mergedConfig);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Delegating to %s to load context for AOT processing for %s"
|
||||
.formatted(name(loader), mergedConfig));
|
||||
}
|
||||
return loader.loadContextForAotProcessing(mergedConfig, runtimeHints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||
* an {@link ApplicationContext} for AOT run-time execution.
|
||||
|
||||
+1
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,6 @@ import java.util.Arrays;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -127,41 +126,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @throws Exception if context loading failed
|
||||
* @since 6.0
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
* @deprecated as of Spring Framework 6.2.4, in favor of
|
||||
* {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)};
|
||||
* to be removed in Spring Framework 8.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public final GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
|
||||
return loadContext(mergedConfig, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a {@link GenericApplicationContext} for AOT build-time processing based
|
||||
* on the supplied {@link MergedContextConfiguration}.
|
||||
* <p>In contrast to {@link #loadContext(MergedContextConfiguration)}, this
|
||||
* method does not
|
||||
* {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh()
|
||||
* refresh} the {@code ApplicationContext} or
|
||||
* {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
|
||||
* register a JVM shutdown hook} for it. Otherwise, this method implements
|
||||
* behavior identical to {@link #loadContext(MergedContextConfiguration)}.
|
||||
* @param mergedConfig the merged context configuration to use to load the
|
||||
* application context
|
||||
* @param runtimeHints the runtime hints
|
||||
* @return a new application context
|
||||
* @throws Exception if context loading failed
|
||||
* @since 6.2.4
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
*/
|
||||
@Override
|
||||
public final GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) throws Exception {
|
||||
|
||||
return loadContext(mergedConfig, true);
|
||||
}
|
||||
|
||||
|
||||
+5
-36
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import jakarta.servlet.ServletContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
@@ -42,9 +41,9 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
* Abstract, generic extension of {@link AbstractContextLoader} that loads a
|
||||
* {@link GenericWebApplicationContext}.
|
||||
*
|
||||
* <p>Instances of concrete subclasses are invoked via the
|
||||
* <p>If instances of concrete subclasses are invoked via the
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||
* SPI, and the context will be loaded from the {@link MergedContextConfiguration}
|
||||
* SPI, the context will be loaded from the {@link MergedContextConfiguration}
|
||||
* provided to {@link #loadContext(MergedContextConfiguration)}. In such cases, a
|
||||
* {@code SmartContextLoader} will decide whether to load the context from
|
||||
* <em>locations</em> or <em>annotated classes</em>. Note that {@code
|
||||
@@ -59,6 +58,7 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
* @author Phillip Webb
|
||||
* @since 3.2
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @see #loadContext(String...)
|
||||
*/
|
||||
public abstract class AbstractGenericWebContextLoader extends AbstractContextLoader implements AotContextLoader {
|
||||
|
||||
@@ -121,41 +121,10 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
|
||||
* @throws Exception if context loading failed
|
||||
* @since 6.0
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
* @deprecated as of Spring Framework 6.2.4, in favor of
|
||||
* {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)};
|
||||
* to be removed in Spring Framework 8.0
|
||||
*/
|
||||
@Deprecated(since = "6.2.4", forRemoval = true)
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public final GenericWebApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
|
||||
return loadContext(mergedConfig, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a {@link GenericWebApplicationContext} for AOT build-time processing based
|
||||
* on the supplied {@link MergedContextConfiguration}.
|
||||
* <p>In contrast to {@link #loadContext(MergedContextConfiguration)}, this
|
||||
* method does not
|
||||
* {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh()
|
||||
* refresh} the {@code ApplicationContext} or
|
||||
* {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
|
||||
* register a JVM shutdown hook} for it. Otherwise, this method implements
|
||||
* behavior identical to {@link #loadContext(MergedContextConfiguration)}.
|
||||
* @param mergedConfig the merged context configuration to use to load the
|
||||
* application context
|
||||
* @param runtimeHints the runtime hints
|
||||
* @return a new web application context
|
||||
* @throws Exception if context loading failed
|
||||
* @since 6.2.4
|
||||
* @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
*/
|
||||
@Override
|
||||
public final GenericWebApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) throws Exception {
|
||||
|
||||
return loadContext(mergedConfig, true);
|
||||
}
|
||||
|
||||
@@ -219,7 +188,7 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
|
||||
* register a JVM shutdown hook for it
|
||||
* @return a new web application context
|
||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
|
||||
* @see org.springframework.test.context.aot.AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* @see org.springframework.test.context.aot.AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
*/
|
||||
private GenericWebApplicationContext loadContext(
|
||||
MergedContextConfiguration mergedConfig, boolean forAotProcessing) throws Exception {
|
||||
|
||||
-2
@@ -130,7 +130,6 @@ open class MockHttpServletRequestDsl(private val builder: AbstractMockHttpServle
|
||||
var queryParams: MultiValueMap<String, String>? = null
|
||||
|
||||
/**
|
||||
* @since 6.2.3
|
||||
* @see [MockHttpServletRequestBuilder.formField]
|
||||
*/
|
||||
fun formField(name: String, vararg values: String) {
|
||||
@@ -138,7 +137,6 @@ open class MockHttpServletRequestDsl(private val builder: AbstractMockHttpServle
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.2.3
|
||||
* @see [MockHttpServletRequestBuilder.formFields]
|
||||
*/
|
||||
var formFields: MultiValueMap<String, String>? = null
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,7 +71,7 @@ class ContentResultMatchersDsl internal constructor (private val actions: Result
|
||||
/**
|
||||
* @see ContentResultMatchers.string
|
||||
*/
|
||||
fun string(matcher: Matcher<in String>) {
|
||||
fun string(matcher: Matcher<String>) {
|
||||
actions.andExpect(matchers.string(matcher))
|
||||
}
|
||||
|
||||
@@ -99,14 +99,14 @@ class ContentResultMatchersDsl internal constructor (private val actions: Result
|
||||
/**
|
||||
* @see ContentResultMatchers.node
|
||||
*/
|
||||
fun node(matcher: Matcher<in Node>) {
|
||||
fun node(matcher: Matcher<Node>) {
|
||||
actions.andExpect(matchers.node(matcher))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ContentResultMatchers.source
|
||||
*/
|
||||
fun source(matcher: Matcher<in Source>) {
|
||||
fun source(matcher: Matcher<Source>) {
|
||||
actions.andExpect(matchers.source(matcher))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -68,8 +68,8 @@ class MockCookieTests {
|
||||
assertCookie(cookie, "SESSION", "123");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
@Test
|
||||
void parseHeaderWithAttributes() {
|
||||
MockCookie cookie = MockCookie.parse("SESSION=123; Domain=example.com; Max-Age=60; " +
|
||||
"Expires=Tue, 8 Oct 2019 19:50:00 GMT; Path=/; Secure; HttpOnly; Partitioned; SameSite=Lax");
|
||||
@@ -87,19 +87,6 @@ class MockCookieTests {
|
||||
assertThat(cookie.getComment()).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-34575
|
||||
void parseHeaderWithOptionalAttributes() {
|
||||
MockCookie cookie = MockCookie.parse("SESSION=123; HttpOnly; Version=1; Partitioned; Secure");
|
||||
|
||||
assertCookie(cookie, "SESSION", "123");
|
||||
assertThat(cookie.isHttpOnly()).isTrue();
|
||||
assertThat(cookie.getSecure()).isTrue();
|
||||
assertThat(cookie.isPartitioned()).isTrue();
|
||||
assertThat(cookie.getAttribute("Partitioned")).isEmpty();
|
||||
assertThat(cookie.getAttribute("Version")).isEqualTo("1");
|
||||
assertThat(cookie.getAttribute("BOGUS")).isNull();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"0", "bogus"})
|
||||
void parseHeaderWithInvalidExpiresAttribute(String expiresValue) {
|
||||
@@ -222,13 +209,10 @@ class MockCookieTests {
|
||||
void setPartitioned() {
|
||||
MockCookie cookie = new MockCookie("SESSION", "123");
|
||||
assertThat(cookie.isPartitioned()).isFalse();
|
||||
assertThat(cookie.getAttribute("Partitioned")).isNull();
|
||||
cookie.setPartitioned(true);
|
||||
assertThat(cookie.isPartitioned()).isTrue();
|
||||
assertThat(cookie.getAttribute("Partitioned")).isEmpty();
|
||||
cookie.setPartitioned(false);
|
||||
assertThat(cookie.isPartitioned()).isFalse();
|
||||
assertThat(cookie.getAttribute("Partitioned")).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-20
@@ -88,18 +88,6 @@ class MockHttpServletResponseTests {
|
||||
assertThat(response.containsHeader(headerName)).isFalse();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
CONTENT_TYPE,
|
||||
CONTENT_LANGUAGE,
|
||||
"X-Test-Header"
|
||||
})
|
||||
void removeHeaderIfNullValue(String headerName) {
|
||||
response.addHeader(headerName, "test");
|
||||
response.setHeader(headerName, null);
|
||||
assertThat(response.containsHeader(headerName)).isFalse();
|
||||
}
|
||||
|
||||
@Test // gh-26493
|
||||
void setLocaleWithNullValue() {
|
||||
assertThat(response.getLocale()).isEqualTo(Locale.getDefault());
|
||||
@@ -641,12 +629,4 @@ class MockHttpServletResponseTests {
|
||||
assertThat(response.getContentAsString()).isEqualTo(content);
|
||||
}
|
||||
|
||||
@Test // gh-34488
|
||||
void shouldAddMultipleContentLanguage() {
|
||||
response.addHeader("Content-Language", "en");
|
||||
response.addHeader("Content-Language", "fr");
|
||||
assertThat(response.getHeaders("Content-Language")).contains("en", "fr");
|
||||
assertThat(response.getLocale()).isEqualTo(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author 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.test.context.aot;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.support.AbstractContextLoader;
|
||||
|
||||
/**
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.4
|
||||
*/
|
||||
class AbstractAotContextLoader extends AbstractContextLoader implements AotContextLoader {
|
||||
|
||||
@Override
|
||||
public final GenericApplicationContext loadContext(MergedContextConfiguration mergedConfig) {
|
||||
return new StaticApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GenericApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig,
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext> initializer) {
|
||||
|
||||
return loadContext(mergedConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final String getResourceSuffix() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author 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.test.context.aot;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.generate.InMemoryGeneratedFiles;
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
|
||||
|
||||
/**
|
||||
* Tests for registering run-time hints within an {@link AotContextLoader}, tested
|
||||
* via the {@link TestContextAotGenerator}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.4
|
||||
*/
|
||||
class AotContextLoaderRuntimeHintsTests {
|
||||
|
||||
@Test // gh-34513
|
||||
void aotContextLoaderCanRegisterRuntimeHints() {
|
||||
RuntimeHints runtimeHints = new RuntimeHints();
|
||||
TestContextAotGenerator generator = new TestContextAotGenerator(new InMemoryGeneratedFiles(), runtimeHints);
|
||||
|
||||
generator.processAheadOfTime(Stream.of(TestCase.class));
|
||||
|
||||
assertThat(reflection().onMethod(ConfigWithMain.class, "main").invoke()).accepts(runtimeHints);
|
||||
}
|
||||
|
||||
|
||||
@ContextConfiguration(classes = ConfigWithMain.class, loader = RuntimeHintsAwareAotContextLoader.class)
|
||||
static class TestCase {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ConfigWithMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Mimics main() method for Spring Boot app
|
||||
}
|
||||
}
|
||||
|
||||
static class RuntimeHintsAwareAotContextLoader extends AbstractAotContextLoader {
|
||||
|
||||
@Override
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) throws Exception {
|
||||
|
||||
// Mimics SpringBootContextLoader
|
||||
Method mainMethod = mergedConfig.getClasses()[0].getMethod("main", String[].class);
|
||||
runtimeHints.reflection().registerMethod(mainMethod, ExecutableMode.INVOKE);
|
||||
|
||||
return loadContext(mergedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author 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.test.context.aot;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.never;
|
||||
import static org.mockito.BDDMockito.spy;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AotContextLoader}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.4
|
||||
*/
|
||||
class AotContextLoaderTests {
|
||||
|
||||
/**
|
||||
* Verifies that a legacy {@link AotContextLoader} which only overrides
|
||||
* {@link AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration)
|
||||
* is still supported.
|
||||
*/
|
||||
@Test // gh-34513
|
||||
@SuppressWarnings("removal")
|
||||
void legacyAotContextLoader() throws Exception {
|
||||
// Prerequisites
|
||||
assertDeclaringClasses(LegacyAotContextLoader.class, LegacyAotContextLoader.class, AotContextLoader.class);
|
||||
|
||||
AotContextLoader loader = spy(new LegacyAotContextLoader());
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), null, null, null, loader);
|
||||
|
||||
loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints());
|
||||
|
||||
then(loader).should().loadContextForAotProcessing(mergedConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a modern {@link AotContextLoader} which only overrides
|
||||
* {@link AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)
|
||||
* is supported.
|
||||
*/
|
||||
@Test // gh-34513
|
||||
@SuppressWarnings("removal")
|
||||
void runtimeHintsAwareAotContextLoader() throws Exception {
|
||||
// Prerequisites
|
||||
assertDeclaringClasses(RuntimeHintsAwareAotContextLoader.class, AotContextLoader.class, RuntimeHintsAwareAotContextLoader.class);
|
||||
|
||||
AotContextLoader loader = spy(new RuntimeHintsAwareAotContextLoader());
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), null, null, null, loader);
|
||||
|
||||
loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints());
|
||||
|
||||
then(loader).should(never()).loadContextForAotProcessing(mergedConfig);
|
||||
}
|
||||
|
||||
|
||||
private static void assertDeclaringClasses(Class<? extends AotContextLoader> loaderClass,
|
||||
Class<?> declaringClassForLegacyMethod, Class<?> declaringClassForNewMethod) throws Exception {
|
||||
|
||||
Method legacyMethod = loaderClass.getMethod("loadContextForAotProcessing", MergedContextConfiguration.class);
|
||||
Method newMethod = loaderClass.getMethod("loadContextForAotProcessing", MergedContextConfiguration.class, RuntimeHints.class);
|
||||
|
||||
assertThat(legacyMethod.getDeclaringClass()).isEqualTo(declaringClassForLegacyMethod);
|
||||
assertThat(newMethod.getDeclaringClass()).isEqualTo(declaringClassForNewMethod);
|
||||
}
|
||||
|
||||
|
||||
private static class LegacyAotContextLoader extends AbstractAotContextLoader {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) {
|
||||
return loadContext(mergedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RuntimeHintsAwareAotContextLoader extends AbstractAotContextLoader {
|
||||
|
||||
@Override
|
||||
public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
RuntimeHints runtimeHints) {
|
||||
|
||||
return loadContext(mergedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
* @author Sam Brannen
|
||||
* @since 6.1
|
||||
*/
|
||||
class TestPropertySourceRuntimeHintsTests {
|
||||
class TestPropertySourceRuntimeHintsTests extends AbstractAotTests {
|
||||
|
||||
private final RuntimeHints runtimeHints = new RuntimeHints();
|
||||
|
||||
@@ -93,7 +93,7 @@ class TestPropertySourceRuntimeHintsTests {
|
||||
static class WildcardLocationPatternTestCase {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Configuration
|
||||
static class Config {
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
@@ -80,7 +79,7 @@ class AnnotationConfigContextLoaderTests {
|
||||
AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY,
|
||||
new Class<?>[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class},
|
||||
EMPTY_STRING_ARRAY, contextLoader);
|
||||
ConfigurableApplicationContext context = contextLoader.loadContextForAotProcessing(mergedConfig, new RuntimeHints());
|
||||
ConfigurableApplicationContext context = contextLoader.loadContextForAotProcessing(mergedConfig);
|
||||
assertThat(context.isActive()).as("ApplicationContext is active").isFalse();
|
||||
assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains("FooConfig"));
|
||||
context.close();
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,6 @@ import java.util.Arrays;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -182,7 +181,7 @@ class DelegatingSmartContextLoaderTests {
|
||||
private void assertApplicationContextLoadsForAotProcessing(MergedContextConfiguration mergedConfig,
|
||||
String expectedBeanDefName) throws Exception {
|
||||
|
||||
ApplicationContext context = loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints());
|
||||
ApplicationContext context = loader.loadContextForAotProcessing(mergedConfig);
|
||||
assertThat(context).isInstanceOf(ConfigurableApplicationContext.class);
|
||||
ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
|
||||
assertThat(cac.isActive()).as("ApplicationContext is active").isFalse();
|
||||
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author 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.test.web.servlet.result
|
||||
|
||||
import io.mockk.mockk
|
||||
import org.hamcrest.text.CharSequenceLength.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.test.web.servlet.*
|
||||
import org.springframework.web.servlet.FlashMap
|
||||
import org.springframework.web.servlet.ModelAndView
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
/**
|
||||
* Tests for [ContentResultMatchersDsl].
|
||||
*
|
||||
* @author Dmitry Sulman
|
||||
*/
|
||||
class ContentResultMatchersDslTests {
|
||||
|
||||
val mockMvc = mockk<MockMvc>()
|
||||
|
||||
@Test
|
||||
fun `ContentResultMatchersDsl#string accepts Matcher parameterized with String supertype`() {
|
||||
getStubResultActionsDsl("some string")
|
||||
.andExpect { content { string(hasLength(11)) } }
|
||||
}
|
||||
|
||||
private fun getStubResultActionsDsl(content: String): ResultActionsDsl {
|
||||
val resultActions = object : ResultActions {
|
||||
override fun andExpect(matcher: ResultMatcher): ResultActions {
|
||||
matcher.match(getStubMvcResult(content))
|
||||
return this
|
||||
}
|
||||
|
||||
override fun andDo(handler: ResultHandler): ResultActions {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun andReturn(): MvcResult {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
}
|
||||
return ResultActionsDsl(resultActions, mockMvc)
|
||||
}
|
||||
|
||||
private fun getStubMvcResult(content: String): StubMvcResult {
|
||||
val response = MockHttpServletResponse()
|
||||
response.outputStream.write(content.toByteArray(StandardCharsets.UTF_8))
|
||||
return StubMvcResult(MockHttpServletRequest(), Any(), emptyArray(), Exception(), ModelAndView(), FlashMap(), response)
|
||||
}
|
||||
}
|
||||
-1
@@ -90,7 +90,6 @@ class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
|
||||
.maxAge(getMaxAgeSeconds(cookie))
|
||||
.secure(cookie.isSecure())
|
||||
.httpOnly(cookie.containsAttribute("httponly"))
|
||||
.partitioned(cookie.containsAttribute("partitioned"))
|
||||
.sameSite(cookie.getAttribute("samesite"))
|
||||
.build());
|
||||
}
|
||||
|
||||
-8
@@ -148,7 +148,6 @@ class ReactorClientHttpResponse implements ClientHttpResponse {
|
||||
.secure(cookie.isSecure())
|
||||
.httpOnly(cookie.isHttpOnly())
|
||||
.sameSite(getSameSite(cookie))
|
||||
.partitioned(getPartitioned(cookie))
|
||||
.build()));
|
||||
return CollectionUtils.unmodifiableMultiValueMap(result);
|
||||
}
|
||||
@@ -161,13 +160,6 @@ class ReactorClientHttpResponse implements ClientHttpResponse {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean getPartitioned(Cookie cookie) {
|
||||
if (cookie instanceof DefaultCookie defaultCookie) {
|
||||
return defaultCookie.isPartitioned();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link ReactorClientHttpConnector} when a cancellation is detected
|
||||
* but the content has not been subscribed to. If the subscription never
|
||||
|
||||
@@ -100,7 +100,6 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
|
||||
return Flux.create(sink -> {
|
||||
MultipartParser parser = new MultipartParser(sink, boundary, maxHeadersSize, headersCharset);
|
||||
sink.onCancel(parser::onSinkCancel);
|
||||
sink.onRequest(l -> parser.requestBuffer());
|
||||
buffers.subscribe(parser);
|
||||
});
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -93,6 +93,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
|
||||
private static final boolean protobufPresent;
|
||||
|
||||
static final boolean synchronossMultipartPresent;
|
||||
|
||||
static final boolean nettyByteBufPresent;
|
||||
|
||||
static final boolean netty5BufferPresent;
|
||||
@@ -110,6 +112,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
|
||||
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader);
|
||||
protobufPresent = ClassUtils.isPresent("com.google.protobuf.Message", classLoader);
|
||||
synchronossMultipartPresent = ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", classLoader);
|
||||
nettyByteBufPresent = ClassUtils.isPresent("io.netty.buffer.ByteBuf", classLoader);
|
||||
netty5BufferPresent = ClassUtils.isPresent("io.netty5.buffer.Buffer", classLoader);
|
||||
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", classLoader);
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,7 +43,6 @@ public class JettyCoreHttpHandlerAdapter extends Handler.Abstract.NonBlocking {
|
||||
this.httpHandler = httpHandler;
|
||||
}
|
||||
|
||||
|
||||
public void setDataBufferFactory(JettyDataBufferFactory dataBufferFactory) {
|
||||
Assert.notNull(dataBufferFactory, "DataBufferFactory must not be null");
|
||||
this.dataBufferFactory = dataBufferFactory;
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,7 +61,6 @@ class JettyCoreServerHttpRequest extends AbstractServerHttpRequest {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MultiValueMap<String, HttpCookie> initCookies() {
|
||||
List<org.eclipse.jetty.http.HttpCookie> httpCookies = Request.getCookies(this.request);
|
||||
|
||||
+12
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,10 +59,10 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
super(dataBufferFactory, new HttpHeaders(new JettyHeadersAdapter(response.getHeaders())));
|
||||
this.response = response;
|
||||
|
||||
// Remove all existing cookies from the response and add them to the cookie map, to be added back later
|
||||
for (ListIterator<HttpField> it = this.response.getHeaders().listIterator(); it.hasNext();) {
|
||||
HttpField field = it.next();
|
||||
if (field instanceof HttpCookieUtils.SetCookieHttpField setCookieHttpField) {
|
||||
// remove all existing cookies from the response and add them to the cookie map, to be added back later
|
||||
for (ListIterator<HttpField> i = this.response.getHeaders().listIterator(); i.hasNext(); ) {
|
||||
HttpField f = i.next();
|
||||
if (f instanceof HttpCookieUtils.SetCookieHttpField setCookieHttpField) {
|
||||
HttpCookie httpCookie = setCookieHttpField.getHttpCookie();
|
||||
ResponseCookie responseCookie = ResponseCookie.from(httpCookie.getName(), httpCookie.getValue())
|
||||
.httpOnly(httpCookie.isHttpOnly())
|
||||
@@ -72,8 +72,8 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
.secure(httpCookie.isSecure())
|
||||
.partitioned(httpCookie.isPartitioned())
|
||||
.build();
|
||||
addCookie(responseCookie);
|
||||
it.remove();
|
||||
this.addCookie(responseCookie);
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,9 +94,7 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
@Override
|
||||
protected void applyStatusCode() {
|
||||
HttpStatusCode status = getStatusCode();
|
||||
if (status != null){
|
||||
this.response.setStatus(status.value());
|
||||
}
|
||||
this.response.setStatus(status == null ? 0 : status.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +103,7 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
|
||||
@Override
|
||||
protected void applyCookies() {
|
||||
getCookies().values().stream()
|
||||
this.getCookies().values().stream()
|
||||
.flatMap(List::stream)
|
||||
.forEach(cookie -> Response.addCookie(this.response, new ResponseHttpCookie(cookie)));
|
||||
}
|
||||
@@ -167,10 +165,12 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
|
||||
private final ResponseCookie responseCookie;
|
||||
|
||||
|
||||
ResponseHttpCookie(ResponseCookie responseCookie) {
|
||||
this.responseCookie = responseCookie;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.responseCookie.getName();
|
||||
@@ -235,6 +235,7 @@ class JettyCoreServerHttpResponse extends AbstractServerHttpResponse implements
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-53
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,19 +44,13 @@ import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter;
|
||||
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
|
||||
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
|
||||
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.protobuf.KotlinSerializationProtobufHttpMessageConverter;
|
||||
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
|
||||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -90,13 +84,13 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||
|
||||
// message factories
|
||||
|
||||
private static final boolean romePresent;
|
||||
|
||||
private static final boolean jaxb2Present;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean jackson2XmlPresent;
|
||||
private static final boolean gsonPresent;
|
||||
|
||||
private static final boolean jsonbPresent;
|
||||
|
||||
private static final boolean kotlinSerializationJsonPresent;
|
||||
|
||||
private static final boolean jackson2SmilePresent;
|
||||
|
||||
@@ -104,16 +98,6 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||
|
||||
private static final boolean jackson2YamlPresent;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
|
||||
private static final boolean jsonbPresent;
|
||||
|
||||
private static final boolean kotlinSerializationCborPresent;
|
||||
|
||||
private static final boolean kotlinSerializationJsonPresent;
|
||||
|
||||
private static final boolean kotlinSerializationProtobufPresent;
|
||||
|
||||
|
||||
static {
|
||||
ClassLoader loader = DefaultRestClientBuilder.class.getClassLoader();
|
||||
@@ -123,19 +107,14 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||
reactorNettyClientPresent = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", loader);
|
||||
jdkClientPresent = ClassUtils.isPresent("java.net.http.HttpClient", loader);
|
||||
|
||||
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", loader);
|
||||
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", loader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", loader) &&
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", loader);
|
||||
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", loader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", loader);
|
||||
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", loader);
|
||||
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", loader);
|
||||
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", loader);
|
||||
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", loader);
|
||||
jackson2YamlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", loader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", loader);
|
||||
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", loader);
|
||||
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", loader);
|
||||
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", loader);
|
||||
kotlinSerializationProtobufPresent = ClassUtils.isPresent("kotlinx.serialization.protobuf.ProtoBuf", loader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -444,28 +423,11 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||
private List<HttpMessageConverter<?>> initMessageConverters() {
|
||||
if (this.messageConverters == null) {
|
||||
this.messageConverters = new ArrayList<>();
|
||||
|
||||
this.messageConverters.add(new ByteArrayHttpMessageConverter());
|
||||
this.messageConverters.add(new StringHttpMessageConverter());
|
||||
this.messageConverters.add(new ResourceHttpMessageConverter(false));
|
||||
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
|
||||
|
||||
if (romePresent) {
|
||||
this.messageConverters.add(new AtomFeedHttpMessageConverter());
|
||||
this.messageConverters.add(new RssChannelHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (jackson2XmlPresent) {
|
||||
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
|
||||
}
|
||||
else if (jaxb2Present) {
|
||||
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (kotlinSerializationProtobufPresent) {
|
||||
this.messageConverters.add(new KotlinSerializationProtobufHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (kotlinSerializationJsonPresent) {
|
||||
this.messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
|
||||
}
|
||||
@@ -478,18 +440,12 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||
else if (jsonbPresent) {
|
||||
this.messageConverters.add(new JsonbHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (jackson2SmilePresent) {
|
||||
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (jackson2CborPresent) {
|
||||
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
|
||||
}
|
||||
else if (kotlinSerializationCborPresent) {
|
||||
this.messageConverters.add(new KotlinSerializationCborHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (jackson2YamlPresent) {
|
||||
this.messageConverters.add(new MappingJackson2YamlHttpMessageConverter());
|
||||
}
|
||||
|
||||
@@ -148,7 +148,6 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = RestTemplate.class.getClassLoader();
|
||||
|
||||
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
|
||||
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
|
||||
@@ -187,6 +186,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
this.messageConverters.add(new ByteArrayHttpMessageConverter());
|
||||
this.messageConverters.add(new StringHttpMessageConverter());
|
||||
this.messageConverters.add(new ResourceHttpMessageConverter(false));
|
||||
|
||||
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
|
||||
|
||||
if (romePresent) {
|
||||
@@ -208,7 +208,6 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
if (kotlinSerializationJsonPresent) {
|
||||
this.messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
|
||||
}
|
||||
|
||||
if (jackson2Present) {
|
||||
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
|
||||
}
|
||||
|
||||
@@ -186,7 +186,6 @@ public class HandlerMethod extends AnnotatedMethod {
|
||||
* validation annotations.
|
||||
* <p>Subclasses can override this to ensure that a HandlerMethod is of the
|
||||
* same type if re-created.
|
||||
* @since 6.2.3
|
||||
*/
|
||||
protected HandlerMethod(HandlerMethod handlerMethod, @Nullable Object handler, boolean initValidateFlags) {
|
||||
super(handlerMethod);
|
||||
|
||||
+2
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -146,12 +146,7 @@ public class HandlerMethodValidationException extends ResponseStatusException im
|
||||
}
|
||||
RequestBody requestBody = param.getParameterAnnotation(RequestBody.class);
|
||||
if (requestBody != null) {
|
||||
if (result instanceof ParameterErrors errors) {
|
||||
visitor.requestBody(requestBody, errors);
|
||||
}
|
||||
else {
|
||||
visitor.requestBodyValidationResult(requestBody, result);
|
||||
}
|
||||
visitor.requestBody(requestBody, asErrors(result));
|
||||
continue;
|
||||
}
|
||||
RequestHeader requestHeader = param.getParameterAnnotation(RequestHeader.class);
|
||||
@@ -221,20 +216,6 @@ public class HandlerMethodValidationException extends ResponseStatusException im
|
||||
*/
|
||||
void requestBody(RequestBody requestBody, ParameterErrors errors);
|
||||
|
||||
/**
|
||||
* An additional {@code @RequestBody} callback for validation failures
|
||||
* for constraints on the method parameter. For example:
|
||||
* <pre class="code">
|
||||
* @RequestBody List<@NotEmpty String> ids
|
||||
* </pre>
|
||||
* Handle results for {@code @RequestBody} method parameters.
|
||||
* @param requestBody the annotation declared on the parameter
|
||||
* @param result the validation result
|
||||
* @since 6.2.4
|
||||
*/
|
||||
default void requestBodyValidationResult(RequestBody requestBody, ParameterValidationResult result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle results for {@code @RequestHeader} method parameters.
|
||||
* @param requestHeader the annotation declared on the parameter
|
||||
|
||||
+1
-1
@@ -493,7 +493,7 @@ public class HttpRequestValues {
|
||||
|
||||
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(uriTemplate);
|
||||
for (Map.Entry<String, List<String>> entry : requestParams.entrySet()) {
|
||||
String nameVar = "queryParam-" + entry.getKey().replace(":", "%3A"); // suppress treatment as regex
|
||||
String nameVar = entry.getKey().replace(":", "%3A"); // suppress treatment as regex
|
||||
uriVars.put(nameVar, entry.getKey());
|
||||
for (int j = 0; j < entry.getValue().size(); j++) {
|
||||
String valueVar = nameVar + "[" + j + "]";
|
||||
|
||||
+1
-7
@@ -164,13 +164,7 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
|
||||
@Override
|
||||
public void setHeader(String name, String value) {
|
||||
if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) {
|
||||
if (value != null) {
|
||||
this.contentLength = toContentLengthInt(Long.parseLong(value));
|
||||
}
|
||||
else {
|
||||
this.contentLength = null;
|
||||
super.setHeader(name, null);
|
||||
}
|
||||
this.contentLength = toContentLengthInt(Long.parseLong(value));
|
||||
}
|
||||
else {
|
||||
super.setHeader(name, value);
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.NestedExceptionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -101,11 +100,7 @@ public class DisconnectedClientHelper {
|
||||
* <li>IOException "Broken pipe" or "connection reset by peer"
|
||||
* </ul>
|
||||
*/
|
||||
public static boolean isClientDisconnectedException(@Nullable Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isClientDisconnectedException(Throwable ex) {
|
||||
Throwable currentEx = ex;
|
||||
Throwable lastEx = null;
|
||||
while (currentEx != null && currentEx != lastEx) {
|
||||
|
||||
+1
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,7 +41,6 @@ import okhttp3.mockwebserver.RecordedRequest;
|
||||
import okio.Buffer;
|
||||
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Named;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -202,25 +201,6 @@ class ClientHttpConnectorTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@ParameterizedConnectorTest
|
||||
void partitionedCookieSupport(ClientHttpConnector connector) {
|
||||
Assumptions.assumeFalse(connector instanceof JettyClientHttpConnector, "Jetty client does not support partitioned cookies");
|
||||
Assumptions.assumeFalse(connector instanceof JdkClientHttpConnector, "JDK client does not support partitioned cookies");
|
||||
prepareResponse(response -> {
|
||||
response.setResponseCode(200);
|
||||
response.addHeader("Set-Cookie", "id=test; Partitioned;");
|
||||
});
|
||||
Mono<ClientHttpResponse> futureResponse =
|
||||
connector.connect(HttpMethod.GET, this.server.url("/").uri(), ReactiveHttpOutputMessage::setComplete);
|
||||
StepVerifier.create(futureResponse)
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getCookies().getFirst("id").isPartitioned()).isTrue();
|
||||
}
|
||||
)
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void disableCookieWithHttpComponents() {
|
||||
ClientHttpConnector connector = new HttpComponentsClientHttpConnector(
|
||||
|
||||
-11
@@ -270,17 +270,6 @@ class ContentCachingResponseWrapperTests {
|
||||
.withMessageContaining(overflow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setContentLengthNull() {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
|
||||
responseWrapper.setContentLength(1024);
|
||||
responseWrapper.setHeader(CONTENT_LENGTH, null);
|
||||
|
||||
assertThat(response.getHeaderNames()).doesNotContain(CONTENT_LENGTH);
|
||||
assertThat(responseWrapper.getHeader(CONTENT_LENGTH)).isNull();
|
||||
}
|
||||
|
||||
|
||||
private void assertHeader(HttpServletResponse response, String header, int value) {
|
||||
assertHeader(response, header, Integer.toString(value));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user