Compare commits

..

1 Commits

Author SHA1 Message Date
Brian Clozel 006c0bc418 Release v7.0.4 2026-02-12 10:06:55 +01:00
317 changed files with 2290 additions and 6250 deletions
+12 -12
View File
@@ -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.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/"
"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/"
] 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.3.0");
checkstyle.setToolVersion("13.2.0");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
+2 -2
View File
@@ -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 })
}
+4 -4
View File
@@ -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
)
}
+1 -2
View File
@@ -330,10 +330,9 @@
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/default-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.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,11 +81,6 @@ 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.
flag for `javac`. Recommended approach on Java 8+.
`AspectJAdviceParameterNameDiscoverer` :: Deduces parameter names from the pointcut
expression, `returning`, and `throwing` clauses. See the
{spring-framework-api}/aop/aspectj/AspectJAdviceParameterNameDiscoverer.html[javadoc]
@@ -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, 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).
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).
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.
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.
====
As an alternative for injection by name, consider the JSR-250 `@Resource` annotation
@@ -309,8 +309,7 @@ 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` or `@Fallback` on a single bean
for each type.
through `@Order` values in combination with `@Primary` on a single bean for each type.
====
Even typed `Map` instances can be autowired as long as the expected key type is `String`.
@@ -27,5 +27,4 @@ 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. For annotation-based configuration, see
xref:core/beans/annotation-config/autowired-primary.adoc[Fine-tuning with `@Primary` or `@Fallback`].
attribute set to `true`, it is selected.
@@ -556,11 +556,18 @@ Kotlin::
======
If you do not want to rely on the default bean-naming strategy, you can provide a custom
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`]
bean-naming strategy. First, implement the
{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`]
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 examples show.
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.
[tabs]
======
@@ -595,27 +602,6 @@ 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,13 +67,6 @@ 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
@@ -87,7 +80,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 early initialization
.`BeanPostProcessor` instances and AOP auto-proxying
[NOTE]
====
Classes that implement the `BeanPostProcessor` interface are special and are treated
@@ -97,23 +90,17 @@ 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. More generally, any bean that is instantiated
during this early phase is not eligible for full post-processing by all
`BeanPostProcessor` instances.
thus, do not have aspects woven into them.
For any such bean, you should see a WARN-level log message similar to the following.
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)`.
[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
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.
====
@@ -148,7 +135,7 @@ Java::
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " + bean);
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}
@@ -177,48 +164,7 @@ Kotlin::
----
======
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:
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -246,7 +192,7 @@ Alternatively, the `InstantiationTracingBeanPostProcessor` can be registered via
----
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 with any
even have a name, and, because it is a bean, it can be dependency-injected as you would any
other bean. (The preceding configuration also defines a bean that is backed by a Groovy
script.)
@@ -354,23 +300,6 @@ 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,10 +17,9 @@ 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
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:
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:
[tabs]
======
@@ -127,7 +126,7 @@ Kotlin::
----
======
However, this limits the visibility for advanced type prediction to the specified
However, this limits the visibility for advance 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,
@@ -474,15 +473,8 @@ Kotlin::
== Customizing Bean Naming
By default, configuration classes use a `@Bean` method's name as the name of the
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:
resulting bean. This functionality can be overridden, however, with the `name` attribute,
as the following example shows:
[tabs]
======
@@ -513,7 +505,6 @@ Kotlin::
----
======
NOTE: `@Bean("myThing")` is equivalent to `@Bean(name = "myThing")`.
[[beans-java-bean-aliasing]]
== Bean Aliasing
@@ -531,7 +531,6 @@ 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(Char::class.java)
.getValue(Character::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,7 +541,32 @@ 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.
include-code::./ListConcatenation[]
[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));
}
}
----
If we register `ListConcatenation` as the `OperatorOverloader` in a
`StandardEvaluationContext`, we can then evaluate expressions like `{1, 2, 3} + {4, 5}`
@@ -564,8 +589,8 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = StandardEvaluationContext()
context.operatorOverloader = ListConcatenation()
StandardEvaluationContext context = StandardEvaluationContext()
context.setOperatorOverloader(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,6 +183,9 @@ 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`
@@ -193,9 +196,6 @@ 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>
@@ -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 for Spring's own annotation. Please refer to the JTA documentation
a drop-in replacement to 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,16 +89,47 @@ annotation in a `@Configuration` class. See the
{spring-framework-api}/transaction/annotation/EnableTransactionManagement.html[javadoc]
for full details.
The following example shows the configuration needed to enable annotation-driven transaction management:
In XML configuration, the `<tx:annotation-driven/>` tag provides similar convenience:
include-code::./AppConfig[tag=snippet,indent=0]
[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">
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.
<!-- 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.
Reactive transactional methods use reactive return types in contrast to imperative
programming arrangements as the following listing shows:
@@ -203,10 +234,8 @@ 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 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.
transactional behavior. In the preceding example, 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,
@@ -35,7 +35,7 @@ xref:integration/cache/store-configuration.adoc#cache-store-configuration-jsr107
[[cache-store-configuration-caffeine]]
== Caffeine Cache
Caffeine is a rewrite of Guava's cache, and its implementation is located in the
Caffeine is a Java 8 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, so you can associate
TIP: `@JmsListener` is a repeatable annotation on Java 8, 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 lambda expressions
* Functional-style, fluent API that takes advantage of Java 8 lambdas
* Synchronous and asynchronous interactions
* Streaming up to or streaming down from a server
@@ -533,7 +533,8 @@ that returns a value:
----
TIP: `@Async` methods may not only declare a regular `java.util.concurrent.Future` return
type but also `java.util.concurrent.CompletableFuture`, for richer interaction with
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
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,15 +3,13 @@
:page-section-summary-toc: 1
The Spring Framework supports various Kotlin constructs, such as instantiating Kotlin classes
through primary constructors, data binding for immutable classes, and optional parameters
with default values for functions.
through primary constructors, immutable classes data binding, and function optional parameters
with default values.
Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,
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.
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.)
You can declare configuration classes as
{kotlin-docs}/nested-classes.html[top level or nested but not inner],
@@ -4,7 +4,8 @@
`@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 interface default methods.
are not required to be `public` and may be declared on Java 8-based interface default
methods.
[tabs]
======
@@ -4,7 +4,8 @@
`@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 interface default methods.
are not required to be `public` and may be declared on Java 8-based interface default
methods.
The following example shows how to use the `@BeforeTransaction` annotation:
@@ -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's support for repeatable annotations, where `@Sql` can be
in conjunction with Java 8'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 lambda expressions, streams, and
"Fluent assertions for Java", including support for Java 8 lambdas, 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] ::
@@ -49,6 +49,7 @@ 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:
@@ -86,6 +87,7 @@ 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]).
@@ -94,24 +96,22 @@ 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 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].
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.
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.
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.
* xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[Context Configuration with Component Classes]
* xref:testing/testcontext-framework/ctx-management/xml.adoc[Context Configuration with XML Resources]
* 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/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/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]
@@ -1,53 +0,0 @@
[[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.
@@ -1,32 +1,33 @@
[[testcontext-ctx-management-mixed-config]]
= Mixing Component Classes, XML, and Groovy Scripts
= Mixing XML, Groovy Scripts, and Component Classes
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
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
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, `@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
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
`GenericGroovyXmlWebContextLoader` support both XML configuration files and Groovy
scripts simultaneously. Furthermore, third-party frameworks may choose to support the
declaration of both `classes` and `locations` through `@ContextConfiguration`, and, with
declaration of both `locations` and `classes` through `@ContextConfiguration`, and, with
the standard testing support in the TestContext framework, you have the following options.
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
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
to how you configure your application in production: In production configuration, you
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.
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.
@@ -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 a
In WebFlux.fn, an HTTP request is handled with a `HandlerFunction`: a function that takes
`ServerRequest` and returns a delayed `ServerResponse` (i.e. `Mono<ServerResponse>`).
Both the request and the response object have immutable contracts that offer convenient
Both the request and the response object have immutable contracts that offer JDK 8-friendly
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 convenient
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
access to the HTTP request and response.
Both request and response provide {reactive-streams-site}[Reactive Streams] back pressure
against the body streams.
@@ -49,9 +49,10 @@ 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`.
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.
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.
@@ -251,8 +251,7 @@ Kotlin::
======
TIP: If you need to have a `LocalValidatorFactoryBean` injected somewhere, create a bean and
mark it with `@Primary`, or mark the one declared in the MVC config with `@Fallback`, in
order to avoid conflict.
mark it with `@Primary` in order to avoid conflict with the one declared in the MVC config.
[[webflux-config-content-negotiation]]
@@ -394,8 +394,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 and
xref:web/webflux/config.adoc#webflux-config-api-version[supported versions] above
- Baseline version ("1.2+") -- matches the given version and 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,
@@ -444,9 +443,6 @@ 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
@@ -463,6 +459,10 @@ 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 `Stream` API but not only for collections.
compose async logic -- similar to the Java 8 `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
* If you are interested in a lightweight, functional web framework for use with Java 8 lambdas
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 convenient
Both the request and the response object have immutable contracts that offer JDK 8-friendly
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 convenient
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
access to the HTTP request and response, including headers, body, method, and status code.
[[webmvc-fn-request]]
@@ -49,9 +49,10 @@ 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`.
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.
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.
@@ -19,5 +19,4 @@ 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`, or mark the one declared in the MVC configuration with
`@Fallback`, in order to avoid conflict.
mark it with `@Primary` in order to avoid conflict with the one declared in the MVC configuration.
@@ -6,7 +6,7 @@
The next table describes the supported controller method arguments. Reactive types are not supported
for any arguments.
`java.util.Optional` is supported as a method argument in combination with
JDK 8's `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 and xref:web/webmvc/mvc-config/api-version.adoc[supported versions] above
- Baseline version ("1.2+") -- matches the given version and 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 supported versions above
<3> match version 1.2 and above
<4> match version 1.5
======
@@ -474,9 +474,6 @@ 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
@@ -493,6 +490,10 @@ 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 URIs.
This section describes various options available in the Spring Framework to work with URI's.
include::partial$web/web-uris.adoc[leveloffset=+1]
@@ -2,7 +2,7 @@
= UriComponents
[.small]#Spring MVC and Spring WebFlux#
`UriComponentsBuilder` helps to build URIs from URI templates with variables, as the following example shows:
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
[tabs]
======
@@ -128,7 +128,7 @@ Kotlin::
= UriBuilder
[.small]#Spring MVC and Spring WebFlux#
<<uricomponents, `UriComponentsBuilder`>> implements `UriBuilder`. You can create a
<<web-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 URLs. For more details, see the URL Living Standard and URL parsing
leniently user typed URL's. 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 URLs in order to inspect and possibly validated URI components
to parse user provided URL's 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 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
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
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()
----
======
+1 -1
View File
@@ -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.8",
"fast-xml-parser": "5.3.4",
"@springio/asciidoctor-extensions": "1.0.0-alpha.17"
}
}
@@ -1,47 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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));
}
}
@@ -1,42 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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[]
@@ -1,20 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations;
public class DefaultFooService implements FooService {
}
@@ -1,20 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations;
public interface FooService {
}
@@ -21,6 +21,7 @@ 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
@@ -17,7 +17,9 @@
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;
@@ -17,7 +17,9 @@
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;
@@ -22,6 +22,7 @@ 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[]
@@ -19,8 +19,13 @@ 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
@@ -17,6 +17,7 @@
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;
@@ -1,37 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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]")
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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[]
@@ -1,20 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations
class DefaultFooService : FooService {
}
@@ -1,20 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.dataaccess.transaction.declarative.transactiondeclarativeannotations
interface FooService {
}
@@ -16,9 +16,12 @@
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.*
/**
@@ -1,30 +0,0 @@
<?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[] -->
+15 -15
View File
@@ -8,19 +8,19 @@ javaPlatform {
dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.20.2"))
api(platform("io.micrometer:micrometer-bom:1.16.4"))
api(platform("io.micrometer:micrometer-bom:1.16.3"))
api(platform("io.netty:netty-bom:4.2.10.Final"))
api(platform("io.projectreactor:reactor-bom:2025.0.4"))
api(platform("io.projectreactor:reactor-bom:2025.0.3"))
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.7"))
api(platform("org.eclipse.jetty.ee11:jetty-ee11-bom:12.1.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.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.3"))
api(platform("org.mockito:mockito-bom:5.22.0"))
api(platform("org.junit:junit-bom:6.0.2"))
api(platform("org.mockito:mockito-bom:5.21.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.34.0")
api("com.h2database:h2:2.4.240")
api("com.google.protobuf:protobuf-java-util:4.33.4")
api("com.h2database:h2:2.3.232")
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.1.0.RELEASE")
api("io.r2dbc:r2dbc-h2:1.0.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.2")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.4")
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-RC1")
api("org.eclipse.persistence:org.eclipse.persistence.jpa:5.0.0-B13")
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.6.Final")
api("org.hibernate.orm:hibernate-core:7.2.4.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.41.0")
api("org.seleniumhq.selenium:selenium-java:4.41.0")
api("org.seleniumhq.selenium:htmlunit3-driver:4.40.0")
api("org.seleniumhq.selenium:selenium-java:4.40.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.6")
api("org.yaml:snakeyaml:2.5")
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
version=7.0.6
version=7.0.4
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m
+1 -1
View File
@@ -61,4 +61,4 @@ void configureDeploymentRepository(Project project) {
}
}
}
}
}
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/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/.
@@ -283,7 +283,7 @@ public final class CachedIntrospectionResults {
}
// Explicitly check implemented interfaces for setter/getter methods as well,
// in particular for interface default methods.
// in particular for Java 8 default methods...
Class<?> currClass = beanClass;
while (currClass != null && currClass != Object.class) {
introspectInterfaces(beanClass, currClass, readMethodNames);
@@ -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
* {@link java.util.Optional}, {@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 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.
*
* <h3>Autowiring Arrays, Collections, and Maps</h3>
* <p>In case of an array, {@link java.util.Collection}, or {@link java.util.Map}
@@ -33,7 +33,6 @@ 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;
@@ -622,12 +621,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 a {@link MergedAnnotation} representing the Autowired annotation
* @param ann the Autowired annotation
* @return whether the annotation indicates that a dependency is required
*/
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
Optional<Boolean> requiredAttribute = ann.getValue(this.requiredParameterName, Boolean.class);
return (requiredAttribute.isEmpty() || this.requiredParameterValue == requiredAttribute.get());
return (ann.getValue(this.requiredParameterName).isEmpty() ||
this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
}
/**
@@ -348,20 +348,8 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
if (!super.isRequired(descriptor)) {
return false;
}
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;
Autowired autowired = descriptor.getAnnotation(Autowired.class);
return (autowired == null || autowired.required());
}
/**
@@ -40,13 +40,6 @@ 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
@@ -35,14 +35,6 @@ 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
@@ -149,10 +149,10 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
/**
* Return whether this dependency is required.
* <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.
* <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.
*/
public boolean isRequired() {
if (!this.required) {
@@ -23,7 +23,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
*
* @author Juergen Hoeller
* @since 2.0.3
* @see org.springframework.context.annotation.ConfigurationBeanNameGenerator
*/
public interface BeanNameGenerator {
@@ -1,179 +0,0 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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 {
}
}
@@ -109,9 +109,7 @@ public class AnnotatedBeanDefinitionReader {
/**
* Set the {@code BeanNameGenerator} to use for detected bean classes.
* <p>The default is an {@link AnnotationBeanNameGenerator}.
* @see FullyQualifiedAnnotationBeanNameGenerator
* @see FullyQualifiedConfigurationBeanNameGenerator
* <p>The default is a {@link AnnotationBeanNameGenerator}.
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator =
@@ -118,20 +118,14 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
/**
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* 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.
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
* <p>Default is {@link AnnotationBeanNameGenerator}.
* <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,47 +35,48 @@ import org.springframework.core.annotation.AliasFor;
* example:
*
* <pre class="code">
* &#064;Bean
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
* }</pre>
* &#064;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 default can be overridden by configuring a {@link ConfigurationBeanNameGenerator}
* &mdash; 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.
* 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.
*
* <pre class="code">
* &#064;Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
* }</pre>
* &#064;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, Fallback, Order</h3>
* <h3>Profile, Scope, Lazy, DependsOn, Primary, 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">
* &#064;Bean
* &#064;Profile("production")
* &#064;Scope("prototype")
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
* }</pre>
* &#064;Bean
* &#064;Profile("production")
* &#064;Scope("prototype")
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
* }
* </pre>
*
* The semantics of the aforementioned annotations match their use at the component
* The semantics of the above-mentioned 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.
@@ -84,9 +85,6 @@ 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
@@ -102,8 +100,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} or
* {@code @Fallback} on a single bean per type.
* be modeled through {@code @Order} values in combination with {@code @Primary} on
* a single bean per type.
*
* <h3>{@code @Bean} Methods in {@code @Configuration} Classes</h3>
*
@@ -121,17 +119,17 @@ import org.springframework.core.annotation.AliasFor;
* &#064;Configuration
* public class AppConfig {
*
* &#064;Bean
* public FooService fooService() {
* return new FooService(fooRepository());
* }
* &#064;Bean
* public FooService fooService() {
* return new FooService(fooRepository());
* }
*
* &#064;Bean
* public FooRepository fooRepository() {
* return new JdbcFooRepository(dataSource());
* }
* &#064;Bean
* public FooRepository fooRepository() {
* return new JdbcFooRepository(dataSource());
* }
*
* // ...
* // ...
* }</pre>
*
* <h3>{@code @Bean} <em>Lite</em> Mode</h3>
@@ -160,21 +158,20 @@ import org.springframework.core.annotation.AliasFor;
* <pre class="code">
* &#064;Component
* public class Calculator {
* public int sum(int a, int b) {
* return a+b;
* }
* public int sum(int a, int b) {
* return a+b;
* }
*
* &#064;Bean
* public MyBean myBean() {
* return new MyBean();
* }
* &#064;Bean
* public MyBean myBean() {
* return new MyBean();
* }
* }</pre>
*
* <h3>Bootstrapping</h3>
*
* <p>See the {@link Configuration @Configuration} javadoc for further details
* including how to bootstrap the container using
* {@link AnnotationConfigApplicationContext} and friends.
* <p>See the @{@link Configuration} javadoc for further details including how to bootstrap
* the container using {@link AnnotationConfigApplicationContext} and friends.
*
* <h3>{@code BeanFactoryPostProcessor}-returning {@code @Bean} methods</h3>
*
@@ -186,44 +183,20 @@ import org.springframework.core.annotation.AliasFor;
* lifecycle issues, mark {@code BFPP}-returning {@code @Bean} methods as {@code static}. For example:
*
* <pre class="code">
* &#064;Bean
* public static PropertySourcesPlaceholderConfigurer pspc() {
* // instantiate, configure and return pspc ...
* }</pre>
* &#064;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 aforementioned lifecycle conflicts.
* declaring {@code @Configuration} class, thus avoiding the above-mentioned 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">
* &#064;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
@@ -235,13 +208,9 @@ 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)
@@ -260,11 +229,10 @@ public @interface Bean {
/**
* The name of this bean, or if several names, a primary bean name plus aliases.
* <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>If left unspecified, the name of the bean is the name of the annotated method.
* If specified, the method name is ignored.
* <p>The bean name and aliases may also be configured via the {@link #value}
* attribute.
* attribute if no other attributes are declared.
* @see #value
*/
@AliasFor("value")
@@ -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 or meta-annotated with Spring's
* {@link org.springframework.stereotype.Component @Component} annotation, such as the
* default filters include classes that are annotated with Spring's
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotypes.
* {@link org.springframework.stereotype.Service @Service}, or
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
*
* <p>Also supports JSR-330's {@link jakarta.inject.Named} annotations, if available.
*
@@ -204,11 +204,8 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
}
/**
* Set the {@link BeanNameGenerator} to use for detected bean classes.
* <p>Default is an {@code AnnotationBeanNameGenerator}.
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
* @see FullyQualifiedConfigurationBeanNameGenerator
* Set the BeanNameGenerator to use for detected bean classes.
* <p>Default is a {@link AnnotationBeanNameGenerator}.
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator =
@@ -109,18 +109,14 @@ public @interface ComponentScan {
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>The default value of the {@code BeanNameGenerator} interface itself indicates
* <p>The default value of the {@link 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. 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.
* application context at bootstrap time.
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
* @see FullyQualifiedConfigurationBeanNameGenerator
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@@ -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's support for repeatable annotations,
* where {@link ComponentScan @ComponentScan} can simply be declared several times
* on the same method, implicitly generating this container annotation.
* 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.
*
* @author Juergen Hoeller
* @since 4.3
@@ -437,8 +437,6 @@ 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 "";
@@ -37,10 +37,9 @@ public interface ConfigurationBeanNameGenerator extends BeanNameGenerator {
/**
* Derive a default bean name for the given {@link Bean @Bean} method,
* taking into account the specified {@link Bean#name() name} attribute.
* providing the {@link Bean#name() name} attribute specified.
* @param beanMethod the method metadata for the {@link Bean @Bean} method
* @param beanName the {@link Bean#name() name} attribute or {@code null} if
* none is specified
* @param beanName the {@link Bean#name() name} attribute or {@code null} if non is specified
* @return the default bean name to use
*/
String deriveBeanName(MethodMetadata beanMethod, @Nullable String beanName);
@@ -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) : localBeanName);
cbng.deriveBeanName(metadata, beanName) : defaultBeanName(beanName, methodName));
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() with bean name '%s'"
.formatted(configClass.getMetadata().getClassName(), methodName, beanName));
logger.trace("Registering bean definition for @Bean method %s.%s()"
.formatted(configClass.getMetadata().getClassName(), 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;
}
@@ -387,13 +387,13 @@ class ConfigurationClassEnhancer {
// create the bean instance.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
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()));
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()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
@@ -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 interface...
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
@@ -242,15 +242,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
/**
* Set the {@link BeanNameGenerator} to be used when triggering component scanning
* 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})
* 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})
* and a variant thereof for imported configuration classes (using unique fully-qualified
* class names instead of standard component overriding).
* <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>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
* <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
@@ -258,9 +255,6 @@ 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");
@@ -26,10 +26,9 @@ 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'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.
* 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.
*
* @author Phillip Webb
* @since 4.0
@@ -16,7 +16,6 @@
package org.springframework.context.support;
import java.nio.charset.Charset;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
@@ -33,7 +32,6 @@ import org.springframework.util.ObjectUtils;
* configuration methods and corresponding semantic definitions.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.3
* @see ResourceBundleMessageSource
* @see ReloadableResourceBundleMessageSource
@@ -42,7 +40,7 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
private final Set<String> basenameSet = new LinkedHashSet<>(4);
private @Nullable Charset defaultCharset;
private @Nullable String defaultEncoding;
private boolean fallbackToSystemLocale = true;
@@ -55,7 +53,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
@@ -120,52 +118,25 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
/**
* Set the default charset to use for parsing properties files.
* <p>Used if no file-specific charset is specified for a file.
* 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.defaultCharset = (defaultEncoding != null ? Charset.forName(defaultEncoding) : null);
this.defaultEncoding = defaultEncoding;
}
/**
* Return the default charset to use for parsing properties files, if any.
* @since 4.3
* @see #getDefaultCharset()
*/
protected @Nullable String getDefaultEncoding() {
return (this.defaultCharset != null ? this.defaultCharset.name() : null);
return this.defaultEncoding;
}
/**
* 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
@@ -24,8 +24,6 @@ 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;
@@ -100,8 +98,7 @@ class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor,
try {
ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
multicaster.removeApplicationListener(applicationListener);
multicaster.removeApplicationListenerBean(
bean instanceof FactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
multicaster.removeApplicationListenerBean(beanName);
}
catch (IllegalStateException ex) {
// ApplicationEventMulticaster not initialized yet - no need to remove a listener
@@ -19,7 +19,6 @@ 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;
@@ -81,10 +80,9 @@ import org.springframework.util.StringUtils;
*
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @author Sam Brannen
* @see #setCacheSeconds
* @see #setBasenames
* @see #setDefaultCharset
* @see #setDefaultEncoding
* @see #setFileEncodings
* @see #setPropertiesPersister
* @see #setResourceLoader
@@ -95,12 +93,10 @@ 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_EXTENSION, XML_EXTENSION);
private List<String> fileExtensions = List.of(".properties", XML_EXTENSION);
private @Nullable Properties fileEncodings;
@@ -139,7 +135,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 object with filenames as keys and charset
* @param fileEncodings a Properties 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".
@@ -382,18 +378,18 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
StringBuilder temp = new StringBuilder(basename);
temp.append('_');
if (!language.isEmpty()) {
if (language.length() > 0) {
temp.append(language);
result.add(0, temp.toString());
}
temp.append('_');
if (!country.isEmpty()) {
if (country.length() > 0) {
temp.append(country);
result.add(0, temp.toString());
}
if (!variant.isEmpty() && (!language.isEmpty() || !country.isEmpty())) {
if (variant.length() > 0 && (language.length() > 0 || country.length() > 0)) {
temp.append('_').append(variant);
result.add(0, temp.toString());
}
@@ -562,36 +558,33 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
*/
protected Properties loadProperties(Resource resource, String filename) throws IOException {
Properties props = newProperties();
try (InputStream inputStream = resource.getInputStream()) {
try (InputStream is = 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, inputStream);
this.propertiesPersister.loadFromXml(props, is);
}
else {
Charset charset = null;
String encoding = null;
if (this.fileEncodings != null) {
String charsetName = this.fileEncodings.getProperty(filename);
if (charsetName != null) {
charset = Charset.forName(charsetName);
}
encoding = this.fileEncodings.getProperty(filename);
}
if (charset == null) {
charset = getDefaultCharset();
if (encoding == null) {
encoding = getDefaultEncoding();
}
if (charset != null) {
if (encoding != null) {
if (logger.isDebugEnabled()) {
logger.debug("Loading properties [" + resource.getFilename() + "] with encoding '" + charset + "'");
logger.debug("Loading properties [" + resource.getFilename() + "] with encoding '" + encoding + "'");
}
this.propertiesPersister.load(props, new InputStreamReader(inputStream, charset));
this.propertiesPersister.load(props, new InputStreamReader(is, encoding));
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Loading properties [" + resource.getFilename() + "]");
}
this.propertiesPersister.load(props, inputStream);
this.propertiesPersister.load(props, is);
}
}
return props;
@@ -22,8 +22,6 @@ 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;
@@ -59,11 +57,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 #setDefaultCharset Charset}: by default, ISO-8859-1; consider switching
* {@link #setDefaultEncoding encoding}: 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 an ISO-8859-1 fallback on
* retrieval with the platform default encoding: UTF-8 with a 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.
@@ -72,7 +70,6 @@ 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
@@ -86,7 +83,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
/**
* Cache to hold loaded ResourceBundles.
* <p>This Map is keyed with the bundle basename, which holds a Map that is
* 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.
@@ -96,7 +93,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
/**
* Cache to hold already generated MessageFormats.
* <p>This Map is keyed with the ResourceBundle, which holds a Map that is
* 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.
@@ -109,7 +106,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
public ResourceBundleMessageSource() {
setDefaultCharset(StandardCharsets.ISO_8859_1);
setDefaultEncoding("ISO-8859-1");
}
@@ -242,12 +239,12 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
catch (UnsupportedOperationException ex) {
// Probably in a Java Module System environment on JDK 9+
this.control = null;
Charset charset = getDefaultCharset();
if (charset != null && logger.isInfoEnabled()) {
String encoding = getDefaultEncoding();
if (encoding != null && logger.isInfoEnabled()) {
logger.info("ResourceBundleMessageSource is configured to read resources with encoding '" +
charset + "' but ResourceBundle.Control is not supported in current system environment: " +
encoding + "' 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 'defaultCharset' property to 'null' " +
"platform default encoding. Consider setting the 'defaultEncoding' property to 'null' " +
"for participating in the platform default and therefore avoiding this log message.");
}
}
@@ -259,7 +256,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 {@linkplain #setDefaultCharset "defaultCharset"},
* <p>This will be called in case of a {@link #setDefaultEncoding "defaultEncoding"},
* 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
@@ -279,9 +276,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 {@linkplain #setDefaultCharset "defaultCharset"}
* <p>This will only be called with {@link #setDefaultEncoding "defaultEncoding"}
* set to {@code null}, explicitly enforcing the platform default encoding
* (which is UTF-8 with an ISO-8859-1 fallback on JDK 9+ but configurable
* (which is UTF-8 with a 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
@@ -407,9 +404,9 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
inputStream = classLoader.getResourceAsStream(resourceName);
}
if (inputStream != null) {
Charset charset = getDefaultCharset();
if (charset != null) {
try (InputStreamReader bundleReader = new InputStreamReader(inputStream, charset)) {
String encoding = getDefaultEncoding();
if (encoding != null) {
try (InputStreamReader bundleReader = new InputStreamReader(inputStream, encoding)) {
return loadBundle(bundleReader);
}
}
@@ -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.
* JSR-310 <code>java.time</code> package in JDK 8.
*
* @author Juergen Hoeller
* @author Sam Brannen
@@ -1,5 +1,5 @@
/**
* Integration with the JSR-310 <code>java.time</code> package.
* Integration with the JSR-310 <code>java.time</code> package in JDK 8.
*/
@NullMarked
package org.springframework.format.datetime.standard;
@@ -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's support for repeatable annotations,
* where {@link Scheduled @Scheduled} can simply be declared several times on the
* same method, implicitly generating this container annotation.
* 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.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em>.
@@ -49,15 +49,14 @@ public class ForkJoinPoolFactoryBean implements FactoryBean<ForkJoinPool>, Initi
/**
* 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
* 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
* properties on this FactoryBean, reusing the shared common JDK {@link ForkJoinPool}
* instead. This is a fine choice but does remove the application's ability
* instead. This is a fine choice on JDK 8 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()
@@ -239,8 +239,8 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
* @since 6.1.4
* @see #initiateShutdown()
*/
public void setStrictEarlyShutdown(boolean strictEarlyShutdown) {
this.strictEarlyShutdown = strictEarlyShutdown;
public void setStrictEarlyShutdown(boolean defaultEarlyShutdown) {
this.strictEarlyShutdown = defaultEarlyShutdown;
}
/**
@@ -30,7 +30,6 @@ 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;
@@ -436,15 +435,12 @@ 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();
@@ -786,27 +782,6 @@ 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;
@@ -16,7 +16,6 @@
package org.springframework.context.support;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -31,18 +30,14 @@ 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 {
@@ -277,30 +272,25 @@ 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 resourceBundleMessageSourceWithDefaultCharsetName() {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setBasename("org/springframework/context/support/messages");
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 // gh-36413
void resourceBundleMessageSourceWithDefaultCharset() {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setBasename("org/springframework/context/support/messages");
ms.setDefaultCharset(ISO_8859_1);
ms.setDefaultEncoding("ISO-8859-1");
assertThat(ms.getMessage("code1", null, Locale.ENGLISH)).isEqualTo("message1");
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
}
@Test
void resourceBundleMessageSourceWithInappropriateDefaultCharset() {
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));
}
@Test
void reloadableResourceBundleMessageSourceStandalone() {
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
@@ -363,13 +353,13 @@ class ResourceBundleMessageSourceTests {
void reloadableResourceBundleMessageSourceWithDefaultCharset() {
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
ms.setBasename("org/springframework/context/support/messages");
ms.setDefaultCharset(ISO_8859_1);
ms.setDefaultEncoding("ISO-8859-1");
assertThat(ms.getMessage("code1", null, Locale.ENGLISH)).isEqualTo("message1");
assertThat(ms.getMessage("code2", null, Locale.GERMAN)).isEqualTo("nachricht2");
}
@Test
void reloadableResourceBundleMessageSourceWithInappropriateDefaultCharsetName() {
void reloadableResourceBundleMessageSourceWithInappropriateDefaultCharset() {
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
ms.setBasename("org/springframework/context/support/messages");
ms.setDefaultEncoding("unicode");
+2 -2
View File
@@ -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,6 +16,7 @@
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;
@@ -50,9 +51,7 @@ public enum HintType {
/**
* Java serialization hint, as described by {@link org.springframework.aot.hint.JavaSerializationHint}.
*/
@Deprecated(since = "7.0.5", forRemoval = true)
@SuppressWarnings("removal")
JAVA_SERIALIZATION(org.springframework.aot.hint.JavaSerializationHint.class),
JAVA_SERIALIZATION(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