Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds c37f685bb7 Release v6.1.2 2023-12-14 10:28:53 +00:00
1611 changed files with 11842 additions and 14610 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.9-librca
java=17.0.8.1-librca
+1 -1
View File
@@ -31,7 +31,7 @@ Information regarding CI builds can be found in the [Spring Framework Concourse
## Stay in Touch
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on 𝕏. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [releases feed](https://spring.io/blog/category/releases).
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on Twitter. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [releases feed](https://spring.io/blog/category/releases).
## License
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka' version '1.8.20'
id 'org.unbroken-dome.xjc' version '2.0.0' apply false
id 'com.github.ben-manes.versions' version '0.50.0'
id 'com.github.ben-manes.versions' version '0.49.0'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
id 'de.undercouch.download' version '5.4.0'
id 'me.champeau.jmh' version '0.7.2' apply false
+1 -1
View File
@@ -1,2 +1,2 @@
org.gradle.caching=true
javaFormatVersion=0.0.41
javaFormatVersion=0.0.39
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,12 +50,12 @@ public class CheckstyleConventions {
project.getPlugins().apply(CheckstylePlugin.class);
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g"));
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.setToolVersion("10.12.7");
checkstyle.setToolVersion("10.12.5");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
checkstyleDependencies.add(
project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
checkstyleDependencies
.add(project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
});
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:jammy-20231211.1
FROM ubuntu:jammy-20231128
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
+1 -1
View File
@@ -9,7 +9,7 @@ case "$1" in
echo "https://download.bell-sw.com/java/21.0.1+12/bellsoft-jdk21.0.1+12-linux-amd64.tar.gz"
;;
java22)
echo "https://download.java.net/java/early_access/jdk22/28/GPL/openjdk-22-ea+28_linux-x64_bin.tar.gz"
echo "https://download.java.net/java/early_access/jdk22/27/GPL/openjdk-22-ea+27_linux-x64_bin.tar.gz"
;;
*)
echo $"Unknown java version"
-2
View File
@@ -255,8 +255,6 @@ jobs:
plan:
- get: ci-image
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk22-build
params: { state: "pending", commit: "git-repo" }
- do:
+1 -1
View File
@@ -4,6 +4,6 @@ set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21,JDK22 \
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK21 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check antora
popd > /dev/null
+2 -2
View File
@@ -28,7 +28,7 @@ javadoc {
header = rootProject.description
use = true
overview = project.relativePath("$rootProject.rootDir/framework-docs/src/docs/api/overview.html")
destinationDir = file("$project.docsDir/javadoc-api")
destinationDir = file("${project.buildDir}/docs/javadoc-api")
splitIndex = true
links(rootProject.ext.javadocLinks)
addBooleanOption('Xdoclint:syntax,reference', true) // only check syntax and reference with doclint
@@ -52,7 +52,7 @@ rootProject.tasks.dokkaHtmlMultiModule.configure {
tasks.named("javadoc")
}
moduleName.set("spring-framework")
outputDirectory.set(file("$docsDir/kdoc-api"))
outputDirectory.set(project.file("$buildDir/docs/kdoc-api"))
includes.from("$rootProject.rootDir/framework-docs/src/docs/api/dokka-overview.md")
}
@@ -19,53 +19,15 @@ of the classpath -- for example, deployed within the application's JAR file.
The following table lists all currently supported Spring properties.
.Supported Spring Properties
[cols="1,1", stripes=odd]
|===
| Name | Description
| `spring.aot.enabled`
| Indicates the application should run with AOT generated artifacts. See
xref:core/aot.adoc[Ahead of Time Optimizations] and
{spring-framework-api}++/aot/AotDetector.html#AOT_ENABLED++[`AotDetector`]
for details.
| `spring.beaninfo.ignore`
| Instructs Spring to use the `Introspector.IGNORE_ALL_BEANINFO` mode when calling the
JavaBeans `Introspector`. See
{spring-framework-api}++/beans/StandardBeanInfoFactory.html#IGNORE_BEANINFO_PROPERTY_NAME++[`CachedIntrospectionResults`]
for details.
| `spring.cache.reactivestreams.ignore`
| Instructs Spring's caching infrastructure to ignore the presence of Reactive Streams,
in particular Reactor's `Mono`/`Flux` in `@Cacheable` method return type declarations. See
{spring-framework-api}++/cache/interceptor/CacheAspectSupport.html#IGNORE_REACTIVESTREAMS_PROPERTY_NAME++[`CacheAspectSupport`]
for details.
| `spring.classformat.ignore`
| Instructs Spring to ignore class format exceptions during classpath scanning, in
particular for unsupported class file versions. See
{spring-framework-api}++/context/annotation/ClassPathScanningCandidateComponentProvider.html#IGNORE_CLASSFORMAT_PROPERTY_NAME++[`ClassPathScanningCandidateComponentProvider`]
for details.
| `spring.context.checkpoint`
| Property that specifies a common context checkpoint. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic
checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#CHECKPOINT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.exit`
| Property for terminating the JVM when the context reaches a specific phase. See
xref:integration/checkpoint-restore.adoc#_automatic_checkpointrestore_at_startup[Automatic
checkpoint/restore at startup] and
{spring-framework-api}++/context/support/DefaultLifecycleProcessor.html#EXIT_PROPERTY_NAME++[`DefaultLifecycleProcessor`]
for details.
| `spring.context.expression.maxLength`
| The maximum length for
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expressions used in XML bean definitions, `@Value`, etc.
| `spring.expression.compiler.mode`
| The mode to use when compiling expressions for the
xref:core/expressions/evaluation.adoc#expressions-compiler-configuration[Spring Expression Language].
@@ -291,8 +291,6 @@ to consider:
* `final` classes cannot be proxied, because they cannot be extended.
* `final` methods cannot be advised, because they cannot be overridden.
* `private` methods cannot be advised, because they cannot be overridden.
* Methods that are not visible, typically package private methods in a parent class
from a different package, cannot be advised because they are effectively private.
NOTE: There is no need to add CGLIB to your classpath. CGLIB is repackaged and included
in the `spring-core` JAR. In other words, CGLIB-based AOP works "out of the box", as do
@@ -168,7 +168,7 @@ Kotlin::
======
NOTE: Pooling stateless service objects is not usually necessary. We do not believe it should
be the default choice, as most stateless objects are naturally thread-safe, and instance
be the default choice, as most stateless objects are naturally thread safe, and instance
pooling is problematic if resources are cached.
Simpler pooling is available by using auto-proxying. You can set the `TargetSource` implementations
@@ -533,11 +533,6 @@ standard AspectJ. The following example shows the `aop.xml` file:
</aspectj>
----
NOTE: It is recommended to only weave specific classes (typically those in the
application packages, as shown in the `aop.xml` example above) in order
to avoid side effects such as AspectJ dump files and warnings.
This is also a best practice from an efficiency perspective.
Now we can move on to the Spring-specific portion of the configuration. We need
to configure a `LoadTimeWeaver` (explained later). This load-time weaver is the
essential component responsible for weaving the aspect configuration in one or
@@ -719,29 +714,10 @@ Furthermore, the compiled aspect classes need to be available on the classpath.
[[aop-aj-ltw-aop_dot_xml]]
=== `META-INF/aop.xml`
=== 'META-INF/aop.xml'
The AspectJ LTW infrastructure is configured by using one or more `META-INF/aop.xml`
files that are on the Java classpath (either directly or, more typically, in jar files).
For example:
[source,xml,indent=0,subs="verbatim"]
----
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="com.xyz.*"/>
</weaver>
</aspectj>
----
NOTE: It is recommended to only weave specific classes (typically those in the
application packages, as shown in the `aop.xml` example above) in order
to avoid side effects such as AspectJ dump files and warnings.
This is also a best practice from an efficiency perspective.
The structure and contents of this file is detailed in the LTW part of the
{aspectj-docs-devguide}/ltw-configuration.html[AspectJ reference
@@ -155,8 +155,6 @@ If there is no other resolution indicator (such as a qualifier or a primary mark
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.
Since version 6.1, this requires the `-parameters` Java compiler flag to be present.
====
That said, if you intend to express annotation-driven injection by name, do not
@@ -592,40 +592,6 @@ Kotlin::
[[beans-factory-thread-safety]]
=== Thread Safety and Visibility
The Spring core container publishes created singleton instances in a thread-safe manner,
guarding access through a singleton lock and guaranteeing visibility in other threads.
As a consequence, application-provided bean classes do not have to be concerned about the
visibility of their initialization state. Regular configuration fields do not have to be
marked as `volatile` as long as they are only mutated during the initialization phase,
providing visibility guarantees similar to `final` even for setter-based configuration
state that is mutable during that initial phase. If such fields get changed after the
bean creation phase and its subsequent initial publication, they need to be declared as
`volatile` or guarded by a common lock whenever accessed.
Note that concurrent access to such configuration state in singleton bean instances,
e.g. for controller instances or repository instances, is perfectly thread-safe after
such safe initial publication from the container side. This includes common singleton
`FactoryBean` instances which are processed within the general singleton lock as well.
For destruction callbacks, the configuration state remains thread-safe but any runtime
state accumulated between initialization and destruction should be kept in thread-safe
structures (or in `volatile` fields for simple cases) as per common Java guidelines.
Deeper `Lifecycle` integration as shown above involves runtime-mutable state such as
a `runnable` field which will have to be declared as `volatile`. While the common
lifecycle callbacks follow a certain order, e.g. a start callback is guaranteed to
only happen after full initialization and a stop callback only after an initial start,
there is a special case with the common stop before destroy arrangement: It is strongly
recommended that the internal state in any such bean also allows for an immediate
destroy callback without a preceding stop since this may happen during an extraordinary
shutdown after a cancelled bootstrap or in case of a stop timeout caused by another bean.
[[beans-factory-aware]]
== `ApplicationContextAware` and `BeanNameAware`
@@ -324,6 +324,7 @@ Kotlin::
[[beans-factory-scopes-application]]
=== Application Scope
@@ -373,6 +374,7 @@ Kotlin::
[[beans-factory-scopes-websocket]]
=== WebSocket Scope
@@ -382,6 +384,7 @@ xref:web/websocket/stomp/scope.adoc[WebSocket scope] for more details.
[[beans-factory-scopes-other-injection]]
=== Scoped Beans as Dependencies
@@ -541,19 +544,6 @@ see xref:core/aop/proxying.adoc[Proxying Mechanisms].
[[beans-factory-scopes-injection]]
=== Injecting Request/Session References Directly
As an alternative to factory scopes, a Spring `WebApplicationContext` also supports
the injection of `HttpServletRequest`, `HttpServletResponse`, `HttpSession`,
`WebRequest` and (if JSF is present) `FacesContext` and `ExternalContext` into
Spring-managed beans, simply through type-based autowiring next to regular injection
points for other beans. Spring generally injects proxies for such request and session
objects which has the advantage of working in singleton beans and serializable beans
as well, similar to scoped proxies for factory-scoped beans.
[[beans-factory-scopes-custom]]
== Custom Scopes
@@ -1,12 +1,12 @@
[[expressions-evaluation]]
= Evaluation
This section introduces programmatic use of SpEL's interfaces and its expression language.
The complete language reference can be found in the
This section introduces the simple use of SpEL interfaces and its expression language.
The complete language reference can be found in
xref:core/expressions/language-ref.adoc[Language Reference].
The following code demonstrates how to use the SpEL API to evaluate the literal string
expression, `Hello World`.
The following code introduces the SpEL API to evaluate the literal string expression,
`Hello World`.
[tabs]
======
@@ -18,7 +18,7 @@ Java::
Expression exp = parser.parseExpression("'Hello World'"); // <1>
String message = (String) exp.getValue();
----
<1> The value of the message variable is `"Hello World"`.
<1> The value of the message variable is `'Hello World'`.
Kotlin::
+
@@ -28,24 +28,24 @@ Kotlin::
val exp = parser.parseExpression("'Hello World'") // <1>
val message = exp.value as String
----
<1> The value of the message variable is `"Hello World"`.
<1> The value of the message variable is `'Hello World'`.
======
The SpEL classes and interfaces you are most likely to use are located in the
`org.springframework.expression` package and its sub-packages, such as `spel.support`.
The `ExpressionParser` interface is responsible for parsing an expression string. In the
preceding example, the expression string is a string literal denoted by the surrounding
single quotation marks. The `Expression` interface is responsible for evaluating the
defined expression string. The two types of exceptions that can be thrown when calling
`parser.parseExpression(...)` and `exp.getValue(...)` are `ParseException` and
`EvaluationException`, respectively.
The `ExpressionParser` interface is responsible for parsing an expression string. In
the preceding example, the expression string is a string literal denoted by the surrounding single
quotation marks. The `Expression` interface is responsible for evaluating the previously defined
expression string. Two exceptions that can be thrown, `ParseException` and
`EvaluationException`, when calling `parser.parseExpression` and `exp.getValue`,
respectively.
SpEL supports a wide range of features such as calling methods, accessing properties,
SpEL supports a wide range of features, such as calling methods, accessing properties,
and calling constructors.
In the following method invocation example, we call the `concat` method on the string
literal, `Hello World`.
In the following example of method invocation, we call the `concat` method on the string literal:
[tabs]
======
@@ -57,7 +57,7 @@ Java::
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
String message = (String) exp.getValue();
----
<1> The value of `message` is now `"Hello World!"`.
<1> The value of `message` is now 'Hello World!'.
Kotlin::
+
@@ -67,11 +67,10 @@ Kotlin::
val exp = parser.parseExpression("'Hello World'.concat('!')") // <1>
val message = exp.value as String
----
<1> The value of `message` is now `"Hello World!"`.
<1> The value of `message` is now 'Hello World!'.
======
The following example demonstrates how to access the `Bytes` JavaBean property of the
string literal, `Hello World`.
The following example of calling a JavaBean property calls the `String` property `Bytes`:
[tabs]
======
@@ -101,10 +100,10 @@ Kotlin::
======
SpEL also supports nested properties by using the standard dot notation (such as
`prop1.prop2.prop3`) as well as the corresponding setting of property values.
`prop1.prop2.prop3`) and also the corresponding setting of property values.
Public fields may also be accessed.
The following example shows how to use dot notation to get the length of a string literal.
The following example shows how to use dot notation to get the length of a literal:
[tabs]
======
@@ -134,7 +133,7 @@ Kotlin::
======
The String's constructor can be called instead of using a string literal, as the following
example shows.
example shows:
[tabs]
======
@@ -146,7 +145,7 @@ Java::
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
String message = exp.getValue(String.class);
----
<1> Construct a new `String` from the literal and convert it to upper case.
<1> Construct a new `String` from the literal and make it be upper case.
Kotlin::
+
@@ -156,9 +155,10 @@ Kotlin::
val exp = parser.parseExpression("new String('hello world').toUpperCase()") // <1>
val message = exp.getValue(String::class.java)
----
<1> Construct a new `String` from the literal and convert it to upper case.
<1> Construct a new `String` from the literal and make it be upper case.
======
Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`.
Using this method removes the need to cast the value of the expression to the desired
result type. An `EvaluationException` is thrown if the value cannot be cast to the
@@ -166,8 +166,8 @@ type `T` or converted by using the registered type converter.
The more common usage of SpEL is to provide an expression string that is evaluated
against a specific object instance (called the root object). The following example shows
how to retrieve the `name` property from an instance of the `Inventor` class and how to
reference the `name` property in a boolean expression.
how to retrieve the `name` property from an instance of the `Inventor` class or
create a boolean condition:
[tabs]
======
@@ -240,7 +240,7 @@ It excludes Java type references, constructors, and bean references. It also req
you to explicitly choose the level of support for properties and methods in expressions.
By default, the `create()` static factory method enables only read access to properties.
You can also obtain a builder to configure the exact level of support needed, targeting
one or some combination of the following.
one or some combination of the following:
* Custom `PropertyAccessor` only (no reflection)
* Data binding properties for read-only access
@@ -252,15 +252,16 @@ one or some combination of the following.
By default, SpEL uses the conversion service available in Spring core
(`org.springframework.core.convert.ConversionService`). This conversion service comes
with many built-in converters for common conversions, but is also fully extensible so
that you can add custom conversions between types. Additionally, it is generics-aware.
This means that, when you work with generic types in expressions, SpEL attempts
conversions to maintain type correctness for any objects it encounters.
with many built-in converters for common conversions but is also fully extensible so that
you can add custom conversions between types. Additionally, it is
generics-aware. This means that, when you work with generic types in
expressions, SpEL attempts conversions to maintain type correctness for any objects
it encounters.
What does this mean in practice? Suppose assignment, using `setValue()`, is being used
to set a `List` property. The type of the property is actually `List<Boolean>`. SpEL
recognizes that the elements of the list need to be converted to `Boolean` before
being placed in it. The following example shows how to do so.
being placed in it. The following example shows how to do so:
[tabs]
======
@@ -324,7 +325,7 @@ constructor before setting the specified value. If the element type does not hav
default constructor, `null` will be added to the array or list. If there is no built-in
or custom converter that knows how to set the value, `null` will remain in the array or
list at the specified index. The following example demonstrates how to automatically grow
the list.
the list:
[tabs]
======
@@ -379,25 +380,16 @@ Kotlin::
----
======
By default, a SpEL expression cannot contain more than 10,000 characters; however, the
`maxExpressionLength` is configurable. If you create a `SpelExpressionParser`
programmatically, you can specify a custom `maxExpressionLength` when creating the
`SpelParserConfiguration` that you provide to the `SpelExpressionParser`. If you wish to
set the `maxExpressionLength` used for parsing SpEL expressions within an
`ApplicationContext` -- for example, in XML bean definitions, `@Value`, etc. -- you can
set a JVM system property or Spring property named `spring.context.expression.maxLength`
to the maximum expression length needed by your application (see
xref:appendix.adoc#appendix-spring-properties[Supported Spring Properties]).
[[expressions-spel-compilation]]
== SpEL Compilation
Spring provides a basic compiler for SpEL expressions. Expressions are usually
interpreted, which provides a lot of dynamic flexibility during evaluation but does not
provide optimum performance. For occasional expression usage, this is fine, but, when
used by other components such as Spring Integration, performance can be very important,
and there is no real need for the dynamism.
Spring Framework 4.1 includes a basic expression compiler. Expressions are usually
interpreted, which provides a lot of dynamic flexibility during evaluation but
does not provide optimum performance. For occasional expression usage,
this is fine, but, when used by other components such as Spring Integration,
performance can be very important, and there is no real need for the dynamism.
The SpEL compiler is intended to address this need. During evaluation, the compiler
generates a Java class that embodies the expression behavior at runtime and uses that
@@ -410,17 +402,16 @@ information can cause trouble later if the types of the various expression eleme
change over time. For this reason, compilation is best suited to expressions whose
type information is not going to change on repeated evaluations.
Consider the following basic expression.
Consider the following basic expression:
[source,java,indent=0,subs="verbatim,quotes"]
----
someArray[0].someProperty.someOtherProperty < 0.1
someArray[0].someProperty.someOtherProperty < 0.1
----
Because the preceding expression involves array access, some property de-referencing, and
numeric operations, the performance gain can be very noticeable. In an example micro
benchmark run of 50,000 iterations, it took 75ms to evaluate by using the interpreter and
only 3ms using the compiled version of the expression.
Because the preceding expression involves array access, some property de-referencing,
and numeric operations, the performance gain can be very noticeable. In an example
micro benchmark run of 50000 iterations, it took 75ms to evaluate by using the
interpreter and only 3ms using the compiled version of the expression.
[[expressions-compiler-configuration]]
@@ -428,34 +419,33 @@ only 3ms using the compiled version of the expression.
The compiler is not turned on by default, but you can turn it on in either of two
different ways. You can turn it on by using the parser configuration process
(xref:core/expressions/evaluation.adoc#expressions-parser-configuration[discussed
earlier]) or by using a Spring property when SpEL usage is embedded inside another
component. This section discusses both of these options.
(xref:core/expressions/evaluation.adoc#expressions-parser-configuration[discussed earlier]) or by using a Spring property
when SpEL usage is embedded inside another component. This section discusses both of
these options.
The compiler can operate in one of three modes, which are captured in the
`org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows.
`org.springframework.expression.spel.SpelCompilerMode` enum. The modes are as follows:
* `OFF` (default): The compiler is switched off.
* `IMMEDIATE`: In immediate mode, the expressions are compiled as soon as possible. This
is typically after the first interpreted evaluation. If the compiled expression fails
(typically due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception.
* `MIXED`: In mixed mode, the expressions silently switch between interpreted and
compiled mode over time. After some number of interpreted runs, they switch to compiled
form and, if something goes wrong with the compiled form (such as a type changing, as
described earlier), the expression automatically switches back to interpreted form
again. Sometime later, it may generate another compiled form and switch to it.
Basically, the exception that the user gets in `IMMEDIATE` mode is instead handled
internally.
is typically after the first interpreted evaluation. If the compiled expression fails
(typically due to a type changing, as described earlier), the caller of the expression
evaluation receives an exception.
* `MIXED`: In mixed mode, the expressions silently switch between interpreted and compiled
mode over time. After some number of interpreted runs, they switch to compiled
form and, if something goes wrong with the compiled form (such as a type changing, as
described earlier), the expression automatically switches back to interpreted form
again. Sometime later, it may generate another compiled form and switch to it. Basically,
the exception that the user gets in `IMMEDIATE` mode is instead handled internally.
`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that
have side effects. If a compiled expression blows up after partially succeeding, it
may have already done something that has affected the state of the system. If this
has happened, the caller may not want it to silently re-run in interpreted mode,
since part of the expression may be run twice.
since part of the expression may be running twice.
After selecting a mode, use the `SpelParserConfiguration` to configure the parser. The
following example shows how to do so.
following example shows how to do so:
[tabs]
======
@@ -492,16 +482,15 @@ Kotlin::
----
======
When you specify the compiler mode, you can also specify a `ClassLoader` (passing `null`
is allowed). Compiled expressions are defined in a child `ClassLoader` created under any
that is supplied. It is important to ensure that, if a `ClassLoader` is specified, it can
see all the types involved in the expression evaluation process. If you do not specify a
`ClassLoader`, a default `ClassLoader` is used (typically the context `ClassLoader` for
the thread that is running during expression evaluation).
When you specify the compiler mode, you can also specify a classloader (passing null is allowed).
Compiled expressions are defined in a child classloader created under any that is supplied.
It is important to ensure that, if a classloader is specified, it can see all the types involved in
the expression evaluation process. If you do not specify a classloader, a default classloader is used
(typically the context classloader for the thread that is running during expression evaluation).
The second way to configure the compiler is for use when SpEL is embedded inside some
other component and it may not be possible to configure it through a configuration
object. In such cases, it is possible to set the `spring.expression.compiler.mode`
object. In these cases, it is possible to set the `spring.expression.compiler.mode`
property via a JVM system property (or via the
xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism) to one of the
`SpelCompilerMode` enum values (`off`, `immediate`, or `mixed`).
@@ -510,14 +499,18 @@ xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism) to
[[expressions-compiler-limitations]]
=== Compiler Limitations
Spring does not support compiling every kind of expression. The primary focus is on
common expressions that are likely to be used in performance-critical contexts. The
following kinds of expressions cannot be compiled.
Since Spring Framework 4.1, the basic compilation framework is in place. However, the framework
does not yet support compiling every kind of expression. The initial focus has been on the
common expressions that are likely to be used in performance-critical contexts. The following
kinds of expression cannot be compiled at the moment:
* Expressions involving assignment
* Expressions relying on the conversion service
* Expressions using custom resolvers or accessors
* Expressions using selection or projection
Compilation of additional kinds of expressions may be supported in the future.
More types of expressions will be compilable in the future.
@@ -4,7 +4,7 @@
Projection lets a collection drive the evaluation of a sub-expression, and the result is
a new collection. The syntax for projection is `.![projectionExpression]`. For example,
suppose we have a list of inventors but want the list of cities where they were born.
Effectively, we want to evaluate `placeOfBirth.city` for every entry in the inventor
Effectively, we want to evaluate 'placeOfBirth.city' for every entry in the inventor
list. The following example uses projection to do so:
[tabs]
@@ -440,8 +440,12 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val tuples: MutableList<Array<Any>> = ArrayList()
tuples.add(arrayOf("John", 35))
tuples.add(arrayOf("Ann", 50))
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
.bind("ages", arrayOf(35, 50))
.bind("tuples", arrayOf(35, 50))
----
======
@@ -38,11 +38,6 @@ within the method.
A reactive transaction managed by `ReactiveTransactionManager` uses the Reactor context
instead of thread-local attributes. As a consequence, all participating data access
operations need to execute within the same Reactor context in the same reactive pipeline.
When configured with a `ReactiveTransactionManager`, all transaction-demarcated methods
are expected to return a reactive pipeline. Void methods or regular return types need
to be associated with a regular `PlatformTransactionManager`, e.g. through the
`transactionManager` attribute of the corresponding `@Transactional` declarations.
====
The following image shows a conceptual view of calling a method on a transactional proxy:
+1 -1
View File
@@ -29,7 +29,7 @@ Brannen, Ramnivas Laddad, Arjen Poutsma, Chris Beams, Tareq Abedrabbo, Andy Clem
Syer, Oliver Gierke, Rossen Stoyanchev, Phillip Webb, Rob Winch, Brian Clozel, Stephane
Nicoll, Sebastien Deleuze, Jay Bryant, Mark Paluch
Copyright © 2002 - 2024 VMware, Inc. All Rights Reserved.
Copyright © 2002 - 2023 VMware, Inc. All Rights Reserved.
Copies of this document may be made for your own use and for distribution to others,
provided that you do not charge any fee for such copies and further provided that each
@@ -85,7 +85,7 @@ email when someone places an order:
// Call the collaborators to persist the order...
// Create a thread-safe "copy" of the template message and customize it
// Create a thread safe "copy" of the template message and customize it
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
msg.setTo(order.getCustomer().getEmailAddress());
msg.setText(
@@ -108,7 +108,7 @@ By default, the following `KeyValues` are created:
|===
|Name | Description
|`code.function` _(required)_|Name of Java `Method` that is scheduled for execution.
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method, or `"ANONYMOUS"` for anonymous classes.
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method.
|`error` _(required)_|Class name of the exception thrown during the execution, or `"none"` if no exception happened.
|`exception` _(deprecated)_|Duplicates the `error` key and might be removed in the future.
|`outcome` _(required)_|Outcome of the method execution. Can be `"SUCCESS"`, `"ERROR"` or `"UNKNOWN"` (if for example the operation was cancelled during execution).
@@ -906,8 +906,8 @@ For `WebClient`:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.forClient(webClient)
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
@@ -1078,34 +1078,11 @@ underlying HTTP client, which operates at a lower level and provides more contro
[[rest-http-interface-exceptions]]
=== Error Handling
=== Exception Handling
To customize error response handling, you need to configure the underlying HTTP client.
For `RestClient`:
By default, `RestClient` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestClient restClient = RestClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
.build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `RestClient.Builder`.
For `WebClient`:
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status
codes. To customize this, you can register a response status handler that applies to all
responses performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -1113,28 +1090,10 @@ performed through the client:
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(clientAdapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `WebClient.Builder`.
For `RestTemplate`:
By default, `RestTemplate` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register an error handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and
the `ResponseErrorHandler` hierarchy.
@@ -252,9 +252,7 @@ application server environments, as well -- in particular on Tomcat and Jetty.
As of 6.1, `ThreadPoolTaskScheduler` provides a pause/resume capability and graceful
shutdown through Spring's lifecycle management. There is also a new option called
`SimpleAsyncTaskScheduler` which is aligned with JDK 21's Virtual Threads, using a
single scheduler thread but firing up a new thread for every scheduled task execution
(except for fixed-delay tasks which all operate on a single scheduler thread, so for
this virtual-thread-aligned option, fixed rates and cron triggers are recommended).
single scheduler thread but firing up a new thread for every scheduled task execution.
@@ -479,12 +477,12 @@ the framework to invoke a suspending function as a `Publisher`.
The Spring Framework will obtain a `Publisher` for the annotated method once and will
schedule a `Runnable` in which it subscribes to said `Publisher`. These inner regular
subscriptions occur according to the corresponding `cron`/`fixedDelay`/`fixedRate` configuration.
subscriptions occur according to the corresponding `cron`/fixedDelay`/`fixedRate` configuration.
If the `Publisher` emits `onNext` signal(s), these are ignored and discarded (the same way
return values from synchronous `@Scheduled` methods are ignored).
In the following example, the `Flux` emits `onNext("Hello")`, `onNext("World")` every 5
In the following example, the `Flux` emits `onNext("Hello"), onNext("World")` every 5
seconds, but these values are unused:
[source,java,indent=0,subs="verbatim,quotes"]
@@ -13,7 +13,7 @@ Most of the code samples of the reference documentation are
provided in Kotlin in addition to Java.
The easiest way to build a Spring application with Kotlin is to leverage Spring Boot and
its {spring-boot-docs}/boot-features-kotlin.html[dedicated Kotlin support].
its{spring-boot-docs}/boot-features-kotlin.html[dedicated Kotlin support].
{spring-site-guides}/tutorials/spring-boot-kotlin/[This comprehensive tutorial]
will teach you how to build Spring Boot applications with Kotlin using https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
@@ -107,7 +107,7 @@ NOTE: Spring Boot is based on JavaConfig and
{spring-boot-issues}/8115[does not yet provide specific support for functional bean definition],
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
See {stackoverflow-questions}/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}-experimental/spring-fu[Spring Fu incubator].
for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}/spring-fu[Spring Fu incubator].
@@ -14,10 +14,8 @@ Spring Framework provides support for Coroutines on the following scope:
* Suspending function support in Spring MVC and WebFlux annotated `@Controller`
* Extensions for WebFlux {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.client/index.html[client] and {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/index.html[server] functional API.
* WebFlux.fn {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }] DSL
* WebFlux {spring-framework-api-kdoc}/spring-web/org.springframework.web.server/-co-web-filter/index.html[`CoWebFilter`]
* Suspending function and `Flow` support in RSocket `@MessageMapping` annotated methods
* Extensions for {spring-framework-api-kdoc}/spring-messaging/org.springframework.messaging.rsocket/index.html[`RSocketRequester`]
* Spring AOP
@@ -10,21 +10,22 @@ The easiest way to learn how to build a Spring application with Kotlin is to fol
== `start.spring.io`
The easiest way to start a new Spring Framework project in Kotlin is to create a new Spring
Boot project on https://start.spring.io/#!language=kotlin&type=gradle-project-kotlin[start.spring.io].
Boot 2 project on https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
[[choosing-the-web-flavor]]
== Choosing the Web Flavor
Spring Framework comes with two different web stacks: xref:web/webmvc.adoc#mvc[Spring MVC] and
Spring Framework now comes with two different web stacks: xref:web/webmvc.adoc#mvc[Spring MVC] and
xref:testing/unit.adoc#mock-objects-web-reactive[Spring WebFlux].
Spring WebFlux is recommended if you want to create applications that will deal with latency,
long-lived connections or streaming scenarios.
long-lived connections, streaming scenarios or if you want to use the web functional
Kotlin DSL.
For other use cases, especially if you are using blocking technologies such as JPA, Spring
MVC is the recommended choice.
MVC and its annotation-based programming model is the recommended choice.
@@ -2,12 +2,15 @@
= Requirements
:page-section-summary-toc: 1
Spring Framework supports Kotlin 1.7+ and requires
Spring Framework supports Kotlin 1.3+ and requires
https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`]
(or one of its variants, such as https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`])
and https://search.maven.org/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`]
to be present on the classpath. They are provided by default if you bootstrap a Kotlin project on
https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
WARNING: Kotlin {kotlin-docs}/inline-classes.html[inline classes] are not yet supported.
NOTE: The {jackson-github-org}/jackson-module-kotlin[Jackson Kotlin module] is required
for serializing or deserializing JSON data for Kotlin classes with Jackson, so make sure to add the
`com.fasterxml.jackson.module:jackson-module-kotlin` dependency to your project if you have such need.
@@ -18,9 +18,28 @@ Kotlin and the Spring Framework:
The following Github projects offer examples that you can learn from and possibly even extend:
* https://github.com/spring-guides/tut-spring-boot-kotlin[tut-spring-boot-kotlin]: Sources of {spring-site}/guides/tutorials/spring-boot-kotlin/[the official Spring + Kotlin tutorial]
* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: Regular Spring Boot and Spring Data JPA project
* https://github.com/mixitconf/mixit[mixit]: Spring Boot, WebFlux, and Reactive Spring Data MongoDB
* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2, WebFlux, and Reactive Spring Data MongoDB
* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: Standalone WebFlux and functional bean definition DSL
* https://github.com/sdeleuze/spring-kotlin-fullstack[spring-kotlin-fullstack]: WebFlux Kotlin fullstack example with Kotlin2js for frontend instead of JavaScript or TypeScript
* https://github.com/spring-petclinic/spring-petclinic-kotlin[spring-petclinic-kotlin]: Kotlin version of the Spring PetClinic Sample Application
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin
* https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples/spring-cloud-gcp-kotlin-app-sample[spring-cloud-gcp-kotlin-app-sample]: Spring Boot with Google Cloud Platform Integrations
[[issues]]
== Issues
The following list categorizes the pending issues related to Spring and Kotlin support:
* Spring Framework
** {spring-framework-issues}/20606[Unable to use WebTestClient with mock server in Kotlin]
** {spring-framework-issues}/20496[Support null-safety at generics, varargs and array elements level]
* Kotlin
** {kotlin-issues}/KT-6380[Parent issue for Spring Framework support]
** {kotlin-issues}/KT-5464[Kotlin requires type inference where Java doesn't]
** {kotlin-issues}/KT-20283[Smart cast regression with open classes]
** {kotlin-issues}/KT-14984[Impossible to pass not all SAM argument as function]
** {kotlin-issues}/KT-15125[Support JSR 223 bindings directly via script variables]
** {kotlin-issues}/KT-6653[Kotlin properties do not override Java-style getters and setters]
@@ -97,9 +97,6 @@ does not require the `kotlin-noarg` plugin if the module uses Spring Data object
[[injecting-dependencies]]
== Injecting Dependencies
[[favor-constructor-injection]]
=== Favor constructor injection
Our recommendation is to try to favor constructor injection with `val` read-only (and
non-nullable when possible) {kotlin-docs}/properties.html[properties],
as the following example shows:
@@ -133,41 +130,7 @@ as the following example shows:
}
----
[[internal-functions-name-mangling]]
=== Internal functions name mangling
Kotlin functions with the `internal` {kotlin-docs}/visibility-modifiers.html#class-members[visibility modifier] have
their names mangled when compiled to JVM bytecode, which has a side effect when injecting dependencies by name.
For example, this Kotlin class:
[source,kotlin,indent=0]
----
@Configuration
class SampleConfiguration {
@Bean
internal fun sampleBean() = SampleBean()
}
----
Translates to this Java representation of the compiled JVM bytecode:
[source,java,indent=0]
----
@Configuration
@Metadata(/* ... */)
public class SampleConfiguration {
@Bean
@NotNull
public SampleBean sampleBean$demo_kotlin_internal_test() {
return new SampleBean();
}
}
----
As a consequence, the related bean name represented as a Kotlin string is `"sampleBean\$demo_kotlin_internal_test"`,
instead of `"sampleBean"` for the regular `public` function use-case. Make sure to use the mangled name when injecting
such bean by name.
[[injecting-configuration-properties]]
== Injecting Configuration Properties
@@ -8,9 +8,9 @@
Spring Framework comes with a Kotlin router DSL available in 3 flavors:
* xref:web/webmvc-functional.adoc[WebMvc.fn DSL] with {spring-framework-api-kdoc}/spring-webmvc/org.springframework.web.servlet.function/router.html[router { }]
* xref:web/webflux-functional.adoc[WebFlux.fn Reactive DSL] with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/router.html[router { }]
* xref:languages/kotlin/coroutines.adoc[WebFlux.fn Coroutines DSL] with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
* WebMvc.fn DSL with {spring-framework-api-kdoc}/spring-webmvc/org.springframework.web.servlet.function/router.html[router { }]
* WebFlux.fn <<web-reactive#webflux-fn, Reactive>> DSL with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/router.html[router { }]
* WebFlux.fn <<Coroutines>> DSL with {spring-framework-api-kdoc}/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
These DSL let you write clean and idiomatic Kotlin code to build a `RouterFunction` instance as the following example shows:
@@ -126,7 +126,7 @@ project for more details.
[[kotlin-multiplatform-serialization]]
== Kotlin multiplatform serialization
{kotlin-github-org}/kotlinx.serialization[Kotlin multiplatform serialization] is
As of Spring Framework 5.3, {kotlin-github-org}/kotlinx.serialization[Kotlin multiplatform serialization] is
supported in Spring MVC, Spring WebFlux and Spring Messaging (RSocket). The builtin support currently targets CBOR, JSON, and ProtoBuf formats.
To enable it, follow {kotlin-github-org}/kotlinx.serialization#setup[those instructions] to add the related dependency and plugin.
@@ -78,9 +78,8 @@ it does the same, but it also compares the computed value against the `If-None-M
request header and, if the two are equal, returns a 304 (NOT_MODIFIED).
This strategy saves network bandwidth but not CPU, as the full response must be computed for each request.
State-changing HTTP methods and other HTTP conditional request headers such as `If-Match` and
`If-Unmodified-Since` are outside the scope of this filter. Other strategies at the controller level
can avoid the computation and have a broader support for HTTP conditional requests.
State-changing HTTP methods and other HTTP conditional request headers such as `If-Match` and `If-Unmodified-Since` are outside the scope of this filter.
Other strategies at the controller level can avoid the computation and have a broader support for HTTP conditional requests.
See xref:web/webmvc/mvc-caching.adoc[HTTP Caching].
This filter has a `writeWeakETag` parameter that configures the filter to write weak ETags
@@ -38,7 +38,7 @@ The next example uses server-side configuration to register a custom authenticat
interceptor. Note that an interceptor needs only to authenticate and set
the user header on the CONNECT `Message`. Spring notes and saves the authenticated
user and associate it with subsequent STOMP messages on the same session. The following
example shows how to register a custom authentication interceptor:
example shows how register a custom authentication interceptor:
[source,java,indent=0,subs="verbatim,quotes"]
----
+23 -23
View File
@@ -7,17 +7,16 @@ javaPlatform {
}
dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.15.3"))
api(platform("io.micrometer:micrometer-bom:1.12.2"))
api(platform("io.netty:netty-bom:4.1.104.Final"))
api(platform("com.fasterxml.jackson:jackson-bom:2.15.2"))
api(platform("io.micrometer:micrometer-bom:1.12.1"))
api(platform("io.netty:netty-bom:4.1.101.Final"))
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
api(platform("io.projectreactor:reactor-bom:2023.0.2"))
api(platform("io.projectreactor:reactor-bom:2023.0.1"))
api(platform("io.rsocket:rsocket-bom:1.1.3"))
api(platform("org.apache.groovy:groovy-bom:4.0.17"))
api(platform("org.apache.groovy:groovy-bom:4.0.16"))
api(platform("org.apache.logging.log4j:log4j-bom:2.21.1"))
api(platform("org.assertj:assertj-bom:3.25.1"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.5"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.5"))
api(platform("org.eclipse.jetty:jetty-bom:12.0.4"))
api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.3"))
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3"))
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.0"))
api(platform("org.junit:junit-bom:5.10.1"))
@@ -27,11 +26,11 @@ dependencies {
api("com.fasterxml:aalto-xml:1.3.2")
api("com.fasterxml.woodstox:woodstox-core:6.5.1")
api("com.github.ben-manes.caffeine:caffeine:3.1.8")
api("com.github.librepdf:openpdf:1.3.36")
api("com.github.librepdf:openpdf:1.3.33")
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.10.1")
api("com.google.protobuf:protobuf-java-util:3.25.1")
api("com.google.protobuf:protobuf-java-util:3.25.0")
api("com.h2database:h2:2.2.224")
api("com.jayway.jsonpath:json-path:2.8.0")
api("com.rometools:rome:1.19.0")
@@ -100,16 +99,17 @@ dependencies {
api("org.apache.derby:derby:10.16.1.1")
api("org.apache.derby:derbyclient:10.16.1.1")
api("org.apache.derby:derbytools:10.16.1.1")
api("org.apache.httpcomponents.client5:httpclient5:5.3")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.4")
api("org.apache.poi:poi-ooxml:5.2.5")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.18")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.18")
api("org.apache.tomcat:tomcat-util:10.1.18")
api("org.apache.tomcat:tomcat-websocket:10.1.18")
api("org.aspectj:aspectjrt:1.9.21")
api("org.aspectj:aspectjtools:1.9.21")
api("org.aspectj:aspectjweaver:1.9.21")
api("org.apache.httpcomponents.client5:httpclient5:5.2.1")
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.3")
api("org.apache.poi:poi-ooxml:5.2.4")
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.16")
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.16")
api("org.apache.tomcat:tomcat-util:10.1.16")
api("org.apache.tomcat:tomcat-websocket:10.1.16")
api("org.aspectj:aspectjrt:1.9.20.1")
api("org.aspectj:aspectjtools:1.9.20.1")
api("org.aspectj:aspectjweaver:1.9.20.1")
api("org.assertj:assertj-core:3.24.2")
api("org.awaitility:awaitility:4.2.0")
api("org.bouncycastle:bcpkix-jdk18on:1.72")
api("org.codehaus.jettison:jettison:1.5.4")
@@ -131,7 +131,7 @@ dependencies {
api("org.hsqldb:hsqldb:2.7.2")
api("org.javamoney:moneta:1.4.2")
api("org.jruby:jruby:9.4.5.0")
api("org.junit.support:testng-engine:1.0.5")
api("org.junit.support:testng-engine:1.0.4")
api("org.mozilla:rhino:1.7.14")
api("org.ogce:xpp3:1.1.6")
api("org.python:jython-standalone:2.7.3")
@@ -139,8 +139,8 @@ dependencies {
api("org.seleniumhq.selenium:htmlunit-driver:2.70.0")
api("org.seleniumhq.selenium:selenium-java:3.141.59")
api("org.skyscreamer:jsonassert:1.5.1")
api("org.slf4j:slf4j-api:2.0.11")
api("org.testng:testng:7.9.0")
api("org.slf4j:slf4j-api:2.0.9")
api("org.testng:testng:7.8.0")
api("org.webjars:underscorejs:1.8.3")
api("org.webjars:webjars-locator-core:0.55")
api("org.xmlunit:xmlunit-assertj:2.9.1")
+2 -2
View File
@@ -1,10 +1,10 @@
version=6.1.3
version=6.1.2
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m
org.gradle.parallel=true
kotlinVersion=1.9.22
kotlinVersion=1.9.21
kotlin.jvm.target.validation.mode=ignore
kotlin.stdlib.default.dependency=false
@@ -1,19 +1,3 @@
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.aop.framework.autoproxy
import kotlinx.coroutines.delay
@@ -110,12 +94,12 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
open class Echo {
open fun echo(value: String): String {
return value
return value;
}
open suspend fun suspendingEcho(value: String): String {
delay(1)
return value
return value;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -334,15 +334,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
Object targetObject = null;
Object thisObject = null;
try {
MethodInvocation curr = ExposeInvocationInterceptor.currentInvocation();
if (curr.getMethod() == method) {
targetObject = curr.getThis();
if (!(curr instanceof ProxyMethodInvocation currPmi)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + curr);
}
pmi = currPmi;
thisObject = pmi.getProxy();
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
targetObject = mi.getThis();
if (!(mi instanceof ProxyMethodInvocation _pmi)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
pmi = _pmi;
thisObject = pmi.getProxy();
}
catch (IllegalStateException ex) {
// No current invocation...
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -293,7 +293,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
// This can match only on declared pointcut.
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass, args));
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
}
private boolean isAspectMaterialized() {
@@ -201,8 +201,9 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
List<BeanReference> beanReferences = new ArrayList<>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (Element declareParent : declareParents) {
beanDefinitions.add(parseDeclareParents(declareParent, parserContext));
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
@@ -404,14 +405,24 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
*/
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
return switch (elementName) {
case BEFORE -> AspectJMethodBeforeAdvice.class;
case AFTER -> AspectJAfterAdvice.class;
case AFTER_RETURNING_ELEMENT -> AspectJAfterReturningAdvice.class;
case AFTER_THROWING_ELEMENT -> AspectJAfterThrowingAdvice.class;
case AROUND -> AspectJAroundAdvice.class;
default -> throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
};
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,8 +42,10 @@ class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
boolean proxyTargetClass = true;
if (node instanceof Element ele && ele.hasAttribute(PROXY_TARGET_CLASS)) {
proxyTargetClass = Boolean.parseBoolean(ele.getAttribute(PROXY_TARGET_CLASS));
if (node instanceof Element ele) {
if (ele.hasAttribute(PROXY_TARGET_CLASS)) {
proxyTargetClass = Boolean.parseBoolean(ele.getAttribute(PROXY_TARGET_CLASS));
}
}
// Register the original bean definition as it will be referenced by the scoped proxy
@@ -102,23 +102,8 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
private List<Advisor> advisors = new ArrayList<>();
/**
* List of minimal {@link AdvisorKeyEntry} instances,
* to be assigned to the {@link #advisors} field on reduction.
* @since 6.0.10
* @see #reduceToAdvisorKey
*/
private List<Advisor> advisorKey = this.advisors;
/**
* Optional field for {@link AopProxy} implementations to store metadata in.
* Used by {@link JdkDynamicAopProxy}.
* @since 6.1.3
* @see JdkDynamicAopProxy#JdkDynamicAopProxy(AdvisedSupport)
*/
@Nullable
transient volatile Object proxyMetadataCache;
/**
* No-arg constructor for use as a JavaBean.
@@ -506,7 +491,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
*/
protected void adviceChanged() {
this.methodCache.clear();
this.proxyMetadataCache = null;
}
/**
@@ -567,6 +551,18 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.methodCache = new ConcurrentHashMap<>(32);
}
@Override
public String toProxyConfigString() {
return toString();
@@ -588,19 +584,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.methodCache = new ConcurrentHashMap<>(32);
}
/**
* Simple wrapper class around a Method. Used as the key when
* caching methods, for efficient equals and hashCode comparisons.
@@ -650,7 +633,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* @see #getConfigurationOnlyCopy()
* @see #getAdvisorKey()
*/
private static final class AdvisorKeyEntry implements Advisor {
private static class AdvisorKeyEntry implements Advisor {
private final Class<?> adviceType;
@@ -660,6 +643,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
@Nullable
private final String methodMatcherKey;
public AdvisorKeyEntry(Advisor advisor) {
this.adviceType = advisor.getAdvice().getClass();
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
@@ -16,8 +16,6 @@
package org.springframework.aop.framework;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -73,16 +71,34 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
private static final long serialVersionUID = 5531744639992436476L;
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
/*
* NOTE: We could avoid the code duplication between this class and the CGLIB
* proxies by refactoring "invoke" into a template method. However, this approach
* adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice
* elegance for performance (we have a good test suite to ensure that the different
* proxies behave the same :-)).
* This way, we can also more easily take advantage of minor optimizations in each class.
*/
/** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
/** Config used to configure this proxy. */
private final AdvisedSupport advised;
/** Cached in {@link AdvisedSupport#proxyMetadataCache}. */
private transient ProxiedInterfacesCache cache;
private final Class<?>[] proxiedInterfaces;
/**
* Is the {@link #equals} method defined on the proxied interfaces?
*/
private boolean equalsDefined;
/**
* Is the {@link #hashCode} method defined on the proxied interfaces?
*/
private boolean hashCodeDefined;
/**
@@ -94,17 +110,8 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
this.advised = config;
// Initialize ProxiedInterfacesCache if not cached already
ProxiedInterfacesCache cache;
if (config.proxyMetadataCache instanceof ProxiedInterfacesCache proxiedInterfacesCache) {
cache = proxiedInterfacesCache;
}
else {
cache = new ProxiedInterfacesCache(config);
config.proxyMetadataCache = cache;
}
this.cache = cache;
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
@@ -118,13 +125,13 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.cache.proxiedInterfaces, this);
return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this);
}
@SuppressWarnings("deprecation")
@Override
public Class<?> getProxyClass(@Nullable ClassLoader classLoader) {
return Proxy.getProxyClass(determineClassLoader(classLoader), this.cache.proxiedInterfaces);
return Proxy.getProxyClass(determineClassLoader(classLoader), this.proxiedInterfaces);
}
/**
@@ -153,6 +160,28 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return classLoader;
}
/**
* Finds any {@link #equals} or {@link #hashCode} method that may be defined
* on the supplied set of interfaces.
* @param proxiedInterfaces the interfaces to introspect
*/
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
/**
* Implementation of {@code InvocationHandler.invoke}.
@@ -169,11 +198,11 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
Object target = null;
try {
if (!this.cache.equalsDefined && AopUtils.isEqualsMethod(method)) {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.cache.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
@@ -295,63 +324,4 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.cache = new ProxiedInterfacesCache(this.advised);
}
/**
* Holder for the complete proxied interfaces and derived metadata,
* to be cached in {@link AdvisedSupport#proxyMetadataCache}.
* @since 6.1.3
*/
private static final class ProxiedInterfacesCache {
final Class<?>[] proxiedInterfaces;
final boolean equalsDefined;
final boolean hashCodeDefined;
ProxiedInterfacesCache(AdvisedSupport config) {
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(config, true);
// Find any {@link #equals} or {@link #hashCode} method that may be defined
// on the supplied set of interfaces.
boolean equalsDefined = false;
boolean hashCodeDefined = false;
for (Class<?> proxiedInterface : this.proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
equalsDefined = true;
if (hashCodeDefined) {
break;
}
}
if (AopUtils.isHashCodeMethod(method)) {
hashCodeDefined = true;
if (equalsDefined) {
break;
}
}
}
if (equalsDefined && hashCodeDefined) {
break;
}
}
this.equalsDefined = equalsDefined;
this.hashCodeDefined = hashCodeDefined;
}
}
}
@@ -58,7 +58,6 @@ import org.springframework.util.function.SingletonSupplier;
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author He Bo
* @author Sebastien Deleuze
* @since 3.1.2
*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
@@ -293,7 +292,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
else if (Future.class.isAssignableFrom(returnType)) {
return executor.submit(task);
}
else if (void.class == returnType || "kotlin.Unit".equals(returnType.getName())) {
else if (void.class == returnType) {
executor.submit(task);
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* AOP Alliance {@code MethodInterceptor} that processes method invocations
@@ -100,9 +101,10 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport imple
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
final Method userMethod = BridgeMethodResolver.getMostSpecificMethod(invocation.getMethod(), targetClass);
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
AsyncTaskExecutor executor = determineAsyncExecutor(userMethod);
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
@@ -116,10 +118,10 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport imple
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userMethod, invocation.getArguments());
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userMethod, invocation.getArguments());
handleError(ex, userDeclaredMethod, invocation.getArguments());
}
return null;
};
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -199,11 +199,12 @@ public abstract class AopUtils {
* @return the specific target method, or the original method if the
* {@code targetClass} doesn't implement it or is {@code null}
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
* @see org.springframework.core.BridgeMethodResolver#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
return BridgeMethodResolver.getMostSpecificMethod(method, specificTargetClass);
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
/**
* The class against which to match.
* @since 6.1
* <p>Available for use in subclasses since 6.1.
*/
protected final Class<?> clazz;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AspectJAdviceParameterNameDiscoverer}.
* Unit tests for {@link AspectJAdviceParameterNameDiscoverer}.
*
* @author Adrian Colyer
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
import org.junit.jupiter.api.BeforeEach;
@@ -65,7 +66,7 @@ public class AspectJExpressionPointcutTests {
@BeforeEach
public void setup() throws NoSuchMethodException {
public void setUp() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
setAge = TestBean.class.getMethod("setAge", int.class);
setSomeNumber = TestBean.class.getMethod("setSomeNumber", Number.class);
@@ -246,13 +247,14 @@ public class AspectJExpressionPointcutTests {
@Test
public void testInvalidExpression() {
String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number) && args(Double)";
assertThatIllegalArgumentException().isThrownBy(getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution
assertThatIllegalArgumentException().isThrownBy(
getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution
}
private TestBean getAdvisedProxy(String pointcutExpression, CallCountingInterceptor interceptor) {
TestBean target = new TestBean();
AspectJExpressionPointcut pointcut = getPointcut(pointcutExpression);
Pointcut pointcut = getPointcut(pointcutExpression);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setAdvice(interceptor);
@@ -276,31 +278,40 @@ public class AspectJExpressionPointcutTests {
@Test
public void testWithUnsupportedPointcutPrimitive() {
String expression = "call(int org.springframework.beans.testfixture.beans.TestBean.getAge())";
assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class)
.isThrownBy(() -> getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution...
.satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL));
assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class).isThrownBy(() ->
getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution...
.satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL));
}
@Test
public void testAndSubstitution() {
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String)");
String expr = pc.getPointcutExpression().getPointcutExpression();
assertThat(expr).isEqualTo("execution(* *(..)) && args(String)");
Pointcut pc = getPointcut("execution(* *(..)) and args(String)");
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String)");
}
@Test
public void testMultipleAndSubstitutions() {
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
String expr = pc.getPointcutExpression().getPointcutExpression();
assertThat(expr).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
Pointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
}
private AspectJExpressionPointcut getPointcut(String expression) {
private Pointcut getPointcut(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return pointcut;
}
public static class OtherIOther implements IOther {
@Override
public void absquatulate() {
// Empty
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
@@ -520,15 +531,6 @@ public class AspectJExpressionPointcutTests {
}
public static class OtherIOther implements IOther {
@Override
public void absquatulate() {
// Empty
}
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link TypePatternClassFilter}.
* Unit tests for the {@link TypePatternClassFilter} class.
*
* @author Rod Johnson
* @author Rick Evans
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,38 +42,26 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*/
class ArgumentBindingTests {
@Test
void annotationArgumentNameBinding() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalStateException()
.isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
}
@Test
void bindingInPointcutUsedByAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
ITestBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
}
@Test
void bindingWithDynamicAdvice() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(DynamicPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy();
void annotationArgumentNameBinding() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
proxiedTestBean.applyName(1);
assertThatIllegalArgumentException()
.isThrownBy(() -> proxiedTestBean.applyName("enigma"))
.withMessage("enigma");
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalStateException()
.isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
}
@Test
@@ -106,7 +94,6 @@ class ArgumentBindingTests {
}
}
/**
* Mimics Spring's @Transactional annotation without actually introducing the dependency.
*/
@@ -114,16 +101,15 @@ class ArgumentBindingTests {
@interface Transactional {
}
@Aspect
static class PointcutWithAnnotationArgument {
@Around("execution(* org.springframework..*.*(..)) && @annotation(transactional)")
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transactional)")
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
throw new IllegalStateException("Invoked with @Transactional");
}
}
}
@Aspect
static class NamedPointcutWithArgs {
@@ -135,16 +121,7 @@ class ArgumentBindingTests {
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
throw new IllegalArgumentException(aString);
}
}
@Aspect("pertarget(execution(* *(..)))")
static class DynamicPointcutWithArgs {
@Around("execution(* *(..)) && args(java.lang.String)")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
throw new IllegalArgumentException(String.valueOf(pjp.getArgs()[0]));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link DebugInterceptor}.
* Unit tests for the {@link DebugInterceptor} class.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link SimpleTraceInterceptor}.
* Unit tests for the {@link SimpleTraceInterceptor} class.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DefaultScopedObject}.
* Unit tests for the {@link DefaultScopedObject} class.
*
* @author Rick Evans
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link ScopedProxyUtils}.
* Unit tests for {@link ScopedProxyUtils}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link ClassFilters}.
* Unit tests for {@link ClassFilters}.
*
* @author Rod Johnson
* @author Chris Beams
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import org.springframework.beans.testfixture.beans.ITestBean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link RootClassFilter}.
* Unit tests for {@link RootClassFilter}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AnnotationMatchingPointcut}.
* Unit tests for {@link AnnotationMatchingPointcut}.
*
* @author Sam Brannen
* @since 5.1.10
@@ -46,7 +46,7 @@ class AopUtilsKotlinTests {
@Suppress("unused")
suspend fun suspendingFunction(value: String): String {
delay(1)
return value
return value;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
/**
* Tests for {@link AnnotationAsyncExecutionAspect}.
* Unit tests for {@link AnnotationAsyncExecutionAspect}.
*
* @author Ramnivas Laddad
* @author Stephane Nicoll
@@ -221,7 +221,7 @@ public class AnnotationAsyncExecutionAspectTests {
@Async public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<>(5);
return new AsyncResult<Integer>(5);
}
/**
@@ -256,7 +256,7 @@ public class AnnotationAsyncExecutionAspectTests {
public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<>(5);
return new AsyncResult<Integer>(5);
}
}
@@ -265,12 +265,12 @@ public class AnnotationAsyncExecutionAspectTests {
@Async
public Future<Thread> defaultWork() {
return new AsyncResult<>(Thread.currentThread());
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
public ListenableFuture<Thread> e1Work() {
return new AsyncResult<>(Thread.currentThread());
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.beans
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.BenchmarkMode
@@ -30,22 +30,22 @@ import org.openjdk.jmh.annotations.State
@OutputTimeUnit(TimeUnit.NANOSECONDS)
open class KotlinBeanUtilsBenchmark {
private val noArgConstructor = TestClass1::class.java.getDeclaredConstructor()
private val constructor = TestClass2::class.java.getDeclaredConstructor(Int::class.java, String::class.java)
private val noArgConstructor = TestClass1::class.java.getDeclaredConstructor()
private val constructor = TestClass2::class.java.getDeclaredConstructor(Int::class.java, String::class.java)
@Benchmark
fun emptyConstructor(): Any {
@Benchmark
fun emptyConstructor(): Any {
return BeanUtils.instantiateClass(noArgConstructor)
}
}
@Benchmark
fun nonEmptyConstructor(): Any {
@Benchmark
fun nonEmptyConstructor(): Any {
return BeanUtils.instantiateClass(constructor, 1, "str")
}
}
class TestClass1
class TestClass1()
@Suppress("UNUSED_PARAMETER")
class TestClass2(int: Int, string: String)
@Suppress("UNUSED_PARAMETER")
class TestClass2(int: Int, string: String)
}
@@ -461,9 +461,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
if (!ph.setValueFallbackIfPossible(pv.getValue())) {
throw ex;
}
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
@@ -1063,10 +1061,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
public abstract Object getValue() throws Exception;
public abstract void setValue(@Nullable Object value) throws Exception;
public boolean setValueFallbackIfPossible(@Nullable Object value) {
return false;
}
}
@@ -19,8 +19,6 @@ package org.springframework.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
@@ -280,22 +278,6 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
}
@Override
public boolean setValueFallbackIfPossible(@Nullable Object value) {
Method writeMethod = this.pd.getWriteMethodFallback(value != null ? value.getClass() : null);
if (writeMethod != null) {
ReflectionUtils.makeAccessible(writeMethod);
try {
writeMethod.invoke(getWrappedInstance(), value);
return true;
}
catch (Exception ex) {
LogFactory.getLog(BeanPropertyHandler.class).debug("Write method fallback failed", ex);
}
}
return false;
}
}
}
@@ -524,7 +524,20 @@ class ExtendedBeanInfo implements BeanInfo {
@Override
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
return desc1.getName().compareTo(desc2.getName());
String left = desc1.getName();
String right = desc2.getName();
byte[] leftBytes = left.getBytes();
byte[] rightBytes = right.getBytes();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = leftBytes[i] - rightBytes[i];
if (result != 0) {
return result;
}
}
return left.length() - right.length();
}
}
@@ -54,9 +54,7 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
private final Method writeMethod;
@Nullable
private Set<Method> ambiguousWriteMethods;
private volatile boolean ambiguousWriteMethodsLogged;
private volatile Set<Method> ambiguousWriteMethods;
@Nullable
private MethodParameter writeMethodParameter;
@@ -149,28 +147,16 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
public Method getWriteMethodForActualAccess() {
Assert.state(this.writeMethod != null, "No write method available");
if (this.ambiguousWriteMethods != null && !this.ambiguousWriteMethodsLogged) {
this.ambiguousWriteMethodsLogged = true;
Set<Method> ambiguousCandidates = this.ambiguousWriteMethods;
if (ambiguousCandidates != null) {
this.ambiguousWriteMethods = null;
LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).debug("Non-unique JavaBean property '" +
getName() + "' being accessed! Ambiguous write methods found next to actually used [" +
this.writeMethod + "]: " + this.ambiguousWriteMethods);
this.writeMethod + "]: " + ambiguousCandidates);
}
return this.writeMethod;
}
@Nullable
public Method getWriteMethodFallback(@Nullable Class<?> valueType) {
if (this.ambiguousWriteMethods != null) {
for (Method method : this.ambiguousWriteMethods) {
Class<?> paramType = method.getParameterTypes()[0];
if (valueType != null ? paramType.isAssignableFrom(valueType) : !paramType.isPrimitive()) {
return method;
}
}
}
return null;
}
public MethodParameter getWriteMethodParameter() {
Assert.state(this.writeMethodParameter != null, "No write method available");
return this.writeMethodParameter;
@@ -170,8 +170,6 @@ public interface BeanFactory {
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* Note that the provided arguments need to match a specific candidate constructor /
* factory method in the order of declared parameters.
* @param name the name of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
@@ -204,8 +202,6 @@ public interface BeanFactory {
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* Note that the provided arguments need to match a specific candidate constructor /
* factory method in the order of declared parameters.
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -517,9 +517,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
/**
* <em>Native</em> processing method for direct calls with an arbitrary target
* instance, resolving all of its fields and methods which are annotated with
* one of the configured 'autowired' annotation types.
* 'Native' processing method for direct calls with an arbitrary target instance,
* resolving all of its fields and methods which are annotated with one of the
* configured 'autowired' annotation types.
* @param bean the target instance to process
* @throws BeanCreationException if autowiring failed
* @see #setAutowiredAnnotationTypes(Set)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -367,7 +367,7 @@ class BeanDefinitionPropertiesCodeGenerator {
* @param castNecessary whether a cast is necessary
* @param castType the type to cast to
* @param valueCode the code for the value
* @return the existing value or a form of {@code (castType) valueCode} if a
* @return the existing value or a form of {@code (CastType) valueCode} if a
* cast is necessary
*/
private CodeBlock castIfNecessary(boolean castNecessary, Class<?> castType, CodeBlock valueCode) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -98,7 +98,9 @@ public final class ParseState {
for (ParseState.Entry entry : this.state) {
if (i > 0) {
sb.append('\n');
sb.append("\t".repeat(i));
for (int j = 0; j < i; j++) {
sb.append('\t');
}
sb.append("-> ");
}
sb.append(entry);
@@ -92,10 +92,10 @@ import org.springframework.util.function.ThrowingSupplier;
* Supports autowiring constructors, properties by name, and properties by type.
*
* <p>The main template method to be implemented by subclasses is
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)}, used for
* autowiring. In case of a {@link org.springframework.beans.factory.ListableBeanFactory}
* which is capable of searching its bean definitions, matching beans will typically be
* implemented through such a search. Otherwise, simplified matching can be implemented.
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)},
* used for autowiring by type. In case of a factory which is capable of searching
* its bean definitions, matching beans will typically be implemented through such
* a search. For other factory styles, simplified matching algorithms can be implemented.
*
* <p>Note that this class does <i>not</i> assume or implement bean definition
* registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
@@ -653,7 +653,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
// eventual type after a before-instantiation shortcut.
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
boolean matchingOnlyFactoryBean = (typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class);
boolean matchingOnlyFactoryBean = typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class;
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Class<?> predicted = bp.predictBeanType(targetType, beanName);
if (predicted != null &&
@@ -581,7 +581,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
*/
@Override
public boolean isLazyInit() {
return (this.lazyInit != null && this.lazyInit);
return (this.lazyInit != null && this.lazyInit.booleanValue());
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ public class BeanDefinitionDefaults {
* @return whether to apply lazy-init semantics ({@code false} by default)
*/
public boolean isLazyInit() {
return (this.lazyInit != null && this.lazyInit);
return (this.lazyInit != null && this.lazyInit.booleanValue());
}
/**
@@ -121,7 +121,11 @@ class ConstructorResolver {
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>This corresponds to constructor injection: In this mode, a Spring
* bean factory is able to host components that expect constructor-based
* dependency resolution.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param chosenCtors chosen candidate constructors (or {@code null} if none)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -294,7 +294,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setNestedPropertyPolymorphic() {
void setNestedPropertyPolymorphic() throws Exception {
ITestBean target = new TestBean("rod", 31);
ITestBean kerry = new Employee();
@@ -316,7 +316,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setAnotherNestedProperty() {
void setAnotherNestedProperty() throws Exception {
ITestBean target = new TestBean("rod", 31);
ITestBean kerry = new TestBean("kerry", 0);
@@ -386,7 +386,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setAnotherPropertyIntermediatePropertyIsNull() {
void setAnotherPropertyIntermediatePropertyIsNull() throws Exception {
ITestBean target = new TestBean("rod", 31);
AbstractPropertyAccessor accessor = createAccessor(target);
assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() ->
@@ -406,6 +406,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
@SuppressWarnings("unchecked")
void setPropertyIntermediateListIsNullWithAutoGrow() {
Foo target = new Foo();
AbstractPropertyAccessor accessor = createAccessor(target);
@@ -552,7 +553,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringPropertyWithCustomEditor() {
void setStringPropertyWithCustomEditor() throws Exception {
TestBean target = new TestBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String.class, "name", new PropertyEditorSupport() {
@@ -723,7 +724,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setPropertiesProperty() {
void setPropertiesProperty() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setPropertyValue("name", "ptest");
@@ -741,7 +742,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayProperty() {
void setStringArrayProperty() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
@@ -766,7 +767,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithCustomStringEditor() {
void setStringArrayPropertyWithCustomStringEditor() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String.class, "stringArray", new PropertyEditorSupport() {
@@ -795,7 +796,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithStringSplitting() {
void setStringArrayPropertyWithStringSplitting() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.useConfigValueEditors();
@@ -804,7 +805,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayPropertyWithCustomStringDelimiter() {
void setStringArrayPropertyWithCustomStringDelimiter() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.registerCustomEditor(String[].class, "stringArray", new StringArrayPropertyEditor("-"));
@@ -813,7 +814,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setStringArrayWithAutoGrow() {
void setStringArrayWithAutoGrow() throws Exception {
StringArrayBean target = new StringArrayBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setAutoGrowNestedPaths(true);
@@ -887,7 +888,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setIntArrayPropertyWithStringSplitting() {
void setIntArrayPropertyWithStringSplitting() throws Exception {
PropsTester target = new PropsTester();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.useConfigValueEditors();
@@ -942,7 +943,7 @@ abstract class AbstractPropertyAccessorTests {
}
@Test
void setPrimitiveArrayPropertyWithAutoGrow() {
void setPrimitiveArrayPropertyWithAutoGrow() throws Exception {
PrimitiveArrayBean target = new PrimitiveArrayBean();
AbstractPropertyAccessor accessor = createAccessor(target);
accessor.setAutoGrowNestedPaths(true);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.SoftAssertions.assertSoftly;
/**
* Tests for {@link BeanUtils}.
* Unit tests for {@link BeanUtils}.
*
* @author Juergen Hoeller
* @author Rob Harrop
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Juergen Hoeller
* @author Sam Brannen
*/
class BeanWrapperAutoGrowingTests {
public class BeanWrapperAutoGrowingTests {
private final Bean bean = new Bean();
@@ -38,43 +38,43 @@ class BeanWrapperAutoGrowingTests {
@BeforeEach
void setup() {
public void setup() {
wrapper.setAutoGrowNestedPaths(true);
}
@Test
void getPropertyValueNullValueInNestedPath() {
public void getPropertyValueNullValueInNestedPath() {
assertThat(wrapper.getPropertyValue("nested.prop")).isNull();
}
@Test
void setPropertyValueNullValueInNestedPath() {
public void setPropertyValueNullValueInNestedPath() {
wrapper.setPropertyValue("nested.prop", "test");
assertThat(bean.getNested().getProp()).isEqualTo("test");
}
@Test
void getPropertyValueNullValueInNestedPathNoDefaultConstructor() {
public void getPropertyValueNullValueInNestedPathNoDefaultConstructor() {
assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() ->
wrapper.getPropertyValue("nestedNoConstructor.prop"));
}
@Test
void getPropertyValueAutoGrowArray() {
public void getPropertyValueAutoGrowArray() {
assertNotNull(wrapper.getPropertyValue("array[0]"));
assertThat(bean.getArray()).hasSize(1);
assertThat(bean.getArray()[0]).isInstanceOf(Bean.class);
}
@Test
void setPropertyValueAutoGrowArray() {
public void setPropertyValueAutoGrowArray() {
wrapper.setPropertyValue("array[0].prop", "test");
assertThat(bean.getArray()[0].getProp()).isEqualTo("test");
}
@Test
void getPropertyValueAutoGrowArrayBySeveralElements() {
public void getPropertyValueAutoGrowArrayBySeveralElements() {
assertNotNull(wrapper.getPropertyValue("array[4]"));
assertThat(bean.getArray()).hasSize(5);
assertThat(bean.getArray()[0]).isInstanceOf(Bean.class);
@@ -89,21 +89,21 @@ class BeanWrapperAutoGrowingTests {
}
@Test
void getPropertyValueAutoGrow2dArray() {
public void getPropertyValueAutoGrow2dArray() {
assertThat(wrapper.getPropertyValue("multiArray[0][0]")).isNotNull();
assertThat(bean.getMultiArray()[0]).hasSize(1);
assertThat(bean.getMultiArray()[0][0]).isInstanceOf(Bean.class);
}
@Test
void getPropertyValueAutoGrow3dArray() {
public void getPropertyValueAutoGrow3dArray() {
assertThat(wrapper.getPropertyValue("threeDimensionalArray[1][2][3]")).isNotNull();
assertThat(bean.getThreeDimensionalArray()[1]).hasNumberOfRows(3);
assertThat(bean.getThreeDimensionalArray()[1][2][3]).isInstanceOf(Bean.class);
}
@Test
void setPropertyValueAutoGrow2dArray() {
public void setPropertyValueAutoGrow2dArray() {
Bean newBean = new Bean();
newBean.setProp("enigma");
wrapper.setPropertyValue("multiArray[2][3]", newBean);
@@ -113,7 +113,7 @@ class BeanWrapperAutoGrowingTests {
}
@Test
void setPropertyValueAutoGrow3dArray() {
public void setPropertyValueAutoGrow3dArray() {
Bean newBean = new Bean();
newBean.setProp("enigma");
wrapper.setPropertyValue("threeDimensionalArray[2][3][4]", newBean);
@@ -123,20 +123,20 @@ class BeanWrapperAutoGrowingTests {
}
@Test
void getPropertyValueAutoGrowList() {
public void getPropertyValueAutoGrowList() {
assertNotNull(wrapper.getPropertyValue("list[0]"));
assertThat(bean.getList()).hasSize(1);
assertThat(bean.getList()).element(0).isInstanceOf(Bean.class);
}
@Test
void setPropertyValueAutoGrowList() {
public void setPropertyValueAutoGrowList() {
wrapper.setPropertyValue("list[0].prop", "test");
assertThat(bean.getList().get(0).getProp()).isEqualTo("test");
}
@Test
void getPropertyValueAutoGrowListBySeveralElements() {
public void getPropertyValueAutoGrowListBySeveralElements() {
assertNotNull(wrapper.getPropertyValue("list[4]"));
assertThat(bean.getList()).hasSize(5);
assertThat(bean.getList()).element(0).isInstanceOf(Bean.class);
@@ -151,7 +151,7 @@ class BeanWrapperAutoGrowingTests {
}
@Test
void getPropertyValueAutoGrowListFailsAgainstLimit() {
public void getPropertyValueAutoGrowListFailsAgainstLimit() {
wrapper.setAutoGrowCollectionLimit(2);
assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() ->
wrapper.getPropertyValue("list[4]"))
@@ -159,26 +159,26 @@ class BeanWrapperAutoGrowingTests {
}
@Test
void getPropertyValueAutoGrowMultiDimensionalList() {
public void getPropertyValueAutoGrowMultiDimensionalList() {
assertNotNull(wrapper.getPropertyValue("multiList[0][0]"));
assertThat(bean.getMultiList()).element(0).asList().hasSize(1);
assertThat(bean.getMultiList().get(0)).element(0).isInstanceOf(Bean.class);
}
@Test
void getPropertyValueAutoGrowListNotParameterized() {
public void getPropertyValueAutoGrowListNotParameterized() {
assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() ->
wrapper.getPropertyValue("listNotParameterized[0]"));
}
@Test
void setPropertyValueAutoGrowMap() {
public void setPropertyValueAutoGrowMap() {
wrapper.setPropertyValue("map[A]", new Bean());
assertThat(bean.getMap().get("A")).isInstanceOf(Bean.class);
}
@Test
void setNestedPropertyValueAutoGrowMap() {
public void setNestedPropertyValueAutoGrowMap() {
wrapper.setPropertyValue("map[A].nested", new Bean());
assertThat(bean.getMap().get("A").getNested()).isInstanceOf(Bean.class);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,10 +31,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Juergen Hoeller
* @author Chris Beams
*/
class BeanWrapperEnumTests {
public class BeanWrapperEnumTests {
@Test
void testCustomEnum() {
public void testCustomEnum() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", "VALUE_1");
@@ -42,7 +42,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumWithNull() {
public void testCustomEnumWithNull() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", null);
@@ -50,7 +50,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumWithEmptyString() {
public void testCustomEnumWithEmptyString() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnum", "");
@@ -58,7 +58,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumArrayWithSingleValue() {
public void testCustomEnumArrayWithSingleValue() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", "VALUE_1");
@@ -67,7 +67,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumArrayWithMultipleValues() {
public void testCustomEnumArrayWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", new String[] {"VALUE_1", "VALUE_2"});
@@ -77,7 +77,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumArrayWithMultipleValuesAsCsv() {
public void testCustomEnumArrayWithMultipleValuesAsCsv() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumArray", "VALUE_1,VALUE_2");
@@ -87,7 +87,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumSetWithSingleValue() {
public void testCustomEnumSetWithSingleValue() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", "VALUE_1");
@@ -96,7 +96,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumSetWithMultipleValues() {
public void testCustomEnumSetWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", new String[] {"VALUE_1", "VALUE_2"});
@@ -106,7 +106,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumSetWithMultipleValuesAsCsv() {
public void testCustomEnumSetWithMultipleValuesAsCsv() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSet", "VALUE_1,VALUE_2");
@@ -116,7 +116,7 @@ class BeanWrapperEnumTests {
}
@Test
void testCustomEnumSetWithGetterSetterMismatch() {
public void testCustomEnumSetWithGetterSetterMismatch() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSetMismatch", new String[] {"VALUE_1", "VALUE_2"});
@@ -126,7 +126,7 @@ class BeanWrapperEnumTests {
}
@Test
void testStandardEnumSetWithMultipleValues() {
public void testStandardEnumSetWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setConversionService(new DefaultConversionService());
@@ -138,7 +138,7 @@ class BeanWrapperEnumTests {
}
@Test
void testStandardEnumSetWithAutoGrowing() {
public void testStandardEnumSetWithAutoGrowing() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setAutoGrowNestedPaths(true);
@@ -148,7 +148,7 @@ class BeanWrapperEnumTests {
}
@Test
void testStandardEnumMapWithMultipleValues() {
public void testStandardEnumMapWithMultipleValues() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setConversionService(new DefaultConversionService());
@@ -163,7 +163,7 @@ class BeanWrapperEnumTests {
}
@Test
void testStandardEnumMapWithAutoGrowing() {
public void testStandardEnumMapWithAutoGrowing() {
GenericBean<?> gb = new GenericBean<>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setAutoGrowNestedPaths(true);
@@ -174,7 +174,7 @@ class BeanWrapperEnumTests {
}
@Test
void testNonPublicEnum() {
public void testNonPublicEnum() {
NonPublicEnumHolder holder = new NonPublicEnumHolder();
BeanWrapper bw = new BeanWrapperImpl(holder);
bw.setPropertyValue("nonPublicEnum", "VALUE_1");
@@ -184,7 +184,7 @@ class BeanWrapperEnumTests {
enum NonPublicEnum {
VALUE_1, VALUE_2
VALUE_1, VALUE_2;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -201,7 +201,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("listOfLists[0][0]", 5);
assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5);
assertThat(gb.getListOfLists()).singleElement().asList().containsExactly(5);
assertThat(gb.getListOfLists().get(0)).element(0).isEqualTo(5);
}
@Test
@@ -213,7 +213,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("listOfLists[0][0]", "5");
assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5);
assertThat(gb.getListOfLists()).singleElement().asList().containsExactly(5);
assertThat(gb.getListOfLists().get(0)).element(0).isEqualTo(5);
}
@Test
@@ -298,7 +298,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("mapOfLists[1][0]", 5);
assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).containsExactly(5);
assertThat(gb.getMapOfLists().get(1)).element(0).isEqualTo(5);
}
@Test
@@ -310,7 +310,7 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("mapOfLists[1][0]", "5");
assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5);
assertThat(gb.getMapOfLists().get(1)).containsExactly(5);
assertThat(gb.getMapOfLists().get(1)).element(0).isEqualTo(5);
}
@Test
@@ -516,7 +516,8 @@ class BeanWrapperGenericsTests {
bw.setPropertyValue("genericProperty", "10");
bw.setPropertyValue("genericListProperty", new String[] {"20", "30"});
assertThat(gb.getGenericProperty()).isEqualTo(10);
assertThat(gb.getGenericListProperty()).containsExactly(20, 30);
assertThat(gb.getGenericListProperty()).element(0).isEqualTo(20);
assertThat(gb.getGenericListProperty()).element(1).isEqualTo(30);
}
@Test
@@ -525,9 +526,9 @@ class BeanWrapperGenericsTests {
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("genericProperty", "10");
bw.setPropertyValue("genericListProperty", new String[] {"20", "30"});
assertThat(gb.getGenericProperty()).containsExactly(10);
assertThat(gb.getGenericListProperty().get(0)).containsExactly(20);
assertThat(gb.getGenericListProperty().get(1)).containsExactly(30);
assertThat(gb.getGenericProperty()).element(0).isEqualTo(10);
assertThat(gb.getGenericListProperty().get(0)).element(0).isEqualTo(20);
assertThat(gb.getGenericListProperty().get(1)).element(0).isEqualTo(30);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package org.springframework.beans;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
@@ -173,26 +172,10 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
void setterOverload() {
SetterOverload target = new SetterOverload();
BeanWrapper accessor = createAccessor(target);
accessor.setPropertyValue("object", "a String");
assertThat(target.value).isEqualTo("a String");
assertThat(target.getObject()).isEqualTo("a String");
assertThat(accessor.getPropertyValue("object")).isEqualTo("a String");
accessor.setPropertyValue("object", 1000);
assertThat(target.value).isEqualTo("1000");
assertThat(target.getObject()).isEqualTo("1000");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000");
accessor.setPropertyValue("value", 1000);
assertThat(target.value).isEqualTo("1000i");
assertThat(target.getObject()).isEqualTo("1000i");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000i");
accessor.setPropertyValue("value", Duration.ofSeconds(1000));
assertThat(target.value).isEqualTo("1000s");
assertThat(target.getObject()).isEqualTo("1000s");
assertThat(accessor.getPropertyValue("object")).isEqualTo("1000s");
}
@Test
@@ -399,7 +382,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String value;
public void setObject(Integer length) {
this.value = length + "i";
this.value = length.toString();
}
public void setObject(String object) {
@@ -409,14 +392,6 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
public String getObject() {
return this.value;
}
public void setValue(int length) {
this.value = length + "i";
}
public void setValue(Duration duration) {
this.value = duration.getSeconds() + "s";
}
}
@@ -428,7 +403,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
}
@Override
public void close() {
public void close() throws Exception {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @author Arjen Poutsma
*/
class CachedIntrospectionResultsTests {
public class CachedIntrospectionResultsTests {
@Test
void acceptAndClearClassLoader() throws Exception {
public void acceptAndClearClassLoader() throws Exception {
BeanWrapper bw = new BeanWrapperImpl(TestBean.class);
assertThat(bw.isWritableProperty("name")).isTrue();
assertThat(bw.isWritableProperty("age")).isTrue();
@@ -56,7 +56,7 @@ class CachedIntrospectionResultsTests {
}
@Test
void clearClassLoaderForSystemClassLoader() {
public void clearClassLoaderForSystemClassLoader() throws Exception {
BeanUtils.getPropertyDescriptors(ArrayList.class);
assertThat(CachedIntrospectionResults.strongClassCache.containsKey(ArrayList.class)).isTrue();
CachedIntrospectionResults.clearClassLoader(ArrayList.class.getClassLoader());
@@ -64,7 +64,7 @@ class CachedIntrospectionResultsTests {
}
@Test
void shouldUseExtendedBeanInfoWhenApplicable() throws NoSuchMethodException, SecurityException {
public void shouldUseExtendedBeanInfoWhenApplicable() throws NoSuchMethodException, SecurityException {
// given a class with a non-void returning setter method
@SuppressWarnings("unused")
class C {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2021 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.
@@ -97,7 +97,7 @@ class ConcurrentBeanWrapperTests {
// ByteArrayOutputStream does not throw
// any IOException
}
String value = buffer.toString();
String value = new String(buffer.toByteArray());
BeanWrapperImpl wrapper = new BeanWrapperImpl(bean);
wrapper.setPropertyValue("properties", value);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -558,7 +558,7 @@ class ExtendedBeanInfoTests {
* @see #cornerSpr9702()
*/
@Test
void cornerSpr10111() {
void cornerSpr10111() throws Exception {
assertThatNoException().isThrownBy(() -> new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class)));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,22 +21,22 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link PropertyAccessorUtils}.
* Unit tests for {@link PropertyAccessorUtils}.
*
* @author Juergen Hoeller
* @author Chris Beams
*/
class PropertyAccessorUtilsTests {
public class PropertyAccessorUtilsTests {
@Test
void getPropertyName() {
public void getPropertyName() {
assertThat(PropertyAccessorUtils.getPropertyName("")).isEmpty();
assertThat(PropertyAccessorUtils.getPropertyName("[user]")).isEmpty();
assertThat(PropertyAccessorUtils.getPropertyName("user")).isEqualTo("user");
}
@Test
void isNestedOrIndexedProperty() {
public void isNestedOrIndexedProperty() {
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty(null)).isFalse();
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty("")).isFalse();
assertThat(PropertyAccessorUtils.isNestedOrIndexedProperty("user")).isFalse();
@@ -46,19 +46,19 @@ class PropertyAccessorUtilsTests {
}
@Test
void getFirstNestedPropertySeparatorIndex() {
public void getFirstNestedPropertySeparatorIndex() {
assertThat(PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex("[user]")).isEqualTo(-1);
assertThat(PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex("user.name")).isEqualTo(4);
}
@Test
void getLastNestedPropertySeparatorIndex() {
public void getLastNestedPropertySeparatorIndex() {
assertThat(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex("[user]")).isEqualTo(-1);
assertThat(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex("user.address.street")).isEqualTo(12);
}
@Test
void matchesProperty() {
public void matchesProperty() {
assertThat(PropertyAccessorUtils.matchesProperty("user", "email")).isFalse();
assertThat(PropertyAccessorUtils.matchesProperty("username", "user")).isFalse();
assertThat(PropertyAccessorUtils.matchesProperty("admin[user]", "user")).isFalse();
@@ -68,7 +68,7 @@ class PropertyAccessorUtilsTests {
}
@Test
void canonicalPropertyName() {
public void canonicalPropertyName() {
assertThat(PropertyAccessorUtils.canonicalPropertyName(null)).isEmpty();
assertThat(PropertyAccessorUtils.canonicalPropertyName("map")).isEqualTo("map");
assertThat(PropertyAccessorUtils.canonicalPropertyName("map[key1]")).isEqualTo("map[key1]");
@@ -82,7 +82,7 @@ class PropertyAccessorUtilsTests {
}
@Test
void canonicalPropertyNames() {
public void canonicalPropertyNames() {
assertThat(PropertyAccessorUtils.canonicalPropertyNames(null)).isNull();
String[] original =
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,28 +30,28 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Stephane Nicoll
*/
class PropertyMatchesTests {
public class PropertyMatchesTests {
@Test
void simpleBeanPropertyTypo() {
public void simpleBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).contains("name");
}
@Test
void complexBeanPropertyTypo() {
public void complexBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("desriptn", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
void unknownBeanProperty() {
public void unknownBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("unknown", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
void severalMatchesBeanProperty() {
public void severalMatchesBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches()).contains("counter1");
assertThat(matches.getPossibleMatches()).contains("counter2");
@@ -59,7 +59,7 @@ class PropertyMatchesTests {
}
@Test
void simpleBeanPropertyErrorMessage() {
public void simpleBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("naem");
@@ -69,7 +69,7 @@ class PropertyMatchesTests {
}
@Test
void complexBeanPropertyErrorMessage() {
public void complexBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("counter");
@@ -79,25 +79,25 @@ class PropertyMatchesTests {
}
@Test
void simpleFieldPropertyTypo() {
public void simpleFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).contains("name");
}
@Test
void complexFieldPropertyTypo() {
public void complexFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("desriptn", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
void unknownFieldProperty() {
public void unknownFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("unknown", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).isEmpty();
}
@Test
void severalMatchesFieldProperty() {
public void severalMatchesFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches()).contains("counter1");
assertThat(matches.getPossibleMatches()).contains("counter2");
@@ -105,7 +105,7 @@ class PropertyMatchesTests {
}
@Test
void simpleFieldPropertyErrorMessage() {
public void simpleFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("naem");
@@ -115,7 +115,7 @@ class PropertyMatchesTests {
}
@Test
void complexFieldPropertyErrorMessage() {
public void complexFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg).contains("counter");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,10 +30,10 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @see ExtendedBeanInfoTests
*/
class SimplePropertyDescriptorTests {
public class SimplePropertyDescriptorTests {
@Test
void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
public void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
{
Object pd = new ExtendedBeanInfo.SimplePropertyDescriptor("foo", null, null);
assertThat(pd.toString()).contains(
@@ -71,7 +71,7 @@ class SimplePropertyDescriptorTests {
}
@Test
void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
public void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
Object pd1 = new ExtendedBeanInfo.SimplePropertyDescriptor("foo", null, null);
assertThat(pd1).isEqualTo(pd1);
@@ -108,7 +108,7 @@ class SimplePropertyDescriptorTests {
}
@Test
void indexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
public void indexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
Object pd1 = new ExtendedBeanInfo.SimpleIndexedPropertyDescriptor("foo", null, null, null, null);
assertThat(pd1).isEqualTo(pd1);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
* @author Sam Brannen
* @since 04.07.2003
*/
class BeanFactoryUtilsTests {
public class BeanFactoryUtilsTests {
private static final Class<?> CLASS = BeanFactoryUtilsTests.class;
private static final Resource ROOT_CONTEXT = qualifiedResource(CLASS, "root.xml");
@@ -63,7 +63,7 @@ class BeanFactoryUtilsTests {
@BeforeEach
void setup() {
public void setup() {
// Interesting hierarchical factory to test counts.
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
@@ -81,7 +81,7 @@ class BeanFactoryUtilsTests {
@Test
void testHierarchicalCountBeansWithNonHierarchicalFactory() {
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("t1", new TestBean());
lbf.addBean("t2", new TestBean());
@@ -92,7 +92,7 @@ class BeanFactoryUtilsTests {
* Check that override doesn't count as two separate beans.
*/
@Test
void testHierarchicalCountBeansWithOverride() {
public void testHierarchicalCountBeansWithOverride() {
// Leaf count
assertThat(this.listableBeanFactory.getBeanDefinitionCount()).isEqualTo(1);
// Count minus duplicate
@@ -101,14 +101,14 @@ class BeanFactoryUtilsTests {
}
@Test
void testHierarchicalNamesWithNoMatch() {
public void testHierarchicalNamesWithNoMatch() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertThat(names).isEmpty();
}
@Test
void testHierarchicalNamesWithMatchOnlyInRoot() {
public void testHierarchicalNamesWithMatchOnlyInRoot() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertThat(names).hasSize(1);
@@ -118,7 +118,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testGetBeanNamesForTypeWithOverride() {
public void testGetBeanNamesForTypeWithOverride() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
@@ -130,7 +130,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testNoBeansOfType() {
public void testNoBeansOfType() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("foo", new Object());
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
@@ -138,7 +138,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testFindsBeansOfTypeWithStaticFactory() {
public void testFindsBeansOfTypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean t1 = new TestBean();
TestBean t2 = new TestBean();
@@ -169,7 +169,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testFindsBeansOfTypeWithDefaultFactory() {
public void testFindsBeansOfTypeWithDefaultFactory() {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
@@ -232,7 +232,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testHierarchicalResolutionWithOverride() {
public void testHierarchicalResolutionWithOverride() {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
@@ -271,14 +271,14 @@ class BeanFactoryUtilsTests {
}
@Test
void testHierarchicalNamesForAnnotationWithNoMatch() {
public void testHierarchicalNamesForAnnotationWithNoMatch() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
assertThat(names).isEmpty();
}
@Test
void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
assertThat(names).hasSize(1);
@@ -288,7 +288,7 @@ class BeanFactoryUtilsTests {
}
@Test
void testGetBeanNamesForAnnotationWithOverride() {
public void testGetBeanNamesForAnnotationWithOverride() {
AnnotatedBean annotatedBean = new AnnotatedBean();
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
List<String> names = Arrays.asList(
@@ -299,31 +299,31 @@ class BeanFactoryUtilsTests {
}
@Test
void testADependencies() {
public void testADependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("a");
assertThat(ObjectUtils.isEmpty(deps)).isTrue();
}
@Test
void testBDependencies() {
public void testBDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("b");
assertThat(Arrays.equals(new String[] { "c" }, deps)).isTrue();
}
@Test
void testCDependencies() {
public void testCDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("c");
assertThat(Arrays.equals(new String[] { "int", "long" }, deps)).isTrue();
}
@Test
void testIntDependencies() {
public void testIntDependencies() {
String[] deps = this.dependentBeansFactory.getDependentBeans("int");
assertThat(Arrays.equals(new String[] { "buffer" }, deps)).isTrue();
}
@Test
void findAnnotationOnBean() {
public void findAnnotationOnBean() {
this.listableBeanFactory.registerSingleton("controllerAdvice", new ControllerAdviceClass());
this.listableBeanFactory.registerSingleton("restControllerAdvice", new RestControllerAdviceClass());
testFindAnnotationOnBean(this.listableBeanFactory);
@@ -350,7 +350,7 @@ class BeanFactoryUtilsTests {
}
@Test
void isSingletonAndIsPrototypeWithStaticFactory() {
public void isSingletonAndIsPrototypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean bean = new TestBean();
DummyFactory fb1 = new DummyFactory();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1240,7 +1240,7 @@ class DefaultListableBeanFactoryTests {
}
@Test
void arrayPropertyWithOptionalAutowiring() {
void arrayPropertyWithOptionalAutowiring() throws MalformedURLException {
RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class);
rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
lbf.registerBeanDefinition("arrayBean", rbd);
@@ -3211,7 +3211,7 @@ class DefaultListableBeanFactoryTests {
extends RepositoryFactoryBeanSupport<T, S, ID> {
@Override
public T getObject() {
public T getObject() throws Exception {
throw new IllegalArgumentException("Should not be called");
}
@@ -3460,7 +3460,7 @@ class DefaultListableBeanFactoryTests {
enum NonPublicEnum {
VALUE_1, VALUE_2
VALUE_1, VALUE_2;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,42 +32,42 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Chris Beams
*/
class FactoryBeanLookupTests {
public class FactoryBeanLookupTests {
private BeanFactory beanFactory;
@BeforeEach
void setUp() {
public void setUp() {
beanFactory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory).loadBeanDefinitions(
new ClassPathResource("FactoryBeanLookupTests-context.xml", this.getClass()));
}
@Test
void factoryBeanLookupByNameDereferencing() {
public void factoryBeanLookupByNameDereferencing() {
Object fooFactory = beanFactory.getBean("&fooFactory");
assertThat(fooFactory).isInstanceOf(FooFactoryBean.class);
}
@Test
void factoryBeanLookupByType() {
public void factoryBeanLookupByType() {
FooFactoryBean fooFactory = beanFactory.getBean(FooFactoryBean.class);
assertThat(fooFactory).isNotNull();
}
@Test
void factoryBeanLookupByTypeAndNameDereference() {
public void factoryBeanLookupByTypeAndNameDereference() {
FooFactoryBean fooFactory = beanFactory.getBean("&fooFactory", FooFactoryBean.class);
assertThat(fooFactory).isNotNull();
}
@Test
void factoryBeanObjectLookupByName() {
public void factoryBeanObjectLookupByName() {
Object fooFactory = beanFactory.getBean("fooFactory");
assertThat(fooFactory).isInstanceOf(Foo.class);
}
@Test
void factoryBeanObjectLookupByNameAndType() {
public void factoryBeanObjectLookupByNameAndType() {
Foo foo = beanFactory.getBean("fooFactory", Foo.class);
assertThat(foo).isNotNull();
}
@@ -75,7 +75,7 @@ class FactoryBeanLookupTests {
class FooFactoryBean extends AbstractFactoryBean<Foo> {
@Override
protected Foo createInstance() {
protected Foo createInstance() throws Exception {
return new Foo();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
* @author Juergen Hoeller
* @author Chris Beams
*/
class FactoryBeanTests {
public class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
@@ -48,7 +48,7 @@ class FactoryBeanTests {
@Test
void testFactoryBeanReturnsNull() {
public void testFactoryBeanReturnsNull() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(RETURNS_NULL_CONTEXT);
@@ -56,7 +56,7 @@ class FactoryBeanTests {
}
@Test
void testFactoryBeansWithAutowiring() {
public void testFactoryBeansWithAutowiring() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(WITH_AUTOWIRING_CONTEXT);
@@ -77,7 +77,7 @@ class FactoryBeanTests {
}
@Test
void testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure() {
public void testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(WITH_AUTOWIRING_CONTEXT);
@@ -92,21 +92,21 @@ class FactoryBeanTests {
}
@Test
void testAbstractFactoryBeanViaAnnotation() {
public void testAbstractFactoryBeanViaAnnotation() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansWithAnnotation(Component.class);
}
@Test
void testAbstractFactoryBeanViaType() {
public void testAbstractFactoryBeanViaType() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansOfType(AbstractFactoryBean.class);
}
@Test
void testCircularReferenceWithPostProcessor() {
public void testCircularReferenceWithPostProcessor() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(CIRCULAR_CONTEXT);
@@ -284,7 +284,11 @@ class FactoryBeanTests {
if (bean instanceof FactoryBean) {
return bean;
}
AtomicInteger c = count.computeIfAbsent(beanName, k -> new AtomicInteger());
AtomicInteger c = count.get(beanName);
if (c == null) {
c = new AtomicInteger();
count.put(beanName, c);
}
c.incrementAndGet();
return bean;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,10 +33,10 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.ro
* @author Chris Beams
* @author Juergen Hoeller
*/
class Spr5475Tests {
public class Spr5475Tests {
@Test
void noArgFactoryMethodInvokedWithOneArg() {
public void noArgFactoryMethodInvokedWithOneArg() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
@@ -47,7 +47,7 @@ class Spr5475Tests {
}
@Test
void noArgFactoryMethodInvokedWithTwoArgs() {
public void noArgFactoryMethodInvokedWithTwoArgs() {
assertExceptionMessageForMisconfiguredFactoryMethod(
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
@@ -59,7 +59,7 @@ class Spr5475Tests {
}
@Test
void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() {
public void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() {
RootBeanDefinition def = new RootBeanDefinition(Foo.class);
def.setFactoryMethodName("noArgFactory");
ConstructorArgumentValues cav = new ConstructorArgumentValues();
@@ -82,7 +82,7 @@ class Spr5475Tests {
}
@Test
void singleArgFactoryMethodInvokedWithNoArgs() {
public void singleArgFactoryMethodInvokedWithNoArgs() {
// calling a factory method that accepts arguments without any arguments emits an exception unlike cases
// where a no-arg factory method is called with arguments. Adding this test just to document the difference
assertExceptionMessageForMisconfiguredFactoryMethod(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,30 +27,30 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
* @author Rick Evans
* @author Chris Beams
*/
class AnnotationBeanWiringInfoResolverTests {
public class AnnotationBeanWiringInfoResolverTests {
@Test
void testResolveWiringInfo() {
public void testResolveWiringInfo() throws Exception {
assertThatIllegalArgumentException().isThrownBy(() ->
new AnnotationBeanWiringInfoResolver().resolveWiringInfo(null));
}
@Test
void testResolveWiringInfoWithAnInstanceOfANonAnnotatedClass() {
public void testResolveWiringInfoWithAnInstanceOfANonAnnotatedClass() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo("java.lang.String is not @Configurable");
assertThat(info).as("Must be returning null for a non-@Configurable class instance").isNull();
}
@Test
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClass() {
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClass() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new Soap());
assertThat(info).as("Must *not* be returning null for a non-@Configurable class instance").isNotNull();
}
@Test
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitly() {
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitly() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new WirelessSoap());
assertThat(info).as("Must *not* be returning null for an @Configurable class instance even when autowiring is NO").isNotNull();
@@ -59,7 +59,7 @@ class AnnotationBeanWiringInfoResolverTests {
}
@Test
void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitlyAndCustomBeanName() {
public void testResolveWiringInfoWithAnInstanceOfAnAnnotatedClassWithAutowiringTurnedOffExplicitlyAndCustomBeanName() {
AnnotationBeanWiringInfoResolver resolver = new AnnotationBeanWiringInfoResolver();
BeanWiringInfo info = resolver.resolveWiringInfo(new NamedWirelessSoap());
assertThat(info).as("Must *not* be returning null for an @Configurable class instance even when autowiring is NO").isNotNull();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
@@ -82,15 +83,13 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AutowiredAnnotationBeanPostProcessor}.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @author Chris Beams
* @author Stephane Nicoll
*/
class AutowiredAnnotationBeanPostProcessorTests {
public class AutowiredAnnotationBeanPostProcessorTests {
private DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@@ -120,20 +119,6 @@ class AutowiredAnnotationBeanPostProcessorTests {
.withRootCauseInstanceOf(IllegalStateException.class);
}
@Test
void processInjection() {
ResourceInjectionBean bean = new ResourceInjectionBean();
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
bpp.processInjection(bean);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
}
@Test
void resourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class);
@@ -726,9 +711,15 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansSetter).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansField).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansSetter).hasSize(2);
assertThat(bean.nestedTestBeansSetter).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansSetter).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).element(1).isSameAs(ntb1);
}
@Test
@@ -753,9 +744,15 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansSetter).containsExactly(ntb2, ntb1);
assertThat(bean.nestedTestBeansField).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansSetter).hasSize(2);
assertThat(bean.nestedTestBeansSetter).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansSetter).element(1).isSameAs(ntb1);
assertThat(bean.nestedTestBeansField).hasSize(2);
assertThat(bean.nestedTestBeansField).element(0).isSameAs(ntb2);
assertThat(bean.nestedTestBeansField).element(1).isSameAs(ntb1);
}
@Test
@@ -1115,7 +1112,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
}
@Test
@@ -1130,7 +1129,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
}
@Test
@@ -1157,7 +1158,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
}
@Test
@@ -1184,7 +1187,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).containsExactly(ntb2, ntb1);
assertThat(bean.getNestedTestBeans()).hasSize(2);
assertThat(bean.getNestedTestBeans()).element(0).isSameAs(ntb2);
assertThat(bean.getNestedTestBeans()).element(1).isSameAs(ntb1);
}
@Test
@@ -1495,7 +1500,8 @@ class AutowiredAnnotationBeanPostProcessorTests {
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
SelfInjectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionBean.class);
assertThat(bean.reference).isSameAs(bean2);
assertThat(bean.referenceCollection).containsExactly(bean2);
assertThat(bean.referenceCollection).hasSize(1);
assertThat(bean.referenceCollection).element(0).isSameAs(bean2);
}
@Test
@@ -1980,8 +1986,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -1992,8 +2000,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2022,8 +2032,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2034,8 +2046,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2060,8 +2074,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2125,8 +2141,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray).hasSize(1);
assertThat(bean.repositoryArray[0]).isSameAs(repo);
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).containsExactly(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2184,6 +2201,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2212,8 +2230,9 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.stringRepositoryArray).hasSize(1);
assertThat(bean.repositoryArray[0]).isSameAs(repo);
assertThat(bean.stringRepositoryArray[0]).isSameAs(repo);
assertThat(bean.repositoryList).containsExactly(repo);
assertThat(bean.repositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.repositoryList).element(0).isSameAs(repo);
assertThat(bean.stringRepositoryList).element(0).isSameAs(repo);
assertThat(bean.repositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap).hasSize(1);
@@ -2251,8 +2270,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2263,8 +2284,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2293,8 +2316,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerArray).hasSize(1);
assertThat(bean.stringArray[0]).isSameAs(sv);
assertThat(bean.integerArray[0]).isSameAs(iv);
assertThat(bean.stringList).containsExactly(sv);
assertThat(bean.integerList).containsExactly(iv);
assertThat(bean.stringList).hasSize(1);
assertThat(bean.integerList).hasSize(1);
assertThat(bean.stringList).element(0).isSameAs(sv);
assertThat(bean.integerList).element(0).isSameAs(iv);
assertThat(bean.stringMap).hasSize(1);
assertThat(bean.integerMap).hasSize(1);
assertThat(bean.stringMap.get("stringValue")).isSameAs(sv);
@@ -2305,8 +2330,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2330,8 +2357,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ir);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ir);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ir);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2354,8 +2383,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(gr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(gr);
assertThat(bean.stringRepositoryList).containsExactly(gr);
assertThat(bean.integerRepositoryList).containsExactly(gr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(gr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(gr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("genericRepo")).isSameAs(gr);
@@ -2377,8 +2408,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.stringRepositoryList).containsExactly(ngr);
assertThat(bean.integerRepositoryList).containsExactly(ngr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("simpleRepo")).isSameAs(ngr);
@@ -2403,8 +2436,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(gr);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(gr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(gr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2428,8 +2463,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.integerRepositoryArray).hasSize(1);
assertThat(bean.stringRepositoryArray[0]).isSameAs(sr);
assertThat(bean.integerRepositoryArray[0]).isSameAs(ngr);
assertThat(bean.stringRepositoryList).containsExactly(sr);
assertThat(bean.integerRepositoryList).containsExactly(ngr);
assertThat(bean.stringRepositoryList).hasSize(1);
assertThat(bean.integerRepositoryList).hasSize(1);
assertThat(bean.stringRepositoryList).element(0).isSameAs(sr);
assertThat(bean.integerRepositoryList).element(0).isSameAs(ngr);
assertThat(bean.stringRepositoryMap).hasSize(1);
assertThat(bean.integerRepositoryMap).hasSize(1);
assertThat(bean.stringRepositoryMap.get("stringRepo")).isSameAs(sr);
@@ -2565,7 +2602,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
void mixedNullableArgMethodInjection(){
public void mixedNullableArgMethodInjection(){
bf.registerSingleton("nonNullBean", "Test");
bf.registerBeanDefinition("mixedNullableInjectionBean",
new RootBeanDefinition(MixedNullableInjectionBean.class));
@@ -2575,7 +2612,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
void mixedOptionalArgMethodInjection(){
public void mixedOptionalArgMethodInjection(){
bf.registerSingleton("nonNullBean", "Test");
bf.registerBeanDefinition("mixedOptionalInjectionBean",
new RootBeanDefinition(MixedOptionalInjectionBean.class));
@@ -3426,7 +3463,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
public static class StringFactoryBean implements FactoryBean<String> {
@Override
public String getObject() {
public String getObject() throws Exception {
return "";
}
@@ -3961,7 +3998,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
@SuppressWarnings("unchecked")
public <T> T createMock(Class<T> toMock) {
return (T) Proxy.newProxyInstance(AutowiredAnnotationBeanPostProcessorTests.class.getClassLoader(), new Class<?>[] {toMock},
(proxy, method, args) -> {
(InvocationHandler) (proxy, method, args) -> {
throw new UnsupportedOperationException("mocked!");
});
}
@@ -4109,7 +4146,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
public static class MyCallable implements Callable<Thread> {
@Override
public Thread call() {
public Thread call() throws Exception {
return null;
}
}
@@ -4118,7 +4155,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
public static class SecondCallable implements Callable<Thread>{
@Override
public Thread call() {
public Thread call() throws Exception {
return null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,16 +28,16 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource;
/**
* Tests for {@link CustomAutowireConfigurer}.
* Unit tests for {@link CustomAutowireConfigurer}.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
*/
class CustomAutowireConfigurerTests {
public class CustomAutowireConfigurerTests {
@Test
void testCustomResolver() {
public void testCustomResolver() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
qualifiedResource(CustomAutowireConfigurerTests.class, "context.xml"));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessorTests.StringFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
@@ -50,13 +49,13 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AutowiredAnnotationBeanPostProcessor} processing
* the JSR-330 {@link jakarta.inject.Inject} annotation.
* Unit tests for {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
* processing the JSR-330 {@link jakarta.inject.Inject} annotation.
*
* @author Juergen Hoeller
* @since 3.0
*/
class InjectAnnotationBeanPostProcessorTests {
public class InjectAnnotationBeanPostProcessorTests {
private DefaultListableBeanFactory bf;
@@ -64,7 +63,7 @@ class InjectAnnotationBeanPostProcessorTests {
@BeforeEach
void setup() {
public void setup() {
bf = new DefaultListableBeanFactory();
bf.registerResolvableDependency(BeanFactory.class, bf);
bpp = new AutowiredAnnotationBeanPostProcessor();
@@ -74,13 +73,13 @@ class InjectAnnotationBeanPostProcessorTests {
}
@AfterEach
void close() {
public void close() {
bf.destroySingletons();
}
@Test
void testIncompleteBeanDefinition() {
public void testIncompleteBeanDefinition() {
bf.registerBeanDefinition("testBean", new GenericBeanDefinition());
try {
bf.getBean("testBean");
@@ -91,7 +90,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testResourceInjection() {
public void testResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -108,7 +107,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testExtendedResourceInjection() {
public void testExtendedResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -135,7 +134,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testExtendedResourceInjectionWithOverriding() {
public void testExtendedResourceInjectionWithOverriding() {
RootBeanDefinition annotatedBd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
TestBean tb2 = new TestBean();
annotatedBd.getPropertyValues().add("testBean2", tb2);
@@ -155,7 +154,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testConstructorResourceInjection() {
public void testConstructorResourceInjection() {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -182,7 +181,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testConstructorResourceInjectionWithMultipleCandidatesAsCollection() {
public void testConstructorResourceInjectionWithMultipleCandidatesAsCollection() {
bf.registerBeanDefinition("annotatedBean",
new RootBeanDefinition(ConstructorsCollectionResourceInjectionBean.class));
TestBean tb = new TestBean();
@@ -201,7 +200,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() {
public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
@@ -212,7 +211,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testConstructorInjectionWithMap() {
public void testConstructorInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -237,7 +236,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testFieldInjectionWithMap() {
public void testFieldInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -262,7 +261,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testMethodInjectionWithMap() {
public void testMethodInjectionWithMap() {
RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
@@ -283,7 +282,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testMethodInjectionWithMapAndMultipleMatches() {
public void testMethodInjectionWithMapAndMultipleMatches() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
@@ -292,7 +291,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testMethodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
public void testMethodInjectionWithMapAndMultipleMatchesButOnlyOneAutowireCandidate() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
RootBeanDefinition rbd2 = new RootBeanDefinition(TestBean.class);
@@ -308,7 +307,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryInjection() {
public void testObjectFactoryInjection() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class));
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
@@ -320,7 +319,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryQualifierInjection() {
public void testObjectFactoryQualifierInjection() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class));
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
@@ -331,7 +330,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryFieldInjectionIntoPrototypeBean() {
public void testObjectFactoryFieldInjectionIntoPrototypeBean() {
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryQualifierFieldInjectionBean.class);
annotatedBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
@@ -348,7 +347,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryMethodInjectionIntoPrototypeBean() {
public void testObjectFactoryMethodInjectionIntoPrototypeBean() {
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryQualifierMethodInjectionBean.class);
annotatedBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
@@ -365,7 +364,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithBeanField() throws Exception {
public void testObjectFactoryWithBeanField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -377,7 +376,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithBeanMethod() throws Exception {
public void testObjectFactoryWithBeanMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -389,7 +388,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithTypedListField() throws Exception {
public void testObjectFactoryWithTypedListField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -401,7 +400,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithTypedListMethod() throws Exception {
public void testObjectFactoryWithTypedListMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -413,7 +412,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithTypedMapField() throws Exception {
public void testObjectFactoryWithTypedMapField() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -425,7 +424,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testObjectFactoryWithTypedMapMethod() throws Exception {
public void testObjectFactoryWithTypedMapMethod() throws Exception {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
@@ -442,7 +441,7 @@ class InjectAnnotationBeanPostProcessorTests {
* specifically addressing SPR-4040.
*/
@Test
void testBeanAutowiredWithFactoryBean() {
public void testBeanAutowiredWithFactoryBean() {
bf.registerBeanDefinition("factoryBeanDependentBean", new RootBeanDefinition(FactoryBeanDependentBean.class));
bf.registerSingleton("stringFactoryBean", new StringFactoryBean());
@@ -455,7 +454,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testNullableFieldInjectionWithBeanAvailable() {
public void testNullableFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -464,7 +463,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testNullableFieldInjectionWithBeanNotAvailable() {
public void testNullableFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableFieldInjectionBean.class));
NullableFieldInjectionBean bean = (NullableFieldInjectionBean) bf.getBean("annotatedBean");
@@ -472,7 +471,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testNullableMethodInjectionWithBeanAvailable() {
public void testNullableMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -481,7 +480,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testNullableMethodInjectionWithBeanNotAvailable() {
public void testNullableMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(NullableMethodInjectionBean.class));
NullableMethodInjectionBean bean = (NullableMethodInjectionBean) bf.getBean("annotatedBean");
@@ -489,7 +488,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalFieldInjectionWithBeanAvailable() {
public void testOptionalFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -499,7 +498,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalFieldInjectionWithBeanNotAvailable() {
public void testOptionalFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
OptionalFieldInjectionBean bean = (OptionalFieldInjectionBean) bf.getBean("annotatedBean");
@@ -507,7 +506,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalMethodInjectionWithBeanAvailable() {
public void testOptionalMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -517,7 +516,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalMethodInjectionWithBeanNotAvailable() {
public void testOptionalMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
OptionalMethodInjectionBean bean = (OptionalMethodInjectionBean) bf.getBean("annotatedBean");
@@ -525,7 +524,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalListFieldInjectionWithBeanAvailable() {
public void testOptionalListFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -535,7 +534,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalListFieldInjectionWithBeanNotAvailable() {
public void testOptionalListFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListFieldInjectionBean.class));
OptionalListFieldInjectionBean bean = (OptionalListFieldInjectionBean) bf.getBean("annotatedBean");
@@ -543,7 +542,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalListMethodInjectionWithBeanAvailable() {
public void testOptionalListMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -553,7 +552,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testOptionalListMethodInjectionWithBeanNotAvailable() {
public void testOptionalListMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalListMethodInjectionBean.class));
OptionalListMethodInjectionBean bean = (OptionalListMethodInjectionBean) bf.getBean("annotatedBean");
@@ -561,7 +560,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testProviderOfOptionalFieldInjectionWithBeanAvailable() {
public void testProviderOfOptionalFieldInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -571,7 +570,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testProviderOfOptionalFieldInjectionWithBeanNotAvailable() {
public void testProviderOfOptionalFieldInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalFieldInjectionBean.class));
ProviderOfOptionalFieldInjectionBean bean = (ProviderOfOptionalFieldInjectionBean) bf.getBean("annotatedBean");
@@ -579,7 +578,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testProviderOfOptionalMethodInjectionWithBeanAvailable() {
public void testProviderOfOptionalMethodInjectionWithBeanAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
@@ -589,7 +588,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testProviderOfOptionalMethodInjectionWithBeanNotAvailable() {
public void testProviderOfOptionalMethodInjectionWithBeanNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ProviderOfOptionalMethodInjectionBean.class));
ProviderOfOptionalMethodInjectionBean bean = (ProviderOfOptionalMethodInjectionBean) bf.getBean("annotatedBean");
@@ -597,7 +596,7 @@ class InjectAnnotationBeanPostProcessorTests {
}
@Test
void testAnnotatedDefaultConstructor() {
public void testAnnotatedDefaultConstructor() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedDefaultConstructorBean.class));
assertThat(bf.getBean("annotatedBean")).isNotNull();
@@ -645,6 +644,7 @@ class InjectAnnotationBeanPostProcessorTests {
@Override
@Inject
@SuppressWarnings("deprecation")
public void setTestBean2(TestBean testBean2) {
super.setTestBean2(testBean2);
}
@@ -1108,6 +1108,25 @@ class InjectAnnotationBeanPostProcessorTests {
}
public static class StringFactoryBean implements FactoryBean<String> {
@Override
public String getObject() {
return "";
}
@Override
public Class<String> getObjectType() {
return String.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,13 +31,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Karl Pietrzak
* @author Juergen Hoeller
*/
class LookupAnnotationTests {
public class LookupAnnotationTests {
private DefaultListableBeanFactory beanFactory;
@BeforeEach
void setup() {
public void setup() {
beanFactory = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
aabpp.setBeanFactory(beanFactory);
@@ -51,7 +51,7 @@ class LookupAnnotationTests {
@Test
void testWithoutConstructorArg() {
public void testWithoutConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
Object expected = bean.get();
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -59,7 +59,7 @@ class LookupAnnotationTests {
}
@Test
void testWithOverloadedArg() {
public void testWithOverloadedArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.get("haha");
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -68,7 +68,7 @@ class LookupAnnotationTests {
}
@Test
void testWithOneConstructorArg() {
public void testWithOneConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.getOneArgument("haha");
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -77,7 +77,7 @@ class LookupAnnotationTests {
}
@Test
void testWithTwoConstructorArg() {
public void testWithTwoConstructorArg() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
TestBean expected = bean.getTwoArguments("haha", 72);
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -87,7 +87,7 @@ class LookupAnnotationTests {
}
@Test
void testWithThreeArgsShouldFail() {
public void testWithThreeArgsShouldFail() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
assertThatExceptionOfType(AbstractMethodError.class).as("TestBean has no three arg constructor").isThrownBy(() ->
bean.getThreeArguments("name", 1, 2));
@@ -95,7 +95,7 @@ class LookupAnnotationTests {
}
@Test
void testWithEarlyInjection() {
public void testWithEarlyInjection() {
AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
Object expected = bean.get();
assertThat(expected.getClass()).isEqualTo(TestBean.class);
@@ -115,7 +115,7 @@ class LookupAnnotationTests {
}
@Test
void testWithGenericBean() {
public void testWithGenericBean() {
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
@@ -126,7 +126,7 @@ class LookupAnnotationTests {
}
@Test
void testSingletonWithoutMetadataCaching() {
public void testSingletonWithoutMetadataCaching() {
beanFactory.setCacheBeanMetadata(false);
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
@@ -139,7 +139,7 @@ class LookupAnnotationTests {
}
@Test
void testPrototypeWithoutMetadataCaching() {
public void testPrototypeWithoutMetadataCaching() {
beanFactory.setCacheBeanMetadata(false);
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class, BeanDefinition.SCOPE_PROTOTYPE, null));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,35 +35,35 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ParameterResolutionDelegate}.
* Unit tests for {@link ParameterResolutionDelegate}.
*
* @author Sam Brannen
* @author Juergen Hoeller
* @author Loïc Ledoyen
*/
class ParameterResolutionTests {
public class ParameterResolutionTests {
@Test
void isAutowirablePreconditions() {
public void isAutowirablePreconditions() {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.isAutowirable(null, 0))
.withMessageContaining("Parameter must not be null");
}
@Test
void annotatedParametersInMethodAreCandidatesForAutowiring() throws Exception {
public void annotatedParametersInMethodAreCandidatesForAutowiring() throws Exception {
Method method = getClass().getDeclaredMethod("autowirableMethod", String.class, String.class, String.class, String.class);
assertAutowirableParameters(method);
}
@Test
void annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring() throws Exception {
public void annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring() throws Exception {
Constructor<?> constructor = AutowirableClass.class.getConstructor(String.class, String.class, String.class, String.class);
assertAutowirableParameters(constructor);
}
@Test
void annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring() throws Exception {
public void annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring() throws Exception {
Class<?> innerClass = AutowirableClass.InnerAutowirableClass.class;
assertThat(ClassUtils.isInnerClass(innerClass)).isTrue();
Constructor<?> constructor = innerClass.getConstructor(AutowirableClass.class, String.class, String.class);
@@ -81,7 +81,7 @@ class ParameterResolutionTests {
}
@Test
void nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring() throws Exception {
public void nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring() throws Exception {
Constructor<?> notAutowirableConstructor = AutowirableClass.class.getConstructor(String.class);
Parameter[] parameters = notAutowirableConstructor.getParameters();
@@ -92,21 +92,21 @@ class ParameterResolutionTests {
}
@Test
void resolveDependencyPreconditionsForParameter() {
public void resolveDependencyPreconditionsForParameter() {
assertThatIllegalArgumentException()
.isThrownBy(() -> ParameterResolutionDelegate.resolveDependency(null, 0, null, mock()))
.withMessageContaining("Parameter must not be null");
}
@Test
void resolveDependencyPreconditionsForContainingClass() {
public void resolveDependencyPreconditionsForContainingClass() throws Exception {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.resolveDependency(getParameter(), 0, null, null))
.withMessageContaining("Containing class must not be null");
}
@Test
void resolveDependencyPreconditionsForBeanFactory() {
public void resolveDependencyPreconditionsForBeanFactory() throws Exception {
assertThatIllegalArgumentException().isThrownBy(() ->
ParameterResolutionDelegate.resolveDependency(getParameter(), 0, getClass(), null))
.withMessageContaining("AutowireCapableBeanFactory must not be null");
@@ -118,7 +118,7 @@ class ParameterResolutionTests {
}
@Test
void resolveDependencyForAnnotatedParametersInTopLevelClassConstructor() throws Exception {
public void resolveDependencyForAnnotatedParametersInTopLevelClassConstructor() throws Exception {
Constructor<?> constructor = AutowirableClass.class.getConstructor(String.class, String.class, String.class, String.class);
AutowireCapableBeanFactory beanFactory = mock();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -692,7 +692,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
@Nullable
@Override
public String getObject() {
public String getObject() throws Exception {
return getPrefix() + " " + getName();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@ import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.InjectAnnotationBeanPostProcessorTests.StringFactoryBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.factory.DummyFactory;
import org.springframework.beans.testfixture.beans.factory.StringFactoryBean;
import org.springframework.beans.testfixture.beans.factory.aot.GenericFactoryBean;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationCode;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationsCode;
@@ -275,7 +275,7 @@ class DefaultBeanRegistrationCodeFragmentsTests {
static class PrivilegedTestBeanFactoryBean implements FactoryBean<SimpleBean> {
@Override
public SimpleBean getObject() {
public SimpleBean getObject() throws Exception {
return new SimpleBean();
}

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