mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1526ceec1d | |||
| 739d5ba77b | |||
| 19ab92ef59 | |||
| 04313f062e | |||
| e634ced56b | |||
| 1502c2296e | |||
| cc5c7ba186 | |||
| 0269eb80da | |||
| 9cedcd65ef | |||
| 4e8acb9ef2 | |||
| dbbbf37ac9 | |||
| d8216d719b | |||
| 63ced3f3b4 | |||
| 89391fd94c | |||
| 5168e3a38b | |||
| d4893fb32f | |||
| 104a2033c5 | |||
| cc1514be85 | |||
| 6e9758700a | |||
| 37e8aa76e9 | |||
| 27686dc2e2 | |||
| 3b8efbe5a6 | |||
| 6f2e59a995 | |||
| 644a20ae2a | |||
| 77bc13dc8c | |||
| ab9895b5a9 | |||
| ce5c4f3b4b | |||
| cd0c26b6db | |||
| 1203ace285 | |||
| 1219943e73 | |||
| eeddf9a73a | |||
| b2a4bc8900 | |||
| 3a266e65d6 | |||
| 463138acbc | |||
| b8a4961b81 | |||
| 06d4a8fc4b | |||
| 13b0643828 | |||
| 548b2167b0 | |||
| de417beff7 | |||
| ccc6789cb5 | |||
| f73302a66e | |||
| 348482b5a0 | |||
| 25bb264bd9 | |||
| 9819e1cad5 | |||
| ce2402a581 | |||
| c2d0d292bd | |||
| bbe733def7 | |||
| 03391dfa94 | |||
| 50c29e64f8 | |||
| 22301fd069 | |||
| 11ab0b4351 | |||
| 4734c15d81 | |||
| 02af3e7a17 | |||
| 3c6f1b35ba | |||
| 7a420b28df | |||
| 63723fadb6 | |||
| ab7a2c4e70 | |||
| a87b2e0146 | |||
| bd40f0e6bb | |||
| 04186fdf0e | |||
| b2b731b0ba | |||
| a3b9098850 | |||
| 36815f4021 | |||
| 3b1b7ff594 | |||
| 95080cabfd | |||
| 017892265e | |||
| d096a33f13 | |||
| b6833ff31f | |||
| 3bc55c77ec | |||
| 824aa137f8 | |||
| 0dc44f79d5 | |||
| f481f99516 | |||
| 72ed2eaa31 | |||
| 0676c958f7 | |||
| 482519d03b | |||
| d6b7cea327 | |||
| 9eea227ab9 | |||
| 706c98228d | |||
| b83cb4a947 | |||
| 7e79d0e206 | |||
| e58ba2c665 | |||
| 0c9127d111 | |||
| c2088517b9 | |||
| 59b9057e59 | |||
| 2ec630ef45 | |||
| cf2b59b68b | |||
| f1ca29b05d | |||
| ee6a115a18 | |||
| 95a31c4e8c | |||
| e0b54e244e | |||
| f2b64ad09c | |||
| cff48fff2d | |||
| ab8cb8de6e | |||
| 434da06d1f | |||
| a37447e07f | |||
| b1cb9c5052 | |||
| 057633edb5 | |||
| 7299ff9326 | |||
| 53f1656f56 | |||
| 2691489381 | |||
| f103af4982 | |||
| b9a59853fa | |||
| d4b2a493f9 | |||
| 188cb9b24d | |||
| e3568a3f0a | |||
| e106fc0434 | |||
| ca3adf43eb | |||
| 85c18caf25 | |||
| 22bd8bd704 | |||
| 9b10bb5e08 | |||
| 727ccd04ef | |||
| a9f447e8d7 | |||
| 0841e79e32 | |||
| a1868d3e9e | |||
| e5aac66157 | |||
| 8bf85d2596 | |||
| 508b31da4f | |||
| d291272736 | |||
| db01f07037 | |||
| b9e190e313 | |||
| d712ec3d49 | |||
| 5baa4fdd69 | |||
| 9273a11a2c | |||
| 7ea11baff9 | |||
| 655fd2e2bf | |||
| a31574a0a2 | |||
| 44f3e7b427 | |||
| e8e24e65d2 | |||
| 9a002a77b2 | |||
| 97e96895db | |||
| e98c2fe488 | |||
| 75705bcbb1 | |||
| 47a2e7059e | |||
| 14b6339351 | |||
| bc2e89a786 | |||
| 4abbddf601 | |||
| 926bcbd9a6 | |||
| cb8ed43be1 | |||
| 1703388074 | |||
| d84c4a39e2 | |||
| 6f03c186b9 | |||
| e10d37ad54 |
+12
-12
@@ -68,18 +68,18 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"https://docs.oracle.com/en/java/javase/17/docs/api/",
|
||||
//"https://jakarta.ee/specifications/platform/11/apidocs/",
|
||||
"https://docs.hibernate.org/orm/7.2/javadocs/",
|
||||
"https://www.quartz-scheduler.org/api/2.3.0/",
|
||||
"https://hc.apache.org/httpcomponents-client-5.6.x/current/httpclient5/apidocs/",
|
||||
"https://projectreactor.io/docs/core/release/api/",
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
"https://docs.junit.org/6.0.2/api/",
|
||||
"https://www.reactive-streams.org/reactive-streams-1.0.4-javadoc/",
|
||||
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
|
||||
"https://jspecify.dev/docs/api/"
|
||||
"https://docs.oracle.com/en/java/javase/17/docs/api/",
|
||||
//"https://jakarta.ee/specifications/platform/11/apidocs/",
|
||||
"https://docs.hibernate.org/orm/7.2/javadocs/",
|
||||
"https://www.quartz-scheduler.org/api/2.3.0/",
|
||||
"https://hc.apache.org/httpcomponents-client-5.6.x/current/httpclient5/apidocs/",
|
||||
"https://projectreactor.io/docs/core/release/api/",
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
"https://docs.junit.org/6.0.3/api/",
|
||||
"https://www.reactive-streams.org/reactive-streams-1.0.4-javadoc/",
|
||||
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
|
||||
"https://jspecify.dev/docs/api/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
|
||||
@@ -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("13.2.0");
|
||||
checkstyle.setToolVersion("13.3.0");
|
||||
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
|
||||
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
|
||||
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
|
||||
|
||||
@@ -49,8 +49,8 @@ javadoc {
|
||||
maxMemory = "1024m"
|
||||
doFirst {
|
||||
classpath += files(
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
springAspectsOutput
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
springAspectsOutput
|
||||
)
|
||||
classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath })
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ apply from: "${rootDir}/gradle/publications.gradle"
|
||||
antora {
|
||||
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
|
||||
environment = [
|
||||
'BUILD_REFNAME': 'HEAD',
|
||||
'BUILD_VERSION': project.version,
|
||||
'BUILD_REFNAME': 'HEAD',
|
||||
'BUILD_VERSION': project.version,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ tasks.withType(KotlinCompilationTask.class).configureEach {
|
||||
javaSources.from = []
|
||||
compilerOptions.jvmTarget = JvmTarget.JVM_17
|
||||
compilerOptions.freeCompilerArgs.addAll(
|
||||
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
|
||||
"-Xannotation-default-target=param-property" // Upcoming default, see https://youtrack.jetbrains.com/issue/KT-73255
|
||||
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
|
||||
"-Xannotation-default-target=param-property" // Upcoming default, see https://youtrack.jetbrains.com/issue/KT-73255
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -330,9 +330,10 @@
|
||||
*** xref:testing/testcontext-framework/application-events.adoc[]
|
||||
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
|
||||
*** xref:testing/testcontext-framework/ctx-management.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/default-config.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[]
|
||||
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
|
||||
|
||||
@@ -81,6 +81,11 @@ resolvable otherwise. See
|
||||
{spring-framework-api}++/core/env/AbstractEnvironment.html#IGNORE_GETENV_PROPERTY_NAME++[`AbstractEnvironment`]
|
||||
for details.
|
||||
|
||||
| `spring.http.response.flush.enabled`
|
||||
| Configures the Spring MVC `ServletServerHttpResponse` to allow flushing on the `OutputStream`
|
||||
returned by `ServletServerHttpResponse#getBody()`. By default, such flush calls are ignored and
|
||||
only `ServletServerHttpResponse#flush()` will actually flush the response to the network.
|
||||
|
||||
| `spring.jdbc.getParameterType.ignore`
|
||||
| Instructs Spring to ignore `java.sql.ParameterMetaData.getParameterType` completely.
|
||||
See the note in xref:data-access/jdbc/advanced.adoc#jdbc-batch-list[Batch Operations with a List of Objects].
|
||||
|
||||
@@ -727,7 +727,7 @@ of determining parameter names, an exception will be thrown.
|
||||
parameter names. This discoverer is only used if such APIs are present on the classpath.
|
||||
`StandardReflectionParameterNameDiscoverer` :: Uses the standard `java.lang.reflect.Parameter`
|
||||
API to determine parameter names. Requires that code be compiled with the `-parameters`
|
||||
flag for `javac`. Recommended approach on Java 8+.
|
||||
flag for `javac`. Recommended approach.
|
||||
`AspectJAdviceParameterNameDiscoverer` :: Deduces parameter names from the pointcut
|
||||
expression, `returning`, and `throwing` clauses. See the
|
||||
{spring-framework-api}/aop/aspectj/AspectJAdviceParameterNameDiscoverer.html[javadoc]
|
||||
|
||||
+10
-10
@@ -151,17 +151,17 @@ injected into a `Set<MovieCatalog>` annotated with `@Qualifier("action")`.
|
||||
[TIP]
|
||||
====
|
||||
Letting qualifier values select against target bean names, within the type-matching
|
||||
candidates, does not require a `@Qualifier` annotation at the injection point.
|
||||
If there is no other resolution indicator (such as a qualifier or a primary marker),
|
||||
for a non-unique dependency situation, Spring matches the injection point name
|
||||
(that is, the field name or parameter name) against the target bean names and chooses
|
||||
the same-named candidate, if any (either by bean name or by associated alias).
|
||||
candidates, does not require a `@Qualifier` annotation at the injection point. If there
|
||||
is no other resolution indicator (such as a qualifier, a primary marker, or a fallback
|
||||
marker), for a non-unique dependency situation, Spring matches the injection point name
|
||||
(that is, the field name or parameter name) against the target bean names and chooses the
|
||||
same-named candidate, if any (either by bean name or by associated alias).
|
||||
|
||||
Since version 6.1, this requires the `-parameters` Java compiler flag to be present.
|
||||
As of 6.2, the container applies fast shortcut resolution for bean name matches,
|
||||
bypassing the full type matching algorithm when the parameter name matches the
|
||||
bean name and no type, qualifier or primary conditions override the match. It is
|
||||
therefore recommendable for your parameter names to match the target bean names.
|
||||
Since version 6.1, this requires the `-parameters` Java compiler flag to be present. As
|
||||
of 6.2, the container applies fast shortcut resolution for bean name matches, bypassing
|
||||
the full type matching algorithm when the parameter name matches the bean name and no
|
||||
type, qualifier, primary, or fallback conditions override the match. It is therefore
|
||||
recommendable for your parameter names to match the target bean names.
|
||||
====
|
||||
|
||||
As an alternative for injection by name, consider the JSR-250 `@Resource` annotation
|
||||
|
||||
@@ -309,7 +309,8 @@ set of multiple matches for the specific bean type (as returned by the factory m
|
||||
|
||||
Note that the standard `jakarta.annotation.Priority` annotation is not available at the
|
||||
`@Bean` level, since it cannot be declared on methods. Its semantics can be modeled
|
||||
through `@Order` values in combination with `@Primary` on a single bean for each type.
|
||||
through `@Order` values in combination with `@Primary` or `@Fallback` on a single bean
|
||||
for each type.
|
||||
====
|
||||
|
||||
Even typed `Map` instances can be autowired as long as the expected key type is `String`.
|
||||
|
||||
+2
-1
@@ -27,4 +27,5 @@ with the `CustomAutowireConfigurer`
|
||||
|
||||
When multiple beans qualify as autowire candidates, the determination of a "`primary`" is
|
||||
as follows: If exactly one bean definition among the candidates has a `primary`
|
||||
attribute set to `true`, it is selected.
|
||||
attribute set to `true`, it is selected. For annotation-based configuration, see
|
||||
xref:core/beans/annotation-config/autowired-primary.adoc[Fine-tuning with `@Primary` or `@Fallback`].
|
||||
|
||||
@@ -556,18 +556,11 @@ Kotlin::
|
||||
======
|
||||
|
||||
If you do not want to rely on the default bean-naming strategy, you can provide a custom
|
||||
bean-naming strategy. First, implement the
|
||||
{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`]
|
||||
bean-naming strategy. First, implement either the
|
||||
{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`] or
|
||||
{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
|
||||
interface, and be sure to include a default no-arg constructor. Then, provide the fully
|
||||
qualified class name when configuring the scanner, as the following example annotation
|
||||
and bean definition show.
|
||||
|
||||
TIP: If you run into naming conflicts due to multiple autodetected components having the
|
||||
same non-qualified class name (i.e., classes with identical names but residing in
|
||||
different packages), you may need to configure a `BeanNameGenerator` that defaults to the
|
||||
fully qualified class name for the generated bean name. The
|
||||
`FullyQualifiedAnnotationBeanNameGenerator` located in package
|
||||
`org.springframework.context.annotation` can be used for such purposes.
|
||||
qualified class name when configuring the scanner, as the following examples show.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -602,6 +595,27 @@ Kotlin::
|
||||
</beans>
|
||||
----
|
||||
|
||||
[TIP]
|
||||
====
|
||||
If you run into naming conflicts due to multiple autodetected components having the same
|
||||
non-qualified class name (for example, classes with identical names but residing in
|
||||
different packages), you can configure a `BeanNameGenerator` that defaults to the
|
||||
fully-qualified class name for the generated bean name. The
|
||||
`FullyQualifiedAnnotationBeanNameGenerator` can be used for such purposes.
|
||||
|
||||
As of Spring Framework 7.0, if you encounter naming conflicts among `@Bean` methods in
|
||||
`@Configuration` classes, you can alternatively configure a
|
||||
`ConfigurationBeanNameGenerator` that generates unique bean names for `@Bean` methods.
|
||||
The `FullyQualifiedConfigurationBeanNameGenerator` can be used to generate
|
||||
fully-qualified default bean names for `@Bean` methods without an explicit `name`
|
||||
attribute — for example, `com.example.MyConfig.myBean` for an `@Bean` method named
|
||||
`myBean()` declared in `@Configuration` class `com.example.MyConfig`.
|
||||
|
||||
The `FullyQualifiedAnnotationBeanNameGenerator` and
|
||||
`FullyQualifiedConfigurationBeanNameGenerator` both reside in the
|
||||
`org.springframework.context.annotation` package.
|
||||
====
|
||||
|
||||
As a general rule, consider specifying the name with the annotation whenever other
|
||||
components may be making explicit references to it. On the other hand, the
|
||||
auto-generated names are adequate whenever the container is responsible for wiring.
|
||||
|
||||
@@ -67,6 +67,13 @@ interface, clearly indicating the post-processor nature of that bean. Otherwise,
|
||||
Since a `BeanPostProcessor` needs to be instantiated early in order to apply to the
|
||||
initialization of other beans in the context, this early type detection is critical.
|
||||
|
||||
Furthermore, when registering a `BeanPostProcessor` via an `@Bean` factory method,
|
||||
declare the method as `static` and ideally with no dependencies. Doing so avoids eager
|
||||
initialization of the configuration class and other beans, which would make them
|
||||
ineligible for full post-processing (such as auto-proxying). See the
|
||||
"BeanPostProcessor-returning `@Bean` methods" section in the
|
||||
{spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc for details.
|
||||
|
||||
[[beans-factory-programmatically-registering-beanpostprocessors]]
|
||||
.Programmatically registering `BeanPostProcessor` instances
|
||||
NOTE: While the recommended approach for `BeanPostProcessor` registration is through
|
||||
@@ -80,7 +87,7 @@ of execution. Note also that `BeanPostProcessor` instances registered programmat
|
||||
are always processed before those registered through auto-detection, regardless of any
|
||||
explicit ordering.
|
||||
|
||||
.`BeanPostProcessor` instances and AOP auto-proxying
|
||||
.`BeanPostProcessor` instances and early initialization
|
||||
[NOTE]
|
||||
====
|
||||
Classes that implement the `BeanPostProcessor` interface are special and are treated
|
||||
@@ -90,17 +97,23 @@ of the `ApplicationContext`. Next, all `BeanPostProcessor` instances are registe
|
||||
in a sorted fashion and applied to all further beans in the container. Because AOP
|
||||
auto-proxying is implemented as a `BeanPostProcessor` itself, neither `BeanPostProcessor`
|
||||
instances nor the beans they directly reference are eligible for auto-proxying and,
|
||||
thus, do not have aspects woven into them.
|
||||
thus, do not have aspects woven into them. More generally, any bean that is instantiated
|
||||
during this early phase is not eligible for full post-processing by all
|
||||
`BeanPostProcessor` instances.
|
||||
|
||||
For any such bean, you should see an informational log message: `Bean someBean is not
|
||||
eligible for getting processed by all BeanPostProcessor interfaces (for example: not
|
||||
eligible for auto-proxying)`.
|
||||
For any such bean, you should see a WARN-level log message similar to the following.
|
||||
|
||||
If you have beans wired into your `BeanPostProcessor` by using autowiring or
|
||||
`@Resource` (which may fall back to autowiring), Spring might access unexpected beans
|
||||
when searching for type-matching dependency candidates and, therefore, make them
|
||||
ineligible for auto-proxying or other kinds of bean post-processing. For example, if you
|
||||
have a dependency annotated with `@Resource` where the field or setter name does not
|
||||
[quote]
|
||||
Bean 'someBean' of type [org.example.SomeType] is not eligible for getting processed by
|
||||
all BeanPostProcessors (for example: not eligible for auto-proxying).
|
||||
|
||||
To minimize the number of beans affected, register a `BeanPostProcessor` with a
|
||||
`static` `@Bean` method that has no dependencies (see the note above). If you have
|
||||
beans wired into your `BeanPostProcessor` by using autowiring or `@Resource` (which
|
||||
may fall back to autowiring), Spring might access unexpected beans when searching
|
||||
for type-matching dependency candidates and, therefore, make them ineligible for
|
||||
auto-proxying or other kinds of bean post-processing. For example, if you have a
|
||||
dependency annotated with `@Resource` where the field or setter name does not
|
||||
directly correspond to the declared name of a bean and no name attribute is used,
|
||||
Spring accesses other beans for matching them by type.
|
||||
====
|
||||
@@ -135,7 +148,7 @@ Java::
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
|
||||
System.out.println("Bean '" + beanName + "' created : " + bean);
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -164,7 +177,48 @@ Kotlin::
|
||||
----
|
||||
======
|
||||
|
||||
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
|
||||
You can register the `InstantiationTracingBeanPostProcessor` with Java configuration
|
||||
by using a `static` `@Bean` method (recommended to avoid eager initialization of the
|
||||
configuration class and other beans):
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public static InstantiationTracingBeanPostProcessor instantiationTracingBeanPostProcessor() {
|
||||
return new InstantiationTracingBeanPostProcessor();
|
||||
}
|
||||
|
||||
// ... other bean definitions
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
@Configuration
|
||||
class AppConfig {
|
||||
|
||||
@Bean
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun instantiationTracingBeanPostProcessor() = InstantiationTracingBeanPostProcessor()
|
||||
}
|
||||
|
||||
// ... other bean definitions
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
Alternatively, the `InstantiationTracingBeanPostProcessor` can be registered via the
|
||||
`bean` element with XML configuration:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -192,7 +246,7 @@ The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
|
||||
----
|
||||
|
||||
Notice how the `InstantiationTracingBeanPostProcessor` is merely defined. It does not
|
||||
even have a name, and, because it is a bean, it can be dependency-injected as you would any
|
||||
even have a name, and, because it is a bean, it can be dependency-injected as with any
|
||||
other bean. (The preceding configuration also defines a bean that is backed by a Groovy
|
||||
script.)
|
||||
|
||||
@@ -300,6 +354,23 @@ implement the `BeanFactoryPostProcessor` interface. It uses these beans as bean
|
||||
post-processors, at the appropriate time. You can deploy these post-processor beans as
|
||||
you would any other bean.
|
||||
|
||||
When registering a `BeanFactoryPostProcessor` via an `@Bean` factory method in a
|
||||
`@Configuration` class, declare the method as `static` to avoid lifecycle conflicts
|
||||
with annotation processing (such as `@Autowired`, `@Value`, and `@PostConstruct`) in the
|
||||
configuration class. See the "BeanFactoryPostProcessor-returning `@Bean` methods"
|
||||
section in the {spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc
|
||||
for details and an example.
|
||||
|
||||
For any non-static `@Bean` factory method with a `BeanFactoryPostProcessor` return type,
|
||||
you should see an INFO-level log message similar to the following.
|
||||
|
||||
[quote]
|
||||
@Bean method MyConfig.myBfpp is non-static and returns an object assignable to Spring's
|
||||
BeanFactoryPostProcessor interface. This will result in a failure to process annotations
|
||||
such as @Autowired, @Resource, and @PostConstruct within the method's declaring
|
||||
@Configuration class. Add the 'static' modifier to this method to avoid these container
|
||||
lifecycle issues; see @Bean javadoc for complete details.
|
||||
|
||||
NOTE: As with ``BeanPostProcessor``s , you typically do not want to configure
|
||||
``BeanFactoryPostProcessor``s for lazy initialization. If no other bean references a
|
||||
`Bean(Factory)PostProcessor`, that post-processor will not get instantiated at all.
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
`@Bean` is a method-level annotation and a direct analog of the XML `<bean/>` element.
|
||||
The annotation supports some of the attributes offered by `<bean/>`, such as:
|
||||
|
||||
* xref:core/beans/definition.adoc#beans-beanname[name]
|
||||
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-initializingbean[init-method]
|
||||
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-disposablebean[destroy-method]
|
||||
* xref:core/beans/dependencies/factory-autowire.adoc[autowiring]
|
||||
* `name`.
|
||||
|
||||
You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
|
||||
`@Component`-annotated class.
|
||||
@@ -17,9 +17,10 @@ You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
|
||||
== Declaring a Bean
|
||||
|
||||
To declare a bean, you can annotate a method with the `@Bean` annotation. You use this
|
||||
method to register a bean definition within an `ApplicationContext` of the type
|
||||
specified as the method's return value. By default, the bean name is the same as
|
||||
the method name. The following example shows a `@Bean` method declaration:
|
||||
method to register a bean definition within an `ApplicationContext` of the type specified
|
||||
by the method's return type. By default, the bean name is the same as the method name
|
||||
(unless a different xref:#beans-java-customizing-bean-naming[bean name generator] is
|
||||
configured). The following example shows a `@Bean` method declaration:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -126,7 +127,7 @@ Kotlin::
|
||||
----
|
||||
======
|
||||
|
||||
However, this limits the visibility for advance type prediction to the specified
|
||||
However, this limits the visibility for advanced type prediction to the specified
|
||||
interface type (`TransferService`). Then, with the full type (`TransferServiceImpl`)
|
||||
known to the container only once the affected singleton bean has been instantiated.
|
||||
Non-lazy singleton beans get instantiated according to their declaration order,
|
||||
@@ -473,8 +474,15 @@ Kotlin::
|
||||
== Customizing Bean Naming
|
||||
|
||||
By default, configuration classes use a `@Bean` method's name as the name of the
|
||||
resulting bean. This functionality can be overridden, however, with the `name` attribute,
|
||||
as the following example shows:
|
||||
resulting bean. However, as of Spring Framework 7.0, you can change this default strategy
|
||||
by configuring a custom
|
||||
{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
|
||||
when bootstrapping the context or configuring component scanning. For example,
|
||||
{spring-framework-api}/context/annotation/FullyQualifiedConfigurationBeanNameGenerator.html[`FullyQualifiedConfigurationBeanNameGenerator`]
|
||||
can be used to generate fully-qualified default bean names for `@Bean` methods without an
|
||||
explicit `name` attribute. For individual `@Bean` methods, the default or
|
||||
generator-derived name can be overridden with the `name` attribute, as the following
|
||||
example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -505,6 +513,7 @@ Kotlin::
|
||||
----
|
||||
======
|
||||
|
||||
NOTE: `@Bean("myThing")` is equivalent to `@Bean(name = "myThing")`.
|
||||
|
||||
[[beans-java-bean-aliasing]]
|
||||
== Bean Aliasing
|
||||
|
||||
@@ -531,6 +531,7 @@ following kinds of expressions cannot be compiled.
|
||||
* Expressions relying on the conversion service
|
||||
* Expressions using custom resolvers
|
||||
* Expressions using overloaded operators
|
||||
* Expressions using `Optional` with the null-safe or Elvis operator
|
||||
* Expressions using array construction syntax
|
||||
* Expressions using selection or projection
|
||||
* Expressions using bean references
|
||||
|
||||
@@ -53,7 +53,7 @@ Kotlin::
|
||||
val trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean::class.java)
|
||||
|
||||
// uses CustomValue:::compareTo
|
||||
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java);
|
||||
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java)
|
||||
----
|
||||
======
|
||||
|
||||
@@ -167,7 +167,7 @@ Kotlin::
|
||||
[CAUTION]
|
||||
====
|
||||
The syntax for the `between` operator is `<input> between {<range_begin>, <range_end>}`,
|
||||
which is effectively a shortcut for `<input> >= <range_begin> && <input> \<= <range_end>}`.
|
||||
which is effectively a shortcut for `<input> >= <range_begin> && <input> \<= <range_end>`.
|
||||
|
||||
Consequently, `1 between {1, 5}` evaluates to `true`, while `1 between {5, 1}` evaluates
|
||||
to `false`.
|
||||
@@ -312,13 +312,13 @@ Kotlin::
|
||||
|
||||
// evaluates to 'a'
|
||||
val ch = parser.parseExpression("'d' - 3")
|
||||
.getValue(Character::class.java);
|
||||
.getValue(Char::class.java)
|
||||
|
||||
// -- Repeat --
|
||||
|
||||
// evaluates to "abcabc"
|
||||
val repeated = parser.parseExpression("'abc' * 2")
|
||||
.getValue(String::class.java);
|
||||
.getValue(String::class.java)
|
||||
----
|
||||
======
|
||||
|
||||
@@ -485,7 +485,7 @@ Kotlin::
|
||||
|
||||
// -- Operator precedence --
|
||||
|
||||
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
|
||||
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
|
||||
----
|
||||
======
|
||||
|
||||
@@ -541,32 +541,7 @@ For example, if we want to overload the `ADD` operator to allow two lists to be
|
||||
concatenated using the `+` sign, we can implement a custom `OperatorOverloader` as
|
||||
follows.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
pubic class ListConcatenation implements OperatorOverloader {
|
||||
|
||||
@Override
|
||||
public boolean overridesOperation(Operation operation, Object left, Object right) {
|
||||
return (operation == Operation.ADD &&
|
||||
left instanceof List && right instanceof List);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object operate(Operation operation, Object left, Object right) {
|
||||
if (operation == Operation.ADD &&
|
||||
left instanceof List list1 && right instanceof List list2) {
|
||||
|
||||
List result = new ArrayList(list1);
|
||||
result.addAll(list2);
|
||||
return result;
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"No overload for operation %s and operands [%s] and [%s]"
|
||||
.formatted(operation, left, right));
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::./ListConcatenation[]
|
||||
|
||||
If we register `ListConcatenation` as the `OperatorOverloader` in a
|
||||
`StandardEvaluationContext`, we can then evaluate expressions like `{1, 2, 3} + {4, 5}`
|
||||
@@ -589,8 +564,8 @@ Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
StandardEvaluationContext context = StandardEvaluationContext()
|
||||
context.setOperatorOverloader(ListConcatenation())
|
||||
val context = StandardEvaluationContext()
|
||||
context.operatorOverloader = ListConcatenation()
|
||||
|
||||
// evaluates to a new list: [1, 2, 3, 4, 5]
|
||||
parser.parseExpression("{1, 2, 3} + {2 + 2, 5}").getValue(context, List::class.java)
|
||||
|
||||
@@ -183,9 +183,6 @@ By default, a retryable operation will be retried for any exception thrown: with
|
||||
3 retry attempts (`maxRetries = 3`) after an initial failure, and a delay of 1 second
|
||||
between attempts.
|
||||
|
||||
If you only need to customize the number of retry attempts, you can use the
|
||||
`RetryPolicy.withMaxRetries()` factory method as demonstrated below.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
A retryable operation will be executed at least once and retried at most `maxRetries`
|
||||
@@ -196,6 +193,9 @@ For example, if `maxRetries` is set to `4`, the retryable operation will be invo
|
||||
least once and at most 5 times.
|
||||
====
|
||||
|
||||
If you only need to customize the number of retry attempts, you can use the
|
||||
`RetryPolicy.withMaxRetries()` factory method as demonstrated below.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); // <1>
|
||||
|
||||
+13
-42
@@ -8,7 +8,7 @@ danger of undue coupling, because code that is meant to be used transactionally
|
||||
almost always deployed that way anyway.
|
||||
|
||||
NOTE: The standard `jakarta.transaction.Transactional` annotation is also supported as
|
||||
a drop-in replacement to Spring's own annotation. Please refer to the JTA documentation
|
||||
a drop-in replacement for Spring's own annotation. Please refer to the JTA documentation
|
||||
for more details.
|
||||
|
||||
The ease-of-use afforded by the use of the `@Transactional` annotation is best
|
||||
@@ -89,47 +89,16 @@ annotation in a `@Configuration` class. See the
|
||||
{spring-framework-api}/transaction/annotation/EnableTransactionManagement.html[javadoc]
|
||||
for full details.
|
||||
|
||||
In XML configuration, the `<tx:annotation-driven/>` tag provides similar convenience:
|
||||
The following example shows the configuration needed to enable annotation-driven transaction management:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<!-- from the file 'context.xml' -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/tx
|
||||
https://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
https://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
include-code::./AppConfig[tag=snippet,indent=0]
|
||||
|
||||
<!-- this is the service object that we want to make transactional -->
|
||||
<bean id="fooService" class="x.y.service.DefaultFooService"/>
|
||||
|
||||
<!-- enable the configuration of transactional behavior based on annotations -->
|
||||
<!-- a TransactionManager is still required -->
|
||||
<tx:annotation-driven transaction-manager="txManager"/> <1>
|
||||
|
||||
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<!-- (this dependency is defined somewhere else) -->
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<!-- other <bean/> definitions here -->
|
||||
|
||||
</beans>
|
||||
----
|
||||
<1> The line that makes the bean instance transactional.
|
||||
|
||||
TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>`
|
||||
tag if the bean name of the `TransactionManager` that you want to wire in has the name
|
||||
`transactionManager`. If the `TransactionManager` bean that you want to dependency-inject
|
||||
has any other name, you have to use the `transaction-manager` attribute, as in the
|
||||
preceding example.
|
||||
TIP: In programmatic configuration, the `@EnableTransactionManagement` annotation uses any
|
||||
`TransactionManager` bean in the context. In XML configuration, you can omit
|
||||
the `transaction-manager` attribute in the `<tx:annotation-driven/>` tag if the bean
|
||||
name of the `TransactionManager` that you want to wire in has the name `transactionManager`.
|
||||
If the `TransactionManager` bean has any other name, you have to use the
|
||||
`transaction-manager` attribute explicitly, as in the preceding example.
|
||||
|
||||
Reactive transactional methods use reactive return types in contrast to imperative
|
||||
programming arrangements as the following listing shows:
|
||||
@@ -234,8 +203,10 @@ on an interface, a class definition, or a method on a class. However, the mere p
|
||||
of the `@Transactional` annotation is not enough to activate the transactional behavior.
|
||||
The `@Transactional` annotation is merely metadata that can be consumed by corresponding
|
||||
runtime infrastructure which uses that metadata to configure the appropriate beans with
|
||||
transactional behavior. In the preceding example, the `<tx:annotation-driven/>` element
|
||||
switches on actual transaction management at runtime.
|
||||
transactional behavior. In the preceding examples that use programmatic configuration,
|
||||
the `@EnableTransactionManagement` annotation switches on actual transaction management
|
||||
at runtime. Whereas, in the preceding example that uses XML configuration, the
|
||||
`<tx:annotation-driven/>` element switches on actual transaction management at runtime.
|
||||
|
||||
TIP: The Spring team recommends that you annotate methods of concrete classes with the
|
||||
`@Transactional` annotation, rather than relying on annotated methods in interfaces,
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ xref:integration/cache/store-configuration.adoc#cache-store-configuration-jsr107
|
||||
[[cache-store-configuration-caffeine]]
|
||||
== Caffeine Cache
|
||||
|
||||
Caffeine is a Java 8 rewrite of Guava's cache, and its implementation is located in the
|
||||
Caffeine is a rewrite of Guava's cache, and its implementation is located in the
|
||||
`org.springframework.cache.caffeine` package and provides access to several features
|
||||
of Caffeine.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ behind the scenes for each annotated method, by using a `JmsListenerContainerFac
|
||||
Such a container is not registered against the application context but can be easily
|
||||
located for management purposes by using the `JmsListenerEndpointRegistry` bean.
|
||||
|
||||
TIP: `@JmsListener` is a repeatable annotation on Java 8, so you can associate
|
||||
TIP: `@JmsListener` is a repeatable annotation, so you can associate
|
||||
several JMS destinations with the same method by adding additional `@JmsListener`
|
||||
declarations to it.
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ synchronous, asynchronous, and streaming scenarios.
|
||||
* Non-blocking I/O
|
||||
* Reactive Streams back pressure
|
||||
* High concurrency with fewer hardware resources
|
||||
* Functional-style, fluent API that takes advantage of Java 8 lambdas
|
||||
* Functional-style, fluent API that takes advantage of lambda expressions
|
||||
* Synchronous and asynchronous interactions
|
||||
* Streaming up to or streaming down from a server
|
||||
|
||||
|
||||
@@ -533,8 +533,7 @@ that returns a value:
|
||||
----
|
||||
|
||||
TIP: `@Async` methods may not only declare a regular `java.util.concurrent.Future` return
|
||||
type but also Spring's `org.springframework.util.concurrent.ListenableFuture` or, as of
|
||||
Spring 4.2, JDK 8's `java.util.concurrent.CompletableFuture`, for richer interaction with
|
||||
type but also `java.util.concurrent.CompletableFuture`, for richer interaction with
|
||||
the asynchronous task and for immediate composition with further processing steps.
|
||||
|
||||
You can not use `@Async` in conjunction with lifecycle callbacks such as `@PostConstruct`.
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
The Spring Framework supports various Kotlin constructs, such as instantiating Kotlin classes
|
||||
through primary constructors, immutable classes data binding, and function optional parameters
|
||||
with default values.
|
||||
through primary constructors, data binding for immutable classes, and optional parameters
|
||||
with default values for functions.
|
||||
|
||||
Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,
|
||||
which allows finding interface method parameter names without requiring the Java 8 `-parameters`
|
||||
compiler flag to be enabled during compilation. (For completeness, we nevertheless recommend
|
||||
running the Kotlin compiler with its `-java-parameters` flag for standard Java parameter exposure.)
|
||||
which allows finding interface method parameter names without requiring the Java `-parameters`
|
||||
compiler flag to be enabled during compilation.
|
||||
|
||||
TIP: For completeness, we nevertheless recommend running the Kotlin compiler with its
|
||||
`-java-parameters` flag for standard Java parameter exposure.
|
||||
|
||||
You can declare configuration classes as
|
||||
{kotlin-docs}/nested-classes.html[top level or nested but not inner],
|
||||
|
||||
+1
-2
@@ -4,8 +4,7 @@
|
||||
`@AfterTransaction` indicates that the annotated `void` method should be run after a
|
||||
transaction is ended, for test methods that have been configured to run within a
|
||||
transaction by using Spring's `@Transactional` annotation. `@AfterTransaction` methods
|
||||
are not required to be `public` and may be declared on Java 8-based interface default
|
||||
methods.
|
||||
are not required to be `public` and may be declared on interface default methods.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
|
||||
+1
-2
@@ -4,8 +4,7 @@
|
||||
`@BeforeTransaction` indicates that the annotated `void` method should be run before a
|
||||
transaction is started, for test methods that have been configured to run within a
|
||||
transaction by using Spring's `@Transactional` annotation. `@BeforeTransaction` methods
|
||||
are not required to be `public` and may be declared on Java 8-based interface default
|
||||
methods.
|
||||
are not required to be `public` and may be declared on interface default methods.
|
||||
|
||||
The following example shows how to use the `@BeforeTransaction` annotation:
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
`@SqlGroup` is a container annotation that aggregates several `@Sql` annotations. You can
|
||||
use `@SqlGroup` natively to declare several nested `@Sql` annotations, or you can use it
|
||||
in conjunction with Java 8's support for repeatable annotations, where `@Sql` can be
|
||||
in conjunction with Java's support for repeatable annotations, where `@Sql` can be
|
||||
declared several times on the same class or method, implicitly generating this container
|
||||
annotation. The following example shows how to declare an SQL group:
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ https://testng.org/[TestNG] ::
|
||||
testing, distributed testing, and other features. Supported in the
|
||||
xref:testing/testcontext-framework.adoc[Spring TestContext Framework].
|
||||
{assertj-docs}[AssertJ] ::
|
||||
"Fluent assertions for Java", including support for Java 8 lambdas, streams, and
|
||||
"Fluent assertions for Java", including support for lambda expressions, streams, and
|
||||
numerous other features. Supported in Spring's
|
||||
xref:testing/mockmvc/assertj.adoc[MockMvc testing support].
|
||||
https://en.wikipedia.org/wiki/Mock_Object[Mock Objects] ::
|
||||
|
||||
+15
-15
@@ -49,7 +49,6 @@ Kotlin::
|
||||
<1> Injecting the `ApplicationContext`.
|
||||
======
|
||||
|
||||
|
||||
Similarly, if your test is configured to load a `WebApplicationContext`, you can inject
|
||||
the web application context into your test, as follows:
|
||||
|
||||
@@ -87,7 +86,6 @@ Kotlin::
|
||||
<2> Injecting the `WebApplicationContext`.
|
||||
======
|
||||
|
||||
|
||||
Dependency injection by using `@Autowired` is provided by the
|
||||
`DependencyInjectionTestExecutionListener`, which is configured by default
|
||||
(see xref:testing/testcontext-framework/fixture-di.adoc[Dependency Injection of Test Fixtures]).
|
||||
@@ -96,22 +94,24 @@ Dependency injection by using `@Autowired` is provided by the
|
||||
Test classes that use the TestContext framework do not need to extend any particular
|
||||
class or implement a specific interface to configure their application context. Instead,
|
||||
configuration is achieved by declaring the `@ContextConfiguration` annotation at the
|
||||
class level. If your test class does not explicitly declare application context resource
|
||||
locations or component classes, the configured `ContextLoader` determines how to load a
|
||||
context from a default location or default configuration classes. In addition to context
|
||||
resource locations and component classes, an application context can also be configured
|
||||
through application context initializers.
|
||||
class level. If your test class does not explicitly declare component classes or resource
|
||||
locations, the configured `ContextLoader` determines how to load a context from _default_
|
||||
configuration classes or a _default_ location. In addition to component classes and
|
||||
context resource locations, an application context can also be configured through
|
||||
xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[context customizers]
|
||||
or xref:testing/testcontext-framework/ctx-management/initializers.adoc[context initializers].
|
||||
|
||||
The following sections explain how to use Spring's `@ContextConfiguration` annotation to
|
||||
configure a test `ApplicationContext` by using XML configuration files, Groovy scripts,
|
||||
component classes (typically `@Configuration` classes), or context initializers.
|
||||
Alternatively, you can implement and configure your own custom `SmartContextLoader` for
|
||||
advanced use cases.
|
||||
The following sections explain how to use `@ContextConfiguration` and related annotations
|
||||
to configure a test `ApplicationContext` by using component classes (typically
|
||||
`@Configuration` classes), XML configuration files, Groovy scripts, context customizers,
|
||||
or context initializers. Alternatively, you can implement and configure your own custom
|
||||
`SmartContextLoader` for advanced use cases.
|
||||
|
||||
* xref:testing/testcontext-framework/ctx-management/xml.adoc[Context Configuration with XML resources]
|
||||
* xref:testing/testcontext-framework/ctx-management/groovy.adoc[Context Configuration with Groovy Scripts]
|
||||
* xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[Context Configuration with Component Classes]
|
||||
* xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[Mixing XML, Groovy Scripts, and Component Classes]
|
||||
* xref:testing/testcontext-framework/ctx-management/xml.adoc[Context Configuration with XML Resources]
|
||||
* xref:testing/testcontext-framework/ctx-management/groovy.adoc[Context Configuration with Groovy Scripts]
|
||||
* xref:testing/testcontext-framework/ctx-management/default-config.adoc[Default Context Configuration]
|
||||
* xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[Mixing Component Classes, XML, and Groovy Scripts]
|
||||
* xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[Context Configuration with Context Customizers]
|
||||
* xref:testing/testcontext-framework/ctx-management/initializers.adoc[Context Configuration with Context Initializers]
|
||||
* xref:testing/testcontext-framework/ctx-management/inheritance.adoc[Context Configuration Inheritance]
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
[[testcontext-ctx-management-default-config]]
|
||||
= Default Context Configuration
|
||||
|
||||
As explained in the sections on
|
||||
xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[component classes],
|
||||
xref:testing/testcontext-framework/ctx-management/xml.adoc[XML resources], and
|
||||
xref:testing/testcontext-framework/ctx-management/groovy.adoc[Groovy scripts], the
|
||||
TestContext framework will attempt to locate _default_ context configuration if you do
|
||||
not explicitly specify `@Configuration` classes, XML configuration files, or Groovy
|
||||
scripts from which the test's `ApplicationContext` should be loaded.
|
||||
|
||||
However, due to a bug in the detection algorithm, default context configuration for a
|
||||
superclass or enclosing class is currently ignored if the type hierarchy or enclosing
|
||||
class hierarchy (for `@Nested` test classes) does not declare `@ContextConfiguration`.
|
||||
|
||||
Beginning with Spring Framework 7.1, the TestContext framework will reliably detect
|
||||
**all** _default_ context configuration within a type hierarchy or enclosing class
|
||||
hierarchy above a given test class in such scenarios. Consequently, test suites may
|
||||
encounter issues after the upgrade to 7.1. For example, if a static nested
|
||||
`@Configuration` class in a superclass or enclosing class is ignored due to the
|
||||
aforementioned bug, after the bug has been fixed in 7.1 that `@Configuration` class will
|
||||
no longer be ignored, which may lead to unexpected beans in the resulting
|
||||
`ApplicationContext` our outright failures in tests.
|
||||
|
||||
In the interim, the TestContext framework logs a warning whenever it encounters _default_
|
||||
context configuration that is currently ignored — for example, a `@Configuration` class
|
||||
or XML configuration file. The remainder of this section provides guidance on how to
|
||||
address such issues if you encounter warnings in your test suite.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Annotating the affected subclass or `@Nested` class with `@ContextConfiguration` allows
|
||||
you to take matters into your own hands and specify which classes in the hierarchy are
|
||||
actually intended to contribute context configuration.
|
||||
====
|
||||
|
||||
If you do not want static nested `@Configuration` classes to be processed, you can:
|
||||
|
||||
- Remove the `@Configuration` declaration.
|
||||
- Apply `@ContextConfiguration` only where you actually want such classes to be processed.
|
||||
- Move the static nested `@Configuration` classes to standalone top-level classes so that
|
||||
they cannot be accidentally interpreted as _default_ configuration classes.
|
||||
|
||||
Similarly, if you encounter issues with _default_ XML configuration files or Groovy
|
||||
scripts being detected and you do not want them to be processed, you can:
|
||||
|
||||
- Apply `@ContextConfiguration` only where you actually want such resources to be
|
||||
processed.
|
||||
- Rename the resource files to something that does not match the default naming
|
||||
convention (such as `*-context.xml` for XML configuration) so that they cannot be
|
||||
accidentally interpreted as _default_ configuration files.
|
||||
- Move the affected resource files to a different package or filesystem location within
|
||||
your project.
|
||||
+21
-22
@@ -1,33 +1,32 @@
|
||||
[[testcontext-ctx-management-mixed-config]]
|
||||
= Mixing XML, Groovy Scripts, and Component Classes
|
||||
= Mixing Component Classes, XML, and Groovy Scripts
|
||||
|
||||
It may sometimes be desirable to mix XML configuration files, Groovy scripts, and
|
||||
component classes (typically `@Configuration` classes) to configure an
|
||||
`ApplicationContext` for your tests. For example, if you use XML configuration in
|
||||
production, you may decide that you want to use `@Configuration` classes to configure
|
||||
It may sometimes be desirable to mix component classes (typically `@Configuration`
|
||||
classes), XML configuration files, or Groovy scripts to configure an `ApplicationContext`
|
||||
for your tests. For example, if you use XML configuration in production for legacy
|
||||
reasons, you may decide that you want to use `@Configuration` classes to configure
|
||||
specific Spring-managed components for your tests, or vice versa.
|
||||
|
||||
Furthermore, some third-party frameworks (such as Spring Boot) provide first-class
|
||||
support for loading an `ApplicationContext` from different types of resources
|
||||
simultaneously (for example, XML configuration files, Groovy scripts, and
|
||||
`@Configuration` classes). The Spring Framework, historically, has not supported this for
|
||||
standard deployments. Consequently, most of the `SmartContextLoader` implementations that
|
||||
the Spring Framework delivers in the `spring-test` module support only one resource type
|
||||
for each test context. However, this does not mean that you cannot use both. One
|
||||
exception to the general rule is that the `GenericGroovyXmlContextLoader` and
|
||||
simultaneously (for example, `@Configuration` classes, XML configuration files, and
|
||||
Groovy scripts). The Spring Framework, historically, has not supported this for standard
|
||||
deployments. Consequently, most of the `SmartContextLoader` implementations that the
|
||||
Spring Framework delivers in the `spring-test` module support only one resource type for
|
||||
each test context. However, this does not mean that you cannot use a mixture of resource
|
||||
types. One exception to the general rule is that the `GenericGroovyXmlContextLoader` and
|
||||
`GenericGroovyXmlWebContextLoader` support both XML configuration files and Groovy
|
||||
scripts simultaneously. Furthermore, third-party frameworks may choose to support the
|
||||
declaration of both `locations` and `classes` through `@ContextConfiguration`, and, with
|
||||
declaration of both `classes` and `locations` through `@ContextConfiguration`, and, with
|
||||
the standard testing support in the TestContext framework, you have the following options.
|
||||
|
||||
If you want to use resource locations (for example, XML or Groovy) and `@Configuration`
|
||||
classes to configure your tests, you must pick one as the entry point, and that one must
|
||||
include or import the other. For example, in XML or Groovy scripts, you can include
|
||||
`@Configuration` classes by using component scanning or defining them as normal Spring
|
||||
beans, whereas, in a `@Configuration` class, you can use `@ImportResource` to import XML
|
||||
configuration files or Groovy scripts. Note that this behavior is semantically equivalent
|
||||
If you want to use `@Configuration` classes and resource locations (for example, XML or
|
||||
Groovy) to configure your tests, you must pick one as the entry point, and that one must
|
||||
import or include the other. For example, in a `@Configuration` class, you can use
|
||||
`@ImportResource` to import XML configuration files or Groovy scripts; whereas, in XML or
|
||||
Groovy scripts, you can include `@Configuration` classes by using component scanning or
|
||||
defining them as normal Spring beans. Note that this behavior is semantically equivalent
|
||||
to how you configure your application in production: In production configuration, you
|
||||
define either a set of XML or Groovy resource locations or a set of `@Configuration`
|
||||
classes from which your production `ApplicationContext` is loaded, but you still have the
|
||||
freedom to include or import the other type of configuration.
|
||||
|
||||
define either a set of `@Configuration` classes or a set of XML or Groovy resource
|
||||
locations from which your production `ApplicationContext` is loaded, but you still have
|
||||
the freedom to import or include the other type of configuration.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[[testcontext-ctx-management-xml]]
|
||||
= Context Configuration with XML resources
|
||||
= Context Configuration with XML Resources
|
||||
|
||||
To load an `ApplicationContext` for your tests by using XML configuration files, annotate
|
||||
your test class with `@ContextConfiguration` and configure the `locations` attribute with
|
||||
|
||||
@@ -13,9 +13,9 @@ the same xref:web/webflux/reactive-spring.adoc[Reactive Core] foundation.
|
||||
== Overview
|
||||
[.small]#xref:web/webmvc-functional.adoc#webmvc-fn-overview[See equivalent in the Servlet stack]#
|
||||
|
||||
In WebFlux.fn, an HTTP request is handled with a `HandlerFunction`: a function that takes
|
||||
In WebFlux.fn, an HTTP request is handled with a `HandlerFunction`: a function that takes a
|
||||
`ServerRequest` and returns a delayed `ServerResponse` (i.e. `Mono<ServerResponse>`).
|
||||
Both the request and the response object have immutable contracts that offer JDK 8-friendly
|
||||
Both the request and the response object have immutable contracts that offer convenient
|
||||
access to the HTTP request and response.
|
||||
`HandlerFunction` is the equivalent of the body of a `@RequestMapping` method in the
|
||||
annotation-based programming model.
|
||||
@@ -117,7 +117,7 @@ Most applications can run through the WebFlux Java configuration, see xref:web/w
|
||||
== HandlerFunction
|
||||
[.small]#xref:web/webmvc-functional.adoc#webmvc-fn-handler-functions[See equivalent in the Servlet stack]#
|
||||
|
||||
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
|
||||
`ServerRequest` and `ServerResponse` are immutable interfaces that offer convenient
|
||||
access to the HTTP request and response.
|
||||
Both request and response provide {reactive-streams-site}[Reactive Streams] back pressure
|
||||
against the body streams.
|
||||
|
||||
@@ -49,10 +49,9 @@ This strategy resolves the API version from a request. The WebFlux config provid
|
||||
options to resolve from a header, query parameter, media type parameter,
|
||||
or from the URL path. You can also use a custom `ApiVersionResolver`.
|
||||
|
||||
NOTE: The path resolver always resolves the version from the specified path segment, or
|
||||
raises `InvalidApiVersionException` otherwise, and therefore it cannot yield to other
|
||||
resolvers.
|
||||
|
||||
The path resolver selects the version from a path segment specified by index, or
|
||||
raises `InvalidApiVersionException`, and therefore never results in `null` (no version)
|
||||
unless it is configured with a `Predicate<RequestPath>` to determine if a path is versioned.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -251,7 +251,8 @@ Kotlin::
|
||||
======
|
||||
|
||||
TIP: If you need to have a `LocalValidatorFactoryBean` injected somewhere, create a bean and
|
||||
mark it with `@Primary` in order to avoid conflict with the one declared in the MVC config.
|
||||
mark it with `@Primary`, or mark the one declared in the MVC config with `@Fallback`, in
|
||||
order to avoid conflict.
|
||||
|
||||
|
||||
[[webflux-config-content-negotiation]]
|
||||
|
||||
@@ -394,7 +394,8 @@ Once API versioning is enabled, you can begin to map requests with versions.
|
||||
The `@RequestMapping` `version` attribute supports the following:
|
||||
|
||||
- Fixed version ("1.2") -- matches the given version only
|
||||
- Baseline version ("1.2+") -- matches the given version and above
|
||||
- Baseline version ("1.2+") -- matches the given and
|
||||
xref:web/webflux/config.adoc#webflux-config-api-version[supported versions] above
|
||||
- No value -- matches any version, but is superseded by a more specific version match
|
||||
|
||||
If multiple controller methods have a version less than or equal to the request version,
|
||||
@@ -443,6 +444,9 @@ For request with version `"1.3"`:
|
||||
- (3) matches as it matches 1.2 and above, and is *chosen* as the highest match
|
||||
- (4) is higher and does not match
|
||||
|
||||
NOTE: Version 1.3 must be present in the mappings, or be
|
||||
xref:web/webflux/config.adoc#webflux-config-api-version[configured as supported].
|
||||
|
||||
For request with version `"1.5"`:
|
||||
|
||||
- (1) matches as it matches any version
|
||||
@@ -459,10 +463,6 @@ versioned alternative was introduced. Therefore, even though an unversioned cont
|
||||
method is considered a match for any version, it is in fact given the lowest priority,
|
||||
and is effectively superseded by any alternative controller method with a version.
|
||||
|
||||
NOTE: The above assumes the request version is a
|
||||
xref:web/webflux/config.adoc#webflux-config-api-version["supported" version],
|
||||
or otherwise it would fail.
|
||||
|
||||
See xref:web/webflux-versioning.adoc[API Versioning] for more details on underlying
|
||||
infrastructure and support for API Versioning.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ If a publisher cannot slow down, it has to decide whether to buffer, drop, or fa
|
||||
Reactive Streams plays an important role for interoperability. It is of interest to libraries
|
||||
and infrastructure components but less useful as an application API, because it is too
|
||||
low-level. Applications need a higher-level and richer, functional API to
|
||||
compose async logic -- similar to the Java 8 `Stream` API but not only for collections.
|
||||
compose async logic -- similar to the Java `Stream` API but not only for collections.
|
||||
This is the role that reactive libraries play.
|
||||
|
||||
{reactor-github-org}/reactor[Reactor] is the reactive library of choice for
|
||||
@@ -131,7 +131,7 @@ execution model benefits as others in this space and also provides a choice of s
|
||||
(annotated controllers and functional web endpoints), and a choice of reactive libraries
|
||||
(Reactor, RxJava, or other).
|
||||
|
||||
* If you are interested in a lightweight, functional web framework for use with Java 8 lambdas
|
||||
* If you are interested in a lightweight, functional web framework for use with Java
|
||||
or Kotlin, you can use the Spring WebFlux functional web endpoints. That can also be a good choice
|
||||
for smaller applications or microservices with less complex requirements that can benefit
|
||||
from greater transparency and control.
|
||||
|
||||
@@ -15,7 +15,7 @@ the same xref:web/webmvc/mvc-servlet.adoc[DispatcherServlet].
|
||||
|
||||
In WebMvc.fn, an HTTP request is handled with a `HandlerFunction`: a function that takes
|
||||
`ServerRequest` and returns a `ServerResponse`.
|
||||
Both the request and the response object have immutable contracts that offer JDK 8-friendly
|
||||
Both the request and the response object have immutable contracts that offer convenient
|
||||
access to the HTTP request and response.
|
||||
`HandlerFunction` is the equivalent of the body of a `@RequestMapping` method in the
|
||||
annotation-based programming model.
|
||||
@@ -116,7 +116,7 @@ xref:web/webmvc-functional.adoc#webmvc-fn-running[Running a Server].
|
||||
== HandlerFunction
|
||||
[.small]#xref:web/webflux-functional.adoc#webflux-fn-handler-functions[See equivalent in the Reactive stack]#
|
||||
|
||||
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
|
||||
`ServerRequest` and `ServerResponse` are immutable interfaces that offer convenient
|
||||
access to the HTTP request and response, including headers, body, method, and status code.
|
||||
|
||||
[[webmvc-fn-request]]
|
||||
|
||||
@@ -49,10 +49,9 @@ This strategy resolves the API version from a request. The MVC config provides b
|
||||
options to resolve from a header, query parameter, media type parameter,
|
||||
or from the URL path. You can also use a custom `ApiVersionResolver`.
|
||||
|
||||
NOTE: The path resolver always resolves the version from the specified path segment, or
|
||||
raises `InvalidApiVersionException` otherwise, and therefore it cannot yield to other
|
||||
resolvers.
|
||||
|
||||
The path resolver selects the version from a path segment specified by index, or
|
||||
raises `InvalidApiVersionException`, and therefore never results in `null` (no version)
|
||||
unless it is configured with a `Predicate<RequestPath>` to determine if a path is versioned.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,4 +19,5 @@ example shows:
|
||||
include-code::./MyController[tag=snippet,indent=0]
|
||||
|
||||
TIP: If you need to have a `LocalValidatorFactoryBean` injected somewhere, create a bean and
|
||||
mark it with `@Primary` in order to avoid conflict with the one declared in the MVC configuration.
|
||||
mark it with `@Primary`, or mark the one declared in the MVC configuration with
|
||||
`@Fallback`, in order to avoid conflict.
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
The next table describes the supported controller method arguments. Reactive types are not supported
|
||||
for any arguments.
|
||||
|
||||
JDK 8's `java.util.Optional` is supported as a method argument in combination with
|
||||
`java.util.Optional` is supported as a method argument in combination with
|
||||
annotations that have a `required` attribute (for example, `@RequestParam`, `@RequestHeader`,
|
||||
and others) and is equivalent to `required=false`.
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ Once API versioning is enabled, you can begin to map requests with versions.
|
||||
The `@RequestMapping` `version` attribute supports the following:
|
||||
|
||||
- Fixed version ("1.2") -- matches the given version only
|
||||
- Baseline version ("1.2+") -- matches the given version and above
|
||||
- Baseline version ("1.2+") -- matches the given and xref:web/webmvc/mvc-config/api-version.adoc[supported versions] above
|
||||
- No value -- matches any version, but is superseded by a more specific version match
|
||||
|
||||
If multiple controller methods have a version less than or equal to the request version,
|
||||
@@ -463,7 +463,7 @@ Java::
|
||||
----
|
||||
<1> match any version
|
||||
<2> match version 1.1
|
||||
<3> match version 1.2 and above
|
||||
<3> match version 1.2 and supported versions above
|
||||
<4> match version 1.5
|
||||
======
|
||||
|
||||
@@ -474,6 +474,9 @@ For request with version `"1.3"`:
|
||||
- (3) matches as it matches 1.2 and above, and is *chosen* as the highest match
|
||||
- (4) is higher and does not match
|
||||
|
||||
NOTE: Version 1.3 must be present in the mappings, or be
|
||||
xref:web/webmvc/mvc-config/api-version.adoc[configured as supported].
|
||||
|
||||
For request with version `"1.5"`:
|
||||
|
||||
- (1) matches as it matches any version
|
||||
@@ -490,10 +493,6 @@ versioned alternative was introduced. Therefore, even though an unversioned cont
|
||||
method is considered a match for any version, it is in fact given the lowest priority,
|
||||
and is effectively superseded by any alternative controller method with a version.
|
||||
|
||||
NOTE: The above assumes the request version is a
|
||||
xref:web/webmvc/mvc-config/api-version.adoc["supported" version], or otherwise it
|
||||
would fail.
|
||||
|
||||
See xref:web/webmvc-versioning.adoc[API Versioning] for more details on underlying
|
||||
infrastructure and support for API Versioning.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[.small]#xref:web/webflux/uri-building.adoc[See equivalent in the Reactive stack]#
|
||||
|
||||
This section describes various options available in the Spring Framework to work with URI's.
|
||||
This section describes various options available in the Spring Framework to work with URIs.
|
||||
|
||||
include::partial$web/web-uris.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
= UriComponents
|
||||
[.small]#Spring MVC and Spring WebFlux#
|
||||
|
||||
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
|
||||
`UriComponentsBuilder` helps to build URIs from URI templates with variables, as the following example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -128,7 +128,7 @@ Kotlin::
|
||||
= UriBuilder
|
||||
[.small]#Spring MVC and Spring WebFlux#
|
||||
|
||||
<<web-uricomponents, `UriComponentsBuilder`>> implements `UriBuilder`. You can create a
|
||||
<<uricomponents, `UriComponentsBuilder`>> implements `UriBuilder`. You can create a
|
||||
`UriBuilder`, in turn, with a `UriBuilderFactory`. Together, `UriBuilderFactory` and
|
||||
`UriBuilder` provide a pluggable mechanism to build URIs from URI templates, based on
|
||||
shared configuration, such as a base URL, encoding preferences, and other details.
|
||||
@@ -247,7 +247,7 @@ and treats deviations from the syntax as illegal.
|
||||
https://github.com/web-platform-tests/wpt/tree/master/url[URL parsing algorithm] in the
|
||||
https://url.spec.whatwg.org[WhatWG URL Living standard]. It provides lenient handling of
|
||||
a wide range of cases of unexpected input. Browsers implement this in order to handle
|
||||
leniently user typed URL's. For more details, see the URL Living Standard and URL parsing
|
||||
leniently user typed URLs. For more details, see the URL Living Standard and URL parsing
|
||||
https://github.com/web-platform-tests/wpt/tree/master/url[test cases].
|
||||
|
||||
By default, `RestClient`, `WebClient`, and `RestTemplate` use the RFC parser type, and
|
||||
@@ -255,10 +255,10 @@ expect applications to provide with URL templates that conform to RFC syntax. To
|
||||
that you can customize the `UriBuilderFactory` on any of the clients.
|
||||
|
||||
Applications and frameworks may further rely on `UriComponentsBuilder` for their own needs
|
||||
to parse user provided URL's in order to inspect and possibly validated URI components
|
||||
to parse user provided URLs in order to inspect and possibly validated URI components
|
||||
such as the scheme, host, port, path, and query. Such components can decide to use the
|
||||
WhatWG parser type in order to handle URL's more leniently, and to align with the way
|
||||
browsers parse URI's, in case of a redirect to the input URL or if it is included in a
|
||||
WhatWG parser type in order to handle URLs more leniently, and to align with the way
|
||||
browsers parse URIs, in case of a redirect to the input URL or if it is included in a
|
||||
response to a browser.
|
||||
|
||||
|
||||
@@ -373,14 +373,14 @@ Java::
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
String baseUrl = "https://example.com";
|
||||
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
|
||||
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
|
||||
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
|
||||
|
||||
// Customize the RestTemplate..
|
||||
// Customize the RestTemplate.
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setUriTemplateHandler(factory);
|
||||
|
||||
// Customize the WebClient..
|
||||
// Customize the WebClient.
|
||||
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
|
||||
----
|
||||
|
||||
@@ -393,12 +393,12 @@ Kotlin::
|
||||
encodingMode = EncodingMode.TEMPLATE_AND_VALUES
|
||||
}
|
||||
|
||||
// Customize the RestTemplate..
|
||||
// Customize the RestTemplate.
|
||||
val restTemplate = RestTemplate().apply {
|
||||
uriTemplateHandler = factory
|
||||
}
|
||||
|
||||
// Customize the WebClient..
|
||||
// Customize the WebClient.
|
||||
val client = WebClient.builder().uriBuilderFactory(factory).build()
|
||||
----
|
||||
======
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"@antora/collector-extension": "1.0.2",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.7",
|
||||
"fast-xml-parser": "5.3.4",
|
||||
"fast-xml-parser": "5.3.8",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.17"
|
||||
}
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.core.expressions.languageref.expressionsoperatorsoverloaded;
|
||||
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.OperatorOverloader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ListConcatenation implements OperatorOverloader {
|
||||
|
||||
@Override
|
||||
public boolean overridesOperation(Operation operation, Object left, Object right) {
|
||||
return (operation == Operation.ADD && left instanceof List && right instanceof List);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public Object operate(Operation operation, Object left, Object right) {
|
||||
if (operation == Operation.ADD &&
|
||||
left instanceof List list1 && right instanceof List list2) {
|
||||
|
||||
List result = new ArrayList(list1);
|
||||
result.addAll(list2);
|
||||
return result;
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"No overload for operation %s and operands [%s] and [%s]"
|
||||
.formatted(operation, left, right));
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
// tag::snippet[]
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public FooService fooService() {
|
||||
return new DefaultFooService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txManager(DataSource dataSource) {
|
||||
return new DataSourceTransactionManager(dataSource);
|
||||
}
|
||||
}
|
||||
// end::snippet[]
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations;
|
||||
|
||||
public class DefaultFooService implements FooService {
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations;
|
||||
|
||||
public interface FooService {
|
||||
}
|
||||
-1
@@ -21,7 +21,6 @@ import org.springframework.test.web.servlet.assertj.MockMvcTester;
|
||||
import org.springframework.test.web.servlet.assertj.MvcTestResult;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
|
||||
-2
@@ -17,9 +17,7 @@
|
||||
package org.springframework.docs.web.websocket.stomp.websocketstompconfigurationperformance;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
|
||||
|
||||
|
||||
-2
@@ -17,9 +17,7 @@
|
||||
package org.springframework.docs.web.websocket.stomp.websocketstompconfigurationperformance;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
|
||||
|
||||
|
||||
-1
@@ -22,7 +22,6 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
|
||||
// tag::snippet[]
|
||||
|
||||
-5
@@ -19,13 +19,8 @@ package org.springframework.docs.web.websocket.stomp.websocketstompmessageflow;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
|
||||
// tag::snippet[]
|
||||
@Controller
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
package org.springframework.docs.web.websocket.stomp.websocketstomporderedmessages;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.core.expressions.languageref.expressionsoperatorsoverloaded
|
||||
|
||||
import org.springframework.expression.Operation
|
||||
import org.springframework.expression.OperatorOverloader
|
||||
|
||||
class ListConcatenation: OperatorOverloader {
|
||||
|
||||
override fun overridesOperation(operation: Operation, left: Any?, right: Any?): Boolean {
|
||||
return operation == Operation.ADD && left is List<*> && right is List<*>
|
||||
}
|
||||
|
||||
override fun operate(operation: Operation, left: Any?, right: Any?): Any {
|
||||
if (operation == Operation.ADD && left is List<*> && right is List<*>) {
|
||||
return left + right
|
||||
}
|
||||
|
||||
throw UnsupportedOperationException(
|
||||
"No overload for operation $operation and operands [$left] and [$right]")
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager
|
||||
import org.springframework.transaction.PlatformTransactionManager
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement
|
||||
import javax.sql.DataSource
|
||||
|
||||
// tag::snippet[]
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
class AppConfig {
|
||||
|
||||
@Bean
|
||||
fun fooService(): FooService {
|
||||
return DefaultFooService()
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun txManager(dataSource: DataSource): PlatformTransactionManager {
|
||||
return DataSourceTransactionManager(dataSource)
|
||||
}
|
||||
}
|
||||
// end::snippet[]
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations
|
||||
|
||||
class DefaultFooService : FooService {
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations
|
||||
|
||||
interface FooService {
|
||||
}
|
||||
-3
@@ -16,12 +16,9 @@
|
||||
|
||||
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterintegration
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.assertj.core.api.Assertions.*
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
|
||||
|
||||
/**
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- tag::snippet[] -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/tx
|
||||
https://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
https://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
|
||||
<!-- this is the service object that we want to make transactional -->
|
||||
<bean id="fooService" class="x.y.service.DefaultFooService"/>
|
||||
|
||||
<!-- enable the configuration of transactional behavior based on annotations -->
|
||||
<!-- a TransactionManager is still required -->
|
||||
<tx:annotation-driven transaction-manager="txManager"/>
|
||||
|
||||
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<!-- (this dependency is defined somewhere else) -->
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<!-- other <bean/> definitions here -->
|
||||
|
||||
</beans>
|
||||
<!-- end::snippet[] -->
|
||||
@@ -8,19 +8,19 @@ javaPlatform {
|
||||
|
||||
dependencies {
|
||||
api(platform("com.fasterxml.jackson:jackson-bom:2.20.2"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.16.3"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.16.4"))
|
||||
api(platform("io.netty:netty-bom:4.2.10.Final"))
|
||||
api(platform("io.projectreactor:reactor-bom:2025.0.3"))
|
||||
api(platform("io.projectreactor:reactor-bom:2025.0.4"))
|
||||
api(platform("io.rsocket:rsocket-bom:1.1.5"))
|
||||
api(platform("org.apache.groovy:groovy-bom:5.0.4"))
|
||||
api(platform("org.apache.logging.log4j:log4j-bom:2.25.3"))
|
||||
api(platform("org.assertj:assertj-bom:3.27.7"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:12.1.6"))
|
||||
api(platform("org.eclipse.jetty.ee11:jetty-ee11-bom:12.1.6"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:12.1.7"))
|
||||
api(platform("org.eclipse.jetty.ee11:jetty-ee11-bom:12.1.7"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0"))
|
||||
api(platform("org.junit:junit-bom:6.0.2"))
|
||||
api(platform("org.mockito:mockito-bom:5.21.0"))
|
||||
api(platform("org.junit:junit-bom:6.0.3"))
|
||||
api(platform("org.mockito:mockito-bom:5.22.0"))
|
||||
api(platform("tools.jackson:jackson-bom:3.0.4"))
|
||||
|
||||
constraints {
|
||||
@@ -31,8 +31,8 @@ dependencies {
|
||||
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.13.2")
|
||||
api("com.google.protobuf:protobuf-java-util:4.33.4")
|
||||
api("com.h2database:h2:2.3.232")
|
||||
api("com.google.protobuf:protobuf-java-util:4.34.0")
|
||||
api("com.h2database:h2:2.4.240")
|
||||
api("com.jayway.jsonpath:json-path:2.10.0")
|
||||
api("com.networknt:json-schema-validator:1.5.3")
|
||||
api("com.oracle.database.jdbc:ojdbc11:21.9.0.0")
|
||||
@@ -49,7 +49,7 @@ dependencies {
|
||||
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2")
|
||||
api("io.mockk:mockk:1.14.5")
|
||||
api("io.projectreactor.tools:blockhound:1.0.8.RELEASE")
|
||||
api("io.r2dbc:r2dbc-h2:1.0.0.RELEASE")
|
||||
api("io.r2dbc:r2dbc-h2:1.1.0.RELEASE")
|
||||
api("io.r2dbc:r2dbc-spi-test:1.0.0.RELEASE")
|
||||
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
|
||||
api("io.reactivex.rxjava3:rxjava:3.1.12")
|
||||
@@ -94,7 +94,7 @@ dependencies {
|
||||
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.6")
|
||||
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.4")
|
||||
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.4.2")
|
||||
api("org.apache.poi:poi-ooxml:5.5.1")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-core:11.0.18")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-websocket:11.0.18")
|
||||
@@ -111,7 +111,7 @@ dependencies {
|
||||
api("org.easymock:easymock:5.6.0")
|
||||
api("org.eclipse.angus:angus-mail:2.0.3")
|
||||
api("org.eclipse.jetty:jetty-reactive-httpclient:4.1.4")
|
||||
api("org.eclipse.persistence:org.eclipse.persistence.jpa:5.0.0-B13")
|
||||
api("org.eclipse.persistence:org.eclipse.persistence.jpa:5.0.0-RC1")
|
||||
api("org.eclipse:yasson:3.0.4")
|
||||
api("org.ehcache:ehcache:3.10.8")
|
||||
api("org.ehcache:jcache:1.0.1")
|
||||
@@ -120,7 +120,7 @@ dependencies {
|
||||
api("org.glassfish:jakarta.el:4.0.2")
|
||||
api("org.graalvm.sdk:graal-sdk:22.3.1")
|
||||
api("org.hamcrest:hamcrest:3.0")
|
||||
api("org.hibernate.orm:hibernate-core:7.2.4.Final")
|
||||
api("org.hibernate.orm:hibernate-core:7.2.6.Final")
|
||||
api("org.hibernate.validator:hibernate-validator:9.1.0.Final")
|
||||
api("org.hsqldb:hsqldb:2.7.4")
|
||||
api("org.htmlunit:htmlunit:4.21.0")
|
||||
@@ -134,14 +134,14 @@ dependencies {
|
||||
api("org.python:jython-standalone:2.7.4")
|
||||
api("org.quartz-scheduler:quartz:2.3.2")
|
||||
api("org.reactivestreams:reactive-streams:1.0.4")
|
||||
api("org.seleniumhq.selenium:htmlunit3-driver:4.40.0")
|
||||
api("org.seleniumhq.selenium:selenium-java:4.40.0")
|
||||
api("org.seleniumhq.selenium:htmlunit3-driver:4.41.0")
|
||||
api("org.seleniumhq.selenium:selenium-java:4.41.0")
|
||||
api("org.skyscreamer:jsonassert:1.5.3")
|
||||
api("org.testng:testng:7.12.0")
|
||||
api("org.webjars:underscorejs:1.8.3")
|
||||
api("org.webjars:webjars-locator-lite:1.1.0")
|
||||
api("org.xmlunit:xmlunit-assertj:2.10.4")
|
||||
api("org.xmlunit:xmlunit-matchers:2.10.4")
|
||||
api("org.yaml:snakeyaml:2.5")
|
||||
api("org.yaml:snakeyaml:2.6")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=7.0.4
|
||||
version=7.0.6
|
||||
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
|
||||
@@ -61,4 +61,4 @@ void configureDeploymentRepository(Project project) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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-9.3.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
||||
+1
-1
@@ -283,7 +283,7 @@ public final class CachedIntrospectionResults {
|
||||
}
|
||||
|
||||
// Explicitly check implemented interfaces for setter/getter methods as well,
|
||||
// in particular for Java 8 default methods...
|
||||
// in particular for interface default methods.
|
||||
Class<?> currClass = beanClass;
|
||||
while (currClass != null && currClass != Object.class) {
|
||||
introspectInterfaces(beanClass, currClass, readMethodNames);
|
||||
|
||||
+3
-3
@@ -62,9 +62,9 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <h3>Multiple Arguments and 'required' Semantics</h3>
|
||||
* <p>In the case of a multi-arg constructor or method, the {@link #required} attribute
|
||||
* is applicable to all arguments. Individual parameters may be declared as Java-8 style
|
||||
* {@link java.util.Optional} as well as {@code @Nullable} or a not-null parameter
|
||||
* type in Kotlin, overriding the base 'required' semantics.
|
||||
* is applicable to all arguments. Individual parameters may be declared as
|
||||
* {@link java.util.Optional}, {@code @Nullable}, or a not-null parameter type in
|
||||
* Kotlin, overriding the base 'required' semantics.
|
||||
*
|
||||
* <h3>Autowiring Arrays, Collections, and Maps</h3>
|
||||
* <p>In case of an array, {@link java.util.Collection}, or {@link java.util.Map}
|
||||
|
||||
+4
-3
@@ -33,6 +33,7 @@ import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -621,12 +622,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
* <p>A 'required' dependency means that autowiring should fail when no beans
|
||||
* are found. Otherwise, the autowiring process will simply bypass the field
|
||||
* or method when no beans are found.
|
||||
* @param ann the Autowired annotation
|
||||
* @param ann a {@link MergedAnnotation} representing the Autowired annotation
|
||||
* @return whether the annotation indicates that a dependency is required
|
||||
*/
|
||||
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
|
||||
return (ann.getValue(this.requiredParameterName).isEmpty() ||
|
||||
this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
|
||||
Optional<Boolean> requiredAttribute = ann.getValue(this.requiredParameterName, Boolean.class);
|
||||
return (requiredAttribute.isEmpty() || this.requiredParameterValue == requiredAttribute.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+14
-2
@@ -348,8 +348,20 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
if (!super.isRequired(descriptor)) {
|
||||
return false;
|
||||
}
|
||||
Autowired autowired = descriptor.getAnnotation(Autowired.class);
|
||||
return (autowired == null || autowired.required());
|
||||
|
||||
for (Annotation ann : descriptor.getAnnotations()) {
|
||||
// Directly present?
|
||||
if (ann instanceof Autowired autowired) {
|
||||
return autowired.required();
|
||||
}
|
||||
// Meta-present?
|
||||
Autowired autowired = AnnotationUtils.findAnnotation(ann.annotationType(), Autowired.class);
|
||||
if (autowired != null) {
|
||||
return autowired.required();
|
||||
}
|
||||
}
|
||||
// No @Autowired annotation present: default to true.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
@@ -40,6 +40,13 @@ import org.springframework.beans.BeansException;
|
||||
* A {@code BeanFactoryPostProcessor} may also be registered programmatically
|
||||
* with a {@code ConfigurableApplicationContext}.
|
||||
*
|
||||
* <p>When registering a {@code BeanFactoryPostProcessor} via an {@code @Bean} method
|
||||
* in a {@code @Configuration} class, use a {@code static} method to avoid eager
|
||||
* initialization of other beans in the configuration class. See the
|
||||
* "BeanFactoryPostProcessor-returning {@code @Bean} methods" section in
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}'s javadoc for details
|
||||
* and an example.
|
||||
*
|
||||
* <h3>Ordering</h3>
|
||||
* <p>{@code BeanFactoryPostProcessor} beans that are autodetected in an
|
||||
* {@code ApplicationContext} will be ordered according to
|
||||
|
||||
+8
@@ -35,6 +35,14 @@ import org.springframework.beans.BeansException;
|
||||
* created. A plain {@code BeanFactory} allows for programmatic registration of
|
||||
* post-processors, applying them to all beans created through the bean factory.
|
||||
*
|
||||
* <p>When registering a {@code BeanPostProcessor} via an {@code @Bean} method in
|
||||
* a {@code @Configuration} class, use a {@code static} method with ideally no
|
||||
* dependencies in order to avoid eager initialization that can make other beans
|
||||
* ineligible for full post-processing. See the "BeanPostProcessor-returning
|
||||
* {@code @Bean} methods" section in
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}'s javadoc for details
|
||||
* and an example.
|
||||
*
|
||||
* <h3>Ordering</h3>
|
||||
* <p>{@code BeanPostProcessor} beans that are autodetected in an
|
||||
* {@code ApplicationContext} will be ordered according to
|
||||
|
||||
+4
-4
@@ -149,10 +149,10 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
|
||||
/**
|
||||
* Return whether this dependency is required.
|
||||
* <p>Optional semantics are derived from Java 8's {@link java.util.Optional},
|
||||
* any variant of a parameter-level {@code Nullable} annotation (such as from
|
||||
* JSR-305 or the FindBugs set of annotations), or a language-level nullable
|
||||
* type declaration in Kotlin.
|
||||
* <p>Optional semantics are derived from Java's {@link java.util.Optional},
|
||||
* any variant of a parameter-level {@code @Nullable} annotation (such as from
|
||||
* JSpecify, JSR-305, or the FindBugs set of annotations), or a language-level
|
||||
* nullable type declaration in Kotlin.
|
||||
*/
|
||||
public boolean isRequired() {
|
||||
if (!this.required) {
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.3
|
||||
* @see org.springframework.context.annotation.ConfigurationBeanNameGenerator
|
||||
*/
|
||||
public interface BeanNameGenerator {
|
||||
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.SoftAssertions.assertSoftly;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QualifierAnnotationAutowireCandidateResolver}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 7.0.5
|
||||
*/
|
||||
class QualifierAnnotationAutowireCandidateResolverTests {
|
||||
|
||||
final QualifierAnnotationAutowireCandidateResolver resolver = new QualifierAnnotationAutowireCandidateResolver();
|
||||
|
||||
Method testMethod;
|
||||
|
||||
@RegisterExtension
|
||||
BeforeTestExecutionCallback extension = context -> this.testMethod = context.getRequiredTestMethod();
|
||||
|
||||
|
||||
@Test
|
||||
void isNotAutowired() {
|
||||
assertRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAutowiredRequired() {
|
||||
assertRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAutowiredOptional() {
|
||||
assertNotRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMetaAutowiredRequired() {
|
||||
assertRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMetaAutowiredOptional() {
|
||||
assertNotRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMetaMetaAutowiredRequired() {
|
||||
assertRequired();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMetaMetaAutowiredOptional() {
|
||||
assertNotRequired();
|
||||
}
|
||||
|
||||
|
||||
private void assertRequired() {
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(this.resolver.isRequired(getFieldDescriptor()))
|
||||
.as("%sField is required", this.testMethod.getName()).isTrue();
|
||||
softly.assertThat(this.resolver.isRequired(getParameterDescriptor()))
|
||||
.as("parameter in %sParameter() is required", this.testMethod.getName()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
private void assertNotRequired() {
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(this.resolver.isRequired(getFieldDescriptor()))
|
||||
.as("%sField is not required", this.testMethod.getName()).isFalse();
|
||||
softly.assertThat(this.resolver.isRequired(getParameterDescriptor()))
|
||||
.as("parameter in %sParameter() is not required", this.testMethod.getName()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
private DependencyDescriptor getFieldDescriptor() {
|
||||
var field = ReflectionUtils.findField(getClass(), this.testMethod.getName() + "Field");
|
||||
return new DependencyDescriptor(field, true);
|
||||
}
|
||||
|
||||
private DependencyDescriptor getParameterDescriptor() {
|
||||
var method = ReflectionUtils.findMethod(getClass(), this.testMethod.getName() + "Parameter", String.class);
|
||||
var methodParameter = MethodParameter.forExecutable(method, 0);
|
||||
return new DependencyDescriptor(methodParameter, true);
|
||||
}
|
||||
|
||||
|
||||
String isNotAutowiredField;
|
||||
|
||||
@Autowired
|
||||
String isAutowiredRequiredField;
|
||||
|
||||
@Autowired(required = false)
|
||||
String isAutowiredOptionalField;
|
||||
|
||||
@MetaAutowiredRequired
|
||||
String isMetaAutowiredRequiredField;
|
||||
|
||||
@MetaAutowiredOptional
|
||||
String isMetaAutowiredOptionalField;
|
||||
|
||||
@MetaMetaAutowiredRequired
|
||||
String isMetaMetaAutowiredRequiredField;
|
||||
|
||||
@MetaMetaAutowiredOptional
|
||||
String isMetaMetaAutowiredOptionalField;
|
||||
|
||||
|
||||
|
||||
void isNotAutowiredParameter(String enigma) {
|
||||
}
|
||||
|
||||
void isAutowiredRequiredParameter(@Autowired String enigma) {
|
||||
}
|
||||
|
||||
void isAutowiredOptionalParameter(@Autowired(required = false) String enigma) {
|
||||
}
|
||||
|
||||
void isMetaAutowiredRequiredParameter(@MetaAutowiredRequired String enigma) {
|
||||
}
|
||||
|
||||
void isMetaAutowiredOptionalParameter(@MetaAutowiredOptional String enigma) {
|
||||
}
|
||||
|
||||
void isMetaMetaAutowiredRequiredParameter(@MetaMetaAutowiredRequired String enigma) {
|
||||
}
|
||||
|
||||
void isMetaMetaAutowiredOptionalParameter(@MetaMetaAutowiredOptional String enigma) {
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Autowired
|
||||
@interface MetaAutowiredRequired {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Autowired(required = false)
|
||||
@interface MetaAutowiredOptional {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@MetaAutowiredRequired
|
||||
@interface MetaMetaAutowiredRequired {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@MetaAutowiredOptional
|
||||
@interface MetaMetaAutowiredOptional {
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -109,7 +109,9 @@ public class AnnotatedBeanDefinitionReader {
|
||||
|
||||
/**
|
||||
* Set the {@code BeanNameGenerator} to use for detected bean classes.
|
||||
* <p>The default is a {@link AnnotationBeanNameGenerator}.
|
||||
* <p>The default is an {@link AnnotationBeanNameGenerator}.
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator =
|
||||
|
||||
+8
-2
@@ -118,14 +118,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
||||
|
||||
/**
|
||||
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
|
||||
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
|
||||
* <p>Default is {@link AnnotationBeanNameGenerator}.
|
||||
* and/or {@link ClassPathBeanDefinitionScanner}.
|
||||
* <p>Default is {@code AnnotationBeanNameGenerator}.
|
||||
* <p>When processing {@link Configuration @Configuration} classes, a
|
||||
* {@link ConfigurationBeanNameGenerator} (such as
|
||||
* {@link FullyQualifiedConfigurationBeanNameGenerator}) also determines the
|
||||
* default names for {@link Bean @Bean} methods without an explicit {@code name}
|
||||
* attribute.
|
||||
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
|
||||
* and/or {@link #scan(String...)}.
|
||||
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
|
||||
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
|
||||
* @see AnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.reader.setBeanNameGenerator(beanNameGenerator);
|
||||
|
||||
@@ -35,48 +35,47 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }
|
||||
* </pre>
|
||||
* @Bean
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Bean Names</h3>
|
||||
*
|
||||
* <p>While a {@link #name} attribute is available, the default strategy for
|
||||
* determining the name of a bean is to use the name of the {@code @Bean} method.
|
||||
* This is convenient and intuitive, but if explicit naming is desired, the
|
||||
* {@code name} attribute (or its alias {@code value}) may be used. Also note
|
||||
* that {@code name} accepts an array of Strings, allowing for multiple names
|
||||
* (i.e. a primary bean name plus one or more aliases) for a single bean.
|
||||
* This default can be overridden by configuring a {@link ConfigurationBeanNameGenerator}
|
||||
* — for example, {@link FullyQualifiedConfigurationBeanNameGenerator} for
|
||||
* fully-qualified names. If explicit naming is desired for an individual bean, the
|
||||
* {@code name} attribute (or its alias {@link #value}) may be used. Also note that
|
||||
* {@code name} accepts an array of Strings, allowing for multiple names (i.e., a
|
||||
* primary bean name plus one or more aliases) for a single bean.
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }
|
||||
* </pre>
|
||||
* @Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Profile, Scope, Lazy, DependsOn, Primary, Order</h3>
|
||||
* <h3>Profile, Scope, Lazy, DependsOn, Primary, Fallback, Order</h3>
|
||||
*
|
||||
* <p>Note that the {@code @Bean} annotation does not provide attributes for profile,
|
||||
* scope, lazy, depends-on or primary. Rather, it should be used in conjunction with
|
||||
* {@link Scope @Scope}, {@link Lazy @Lazy}, {@link DependsOn @DependsOn} and
|
||||
* scope, lazy, depends-on, or primary. Rather, it should be used in conjunction with
|
||||
* {@link Scope @Scope}, {@link Lazy @Lazy}, {@link DependsOn @DependsOn}, and
|
||||
* {@link Primary @Primary} annotations to declare those semantics. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* @Profile("production")
|
||||
* @Scope("prototype")
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }
|
||||
* </pre>
|
||||
* @Bean
|
||||
* @Profile("production")
|
||||
* @Scope("prototype")
|
||||
* public MyBean myBean() {
|
||||
* // instantiate and configure MyBean obj
|
||||
* return obj;
|
||||
* }</pre>
|
||||
*
|
||||
* The semantics of the above-mentioned annotations match their use at the component
|
||||
* The semantics of the aforementioned annotations match their use at the component
|
||||
* class level: {@code @Profile} allows for selective inclusion of certain beans.
|
||||
* {@code @Scope} changes the bean's scope from singleton to the specified scope.
|
||||
* {@code @Lazy} only has an actual effect in case of the default singleton scope.
|
||||
@@ -85,6 +84,9 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* through direct references, which is typically helpful for singleton startup.
|
||||
* {@code @Primary} is a mechanism to resolve ambiguity at the injection point level
|
||||
* if a single target component needs to be injected but several beans match by type.
|
||||
* {@link Fallback @Fallback} marks a bean as a fallback candidate in such scenarios;
|
||||
* if all beans but one among multiple matching candidates are marked as fallback, the
|
||||
* remaining bean will be selected.
|
||||
*
|
||||
* <p>Additionally, {@code @Bean} methods may also declare qualifier annotations
|
||||
* and {@link org.springframework.core.annotation.Order @Order} values, to be
|
||||
@@ -100,8 +102,8 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* orthogonal concern determined by dependency relationships and {@code @DependsOn}
|
||||
* declarations as mentioned above. Also, {@link jakarta.annotation.Priority} is not
|
||||
* available at this level since it cannot be declared on methods; its semantics can
|
||||
* be modeled through {@code @Order} values in combination with {@code @Primary} on
|
||||
* a single bean per type.
|
||||
* be modeled through {@code @Order} values in combination with {@code @Primary} or
|
||||
* {@code @Fallback} on a single bean per type.
|
||||
*
|
||||
* <h3>{@code @Bean} Methods in {@code @Configuration} Classes</h3>
|
||||
*
|
||||
@@ -119,17 +121,17 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @Configuration
|
||||
* public class AppConfig {
|
||||
*
|
||||
* @Bean
|
||||
* public FooService fooService() {
|
||||
* return new FooService(fooRepository());
|
||||
* }
|
||||
* @Bean
|
||||
* public FooService fooService() {
|
||||
* return new FooService(fooRepository());
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public FooRepository fooRepository() {
|
||||
* return new JdbcFooRepository(dataSource());
|
||||
* }
|
||||
* @Bean
|
||||
* public FooRepository fooRepository() {
|
||||
* return new JdbcFooRepository(dataSource());
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* // ...
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>{@code @Bean} <em>Lite</em> Mode</h3>
|
||||
@@ -158,20 +160,21 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* <pre class="code">
|
||||
* @Component
|
||||
* public class Calculator {
|
||||
* public int sum(int a, int b) {
|
||||
* return a+b;
|
||||
* }
|
||||
* public int sum(int a, int b) {
|
||||
* return a+b;
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public MyBean myBean() {
|
||||
* return new MyBean();
|
||||
* }
|
||||
* @Bean
|
||||
* public MyBean myBean() {
|
||||
* return new MyBean();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Bootstrapping</h3>
|
||||
*
|
||||
* <p>See the @{@link Configuration} javadoc for further details including how to bootstrap
|
||||
* the container using {@link AnnotationConfigApplicationContext} and friends.
|
||||
* <p>See the {@link Configuration @Configuration} javadoc for further details
|
||||
* including how to bootstrap the container using
|
||||
* {@link AnnotationConfigApplicationContext} and friends.
|
||||
*
|
||||
* <h3>{@code BeanFactoryPostProcessor}-returning {@code @Bean} methods</h3>
|
||||
*
|
||||
@@ -183,20 +186,44 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* lifecycle issues, mark {@code BFPP}-returning {@code @Bean} methods as {@code static}. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* public static PropertySourcesPlaceholderConfigurer pspc() {
|
||||
* // instantiate, configure and return pspc ...
|
||||
* }
|
||||
* </pre>
|
||||
* @Bean
|
||||
* public static PropertySourcesPlaceholderConfigurer pspc() {
|
||||
* // instantiate, configure and return pspc ...
|
||||
* }</pre>
|
||||
*
|
||||
* By marking this method as {@code static}, it can be invoked without causing instantiation of its
|
||||
* declaring {@code @Configuration} class, thus avoiding the above-mentioned lifecycle conflicts.
|
||||
* declaring {@code @Configuration} class, thus avoiding the aforementioned lifecycle conflicts.
|
||||
* Note however that {@code static} {@code @Bean} methods will not be enhanced for scoping and AOP
|
||||
* semantics as mentioned above. This works out in {@code BFPP} cases, as they are not typically
|
||||
* referenced by other {@code @Bean} methods. As a reminder, an INFO-level log message will be
|
||||
* issued for any non-static {@code @Bean} methods having a return type assignable to
|
||||
* {@code BeanFactoryPostProcessor}.
|
||||
*
|
||||
* <h3>{@code BeanPostProcessor}-returning {@code @Bean} methods</h3>
|
||||
*
|
||||
* <p>Similarly, special consideration must be taken for {@code @Bean} methods that return Spring
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
|
||||
* ({@code BPP}) types. Because {@code BPP} objects must be instantiated early in the container
|
||||
* lifecycle, a non-static {@code @Bean} method that returns a {@code BPP} will cause eager
|
||||
* initialization of its declaring {@code @Configuration} class, which can make other beans in the
|
||||
* {@code @Configuration} class (as well as depencencies of those beans) ineligible for full
|
||||
* post-processing. To avoid these lifecycle issues, mark {@code BPP}-returning {@code @Bean}
|
||||
* methods as {@code static}. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* public static MyBeanPostProcessor myBeanPostProcessor() {
|
||||
* return new MyBeanPostProcessor();
|
||||
* }</pre>
|
||||
*
|
||||
* By marking this method as {@code static}, it can be invoked without causing instantiation of its
|
||||
* declaring {@code @Configuration} class. Furthermore, the method should ideally not declare any
|
||||
* dependencies so that the container does not need to instantiate other beans to create the
|
||||
* post-processor, which would make those beans ineligible for post-processing as well. For any such
|
||||
* bean, you should see a WARN-level log message similar to the following: "Bean 'someBean' of type
|
||||
* [org.example.SomeType] is not eligible for getting processed by all BeanPostProcessors (for example:
|
||||
* not eligible for auto-proxying)".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
@@ -208,9 +235,13 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @see DependsOn
|
||||
* @see Lazy
|
||||
* @see Primary
|
||||
* @see Fallback
|
||||
* @see org.springframework.stereotype.Component
|
||||
* @see org.springframework.beans.factory.annotation.Autowired
|
||||
* @see org.springframework.beans.factory.annotation.Value
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
* @see AnnotationConfigApplicationContext#setBeanNameGenerator
|
||||
* @see ComponentScan#nameGenerator()
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -229,10 +260,11 @@ public @interface Bean {
|
||||
|
||||
/**
|
||||
* The name of this bean, or if several names, a primary bean name plus aliases.
|
||||
* <p>If left unspecified, the name of the bean is the name of the annotated method.
|
||||
* If specified, the method name is ignored.
|
||||
* <p>See the "Bean Names" section in the {@linkplain Bean class-level documentation}
|
||||
* for details on how the bean name is determined if this attribute is left
|
||||
* unspecified.
|
||||
* <p>The bean name and aliases may also be configured via the {@link #value}
|
||||
* attribute if no other attributes are declared.
|
||||
* attribute.
|
||||
* @see #value
|
||||
*/
|
||||
@AliasFor("value")
|
||||
|
||||
+9
-6
@@ -43,11 +43,11 @@ import org.springframework.util.PatternMatchUtils;
|
||||
* or {@code ApplicationContext}).
|
||||
*
|
||||
* <p>Candidate classes are detected through configurable type filters. The
|
||||
* default filters include classes that are annotated with Spring's
|
||||
* {@link org.springframework.stereotype.Component @Component},
|
||||
* default filters include classes that are annotated or meta-annotated with Spring's
|
||||
* {@link org.springframework.stereotype.Component @Component} annotation, such as the
|
||||
* {@link org.springframework.stereotype.Repository @Repository},
|
||||
* {@link org.springframework.stereotype.Service @Service}, or
|
||||
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
|
||||
* {@link org.springframework.stereotype.Service @Service}, and
|
||||
* {@link org.springframework.stereotype.Controller @Controller} stereotypes.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link jakarta.inject.Named} annotations, if available.
|
||||
*
|
||||
@@ -204,8 +204,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanNameGenerator to use for detected bean classes.
|
||||
* <p>Default is a {@link AnnotationBeanNameGenerator}.
|
||||
* Set the {@link BeanNameGenerator} to use for detected bean classes.
|
||||
* <p>Default is an {@code AnnotationBeanNameGenerator}.
|
||||
* @see AnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator =
|
||||
|
||||
+6
-2
@@ -109,14 +109,18 @@ public @interface ComponentScan {
|
||||
/**
|
||||
* The {@link BeanNameGenerator} class to be used for naming detected components
|
||||
* within the Spring container.
|
||||
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
|
||||
* <p>The default value of the {@code BeanNameGenerator} interface itself indicates
|
||||
* that the scanner used to process this {@code @ComponentScan} annotation should
|
||||
* use its inherited bean name generator, for example, the default
|
||||
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
|
||||
* application context at bootstrap time.
|
||||
* application context at bootstrap time. If a {@link ConfigurationBeanNameGenerator}
|
||||
* is used (such as {@link FullyQualifiedConfigurationBeanNameGenerator}), it
|
||||
* also affects the default names for {@link Bean @Bean} methods in
|
||||
* {@link Configuration @Configuration} classes.
|
||||
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
|
||||
* @see AnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
|
||||
|
||||
|
||||
+3
-3
@@ -26,9 +26,9 @@ import java.lang.annotation.Target;
|
||||
* Container annotation that aggregates several {@link ComponentScan} annotations.
|
||||
*
|
||||
* <p>Can be used natively, declaring several nested {@link ComponentScan} annotations.
|
||||
* Can also be used in conjunction with Java 8's support for repeatable annotations,
|
||||
* where {@link ComponentScan} can simply be declared several times on the same method,
|
||||
* implicitly generating this container annotation.
|
||||
* Can also be used in conjunction with Java's support for repeatable annotations,
|
||||
* where {@link ComponentScan @ComponentScan} can simply be declared several times
|
||||
* on the same method, implicitly generating this container annotation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.3
|
||||
|
||||
@@ -437,6 +437,8 @@ public @interface Configuration {
|
||||
* <p>Alias for {@link Component#value}.
|
||||
* @return the explicit component name, if any (or empty String otherwise)
|
||||
* @see AnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
@AliasFor(annotation = Component.class)
|
||||
String value() default "";
|
||||
|
||||
+3
-2
@@ -37,9 +37,10 @@ public interface ConfigurationBeanNameGenerator extends BeanNameGenerator {
|
||||
|
||||
/**
|
||||
* Derive a default bean name for the given {@link Bean @Bean} method,
|
||||
* providing the {@link Bean#name() name} attribute specified.
|
||||
* taking into account the specified {@link Bean#name() name} attribute.
|
||||
* @param beanMethod the method metadata for the {@link Bean @Bean} method
|
||||
* @param beanName the {@link Bean#name() name} attribute or {@code null} if non is specified
|
||||
* @param beanName the {@link Bean#name() name} attribute or {@code null} if
|
||||
* none is specified
|
||||
* @return the default bean name to use
|
||||
*/
|
||||
String deriveBeanName(MethodMetadata beanMethod, @Nullable String beanName);
|
||||
|
||||
+5
-5
@@ -209,7 +209,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
String beanName = (explicitNames.length > 0 && StringUtils.hasText(explicitNames[0])) ? explicitNames[0] : null;
|
||||
String localBeanName = defaultBeanName(beanName, methodName);
|
||||
beanName = (this.importBeanNameGenerator instanceof ConfigurationBeanNameGenerator cbng ?
|
||||
cbng.deriveBeanName(metadata, beanName) : defaultBeanName(beanName, methodName));
|
||||
cbng.deriveBeanName(metadata, beanName) : localBeanName);
|
||||
if (explicitNames.length > 0) {
|
||||
// Register aliases even when overridden below.
|
||||
for (int i = 1; i < explicitNames.length; i++) {
|
||||
@@ -303,8 +303,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Registering bean definition for @Bean method %s.%s()"
|
||||
.formatted(configClass.getMetadata().getClassName(), beanName));
|
||||
logger.trace("Registering bean definition for @Bean method %s.%s() with bean name '%s'"
|
||||
.formatted(configClass.getMetadata().getClassName(), methodName, beanName));
|
||||
}
|
||||
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
|
||||
}
|
||||
@@ -368,8 +368,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
"@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Skipping bean definition for %s: a definition for bean '%s' already exists. " +
|
||||
"This top-level bean definition is considered as an override.".formatted(beanMethod, beanName));
|
||||
logger.debug(("Skipping bean definition for %s: a definition for bean '%s' already exists. " +
|
||||
"This top-level bean definition is considered as an override.").formatted(beanMethod, beanName));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+7
-7
@@ -387,13 +387,13 @@ class ConfigurationClassEnhancer {
|
||||
// create the bean instance.
|
||||
if (logger.isInfoEnabled() &&
|
||||
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
|
||||
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
|
||||
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
|
||||
"result in a failure to process annotations such as @Autowired, " +
|
||||
"@Resource and @PostConstruct within the method's declaring " +
|
||||
"@Configuration class. Add the 'static' modifier to this method to avoid " +
|
||||
"these container lifecycle issues; see @Bean javadoc for complete details.",
|
||||
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
|
||||
logger.info("""
|
||||
@Bean method %s.%s is non-static and returns an object assignable to Spring's \
|
||||
BeanFactoryPostProcessor interface. This will result in a failure to process \
|
||||
annotations such as @Autowired, @Resource, and @PostConstruct within the method's \
|
||||
declaring @Configuration class. Add the 'static' modifier to this method to avoid \
|
||||
these container lifecycle issues; see @Bean javadoc for complete details."""
|
||||
.formatted(beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
|
||||
}
|
||||
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
|
||||
}
|
||||
|
||||
+1
-1
@@ -443,7 +443,7 @@ class ConfigurationClassParser {
|
||||
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
|
||||
for (MethodMetadata methodMetadata : beanMethods) {
|
||||
if (!methodMetadata.isAbstract()) {
|
||||
// A default method or other concrete method on a Java 8+ interface...
|
||||
// A default method or other concrete method on a Java interface...
|
||||
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -242,12 +242,15 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
|
||||
/**
|
||||
* Set the {@link BeanNameGenerator} to be used when triggering component scanning
|
||||
* from {@link Configuration} classes and when registering {@link Import}'ed
|
||||
* configuration classes. The default is a standard {@link AnnotationBeanNameGenerator}
|
||||
* for scanned components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
|
||||
* from {@link Configuration @Configuration} classes and when registering
|
||||
* {@link Import @Import}'ed configuration classes.
|
||||
* <p>The default is a standard {@link AnnotationBeanNameGenerator} for scanned
|
||||
* components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
|
||||
* and a variant thereof for imported configuration classes (using unique fully-qualified
|
||||
* class names instead of standard component overriding).
|
||||
* <p>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
|
||||
* <p>If the supplied bean name generator is a {@link ConfigurationBeanNameGenerator}
|
||||
* (such as {@link FullyQualifiedConfigurationBeanNameGenerator}), it also affects the
|
||||
* default names for {@link Bean @Bean} methods in configuration classes.
|
||||
* <p>This setter is typically only appropriate when configuring the post-processor as a
|
||||
* standalone bean definition in XML, for example, not using the dedicated {@code AnnotationConfig*}
|
||||
* application contexts or the {@code <context:annotation-config>} element. Any bean name
|
||||
@@ -255,6 +258,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* @since 3.1.1
|
||||
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
|
||||
* @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
|
||||
* @see AnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
* @see FullyQualifiedConfigurationBeanNameGenerator
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
|
||||
|
||||
+4
-3
@@ -26,9 +26,10 @@ import java.lang.annotation.Target;
|
||||
* Container annotation that aggregates several {@link PropertySource} annotations.
|
||||
*
|
||||
* <p>Can be used natively, declaring several nested {@link PropertySource} annotations.
|
||||
* Can also be used in conjunction with Java 8's support for <em>repeatable annotations</em>,
|
||||
* where {@link PropertySource} can simply be declared several times on the same
|
||||
* {@linkplain ElementType#TYPE type}, implicitly generating this container annotation.
|
||||
* Can also be used in conjunction with Java's support for <em>repeatable annotations</em>,
|
||||
* where {@link PropertySource @PropertySource} can simply be declared several
|
||||
* times on the same {@linkplain ElementType#TYPE type}, implicitly generating
|
||||
* this container annotation.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
|
||||
+34
-5
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* configuration methods and corresponding semantic definitions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 4.3
|
||||
* @see ResourceBundleMessageSource
|
||||
* @see ReloadableResourceBundleMessageSource
|
||||
@@ -40,7 +42,7 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
|
||||
private final Set<String> basenameSet = new LinkedHashSet<>(4);
|
||||
|
||||
private @Nullable String defaultEncoding;
|
||||
private @Nullable Charset defaultCharset;
|
||||
|
||||
private boolean fallbackToSystemLocale = true;
|
||||
|
||||
@@ -53,7 +55,7 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
* Set a single basename, following the basic ResourceBundle convention
|
||||
* of not specifying file extension or language codes. The resource location
|
||||
* format is up to the specific {@code MessageSource} implementation.
|
||||
* <p>Regular and XMl properties files are supported: for example, "messages" will find
|
||||
* <p>Regular and XML properties files are supported: for example, "messages" will find
|
||||
* a "messages.properties", "messages_en.properties" etc arrangement as well
|
||||
* as "messages.xml", "messages_en.xml" etc.
|
||||
* @param basename the single basename
|
||||
@@ -118,25 +120,52 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
|
||||
/**
|
||||
* Set the default charset to use for parsing properties files.
|
||||
* Used if no file-specific charset is specified for a file.
|
||||
* <p>Used if no file-specific charset is specified for a file.
|
||||
* <p>The effective default is the {@code java.util.Properties}
|
||||
* default encoding: ISO-8859-1. A {@code null} value indicates
|
||||
* the platform default encoding.
|
||||
* <p>Only applies to classic properties files, not to XML files.
|
||||
* @param defaultEncoding the default charset
|
||||
* @see #setDefaultCharset(Charset)
|
||||
*/
|
||||
public void setDefaultEncoding(@Nullable String defaultEncoding) {
|
||||
this.defaultEncoding = defaultEncoding;
|
||||
this.defaultCharset = (defaultEncoding != null ? Charset.forName(defaultEncoding) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default charset to use for parsing properties files, if any.
|
||||
* @since 4.3
|
||||
* @see #getDefaultCharset()
|
||||
*/
|
||||
protected @Nullable String getDefaultEncoding() {
|
||||
return this.defaultEncoding;
|
||||
return (this.defaultCharset != null ? this.defaultCharset.name() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default {@link Charset} to use for parsing properties files.
|
||||
* <p>Used if no file-specific charset is specified for a file.
|
||||
* <p>The effective default is the {@code java.util.Properties}
|
||||
* default encoding: ISO-8859-1. A {@code null} value indicates
|
||||
* the platform default encoding.
|
||||
* <p>Only applies to classic properties files, not to XML files.
|
||||
* @param defaultCharset the default charset
|
||||
* @since 7.0.6
|
||||
* @see #setDefaultEncoding(String)
|
||||
*/
|
||||
public void setDefaultCharset(@Nullable Charset defaultCharset) {
|
||||
this.defaultCharset = defaultCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default charset to use for parsing properties files, if any.
|
||||
* @since 7.0.6
|
||||
* @see #setDefaultCharset(Charset)
|
||||
*/
|
||||
protected @Nullable Charset getDefaultCharset() {
|
||||
return this.defaultCharset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to fall back to the system Locale if no files for a specific
|
||||
* Locale have been found. Default is "true"; if this is turned off, the only
|
||||
|
||||
+4
-1
@@ -24,6 +24,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -98,7 +100,8 @@ class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor,
|
||||
try {
|
||||
ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
|
||||
multicaster.removeApplicationListener(applicationListener);
|
||||
multicaster.removeApplicationListenerBean(beanName);
|
||||
multicaster.removeApplicationListenerBean(
|
||||
bean instanceof FactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// ApplicationEventMulticaster not initialized yet - no need to remove a listener
|
||||
|
||||
+26
-19
@@ -19,6 +19,7 @@ package org.springframework.context.support;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -80,9 +81,10 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
* @author Sam Brannen
|
||||
* @see #setCacheSeconds
|
||||
* @see #setBasenames
|
||||
* @see #setDefaultEncoding
|
||||
* @see #setDefaultCharset
|
||||
* @see #setFileEncodings
|
||||
* @see #setPropertiesPersister
|
||||
* @see #setResourceLoader
|
||||
@@ -93,10 +95,12 @@ import org.springframework.util.StringUtils;
|
||||
public class ReloadableResourceBundleMessageSource extends AbstractResourceBasedMessageSource
|
||||
implements ResourceLoaderAware {
|
||||
|
||||
private static final String PROPERTIES_EXTENSION = ".properties";
|
||||
|
||||
private static final String XML_EXTENSION = ".xml";
|
||||
|
||||
|
||||
private List<String> fileExtensions = List.of(".properties", XML_EXTENSION);
|
||||
private List<String> fileExtensions = List.of(PROPERTIES_EXTENSION, XML_EXTENSION);
|
||||
|
||||
private @Nullable Properties fileEncodings;
|
||||
|
||||
@@ -135,7 +139,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
/**
|
||||
* Set per-file charsets to use for parsing properties files.
|
||||
* <p>Only applies to classic properties files, not to XML files.
|
||||
* @param fileEncodings a Properties with filenames as keys and charset
|
||||
* @param fileEncodings a Properties object with filenames as keys and charset
|
||||
* names as values. Filenames have to match the basename syntax,
|
||||
* with optional locale-specific components: for example, "WEB-INF/messages"
|
||||
* or "WEB-INF/messages_en".
|
||||
@@ -378,18 +382,18 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
StringBuilder temp = new StringBuilder(basename);
|
||||
|
||||
temp.append('_');
|
||||
if (language.length() > 0) {
|
||||
if (!language.isEmpty()) {
|
||||
temp.append(language);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
|
||||
temp.append('_');
|
||||
if (country.length() > 0) {
|
||||
if (!country.isEmpty()) {
|
||||
temp.append(country);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
|
||||
if (variant.length() > 0 && (language.length() > 0 || country.length() > 0)) {
|
||||
if (!variant.isEmpty() && (!language.isEmpty() || !country.isEmpty())) {
|
||||
temp.append('_').append(variant);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
@@ -558,33 +562,36 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
*/
|
||||
protected Properties loadProperties(Resource resource, String filename) throws IOException {
|
||||
Properties props = newProperties();
|
||||
try (InputStream is = resource.getInputStream()) {
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
String resourceFilename = resource.getFilename();
|
||||
if (resourceFilename != null && resourceFilename.endsWith(XML_EXTENSION)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "]");
|
||||
}
|
||||
this.propertiesPersister.loadFromXml(props, is);
|
||||
this.propertiesPersister.loadFromXml(props, inputStream);
|
||||
}
|
||||
else {
|
||||
String encoding = null;
|
||||
Charset charset = null;
|
||||
if (this.fileEncodings != null) {
|
||||
encoding = this.fileEncodings.getProperty(filename);
|
||||
}
|
||||
if (encoding == null) {
|
||||
encoding = getDefaultEncoding();
|
||||
}
|
||||
if (encoding != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "] with encoding '" + encoding + "'");
|
||||
String charsetName = this.fileEncodings.getProperty(filename);
|
||||
if (charsetName != null) {
|
||||
charset = Charset.forName(charsetName);
|
||||
}
|
||||
this.propertiesPersister.load(props, new InputStreamReader(is, encoding));
|
||||
}
|
||||
if (charset == null) {
|
||||
charset = getDefaultCharset();
|
||||
}
|
||||
if (charset != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "] with encoding '" + charset + "'");
|
||||
}
|
||||
this.propertiesPersister.load(props, new InputStreamReader(inputStream, charset));
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "]");
|
||||
}
|
||||
this.propertiesPersister.load(props, is);
|
||||
this.propertiesPersister.load(props, inputStream);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
|
||||
+18
-15
@@ -22,6 +22,8 @@ import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -57,11 +59,11 @@ import org.springframework.util.ClassUtils;
|
||||
* This means that "test.theme" is effectively equivalent to "test/theme".
|
||||
*
|
||||
* <p>On the classpath, bundle resources will be read with the locally configured
|
||||
* {@link #setDefaultEncoding encoding}: by default, ISO-8859-1; consider switching
|
||||
* {@link #setDefaultCharset Charset}: by default, ISO-8859-1; consider switching
|
||||
* this to UTF-8, or to {@code null} for the platform default encoding. On the JDK 9+
|
||||
* module path where locally provided {@code ResourceBundle.Control} handles are not
|
||||
* supported, this MessageSource always falls back to {@link ResourceBundle#getBundle}
|
||||
* retrieval with the platform default encoding: UTF-8 with a ISO-8859-1 fallback on
|
||||
* retrieval with the platform default encoding: UTF-8 with an ISO-8859-1 fallback on
|
||||
* JDK 9+ (configurable through the "java.util.PropertyResourceBundle.encoding" system
|
||||
* property). Note that {@link #loadBundle(Reader)}/{@link #loadBundle(InputStream)}
|
||||
* won't be called in this case either, effectively ignoring overrides in subclasses.
|
||||
@@ -70,6 +72,7 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Qimiao Chen
|
||||
* @author Sam Brannen
|
||||
* @see #setBasenames
|
||||
* @see ReloadableResourceBundleMessageSource
|
||||
* @see java.util.ResourceBundle
|
||||
@@ -83,7 +86,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
|
||||
/**
|
||||
* Cache to hold loaded ResourceBundles.
|
||||
* This Map is keyed with the bundle basename, which holds a Map that is
|
||||
* <p>This Map is keyed with the bundle basename, which holds a Map that is
|
||||
* keyed with the Locale and in turn holds the ResourceBundle instances.
|
||||
* This allows for very efficient hash lookups, significantly faster
|
||||
* than the ResourceBundle class's own cache.
|
||||
@@ -93,7 +96,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
|
||||
/**
|
||||
* Cache to hold already generated MessageFormats.
|
||||
* This Map is keyed with the ResourceBundle, which holds a Map that is
|
||||
* <p>This Map is keyed with the ResourceBundle, which holds a Map that is
|
||||
* keyed with the message code, which in turn holds a Map that is keyed
|
||||
* with the Locale and holds the MessageFormat values. This allows for
|
||||
* very efficient hash lookups without concatenated keys.
|
||||
@@ -106,7 +109,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
|
||||
|
||||
public ResourceBundleMessageSource() {
|
||||
setDefaultEncoding("ISO-8859-1");
|
||||
setDefaultCharset(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
|
||||
@@ -239,12 +242,12 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
catch (UnsupportedOperationException ex) {
|
||||
// Probably in a Java Module System environment on JDK 9+
|
||||
this.control = null;
|
||||
String encoding = getDefaultEncoding();
|
||||
if (encoding != null && logger.isInfoEnabled()) {
|
||||
Charset charset = getDefaultCharset();
|
||||
if (charset != null && logger.isInfoEnabled()) {
|
||||
logger.info("ResourceBundleMessageSource is configured to read resources with encoding '" +
|
||||
encoding + "' but ResourceBundle.Control is not supported in current system environment: " +
|
||||
charset + "' but ResourceBundle.Control is not supported in current system environment: " +
|
||||
ex.getMessage() + " - falling back to plain ResourceBundle.getBundle retrieval with the " +
|
||||
"platform default encoding. Consider setting the 'defaultEncoding' property to 'null' " +
|
||||
"platform default encoding. Consider setting the 'defaultCharset' property to 'null' " +
|
||||
"for participating in the platform default and therefore avoiding this log message.");
|
||||
}
|
||||
}
|
||||
@@ -256,7 +259,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
|
||||
/**
|
||||
* Load a property-based resource bundle from the given reader.
|
||||
* <p>This will be called in case of a {@link #setDefaultEncoding "defaultEncoding"},
|
||||
* <p>This will be called in case of a {@linkplain #setDefaultCharset "defaultCharset"},
|
||||
* including {@link ResourceBundleMessageSource}'s default ISO-8859-1 encoding.
|
||||
* Note that this method can only be called with a {@code ResourceBundle.Control}:
|
||||
* When running on the JDK 9+ module path where such control handles are not
|
||||
@@ -276,9 +279,9 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
/**
|
||||
* Load a property-based resource bundle from the given input stream,
|
||||
* picking up the default properties encoding on JDK 9+.
|
||||
* <p>This will only be called with {@link #setDefaultEncoding "defaultEncoding"}
|
||||
* <p>This will only be called with {@linkplain #setDefaultCharset "defaultCharset"}
|
||||
* set to {@code null}, explicitly enforcing the platform default encoding
|
||||
* (which is UTF-8 with a ISO-8859-1 fallback on JDK 9+ but configurable
|
||||
* (which is UTF-8 with an ISO-8859-1 fallback on JDK 9+ but configurable
|
||||
* through the "java.util.PropertyResourceBundle.encoding" system property).
|
||||
* Note that this method can only be called with a {@code ResourceBundle.Control}:
|
||||
* When running on the JDK 9+ module path where such control handles are not
|
||||
@@ -404,9 +407,9 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
|
||||
inputStream = classLoader.getResourceAsStream(resourceName);
|
||||
}
|
||||
if (inputStream != null) {
|
||||
String encoding = getDefaultEncoding();
|
||||
if (encoding != null) {
|
||||
try (InputStreamReader bundleReader = new InputStreamReader(inputStream, encoding)) {
|
||||
Charset charset = getDefaultCharset();
|
||||
if (charset != null) {
|
||||
try (InputStreamReader bundleReader = new InputStreamReader(inputStream, charset)) {
|
||||
return loadBundle(bundleReader);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Formats fields annotated with the {@link DateTimeFormat} annotation using the
|
||||
* JSR-310 <code>java.time</code> package in JDK 8.
|
||||
* JSR-310 <code>java.time</code> package.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Integration with the JSR-310 <code>java.time</code> package in JDK 8.
|
||||
* Integration with the JSR-310 <code>java.time</code> package.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.format.datetime.standard;
|
||||
|
||||
+3
-3
@@ -28,9 +28,9 @@ import org.springframework.aot.hint.annotation.Reflective;
|
||||
* Container annotation that aggregates several {@link Scheduled} annotations.
|
||||
*
|
||||
* <p>Can be used natively, declaring several nested {@link Scheduled} annotations.
|
||||
* Can also be used in conjunction with Java 8's support for repeatable annotations,
|
||||
* where {@link Scheduled} can simply be declared several times on the same method,
|
||||
* implicitly generating this container annotation.
|
||||
* Can also be used in conjunction with Java's support for repeatable annotations,
|
||||
* where {@link Scheduled @Scheduled} can simply be declared several times on the
|
||||
* same method, implicitly generating this container annotation.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em>.
|
||||
|
||||
+8
-7
@@ -49,14 +49,15 @@ public class ForkJoinPoolFactoryBean implements FactoryBean<ForkJoinPool>, Initi
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to expose JDK 8's 'common' {@link ForkJoinPool}.
|
||||
* <p>Default is "false", creating a local {@link ForkJoinPool} instance based on the
|
||||
* {@link #setParallelism "parallelism"}, {@link #setThreadFactory "threadFactory"},
|
||||
* {@link #setUncaughtExceptionHandler "uncaughtExceptionHandler"} and
|
||||
* {@link #setAsyncMode "asyncMode"} properties on this FactoryBean.
|
||||
* <p><b>NOTE:</b> Setting this flag to "true" effectively ignores all other
|
||||
* Set whether to expose Java's 'common' {@link ForkJoinPool}.
|
||||
* <p>Default is {@code false} , creating a local {@link ForkJoinPool} instance
|
||||
* based on the {@link #setParallelism parallelism},
|
||||
* {@link #setThreadFactory threadFactory},
|
||||
* {@link #setUncaughtExceptionHandler uncaughtExceptionHandler}, and
|
||||
* {@link #setAsyncMode asyncMode} properties on this FactoryBean.
|
||||
* <p><b>NOTE:</b> Setting this flag to {@code true} effectively ignores all other
|
||||
* properties on this FactoryBean, reusing the shared common JDK {@link ForkJoinPool}
|
||||
* instead. This is a fine choice on JDK 8 but does remove the application's ability
|
||||
* instead. This is a fine choice but does remove the application's ability
|
||||
* to customize ForkJoinPool behavior, in particular the use of custom threads.
|
||||
* @since 3.2
|
||||
* @see java.util.concurrent.ForkJoinPool#commonPool()
|
||||
|
||||
+2
-2
@@ -239,8 +239,8 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
* @since 6.1.4
|
||||
* @see #initiateShutdown()
|
||||
*/
|
||||
public void setStrictEarlyShutdown(boolean defaultEarlyShutdown) {
|
||||
this.strictEarlyShutdown = defaultEarlyShutdown;
|
||||
public void setStrictEarlyShutdown(boolean strictEarlyShutdown) {
|
||||
this.strictEarlyShutdown = strictEarlyShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+25
@@ -30,6 +30,7 @@ import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@@ -435,12 +436,15 @@ class ApplicationContextEventTests extends AbstractApplicationEventListenerTests
|
||||
RootBeanDefinition listener1Def = new RootBeanDefinition(MyOrderedListener1.class);
|
||||
listener1Def.setDependsOn("nestedChild");
|
||||
context.registerBeanDefinition("listener1", listener1Def);
|
||||
context.registerBeanDefinition("listenerFb", new RootBeanDefinition(MyFactoryBeanListener.class));
|
||||
context.refresh();
|
||||
|
||||
MyOrderedListener1 listener1 = context.getBean("listener1", MyOrderedListener1.class);
|
||||
MyFactoryBeanListener listenerFb = context.getBean("&listenerFb", MyFactoryBeanListener.class);
|
||||
MyEvent event1 = new MyEvent(context);
|
||||
context.publishEvent(event1);
|
||||
assertThat(listener1.seenEvents).contains(event1);
|
||||
assertThat(listenerFb.seenEvents).contains(event1);
|
||||
|
||||
SimpleApplicationEventMulticaster multicaster = context.getBean(SimpleApplicationEventMulticaster.class);
|
||||
assertThat(multicaster.getApplicationListeners()).isNotEmpty();
|
||||
@@ -782,6 +786,27 @@ class ApplicationContextEventTests extends AbstractApplicationEventListenerTests
|
||||
}
|
||||
|
||||
|
||||
public static class MyFactoryBeanListener implements FactoryBean<String>, ApplicationListener<ApplicationEvent> {
|
||||
|
||||
public final List<ApplicationEvent> seenEvents = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
this.seenEvents.add(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObject() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class EventPublishingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
+20
-10
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -30,14 +31,18 @@ import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link ResourceBundleMessageSource} and {@link ReloadableResourceBundleMessageSource}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
* @author Sam Brannen
|
||||
* @since 03.02.2004
|
||||
*/
|
||||
class ResourceBundleMessageSourceTests {
|
||||
@@ -272,23 +277,28 @@ class ResourceBundleMessageSourceTests {
|
||||
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
|
||||
}
|
||||
|
||||
@Test // gh-36413
|
||||
void resourceBundleMessageSourceWithInvalidDefaultCharsetName() {
|
||||
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
|
||||
assertThatExceptionOfType(UnsupportedCharsetException.class).isThrownBy(() -> ms.setDefaultEncoding("BOGUS"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resourceBundleMessageSourceWithDefaultCharset() {
|
||||
void resourceBundleMessageSourceWithDefaultCharsetName() {
|
||||
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
|
||||
ms.setBasename("org/springframework/context/support/messages");
|
||||
ms.setDefaultEncoding("ISO-8859-1");
|
||||
ms.setDefaultEncoding(ISO_8859_1.name());
|
||||
assertThat(ms.getMessage("code1", null, Locale.ENGLISH)).isEqualTo("message1");
|
||||
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resourceBundleMessageSourceWithInappropriateDefaultCharset() {
|
||||
@Test // gh-36413
|
||||
void resourceBundleMessageSourceWithDefaultCharset() {
|
||||
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
|
||||
ms.setBasename("org/springframework/context/support/messages");
|
||||
ms.setDefaultEncoding("argh");
|
||||
ms.setFallbackToSystemLocale(false);
|
||||
assertThatExceptionOfType(NoSuchMessageException.class).isThrownBy(() ->
|
||||
ms.getMessage("code1", null, Locale.ENGLISH));
|
||||
ms.setDefaultCharset(ISO_8859_1);
|
||||
assertThat(ms.getMessage("code1", null, Locale.ENGLISH)).isEqualTo("message1");
|
||||
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -353,13 +363,13 @@ class ResourceBundleMessageSourceTests {
|
||||
void reloadableResourceBundleMessageSourceWithDefaultCharset() {
|
||||
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
|
||||
ms.setBasename("org/springframework/context/support/messages");
|
||||
ms.setDefaultEncoding("ISO-8859-1");
|
||||
ms.setDefaultCharset(ISO_8859_1);
|
||||
assertThat(ms.getMessage("code1", null, Locale.ENGLISH)).isEqualTo("message1");
|
||||
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void reloadableResourceBundleMessageSourceWithInappropriateDefaultCharset() {
|
||||
void reloadableResourceBundleMessageSourceWithInappropriateDefaultCharsetName() {
|
||||
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
|
||||
ms.setBasename("org/springframework/context/support/messages");
|
||||
ms.setDefaultEncoding("unicode");
|
||||
|
||||
@@ -12,8 +12,8 @@ dependencies {
|
||||
jar {
|
||||
manifest {
|
||||
attributes(
|
||||
'Premain-Class': 'org.springframework.aot.agent.RuntimeHintsAgent',
|
||||
'Can-Redefine-Classes': 'true'
|
||||
'Premain-Class': 'org.springframework.aot.agent.RuntimeHintsAgent',
|
||||
'Can-Redefine-Classes': 'true'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.aot.agent;
|
||||
|
||||
import org.springframework.aot.hint.JavaSerializationHint;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.ResourceBundleHint;
|
||||
@@ -51,7 +50,9 @@ public enum HintType {
|
||||
/**
|
||||
* Java serialization hint, as described by {@link org.springframework.aot.hint.JavaSerializationHint}.
|
||||
*/
|
||||
JAVA_SERIALIZATION(JavaSerializationHint.class),
|
||||
@Deprecated(since = "7.0.5", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
JAVA_SERIALIZATION(org.springframework.aot.hint.JavaSerializationHint.class),
|
||||
|
||||
/**
|
||||
* JDK proxies hint, as described by {@link org.springframework.aot.hint.ProxyHints#jdkProxyHints()}.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user