Migrate to Asciidoctor Tabs
This commit is contained in:
parent
71154fd16b
commit
39146f9066
|
|
@ -4,8 +4,6 @@
|
||||||
antora:
|
antora:
|
||||||
extensions:
|
extensions:
|
||||||
- '@antora/collector-extension'
|
- '@antora/collector-extension'
|
||||||
- require: '@springio/antora-extensions/tabs-migration-extension'
|
|
||||||
unwrap_example_block: always
|
|
||||||
site:
|
site:
|
||||||
title: Spring Framework Reference
|
title: Spring Framework Reference
|
||||||
url: https://https://rwinch.github.io/spring-framework/
|
url: https://https://rwinch.github.io/spring-framework/
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,11 @@ point.
|
||||||
|
|
||||||
The following example shows a simple `MethodInterceptor` implementation:
|
The following example shows a simple `MethodInterceptor` implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class DebugInterceptor implements MethodInterceptor {
|
public class DebugInterceptor implements MethodInterceptor {
|
||||||
|
|
||||||
|
|
@ -67,8 +70,10 @@ The following example shows a simple `MethodInterceptor` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DebugInterceptor : MethodInterceptor {
|
class DebugInterceptor : MethodInterceptor {
|
||||||
|
|
||||||
|
|
@ -80,6 +85,7 @@ The following example shows a simple `MethodInterceptor` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Note the call to the `proceed()` method of `MethodInvocation`. This proceeds down the
|
Note the call to the `proceed()` method of `MethodInvocation`. This proceeds down the
|
||||||
interceptor chain towards the join point. Most interceptors invoke this method and
|
interceptor chain towards the join point. Most interceptors invoke this method and
|
||||||
|
|
@ -129,8 +135,11 @@ wrapped in an unchecked exception by the AOP proxy.
|
||||||
|
|
||||||
The following example shows a before advice in Spring, which counts all method invocations:
|
The following example shows a before advice in Spring, which counts all method invocations:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class CountingBeforeAdvice implements MethodBeforeAdvice {
|
public class CountingBeforeAdvice implements MethodBeforeAdvice {
|
||||||
|
|
||||||
|
|
@ -145,8 +154,10 @@ The following example shows a before advice in Spring, which counts all method i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CountingBeforeAdvice : MethodBeforeAdvice {
|
class CountingBeforeAdvice : MethodBeforeAdvice {
|
||||||
|
|
||||||
|
|
@ -157,6 +168,7 @@ The following example shows a before advice in Spring, which counts all method i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
TIP: Before advice can be used with any pointcut.
|
TIP: Before advice can be used with any pointcut.
|
||||||
|
|
||||||
|
|
@ -181,8 +193,11 @@ arguments. The next two listing show classes that are examples of throws advice.
|
||||||
|
|
||||||
The following advice is invoked if a `RemoteException` is thrown (including from subclasses):
|
The following advice is invoked if a `RemoteException` is thrown (including from subclasses):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class RemoteThrowsAdvice implements ThrowsAdvice {
|
public class RemoteThrowsAdvice implements ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -191,8 +206,10 @@ The following advice is invoked if a `RemoteException` is thrown (including from
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class RemoteThrowsAdvice : ThrowsAdvice {
|
class RemoteThrowsAdvice : ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -201,13 +218,17 @@ The following advice is invoked if a `RemoteException` is thrown (including from
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Unlike the preceding
|
Unlike the preceding
|
||||||
advice, the next example declares four arguments, so that it has access to the invoked method, method
|
advice, the next example declares four arguments, so that it has access to the invoked method, method
|
||||||
arguments, and target object. The following advice is invoked if a `ServletException` is thrown:
|
arguments, and target object. The following advice is invoked if a `ServletException` is thrown:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
|
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -216,8 +237,10 @@ arguments, and target object. The following advice is invoked if a `ServletExcep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ServletThrowsAdviceWithArguments : ThrowsAdvice {
|
class ServletThrowsAdviceWithArguments : ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -226,13 +249,17 @@ arguments, and target object. The following advice is invoked if a `ServletExcep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The final example illustrates how these two methods could be used in a single class
|
The final example illustrates how these two methods could be used in a single class
|
||||||
that handles both `RemoteException` and `ServletException`. Any number of throws advice
|
that handles both `RemoteException` and `ServletException`. Any number of throws advice
|
||||||
methods can be combined in a single class. The following listing shows the final example:
|
methods can be combined in a single class. The following listing shows the final example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static class CombinedThrowsAdvice implements ThrowsAdvice {
|
public static class CombinedThrowsAdvice implements ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -245,8 +272,10 @@ methods can be combined in a single class. The following listing shows the final
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CombinedThrowsAdvice : ThrowsAdvice {
|
class CombinedThrowsAdvice : ThrowsAdvice {
|
||||||
|
|
||||||
|
|
@ -259,6 +288,7 @@ methods can be combined in a single class. The following listing shows the final
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: If a throws-advice method throws an exception itself, it overrides the
|
NOTE: If a throws-advice method throws an exception itself, it overrides the
|
||||||
original exception (that is, it changes the exception thrown to the user). The overriding
|
original exception (that is, it changes the exception thrown to the user). The overriding
|
||||||
|
|
@ -292,8 +322,11 @@ the invoked method, the method's arguments, and the target.
|
||||||
The following after returning advice counts all successful method invocations that have
|
The following after returning advice counts all successful method invocations that have
|
||||||
not thrown exceptions:
|
not thrown exceptions:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
|
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
|
||||||
|
|
||||||
|
|
@ -309,8 +342,10 @@ not thrown exceptions:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CountingAfterReturningAdvice : AfterReturningAdvice {
|
class CountingAfterReturningAdvice : AfterReturningAdvice {
|
||||||
|
|
||||||
|
|
@ -322,6 +357,7 @@ not thrown exceptions:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This advice does not change the execution path. If it throws an exception, it is
|
This advice does not change the execution path. If it throws an exception, it is
|
||||||
thrown up the interceptor chain instead of the return value.
|
thrown up the interceptor chain instead of the return value.
|
||||||
|
|
@ -380,8 +416,11 @@ introduced interfaces can be implemented by the configured `IntroductionIntercep
|
||||||
Consider an example from the Spring test suite and suppose we want to
|
Consider an example from the Spring test suite and suppose we want to
|
||||||
introduce the following interface to one or more objects:
|
introduce the following interface to one or more objects:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public interface Lockable {
|
public interface Lockable {
|
||||||
void lock();
|
void lock();
|
||||||
|
|
@ -389,8 +428,10 @@ introduce the following interface to one or more objects:
|
||||||
boolean locked();
|
boolean locked();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
interface Lockable {
|
interface Lockable {
|
||||||
fun lock()
|
fun lock()
|
||||||
|
|
@ -398,6 +439,7 @@ introduce the following interface to one or more objects:
|
||||||
fun locked(): Boolean
|
fun locked(): Boolean
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This illustrates a mixin. We want to be able to cast advised objects to `Lockable`,
|
This illustrates a mixin. We want to be able to cast advised objects to `Lockable`,
|
||||||
whatever their type and call lock and unlock methods. If we call the `lock()` method, we
|
whatever their type and call lock and unlock methods. If we call the `lock()` method, we
|
||||||
|
|
@ -434,8 +476,11 @@ to that held in the target object.
|
||||||
|
|
||||||
The following example shows the example `LockMixin` class:
|
The following example shows the example `LockMixin` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
|
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
|
||||||
|
|
||||||
|
|
@ -462,8 +507,10 @@ The following example shows the example `LockMixin` class:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class LockMixin : DelegatingIntroductionInterceptor(), Lockable {
|
class LockMixin : DelegatingIntroductionInterceptor(), Lockable {
|
||||||
|
|
||||||
|
|
@ -490,6 +537,7 @@ The following example shows the example `LockMixin` class:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Often, you need not override the `invoke()` method. The
|
Often, you need not override the `invoke()` method. The
|
||||||
`DelegatingIntroductionInterceptor` implementation (which calls the `delegate` method if
|
`DelegatingIntroductionInterceptor` implementation (which calls the `delegate` method if
|
||||||
|
|
@ -504,8 +552,11 @@ interceptor (which would be defined as a prototype). In this case, there is no
|
||||||
configuration relevant for a `LockMixin`, so we create it by using `new`.
|
configuration relevant for a `LockMixin`, so we create it by using `new`.
|
||||||
The following example shows our `LockMixinAdvisor` class:
|
The following example shows our `LockMixinAdvisor` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
|
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
|
||||||
|
|
||||||
|
|
@ -514,11 +565,14 @@ The following example shows our `LockMixinAdvisor` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class LockMixinAdvisor : DefaultIntroductionAdvisor(LockMixin(), Lockable::class.java)
|
class LockMixinAdvisor : DefaultIntroductionAdvisor(LockMixin(), Lockable::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
We can apply this advisor very simply, because it requires no configuration. (However, it
|
We can apply this advisor very simply, because it requires no configuration. (However, it
|
||||||
is impossible to use an `IntroductionInterceptor` without an
|
is impossible to use an `IntroductionInterceptor` without an
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ However you create AOP proxies, you can manipulate them BY using the
|
||||||
interface, no matter which other interfaces it implements. This interface includes the
|
interface, no matter which other interfaces it implements. This interface includes the
|
||||||
following methods:
|
following methods:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Advisor[] getAdvisors();
|
Advisor[] getAdvisors();
|
||||||
|
|
||||||
|
|
@ -29,8 +32,10 @@ following methods:
|
||||||
|
|
||||||
boolean isFrozen();
|
boolean isFrozen();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun getAdvisors(): Array<Advisor>
|
fun getAdvisors(): Array<Advisor>
|
||||||
|
|
||||||
|
|
@ -59,6 +64,7 @@ following methods:
|
||||||
|
|
||||||
fun isFrozen(): Boolean
|
fun isFrozen(): Boolean
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `getAdvisors()` method returns an `Advisor` for every advisor, interceptor, or
|
The `getAdvisors()` method returns an `Advisor` for every advisor, interceptor, or
|
||||||
other advice type that has been added to the factory. If you added an `Advisor`, the
|
other advice type that has been added to the factory. If you added an `Advisor`, the
|
||||||
|
|
@ -80,8 +86,11 @@ change. (You can obtain a new proxy from the factory to avoid this problem.)
|
||||||
The following example shows casting an AOP proxy to the `Advised` interface and examining and
|
The following example shows casting an AOP proxy to the `Advised` interface and examining and
|
||||||
manipulating its advice:
|
manipulating its advice:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Advised advised = (Advised) myObject;
|
Advised advised = (Advised) myObject;
|
||||||
Advisor[] advisors = advised.getAdvisors();
|
Advisor[] advisors = advised.getAdvisors();
|
||||||
|
|
@ -98,8 +107,10 @@ manipulating its advice:
|
||||||
|
|
||||||
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
|
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val advised = myObject as Advised
|
val advised = myObject as Advised
|
||||||
val advisors = advised.advisors
|
val advisors = advised.advisors
|
||||||
|
|
@ -116,6 +127,7 @@ manipulating its advice:
|
||||||
|
|
||||||
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.advisors.size)
|
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.advisors.size)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: It is questionable whether it is advisable (no pun intended) to modify advice on a
|
NOTE: It is questionable whether it is advisable (no pun intended) to modify advice on a
|
||||||
business object in production, although there are, no doubt, legitimate usage cases.
|
business object in production, although there are, no doubt, legitimate usage cases.
|
||||||
|
|
|
||||||
|
|
@ -192,16 +192,22 @@ an instance of the prototype from the factory. Holding a reference is not suffic
|
||||||
The `person` bean definition shown earlier can be used in place of a `Person` implementation, as
|
The `person` bean definition shown earlier can be used in place of a `Person` implementation, as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Person person = (Person) factory.getBean("person");
|
Person person = (Person) factory.getBean("person");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val person = factory.getBean("person") as Person;
|
val person = factory.getBean("person") as Person;
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Other beans in the same IoC context can express a strongly typed dependency on it, as
|
Other beans in the same IoC context can express a strongly typed dependency on it, as
|
||||||
with an ordinary Java object. The following example shows how to do so:
|
with an ordinary Java object. The following example shows how to do so:
|
||||||
|
|
|
||||||
|
|
@ -208,8 +208,11 @@ Because static pointcuts are most useful, you should probably subclass
|
||||||
abstract method (although you can override other methods to customize behavior). The
|
abstract method (although you can override other methods to customize behavior). The
|
||||||
following example shows how to subclass `StaticMethodMatcherPointcut`:
|
following example shows how to subclass `StaticMethodMatcherPointcut`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
class TestStaticPointcut extends StaticMethodMatcherPointcut {
|
class TestStaticPointcut extends StaticMethodMatcherPointcut {
|
||||||
|
|
||||||
|
|
@ -218,8 +221,10 @@ following example shows how to subclass `StaticMethodMatcherPointcut`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TestStaticPointcut : StaticMethodMatcherPointcut() {
|
class TestStaticPointcut : StaticMethodMatcherPointcut() {
|
||||||
|
|
||||||
|
|
@ -228,6 +233,7 @@ following example shows how to subclass `StaticMethodMatcherPointcut`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
There are also superclasses for dynamic pointcuts.
|
There are also superclasses for dynamic pointcuts.
|
||||||
You can use custom pointcuts with any advice type.
|
You can use custom pointcuts with any advice type.
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,28 @@ The interfaces implemented by the target object are
|
||||||
automatically proxied. The following listing shows creation of a proxy for a target object, with one
|
automatically proxied. The following listing shows creation of a proxy for a target object, with one
|
||||||
interceptor and one advisor:
|
interceptor and one advisor:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
|
ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
|
||||||
factory.addAdvice(myMethodInterceptor);
|
factory.addAdvice(myMethodInterceptor);
|
||||||
factory.addAdvisor(myAdvisor);
|
factory.addAdvisor(myAdvisor);
|
||||||
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();
|
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val factory = ProxyFactory(myBusinessInterfaceImpl)
|
val factory = ProxyFactory(myBusinessInterfaceImpl)
|
||||||
factory.addAdvice(myMethodInterceptor)
|
factory.addAdvice(myMethodInterceptor)
|
||||||
factory.addAdvisor(myAdvisor)
|
factory.addAdvisor(myAdvisor)
|
||||||
val tb = factory.proxy as MyBusinessInterface
|
val tb = factory.proxy as MyBusinessInterface
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The first step is to construct an object of type
|
The first step is to construct an object of type
|
||||||
`org.springframework.aop.framework.ProxyFactory`. You can create this with a target
|
`org.springframework.aop.framework.ProxyFactory`. You can create this with a target
|
||||||
|
|
|
||||||
|
|
@ -34,18 +34,24 @@ Changing the target source's target takes effect immediately. The
|
||||||
|
|
||||||
You can change the target by using the `swap()` method on HotSwappableTargetSource, as the follow example shows:
|
You can change the target by using the `swap()` method on HotSwappableTargetSource, as the follow example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
|
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
|
||||||
Object oldTarget = swapper.swap(newTarget);
|
Object oldTarget = swapper.swap(newTarget);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
|
val swapper = beanFactory.getBean("swapper") as HotSwappableTargetSource
|
||||||
val oldTarget = swapper.swap(newTarget)
|
val oldTarget = swapper.swap(newTarget)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows the required XML definitions:
|
The following example shows the required XML definitions:
|
||||||
|
|
||||||
|
|
@ -142,18 +148,24 @@ the `ProxyFactoryBean` that exposes the pooled object.
|
||||||
|
|
||||||
The cast is defined as follows:
|
The cast is defined as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
|
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
|
||||||
System.out.println("Max pool size is " + conf.getMaxSize());
|
System.out.println("Max pool size is " + conf.getMaxSize());
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val conf = beanFactory.getBean("businessObject") as PoolingConfig
|
val conf = beanFactory.getBean("businessObject") as PoolingConfig
|
||||||
println("Max pool size is " + conf.maxSize)
|
println("Max pool size is " + conf.maxSize)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: Pooling stateless service objects is not usually necessary. We do not believe it should
|
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
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,11 @@ You can use the `org.springframework.aop.aspectj.annotation.AspectJProxyFactory`
|
||||||
to create a proxy for a target object that is advised by one or more @AspectJ aspects.
|
to create a proxy for a target object that is advised by one or more @AspectJ aspects.
|
||||||
The basic usage for this class is very simple, as the following example shows:
|
The basic usage for this class is very simple, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// create a factory that can generate a proxy for the given target object
|
// create a factory that can generate a proxy for the given target object
|
||||||
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
|
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
|
||||||
|
|
@ -28,8 +31,10 @@ The basic usage for this class is very simple, as the following example shows:
|
||||||
// now get the proxy object...
|
// now get the proxy object...
|
||||||
MyInterfaceType proxy = factory.getProxy();
|
MyInterfaceType proxy = factory.getProxy();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// create a factory that can generate a proxy for the given target object
|
// create a factory that can generate a proxy for the given target object
|
||||||
val factory = AspectJProxyFactory(targetObject)
|
val factory = AspectJProxyFactory(targetObject)
|
||||||
|
|
@ -45,6 +50,7 @@ The basic usage for this class is very simple, as the following example shows:
|
||||||
// now get the proxy object...
|
// now get the proxy object...
|
||||||
val proxy = factory.getProxy<Any>()
|
val proxy = factory.getProxy<Any>()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the {api-spring-framework}/aop/aspectj/annotation/AspectJProxyFactory.html[javadoc] for more information.
|
See the {api-spring-framework}/aop/aspectj/annotation/AspectJProxyFactory.html[javadoc] for more information.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ You can declare before advice in an aspect by using the `@Before` annotation.
|
||||||
|
|
||||||
The following example uses an inline pointcut expression.
|
The following example uses an inline pointcut expression.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Before;
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
|
@ -28,8 +31,10 @@ The following example uses an inline pointcut expression.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.Before
|
import org.aspectj.lang.annotation.Before
|
||||||
|
|
@ -43,12 +48,16 @@ The following example uses an inline pointcut expression.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If we use a xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[named pointcut], we can rewrite the preceding example
|
If we use a xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[named pointcut], we can rewrite the preceding example
|
||||||
as follows:
|
as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Before;
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
|
@ -62,8 +71,10 @@ as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.Before
|
import org.aspectj.lang.annotation.Before
|
||||||
|
|
@ -77,6 +88,7 @@ as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[aop-advice-after-returning]]
|
[[aop-advice-after-returning]]
|
||||||
|
|
@ -85,8 +97,11 @@ as follows:
|
||||||
After returning advice runs when a matched method execution returns normally.
|
After returning advice runs when a matched method execution returns normally.
|
||||||
You can declare it by using the `@AfterReturning` annotation.
|
You can declare it by using the `@AfterReturning` annotation.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
|
@ -100,8 +115,10 @@ You can declare it by using the `@AfterReturning` annotation.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.AfterReturning
|
import org.aspectj.lang.annotation.AfterReturning
|
||||||
|
|
@ -115,6 +132,7 @@ You can declare it by using the `@AfterReturning` annotation.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: You can have multiple advice declarations (and other members as well),
|
NOTE: You can have multiple advice declarations (and other members as well),
|
||||||
all inside the same aspect. We show only a single advice declaration in these
|
all inside the same aspect. We show only a single advice declaration in these
|
||||||
|
|
@ -124,8 +142,11 @@ Sometimes, you need access in the advice body to the actual value that was retur
|
||||||
You can use the form of `@AfterReturning` that binds the return value to get that
|
You can use the form of `@AfterReturning` that binds the return value to get that
|
||||||
access, as the following example shows:
|
access, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
|
@ -141,8 +162,10 @@ access, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.AfterReturning
|
import org.aspectj.lang.annotation.AfterReturning
|
||||||
|
|
@ -158,6 +181,7 @@ access, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The name used in the `returning` attribute must correspond to the name of a parameter
|
The name used in the `returning` attribute must correspond to the name of a parameter
|
||||||
in the advice method. When a method execution returns, the return value is passed to
|
in the advice method. When a method execution returns, the return value is passed to
|
||||||
|
|
@ -176,8 +200,11 @@ After throwing advice runs when a matched method execution exits by throwing an
|
||||||
exception. You can declare it by using the `@AfterThrowing` annotation, as the
|
exception. You can declare it by using the `@AfterThrowing` annotation, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.AfterThrowing;
|
import org.aspectj.lang.annotation.AfterThrowing;
|
||||||
|
|
@ -191,8 +218,10 @@ following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.AfterThrowing
|
import org.aspectj.lang.annotation.AfterThrowing
|
||||||
|
|
@ -206,6 +235,7 @@ following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Often, you want the advice to run only when exceptions of a given type are thrown,
|
Often, you want the advice to run only when exceptions of a given type are thrown,
|
||||||
and you also often need access to the thrown exception in the advice body. You can
|
and you also often need access to the thrown exception in the advice body. You can
|
||||||
|
|
@ -213,8 +243,11 @@ use the `throwing` attribute to both restrict matching (if desired -- use `Throw
|
||||||
as the exception type otherwise) and bind the thrown exception to an advice parameter.
|
as the exception type otherwise) and bind the thrown exception to an advice parameter.
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.AfterThrowing;
|
import org.aspectj.lang.annotation.AfterThrowing;
|
||||||
|
|
@ -230,8 +263,10 @@ The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.AfterThrowing
|
import org.aspectj.lang.annotation.AfterThrowing
|
||||||
|
|
@ -247,6 +282,7 @@ The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The name used in the `throwing` attribute must correspond to the name of a parameter in
|
The name used in the `throwing` attribute must correspond to the name of a parameter in
|
||||||
the advice method. When a method execution exits by throwing an exception, the exception
|
the advice method. When a method execution exits by throwing an exception, the exception
|
||||||
|
|
@ -271,8 +307,11 @@ using the `@After` annotation. After advice must be prepared to handle both norm
|
||||||
exception return conditions. It is typically used for releasing resources and similar
|
exception return conditions. It is typically used for releasing resources and similar
|
||||||
purposes. The following example shows how to use after finally advice:
|
purposes. The following example shows how to use after finally advice:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.After;
|
import org.aspectj.lang.annotation.After;
|
||||||
|
|
@ -286,8 +325,10 @@ purposes. The following example shows how to use after finally advice:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.After
|
import org.aspectj.lang.annotation.After
|
||||||
|
|
@ -301,6 +342,7 @@ purposes. The following example shows how to use after finally advice:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -371,8 +413,11 @@ value depending on the use case.
|
||||||
|
|
||||||
The following example shows how to use around advice:
|
The following example shows how to use around advice:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
|
@ -390,8 +435,10 @@ The following example shows how to use around advice:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.Around
|
import org.aspectj.lang.annotation.Around
|
||||||
|
|
@ -409,6 +456,7 @@ The following example shows how to use around advice:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[aop-ataspectj-advice-params]]
|
[[aop-ataspectj-advice-params]]
|
||||||
== Advice Parameters
|
== Advice Parameters
|
||||||
|
|
@ -448,22 +496,28 @@ Suppose you want to advise the execution of DAO operations that take an `Account
|
||||||
object as the first parameter, and you need access to the account in the advice body.
|
object as the first parameter, and you need access to the account in the advice body.
|
||||||
You could write the following:
|
You could write the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
||||||
public void validateAccount(Account account) {
|
public void validateAccount(Account account) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
||||||
fun validateAccount(account: Account) {
|
fun validateAccount(account: Account) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `args(account,..)` part of the pointcut expression serves two purposes. First, it
|
The `args(account,..)` part of the pointcut expression serves two purposes. First, it
|
||||||
restricts matching to only those method executions where the method takes at least one
|
restricts matching to only those method executions where the method takes at least one
|
||||||
|
|
@ -475,8 +529,11 @@ Another way of writing this is to declare a pointcut that "provides" the `Accoun
|
||||||
object value when it matches a join point, and then refer to the named pointcut
|
object value when it matches a join point, and then refer to the named pointcut
|
||||||
from the advice. This would look as follows:
|
from the advice. This would look as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
||||||
private void accountDataAccessOperation(Account account) {}
|
private void accountDataAccessOperation(Account account) {}
|
||||||
|
|
@ -486,8 +543,10 @@ from the advice. This would look as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
|
||||||
private fun accountDataAccessOperation(account: Account) {
|
private fun accountDataAccessOperation(account: Account) {
|
||||||
|
|
@ -498,6 +557,7 @@ from the advice. This would look as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the AspectJ programming guide for more details.
|
See the AspectJ programming guide for more details.
|
||||||
|
|
||||||
|
|
@ -508,8 +568,11 @@ set of examples shows how to match the execution of methods annotated with an
|
||||||
|
|
||||||
The following shows the definition of the `@Auditable` annotation:
|
The following shows the definition of the `@Auditable` annotation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
|
|
@ -517,18 +580,24 @@ The following shows the definition of the `@Auditable` annotation:
|
||||||
AuditCode value();
|
AuditCode value();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
annotation class Auditable(val value: AuditCode)
|
annotation class Auditable(val value: AuditCode)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following shows the advice that matches the execution of `@Auditable` methods:
|
The following shows the advice that matches the execution of `@Auditable` methods:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
|
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
|
||||||
public void audit(Auditable auditable) {
|
public void audit(Auditable auditable) {
|
||||||
|
|
@ -536,6 +605,7 @@ The following shows the advice that matches the execution of `@Auditable` method
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
|
|
@ -555,62 +625,80 @@ The following shows the advice that matches the execution of `@Auditable` method
|
||||||
Spring AOP can handle generics used in class declarations and method parameters. Suppose
|
Spring AOP can handle generics used in class declarations and method parameters. Suppose
|
||||||
you have a generic type like the following:
|
you have a generic type like the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public interface Sample<T> {
|
public interface Sample<T> {
|
||||||
void sampleGenericMethod(T param);
|
void sampleGenericMethod(T param);
|
||||||
void sampleGenericCollectionMethod(Collection<T> param);
|
void sampleGenericCollectionMethod(Collection<T> param);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
interface Sample<T> {
|
interface Sample<T> {
|
||||||
fun sampleGenericMethod(param: T)
|
fun sampleGenericMethod(param: T)
|
||||||
fun sampleGenericCollectionMethod(param: Collection<T>)
|
fun sampleGenericCollectionMethod(param: Collection<T>)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can restrict interception of method types to certain parameter types by
|
You can restrict interception of method types to certain parameter types by
|
||||||
tying the advice parameter to the parameter type for which you want to intercept the method:
|
tying the advice parameter to the parameter type for which you want to intercept the method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
|
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
|
||||||
public void beforeSampleMethod(MyType param) {
|
public void beforeSampleMethod(MyType param) {
|
||||||
// Advice implementation
|
// Advice implementation
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
|
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
|
||||||
fun beforeSampleMethod(param: MyType) {
|
fun beforeSampleMethod(param: MyType) {
|
||||||
// Advice implementation
|
// Advice implementation
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This approach does not work for generic collections. So you cannot define a
|
This approach does not work for generic collections. So you cannot define a
|
||||||
pointcut as follows:
|
pointcut as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
|
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
|
||||||
public void beforeSampleMethod(Collection<MyType> param) {
|
public void beforeSampleMethod(Collection<MyType> param) {
|
||||||
// Advice implementation
|
// Advice implementation
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
|
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
|
||||||
fun beforeSampleMethod(param: Collection<MyType>) {
|
fun beforeSampleMethod(param: Collection<MyType>) {
|
||||||
// Advice implementation
|
// Advice implementation
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To make this work, we would have to inspect every element of the collection, which is not
|
To make this work, we would have to inspect every element of the collection, which is not
|
||||||
reasonable, as we also cannot decide how to treat `null` values in general. To achieve
|
reasonable, as we also cannot decide how to treat `null` values in general. To achieve
|
||||||
|
|
@ -668,8 +756,11 @@ needed information.
|
||||||
|
|
||||||
The following example shows how to use the `argNames` attribute:
|
The following example shows how to use the `argNames` attribute:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before(
|
@Before(
|
||||||
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
|
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
|
||||||
|
|
@ -679,6 +770,7 @@ The following example shows how to use the `argNames` attribute:
|
||||||
// ... use code and bean
|
// ... use code and bean
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
||||||
<2> Declares `bean` and `auditable` as the argument names.
|
<2> Declares `bean` and `auditable` as the argument names.
|
||||||
|
|
||||||
|
|
@ -701,8 +793,11 @@ If the first parameter is of type `JoinPoint`, `ProceedingJoinPoint`, or
|
||||||
`argNames` attribute. For example, if you modify the preceding advice to receive the join
|
`argNames` attribute. For example, if you modify the preceding advice to receive the join
|
||||||
point object, the `argNames` attribute does not need to include it:
|
point object, the `argNames` attribute does not need to include it:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before(
|
@Before(
|
||||||
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
|
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
|
||||||
|
|
@ -712,6 +807,7 @@ point object, the `argNames` attribute does not need to include it:
|
||||||
// ... use code, bean, and jp
|
// ... use code, bean, and jp
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
||||||
<2> Declares `bean` and `auditable` as the argument names.
|
<2> Declares `bean` and `auditable` as the argument names.
|
||||||
|
|
||||||
|
|
@ -735,14 +831,18 @@ methods that do not collect any other join point context. In such situations, yo
|
||||||
omit the `argNames` attribute. For example, the following advice does not need to declare
|
omit the `argNames` attribute. For example, the following advice does not need to declare
|
||||||
the `argNames` attribute:
|
the `argNames` attribute:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
|
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
|
||||||
public void audit(JoinPoint jp) {
|
public void audit(JoinPoint jp) {
|
||||||
// ... use jp
|
// ... use jp
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
|
|
@ -764,8 +864,11 @@ arguments that works consistently across Spring AOP and AspectJ. The solution is
|
||||||
to ensure that the advice signature binds each of the method parameters in order.
|
to ensure that the advice signature binds each of the method parameters in order.
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Around("execution(List<Account> find*(..)) && " +
|
@Around("execution(List<Account> find*(..)) && " +
|
||||||
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
|
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
|
||||||
|
|
@ -776,6 +879,7 @@ The following example shows how to do so:
|
||||||
return pjp.proceed(new Object[] {newPattern});
|
return pjp.proceed(new Object[] {newPattern});
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
|
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
|
|
|
||||||
|
|
@ -19,21 +19,27 @@ classpath of your application (version 1.9 or later). This library is available
|
||||||
|
|
||||||
To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy`
|
To enable @AspectJ support with Java `@Configuration`, add the `@EnableAspectJAutoProxy`
|
||||||
annotation, as the following example shows:
|
annotation, as the following example shows:
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableAspectJAutoProxy
|
@EnableAspectJAutoProxy
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableAspectJAutoProxy
|
@EnableAspectJAutoProxy
|
||||||
class AppConfig
|
class AppConfig
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[aop-enable-aspectj-xml]]
|
[[aop-enable-aspectj-xml]]
|
||||||
== Enabling @AspectJ Support with XML Configuration
|
== Enabling @AspectJ Support with XML Configuration
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,11 @@ that points to a bean class that is annotated with `@Aspect`:
|
||||||
The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is
|
The second of the two examples shows the `NotVeryUsefulAspect` class definition, which is
|
||||||
annotated with `@Aspect`:
|
annotated with `@Aspect`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -30,8 +33,10 @@ annotated with `@Aspect`:
|
||||||
public class NotVeryUsefulAspect {
|
public class NotVeryUsefulAspect {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -40,6 +45,7 @@ annotated with `@Aspect`:
|
||||||
@Aspect
|
@Aspect
|
||||||
class NotVeryUsefulAspect
|
class NotVeryUsefulAspect
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Aspects (classes annotated with `@Aspect`) can have methods and fields, the same as any
|
Aspects (classes annotated with `@Aspect`) can have methods and fields, the same as any
|
||||||
other class. They can also contain pointcut, advice, and introduction (inter-type)
|
other class. They can also contain pointcut, advice, and introduction (inter-type)
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,11 @@ aspect.
|
||||||
Because we want to retry the operation, we need to use around advice so that we can
|
Because we want to retry the operation, we need to use around advice so that we can
|
||||||
call `proceed` multiple times. The following listing shows the basic aspect implementation:
|
call `proceed` multiple times. The following listing shows the basic aspect implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Aspect
|
@Aspect
|
||||||
public class ConcurrentOperationExecutor implements Ordered {
|
public class ConcurrentOperationExecutor implements Ordered {
|
||||||
|
|
@ -56,6 +59,7 @@ call `proceed` multiple times. The following listing shows the basic aspect impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
|
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
|
|
@ -123,28 +127,37 @@ The corresponding Spring configuration follows:
|
||||||
To refine the aspect so that it retries only idempotent operations, we might define the following
|
To refine the aspect so that it retries only idempotent operations, we might define the following
|
||||||
`Idempotent` annotation:
|
`Idempotent` annotation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
// marker annotation
|
// marker annotation
|
||||||
public @interface Idempotent {
|
public @interface Idempotent {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
// marker annotation
|
// marker annotation
|
||||||
annotation class Idempotent
|
annotation class Idempotent
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
We can then use the annotation to annotate the implementation of service operations. The change
|
We can then use the annotation to annotate the implementation of service operations. The change
|
||||||
to the aspect to retry only idempotent operations involves refining the pointcut
|
to the aspect to retry only idempotent operations involves refining the pointcut
|
||||||
expression so that only `@Idempotent` operations match, as follows:
|
expression so that only `@Idempotent` operations match, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Around("execution(* com.xyz..service.*.*(..)) && " +
|
@Around("execution(* com.xyz..service.*.*(..)) && " +
|
||||||
"@annotation(com.xyz.service.Idempotent)")
|
"@annotation(com.xyz.service.Idempotent)")
|
||||||
|
|
@ -152,8 +165,10 @@ expression so that only `@Idempotent` operations match, as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Around("execution(* com.xyz..service.*.*(..)) && " +
|
@Around("execution(* com.xyz..service.*.*(..)) && " +
|
||||||
"@annotation(com.xyz.service.Idempotent)")
|
"@annotation(com.xyz.service.Idempotent)")
|
||||||
|
|
@ -161,6 +176,7 @@ expression so that only `@Idempotent` operations match, as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ supported.
|
||||||
You can declare a `perthis` aspect by specifying a `perthis` clause in the `@Aspect`
|
You can declare a `perthis` aspect by specifying a `perthis` clause in the `@Aspect`
|
||||||
annotation. Consider the following example:
|
annotation. Consider the following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
|
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
|
||||||
public class MyAspect {
|
public class MyAspect {
|
||||||
|
|
@ -27,8 +30,10 @@ annotation. Consider the following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
|
@Aspect("perthis(execution(* com.xyz..service.*.*(..)))")
|
||||||
class MyAspect {
|
class MyAspect {
|
||||||
|
|
@ -41,6 +46,7 @@ annotation. Consider the following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example, the effect of the `perthis` clause is that one aspect instance
|
In the preceding example, the effect of the `perthis` clause is that one aspect instance
|
||||||
is created for each unique service object that performs a business service (each unique
|
is created for each unique service object that performs a business service (each unique
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,11 @@ given an interface named `UsageTracked` and an implementation of that interface
|
||||||
`DefaultUsageTracked`, the following aspect declares that all implementors of service
|
`DefaultUsageTracked`, the following aspect declares that all implementors of service
|
||||||
interfaces also implement the `UsageTracked` interface (e.g. for statistics via JMX):
|
interfaces also implement the `UsageTracked` interface (e.g. for statistics via JMX):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Aspect
|
@Aspect
|
||||||
public class UsageTracking {
|
public class UsageTracking {
|
||||||
|
|
@ -27,8 +30,10 @@ interfaces also implement the `UsageTracked` interface (e.g. for statistics via
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Aspect
|
@Aspect
|
||||||
class UsageTracking {
|
class UsageTracking {
|
||||||
|
|
@ -45,6 +50,7 @@ interfaces also implement the `UsageTracked` interface (e.g. for statistics via
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The interface to be implemented is determined by the type of the annotated field. The
|
The interface to be implemented is determined by the type of the annotated field. The
|
||||||
`value` attribute of the `@DeclareParents` annotation is an AspectJ type pattern. Any
|
`value` attribute of the `@DeclareParents` annotation is an AspectJ type pattern. Any
|
||||||
|
|
@ -53,15 +59,21 @@ before advice of the preceding example, service beans can be directly used as
|
||||||
implementations of the `UsageTracked` interface. If accessing a bean programmatically,
|
implementations of the `UsageTracked` interface. If accessing a bean programmatically,
|
||||||
you would write the following:
|
you would write the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
|
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val usageTracked = context.getBean("myService", UsageTracked.class)
|
val usageTracked = context.getBean("myService", UsageTracked.class)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,24 @@ An example may help make this distinction between a pointcut signature and a poi
|
||||||
expression clear. The following example defines a pointcut named `anyOldTransfer` that
|
expression clear. The following example defines a pointcut named `anyOldTransfer` that
|
||||||
matches the execution of any method named `transfer`:
|
matches the execution of any method named `transfer`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* transfer(..))") // the pointcut expression
|
@Pointcut("execution(* transfer(..))") // the pointcut expression
|
||||||
private void anyOldTransfer() {} // the pointcut signature
|
private void anyOldTransfer() {} // the pointcut signature
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* transfer(..))") // the pointcut expression
|
@Pointcut("execution(* transfer(..))") // the pointcut expression
|
||||||
private fun anyOldTransfer() {} // the pointcut signature
|
private fun anyOldTransfer() {} // the pointcut signature
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The pointcut expression that forms the value of the `@Pointcut` annotation is a regular
|
The pointcut expression that forms the value of the `@Pointcut` annotation is a regular
|
||||||
AspectJ pointcut expression. For a full discussion of AspectJ's pointcut language, see
|
AspectJ pointcut expression. For a full discussion of AspectJ's pointcut language, see
|
||||||
|
|
@ -140,8 +146,11 @@ it is natural and straightforward to identify specific beans by name.
|
||||||
You can combine pointcut expressions by using `&&,` `||` and `!`. You can also refer to
|
You can combine pointcut expressions by using `&&,` `||` and `!`. You can also refer to
|
||||||
pointcut expressions by name. The following example shows three pointcut expressions:
|
pointcut expressions by name. The following example shows three pointcut expressions:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -158,6 +167,7 @@ pointcut expressions by name. The following example shows three pointcut express
|
||||||
public void tradingOperation() {} // <3>
|
public void tradingOperation() {} // <3>
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> `publicMethod` matches if a method execution join point represents the execution
|
<1> `publicMethod` matches if a method execution join point represents the execution
|
||||||
of any public method.
|
of any public method.
|
||||||
<2> `inTrading` matches if a method execution is in the trading module.
|
<2> `inTrading` matches if a method execution is in the trading module.
|
||||||
|
|
@ -204,8 +214,11 @@ We recommend defining a dedicated aspect that captures commonly used _named poin
|
||||||
expressions for this purpose. Such an aspect typically resembles the following
|
expressions for this purpose. Such an aspect typically resembles the following
|
||||||
`CommonPointcuts` example (though what you name the aspect is up to you):
|
`CommonPointcuts` example (though what you name the aspect is up to you):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages",fold="none"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -266,8 +279,10 @@ expressions for this purpose. Such an aspect typically resembles the following
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages",fold="none"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -328,6 +343,7 @@ expressions for this purpose. Such an aspect typically resembles the following
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can refer to the pointcuts defined in such an aspect anywhere you need a pointcut
|
You can refer to the pointcuts defined in such an aspect anywhere you need a pointcut
|
||||||
expression by referencing the fully-qualified name of the `@Aspect` class combined with
|
expression by referencing the fully-qualified name of the `@Aspect` class combined with
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,11 @@ it can express than the @AspectJ style: Only the "singleton" aspect instantiatio
|
||||||
is supported, and it is not possible to combine named pointcuts declared in XML.
|
is supported, and it is not possible to combine named pointcuts declared in XML.
|
||||||
For example, in the @AspectJ style you can write something like the following:
|
For example, in the @AspectJ style you can write something like the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* get*())")
|
@Pointcut("execution(* get*())")
|
||||||
public void propertyAccess() {}
|
public void propertyAccess() {}
|
||||||
|
|
@ -67,8 +70,10 @@ For example, in the @AspectJ style you can write something like the following:
|
||||||
@Pointcut("propertyAccess() && operationReturningAnAccount()")
|
@Pointcut("propertyAccess() && operationReturningAnAccount()")
|
||||||
public void accountPropertyAccess() {}
|
public void accountPropertyAccess() {}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Pointcut("execution(* get*())")
|
@Pointcut("execution(* get*())")
|
||||||
fun propertyAccess() {}
|
fun propertyAccess() {}
|
||||||
|
|
@ -79,6 +84,7 @@ For example, in the @AspectJ style you can write something like the following:
|
||||||
@Pointcut("propertyAccess() && operationReturningAnAccount()")
|
@Pointcut("propertyAccess() && operationReturningAnAccount()")
|
||||||
fun accountPropertyAccess() {}
|
fun accountPropertyAccess() {}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the XML style you can declare the first two pointcuts:
|
In the XML style you can declare the first two pointcuts:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,11 @@ Consider first the scenario where you have a plain-vanilla, un-proxied,
|
||||||
nothing-special-about-it, straight object reference, as the following
|
nothing-special-about-it, straight object reference, as the following
|
||||||
code snippet shows:
|
code snippet shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimplePojo implements Pojo {
|
public class SimplePojo implements Pojo {
|
||||||
|
|
||||||
|
|
@ -80,8 +83,10 @@ code snippet shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimplePojo : Pojo {
|
class SimplePojo : Pojo {
|
||||||
|
|
||||||
|
|
@ -95,14 +100,18 @@ code snippet shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you invoke a method on an object reference, the method is invoked directly on
|
If you invoke a method on an object reference, the method is invoked directly on
|
||||||
that object reference, as the following image and listing show:
|
that object reference, as the following image and listing show:
|
||||||
|
|
||||||
image::aop-proxy-plain-pojo-call.png[]
|
image::aop-proxy-plain-pojo-call.png[]
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
|
|
@ -113,8 +122,10 @@ image::aop-proxy-plain-pojo-call.png[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val pojo = SimplePojo()
|
val pojo = SimplePojo()
|
||||||
|
|
@ -122,14 +133,18 @@ image::aop-proxy-plain-pojo-call.png[]
|
||||||
pojo.foo()
|
pojo.foo()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Things change slightly when the reference that client code has is a proxy. Consider the
|
Things change slightly when the reference that client code has is a proxy. Consider the
|
||||||
following diagram and code snippet:
|
following diagram and code snippet:
|
||||||
|
|
||||||
image::aop-proxy-call.png[]
|
image::aop-proxy-call.png[]
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
|
|
@ -144,8 +159,10 @@ image::aop-proxy-call.png[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val factory = ProxyFactory(SimplePojo())
|
val factory = ProxyFactory(SimplePojo())
|
||||||
|
|
@ -157,6 +174,7 @@ fun main() {
|
||||||
pojo.foo()
|
pojo.foo()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The key thing to understand here is that the client code inside the `main(..)` method
|
The key thing to understand here is that the client code inside the `main(..)` method
|
||||||
of the `Main` class has a reference to the proxy. This means that method calls on that
|
of the `Main` class has a reference to the proxy. This means that method calls on that
|
||||||
|
|
@ -175,8 +193,11 @@ The next approach is absolutely horrendous, and we hesitate to point it out, pre
|
||||||
because it is so horrendous. You can (painful as it is to us) totally tie the logic
|
because it is so horrendous. You can (painful as it is to us) totally tie the logic
|
||||||
within your class to Spring AOP, as the following example shows:
|
within your class to Spring AOP, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimplePojo implements Pojo {
|
public class SimplePojo implements Pojo {
|
||||||
|
|
||||||
|
|
@ -190,8 +211,10 @@ within your class to Spring AOP, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimplePojo : Pojo {
|
class SimplePojo : Pojo {
|
||||||
|
|
||||||
|
|
@ -205,14 +228,18 @@ within your class to Spring AOP, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This totally couples your code to Spring AOP, and it makes the class itself aware of
|
This totally couples your code to Spring AOP, and it makes the class itself aware of
|
||||||
the fact that it is being used in an AOP context, which flies in the face of AOP. It
|
the fact that it is being used in an AOP context, which flies in the face of AOP. It
|
||||||
also requires some additional configuration when the proxy is being created, as the
|
also requires some additional configuration when the proxy is being created, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
|
|
@ -228,8 +255,10 @@ following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val factory = ProxyFactory(SimplePojo())
|
val factory = ProxyFactory(SimplePojo())
|
||||||
|
|
@ -242,6 +271,7 @@ following example shows:
|
||||||
pojo.foo()
|
pojo.foo()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Finally, it must be noted that AspectJ does not have this self-invocation issue because
|
Finally, it must be noted that AspectJ does not have this self-invocation issue because
|
||||||
it is not a proxy-based AOP framework.
|
it is not a proxy-based AOP framework.
|
||||||
|
|
|
||||||
|
|
@ -132,20 +132,26 @@ collects the `this` object as the join point context and passes it to the advice
|
||||||
The advice must be declared to receive the collected join point context by including
|
The advice must be declared to receive the collected join point context by including
|
||||||
parameters of the matching names, as follows:
|
parameters of the matching names, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public void monitor(Object service) {
|
public void monitor(Object service) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun monitor(service: Any) {
|
fun monitor(service: Any) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When combining pointcut sub-expressions, `+&&+` is awkward within an XML
|
When combining pointcut sub-expressions, `+&&+` is awkward within an XML
|
||||||
document, so you can use the `and`, `or`, and `not` keywords in place of `+&&+`,
|
document, so you can use the `and`, `or`, and `not` keywords in place of `+&&+`,
|
||||||
|
|
@ -272,16 +278,22 @@ The `doAccessCheck` method must declare a parameter named `retVal`. The type of
|
||||||
parameter constrains matching in the same way as described for `@AfterReturning`. For
|
parameter constrains matching in the same way as described for `@AfterReturning`. For
|
||||||
example, you can declare the method signature as follows:
|
example, you can declare the method signature as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public void doAccessCheck(Object retVal) {...
|
public void doAccessCheck(Object retVal) {...
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun doAccessCheck(retVal: Any) {...
|
fun doAccessCheck(retVal: Any) {...
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[aop-schema-advice-after-throwing]]
|
[[aop-schema-advice-after-throwing]]
|
||||||
|
|
@ -324,16 +336,22 @@ The `doRecoveryActions` method must declare a parameter named `dataAccessEx`.
|
||||||
The type of this parameter constrains matching in the same way as described for
|
The type of this parameter constrains matching in the same way as described for
|
||||||
`@AfterThrowing`. For example, the method signature may be declared as follows:
|
`@AfterThrowing`. For example, the method signature may be declared as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public void doRecoveryActions(DataAccessException dataAccessEx) {...
|
public void doRecoveryActions(DataAccessException dataAccessEx) {...
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun doRecoveryActions(dataAccessEx: DataAccessException) {...
|
fun doRecoveryActions(dataAccessEx: DataAccessException) {...
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[aop-schema-advice-after-finally]]
|
[[aop-schema-advice-after-finally]]
|
||||||
|
|
@ -399,8 +417,11 @@ The following example shows how to declare around advice in XML:
|
||||||
The implementation of the `doBasicProfiling` advice can be exactly the same as in the
|
The implementation of the `doBasicProfiling` advice can be exactly the same as in the
|
||||||
@AspectJ example (minus the annotation, of course), as the following example shows:
|
@AspectJ example (minus the annotation, of course), as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
|
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
// start stopwatch
|
// start stopwatch
|
||||||
|
|
@ -409,8 +430,10 @@ The implementation of the `doBasicProfiling` advice can be exactly the same as i
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any {
|
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any {
|
||||||
// start stopwatch
|
// start stopwatch
|
||||||
|
|
@ -419,6 +442,7 @@ The implementation of the `doBasicProfiling` advice can be exactly the same as i
|
||||||
return pjp.proceed()
|
return pjp.proceed()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[aop-schema-params]]
|
[[aop-schema-params]]
|
||||||
|
|
@ -447,8 +471,11 @@ The `arg-names` attribute accepts a comma-delimited list of parameter names.
|
||||||
The following slightly more involved example of the XSD-based approach shows
|
The following slightly more involved example of the XSD-based approach shows
|
||||||
some around advice used in conjunction with a number of strongly typed parameters:
|
some around advice used in conjunction with a number of strongly typed parameters:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz.service;
|
package com.xyz.service;
|
||||||
|
|
||||||
|
|
@ -464,8 +491,10 @@ some around advice used in conjunction with a number of strongly typed parameter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz.service
|
package com.xyz.service
|
||||||
|
|
||||||
|
|
@ -481,14 +510,18 @@ some around advice used in conjunction with a number of strongly typed parameter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Next up is the aspect. Notice the fact that the `profile(..)` method accepts a number of
|
Next up is the aspect. Notice the fact that the `profile(..)` method accepts a number of
|
||||||
strongly-typed parameters, the first of which happens to be the join point used to
|
strongly-typed parameters, the first of which happens to be the join point used to
|
||||||
proceed with the method call. The presence of this parameter is an indication that the
|
proceed with the method call. The presence of this parameter is an indication that the
|
||||||
`profile(..)` is to be used as `around` advice, as the following example shows:
|
`profile(..)` is to be used as `around` advice, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -509,8 +542,10 @@ proceed with the method call. The presence of this parameter is an indication th
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -531,6 +566,7 @@ proceed with the method call. The presence of this parameter is an indication th
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Finally, the following example XML configuration effects the execution of the
|
Finally, the following example XML configuration effects the execution of the
|
||||||
preceding advice for a particular join point:
|
preceding advice for a particular join point:
|
||||||
|
|
@ -570,8 +606,11 @@ preceding advice for a particular join point:
|
||||||
|
|
||||||
Consider the following driver script:
|
Consider the following driver script:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Boot {
|
public class Boot {
|
||||||
|
|
||||||
|
|
@ -582,8 +621,10 @@ Consider the following driver script:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val ctx = ClassPathXmlApplicationContext("beans.xml")
|
val ctx = ClassPathXmlApplicationContext("beans.xml")
|
||||||
|
|
@ -591,6 +632,7 @@ Consider the following driver script:
|
||||||
person.getPerson("Pengo", 12)
|
person.getPerson("Pengo", 12)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
With such a `Boot` class, we would get output similar to the following on standard output:
|
With such a `Boot` class, we would get output similar to the following on standard output:
|
||||||
|
|
||||||
|
|
@ -668,20 +710,26 @@ through JMX for example.)
|
||||||
|
|
||||||
The class that backs the `usageTracking` bean would then contain the following method:
|
The class that backs the `usageTracking` bean would then contain the following method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public void recordUsage(UsageTracked usageTracked) {
|
public void recordUsage(UsageTracked usageTracked) {
|
||||||
usageTracked.incrementUseCount();
|
usageTracked.incrementUseCount();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun recordUsage(usageTracked: UsageTracked) {
|
fun recordUsage(usageTracked: UsageTracked) {
|
||||||
usageTracked.incrementUseCount()
|
usageTracked.incrementUseCount()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The interface to be implemented is determined by the `implement-interface` attribute. The
|
The interface to be implemented is determined by the `implement-interface` attribute. The
|
||||||
value of the `types-matching` attribute is an AspectJ type pattern. Any bean of a
|
value of the `types-matching` attribute is an AspectJ type pattern. Any bean of a
|
||||||
|
|
@ -690,16 +738,22 @@ advice of the preceding example, service beans can be directly used as implement
|
||||||
the `UsageTracked` interface. To access a bean programmatically, you could write the
|
the `UsageTracked` interface. To access a bean programmatically, you could write the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
|
UsageTracked usageTracked = context.getBean("myService", UsageTracked.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val usageTracked = context.getBean("myService", UsageTracked.class)
|
val usageTracked = context.getBean("myService", UsageTracked.class)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -771,8 +825,11 @@ Because we want to retry the operation, we need to use around advice so that we
|
||||||
call `proceed` multiple times. The following listing shows the basic aspect implementation
|
call `proceed` multiple times. The following listing shows the basic aspect implementation
|
||||||
(which is a regular Java class that uses the schema support):
|
(which is a regular Java class that uses the schema support):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ConcurrentOperationExecutor implements Ordered {
|
public class ConcurrentOperationExecutor implements Ordered {
|
||||||
|
|
||||||
|
|
@ -809,8 +866,10 @@ call `proceed` multiple times. The following listing shows the basic aspect impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ConcurrentOperationExecutor : Ordered {
|
class ConcurrentOperationExecutor : Ordered {
|
||||||
|
|
||||||
|
|
@ -847,6 +906,7 @@ call `proceed` multiple times. The following listing shows the basic aspect impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Note that the aspect implements the `Ordered` interface so that we can set the precedence of
|
Note that the aspect implements the `Ordered` interface so that we can set the precedence of
|
||||||
the aspect higher than the transaction advice (we want a fresh transaction each time we
|
the aspect higher than the transaction advice (we want a fresh transaction each time we
|
||||||
|
|
@ -889,21 +949,27 @@ this is not the case, we can refine the aspect so that it retries only genuinely
|
||||||
idempotent operations, by introducing an `Idempotent` annotation and using the annotation
|
idempotent operations, by introducing an `Idempotent` annotation and using the annotation
|
||||||
to annotate the implementation of service operations, as the following example shows:
|
to annotate the implementation of service operations, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
// marker annotation
|
// marker annotation
|
||||||
public @interface Idempotent {
|
public @interface Idempotent {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
// marker annotation
|
// marker annotation
|
||||||
annotation class Idempotent
|
annotation class Idempotent
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The
|
The
|
||||||
change to the aspect to retry only idempotent operations involves refining the
|
change to the aspect to retry only idempotent operations involves refining the
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,11 @@ The `@Configurable` annotation marks a class as being eligible for Spring-driven
|
||||||
configuration. In the simplest case, you can use purely it as a marker annotation, as the
|
configuration. In the simplest case, you can use purely it as a marker annotation, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz.domain;
|
package com.xyz.domain;
|
||||||
|
|
||||||
|
|
@ -44,8 +47,10 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz.domain
|
package com.xyz.domain
|
||||||
|
|
||||||
|
|
@ -56,6 +61,7 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When used as a marker interface in this way, Spring configures new instances of the
|
When used as a marker interface in this way, Spring configures new instances of the
|
||||||
annotated type (`Account`, in this case) by using a bean definition (typically
|
annotated type (`Account`, in this case) by using a bean definition (typically
|
||||||
|
|
@ -74,8 +80,11 @@ is to omit the `id` attribute, as the following example shows:
|
||||||
If you want to explicitly specify the name of the prototype bean definition to use, you
|
If you want to explicitly specify the name of the prototype bean definition to use, you
|
||||||
can do so directly in the annotation, as the following example shows:
|
can do so directly in the annotation, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz.domain;
|
package com.xyz.domain;
|
||||||
|
|
||||||
|
|
@ -86,8 +95,10 @@ can do so directly in the annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz.domain
|
package com.xyz.domain
|
||||||
|
|
||||||
|
|
@ -98,6 +109,7 @@ can do so directly in the annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Spring now looks for a bean definition named `account` and uses that as the
|
Spring now looks for a bean definition named `account` and uses that as the
|
||||||
definition to configure new `Account` instances.
|
definition to configure new `Account` instances.
|
||||||
|
|
@ -137,16 +149,22 @@ dependencies to be injected before the constructor bodies run and thus be
|
||||||
available for use in the body of the constructors, you need to define this on the
|
available for use in the body of the constructors, you need to define this on the
|
||||||
`@Configurable` declaration, as follows:
|
`@Configurable` declaration, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configurable(preConstruction = true)
|
@Configurable(preConstruction = true)
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configurable(preConstruction = true)
|
@Configurable(preConstruction = true)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can find more information about the language semantics of the various pointcut
|
You can find more information about the language semantics of the various pointcut
|
||||||
types in AspectJ
|
types in AspectJ
|
||||||
|
|
@ -164,22 +182,28 @@ a reference to the bean factory that is to be used to configure new objects). If
|
||||||
use Java-based configuration, you can add `@EnableSpringConfigured` to any
|
use Java-based configuration, you can add `@EnableSpringConfigured` to any
|
||||||
`@Configuration` class, as follows:
|
`@Configuration` class, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableSpringConfigured
|
@EnableSpringConfigured
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableSpringConfigured
|
@EnableSpringConfigured
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you prefer XML based configuration, the Spring
|
If you prefer XML based configuration, the Spring
|
||||||
xref:core/appendix/xsd-schemas.adoc#context[`context` namespace]
|
xref:core/appendix/xsd-schemas.adoc#context[`context` namespace]
|
||||||
|
|
@ -417,8 +441,11 @@ use @AspectJ with xref:core/beans/java.adoc[Java configuration]. Specifically, y
|
||||||
The following example shows the profiling aspect, which is not fancy.
|
The following example shows the profiling aspect, which is not fancy.
|
||||||
It is a time-based profiler that uses the @AspectJ-style of aspect declaration:
|
It is a time-based profiler that uses the @AspectJ-style of aspect declaration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -448,8 +475,10 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration:
|
||||||
public void methodsToBeProfiled(){}
|
public void methodsToBeProfiled(){}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -480,6 +509,7 @@ It is a time-based profiler that uses the @AspectJ-style of aspect declaration:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
We also need to create an `META-INF/aop.xml` file, to inform the AspectJ weaver that
|
We also need to create an `META-INF/aop.xml` file, to inform the AspectJ weaver that
|
||||||
we want to weave our `ProfilingAspect` into our classes. This file convention, namely
|
we want to weave our `ProfilingAspect` into our classes. This file convention, namely
|
||||||
|
|
@ -537,8 +567,11 @@ Now that all the required artifacts (the aspect, the `META-INF/aop.xml`
|
||||||
file, and the Spring configuration) are in place, we can create the following
|
file, and the Spring configuration) are in place, we can create the following
|
||||||
driver class with a `main(..)` method to demonstrate the LTW in action:
|
driver class with a `main(..)` method to demonstrate the LTW in action:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -557,8 +590,10 @@ driver class with a `main(..)` method to demonstrate the LTW in action:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -573,6 +608,7 @@ driver class with a `main(..)` method to demonstrate the LTW in action:
|
||||||
service.calculateEntitlement()
|
service.calculateEntitlement()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
We have one last thing to do. The introduction to this section did say that one could
|
We have one last thing to do. The introduction to this section did say that one could
|
||||||
switch on LTW selectively on a per-`ClassLoader` basis with Spring, and this is true.
|
switch on LTW selectively on a per-`ClassLoader` basis with Spring, and this is true.
|
||||||
|
|
@ -612,8 +648,11 @@ Since this LTW is effected by using full-blown AspectJ, we are not limited only
|
||||||
Spring beans. The following slight variation on the `Main` program yields the same
|
Spring beans. The following slight variation on the `Main` program yields the same
|
||||||
result:
|
result:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.xyz;
|
package com.xyz;
|
||||||
|
|
||||||
|
|
@ -632,8 +671,10 @@ result:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.xyz
|
package com.xyz
|
||||||
|
|
||||||
|
|
@ -648,6 +689,7 @@ result:
|
||||||
service.calculateEntitlement()
|
service.calculateEntitlement()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Notice how, in the preceding program, we bootstrap the Spring container and
|
Notice how, in the preceding program, we bootstrap the Spring container and
|
||||||
then create a new instance of the `StubEntitlementCalculationService` totally outside
|
then create a new instance of the `StubEntitlementCalculationService` totally outside
|
||||||
|
|
@ -721,22 +763,28 @@ enough because the LTW support uses `BeanFactoryPostProcessors`.)
|
||||||
To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver`,
|
To enable the Spring Framework's LTW support, you need to configure a `LoadTimeWeaver`,
|
||||||
which typically is done by using the `@EnableLoadTimeWeaving` annotation, as follows:
|
which typically is done by using the `@EnableLoadTimeWeaving` annotation, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Alternatively, if you prefer XML-based configuration, use the
|
Alternatively, if you prefer XML-based configuration, use the
|
||||||
`<context:load-time-weaver/>` element. Note that the element is defined in the
|
`<context:load-time-weaver/>` element. Note that the element is defined in the
|
||||||
|
|
@ -804,8 +852,11 @@ To specify a specific `LoadTimeWeaver` with Java configuration, implement the
|
||||||
`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method.
|
`LoadTimeWeavingConfigurer` interface and override the `getLoadTimeWeaver()` method.
|
||||||
The following example specifies a `ReflectiveLoadTimeWeaver`:
|
The following example specifies a `ReflectiveLoadTimeWeaver`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
|
|
@ -817,8 +868,10 @@ The following example specifies a `ReflectiveLoadTimeWeaver`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
|
|
@ -829,6 +882,7 @@ The following example specifies a `ReflectiveLoadTimeWeaver`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you use XML-based configuration, you can specify the fully qualified class name
|
If you use XML-based configuration, you can specify the fully qualified class name
|
||||||
as the value of the `weaver-class` attribute on the `<context:load-time-weaver/>`
|
as the value of the `weaver-class` attribute on the `<context:load-time-weaver/>`
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,11 @@ This is the default behavior, since tuning the generated code for a bean definit
|
||||||
|
|
||||||
Taking our previous example, let's assume that `DataSourceConfiguration` is as follows:
|
Taking our previous example, let's assume that `DataSourceConfiguration` is as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
public class DataSourceConfiguration {
|
public class DataSourceConfiguration {
|
||||||
|
|
@ -137,12 +140,16 @@ Taking our previous example, let's assume that `DataSourceConfiguration` is as f
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Since there isn't any particular condition on this class, `dataSourceConfiguration` and `dataSource` are identified as candidates.
|
Since there isn't any particular condition on this class, `dataSourceConfiguration` and `dataSource` are identified as candidates.
|
||||||
The AOT engine will convert the configuration class above to code similar to the following:
|
The AOT engine will convert the configuration class above to code similar to the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,role="primary"]
|
[source,java,indent=0,role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
/**
|
/**
|
||||||
* Bean definitions for {@link DataSourceConfiguration}
|
* Bean definitions for {@link DataSourceConfiguration}
|
||||||
|
|
@ -177,6 +184,7 @@ The AOT engine will convert the configuration class above to code similar to the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: The exact code generated may differ depending on the exact nature of your bean definitions.
|
NOTE: The exact code generated may differ depending on the exact nature of your bean definitions.
|
||||||
|
|
||||||
|
|
@ -197,11 +205,15 @@ Consequently, if the application needs to load a resource, it must be referenced
|
||||||
The {api-spring-framework}/aot/hint/RuntimeHints.html[`RuntimeHints`] API collects the need for reflection, resource loading, serialization, and JDK proxies at runtime.
|
The {api-spring-framework}/aot/hint/RuntimeHints.html[`RuntimeHints`] API collects the need for reflection, resource loading, serialization, and JDK proxies at runtime.
|
||||||
The following example makes sure that `config/app.properties` can be loaded from the classpath at runtime within a native image:
|
The following example makes sure that `config/app.properties` can be loaded from the classpath at runtime within a native image:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
runtimeHints.resources().registerPattern("config/app.properties");
|
runtimeHints.resources().registerPattern("config/app.properties");
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
A number of contracts are handled automatically during AOT processing.
|
A number of contracts are handled automatically during AOT processing.
|
||||||
For instance, the return type of a `@Controller` method is inspected, and relevant reflection hints are added if Spring detects that the type should be serialized (typically to JSON).
|
For instance, the return type of a `@Controller` method is inspected, and relevant reflection hints are added if Spring detects that the type should be serialized (typically to JSON).
|
||||||
|
|
@ -248,8 +260,11 @@ A typical use case is the use of DTOs that the container cannot infer, such as u
|
||||||
`@RegisterReflectionForBinding` can be applied to any Spring bean at the class level, but it can also be applied directly to a method, field, or constructor to better indicate where the hints are actually required.
|
`@RegisterReflectionForBinding` can be applied to any Spring bean at the class level, but it can also be applied directly to a method, field, or constructor to better indicate where the hints are actually required.
|
||||||
The following example registers `Account` for serialization.
|
The following example registers `Account` for serialization.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class OrderService {
|
public class OrderService {
|
||||||
|
|
@ -261,6 +276,7 @@ The following example registers `Account` for serialization.
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[aot.hints.testing]]
|
[[aot.hints.testing]]
|
||||||
=== Testing Runtime Hints
|
=== Testing Runtime Hints
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,11 @@ element results in a single `SimpleDateFormat` bean definition). Spring features
|
||||||
number of convenience classes that support this scenario. In the following example, we
|
number of convenience classes that support this scenario. In the following example, we
|
||||||
use the `NamespaceHandlerSupport` class:
|
use the `NamespaceHandlerSupport` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package org.springframework.samples.xml;
|
package org.springframework.samples.xml;
|
||||||
|
|
||||||
|
|
@ -155,8 +158,10 @@ use the `NamespaceHandlerSupport` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package org.springframework.samples.xml
|
package org.springframework.samples.xml
|
||||||
|
|
||||||
|
|
@ -169,6 +174,7 @@ use the `NamespaceHandlerSupport` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You may notice that there is not actually a whole lot of parsing logic
|
You may notice that there is not actually a whole lot of parsing logic
|
||||||
in this class. Indeed, the `NamespaceHandlerSupport` class has a built-in notion of
|
in this class. Indeed, the `NamespaceHandlerSupport` class has a built-in notion of
|
||||||
|
|
@ -192,8 +198,11 @@ responsible for parsing one distinct top-level XML element defined in the schema
|
||||||
the parser, we' have access to the XML element (and thus to its subelements, too) so that
|
the parser, we' have access to the XML element (and thus to its subelements, too) so that
|
||||||
we can parse our custom XML content, as you can see in the following example:
|
we can parse our custom XML content, as you can see in the following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package org.springframework.samples.xml;
|
package org.springframework.samples.xml;
|
||||||
|
|
||||||
|
|
@ -224,6 +233,7 @@ we can parse our custom XML content, as you can see in the following example:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of
|
<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of
|
||||||
the basic grunt work of creating a single `BeanDefinition`.
|
the basic grunt work of creating a single `BeanDefinition`.
|
||||||
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
|
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
|
||||||
|
|
@ -401,8 +411,11 @@ setter method for the `components` property. This makes it hard (or rather impos
|
||||||
to configure a bean definition for the `Component` class by using setter injection.
|
to configure a bean definition for the `Component` class by using setter injection.
|
||||||
The following listing shows the `Component` class:
|
The following listing shows the `Component` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -432,8 +445,10 @@ The following listing shows the `Component` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -454,13 +469,17 @@ The following listing shows the `Component` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The typical solution to this issue is to create a custom `FactoryBean` that exposes a
|
The typical solution to this issue is to create a custom `FactoryBean` that exposes a
|
||||||
setter property for the `components` property. The following listing shows such a custom
|
setter property for the `components` property. The following listing shows such a custom
|
||||||
`FactoryBean`:
|
`FactoryBean`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -499,8 +518,10 @@ setter property for the `components` property. The following listing shows such
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -538,6 +559,7 @@ setter property for the `components` property. The following listing shows such
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This works nicely, but it exposes a lot of Spring plumbing to the end user. What we are
|
This works nicely, but it exposes a lot of Spring plumbing to the end user. What we are
|
||||||
going to do is write a custom extension that hides away all of this Spring plumbing.
|
going to do is write a custom extension that hides away all of this Spring plumbing.
|
||||||
|
|
@ -571,8 +593,11 @@ listing shows:
|
||||||
Again following xref:core/appendix/xml-custom.adoc#core.appendix.xsd-custom-introduction[the process described earlier],
|
Again following xref:core/appendix/xml-custom.adoc#core.appendix.xsd-custom-introduction[the process described earlier],
|
||||||
we then create a custom `NamespaceHandler`:
|
we then create a custom `NamespaceHandler`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -585,8 +610,10 @@ we then create a custom `NamespaceHandler`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -599,13 +626,17 @@ we then create a custom `NamespaceHandler`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Next up is the custom `BeanDefinitionParser`. Remember that we are creating
|
Next up is the custom `BeanDefinitionParser`. Remember that we are creating
|
||||||
a `BeanDefinition` that describes a `ComponentFactoryBean`. The following
|
a `BeanDefinition` that describes a `ComponentFactoryBean`. The following
|
||||||
listing shows our custom `BeanDefinitionParser` implementation:
|
listing shows our custom `BeanDefinitionParser` implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -653,8 +684,10 @@ listing shows our custom `BeanDefinitionParser` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -702,6 +735,7 @@ listing shows our custom `BeanDefinitionParser` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Finally, the various artifacts need to be registered with the Spring XML infrastructure,
|
Finally, the various artifacts need to be registered with the Spring XML infrastructure,
|
||||||
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
|
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
|
||||||
|
|
@ -748,8 +782,11 @@ the named JCache for us. We can also modify the existing `BeanDefinition` for th
|
||||||
`'checkingAccountService'` so that it has a dependency on this new
|
`'checkingAccountService'` so that it has a dependency on this new
|
||||||
JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`:
|
JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -766,8 +803,10 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -778,6 +817,7 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now we can move onto the custom extension. First, we need to author
|
Now we can move onto the custom extension. First, we need to author
|
||||||
the XSD schema that describes the custom attribute, as follows:
|
the XSD schema that describes the custom attribute, as follows:
|
||||||
|
|
@ -798,8 +838,11 @@ the XSD schema that describes the custom attribute, as follows:
|
||||||
|
|
||||||
Next, we need to create the associated `NamespaceHandler`, as follows:
|
Next, we need to create the associated `NamespaceHandler`, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -814,8 +857,10 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -830,13 +875,17 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Next, we need to create the parser. Note that, in this case, because we are going to parse
|
Next, we need to create the parser. Note that, in this case, because we are going to parse
|
||||||
an XML attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`.
|
an XML attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`.
|
||||||
The following listing shows our `BeanDefinitionDecorator` implementation:
|
The following listing shows our `BeanDefinitionDecorator` implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo;
|
package com.foo;
|
||||||
|
|
||||||
|
|
@ -889,8 +938,10 @@ The following listing shows our `BeanDefinitionDecorator` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo
|
package com.foo
|
||||||
|
|
||||||
|
|
@ -939,6 +990,7 @@ The following listing shows our `BeanDefinitionDecorator` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Finally, we need to register the various artifacts with the Spring XML infrastructure
|
Finally, we need to register the various artifacts with the Spring XML infrastructure
|
||||||
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
|
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,11 @@ easy to do in Spring. You do not actually have to do anything or know anything a
|
||||||
the Spring internals (or even about classes such as the `FieldRetrievingFactoryBean`).
|
the Spring internals (or even about classes such as the `FieldRetrievingFactoryBean`).
|
||||||
The following example enumeration shows how easy injecting an enum value is:
|
The following example enumeration shows how easy injecting an enum value is:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package jakarta.persistence;
|
package jakarta.persistence;
|
||||||
|
|
||||||
|
|
@ -128,8 +131,10 @@ The following example enumeration shows how easy injecting an enum value is:
|
||||||
EXTENDED
|
EXTENDED
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package jakarta.persistence
|
package jakarta.persistence
|
||||||
|
|
||||||
|
|
@ -139,11 +144,15 @@ The following example enumeration shows how easy injecting an enum value is:
|
||||||
EXTENDED
|
EXTENDED
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition:
|
Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
|
@ -156,8 +165,10 @@ Now consider the following setter of type `PersistenceContextType` and the corre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package example
|
package example
|
||||||
|
|
||||||
|
|
@ -166,6 +177,7 @@ Now consider the following setter of type `PersistenceContextType` and the corre
|
||||||
lateinit var persistenceContextType: PersistenceContextType
|
lateinit var persistenceContextType: PersistenceContextType
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,11 @@ autowired value.
|
||||||
Consider the following configuration that defines `firstMovieCatalog` as the
|
Consider the following configuration that defines `firstMovieCatalog` as the
|
||||||
primary `MovieCatalog`:
|
primary `MovieCatalog`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MovieConfiguration {
|
public class MovieConfiguration {
|
||||||
|
|
@ -27,8 +30,10 @@ primary `MovieCatalog`:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class MovieConfiguration {
|
class MovieConfiguration {
|
||||||
|
|
@ -43,12 +48,16 @@ primary `MovieCatalog`:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
With the preceding configuration, the following `MovieRecommender` is autowired with the
|
With the preceding configuration, the following `MovieRecommender` is autowired with the
|
||||||
`firstMovieCatalog`:
|
`firstMovieCatalog`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -58,8 +67,10 @@ With the preceding configuration, the following `MovieRecommender` is autowired
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -69,6 +80,7 @@ class MovieRecommender {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The corresponding bean definitions follow:
|
The corresponding bean definitions follow:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@ chosen for each argument. In the simplest case, this can be a plain descriptive
|
||||||
shown in the following example:
|
shown in the following example:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -21,8 +24,10 @@ shown in the following example:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -33,14 +38,18 @@ shown in the following example:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
You can also specify the `@Qualifier` annotation on individual constructor arguments or
|
You can also specify the `@Qualifier` annotation on individual constructor arguments or
|
||||||
method parameters, as shown in the following example:
|
method parameters, as shown in the following example:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -58,8 +67,10 @@ method parameters, as shown in the following example:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -77,6 +88,7 @@ method parameters, as shown in the following example:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
The following example shows corresponding bean definitions.
|
The following example shows corresponding bean definitions.
|
||||||
|
|
@ -194,8 +206,11 @@ You can create your own custom qualifier annotations. To do so, define an annota
|
||||||
provide the `@Qualifier` annotation within your definition, as the following example shows:
|
provide the `@Qualifier` annotation within your definition, as the following example shows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -205,22 +220,28 @@ provide the `@Qualifier` annotation within your definition, as the following exa
|
||||||
String value();
|
String value();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Qualifier
|
@Qualifier
|
||||||
annotation class Genre(val value: String)
|
annotation class Genre(val value: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
Then you can provide the custom qualifier on autowired fields and parameters, as the
|
Then you can provide the custom qualifier on autowired fields and parameters, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -238,8 +259,10 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -257,6 +280,7 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
Next, you can provide the information for the candidate bean definitions. You can add
|
Next, you can provide the information for the candidate bean definitions. You can add
|
||||||
|
|
@ -306,8 +330,11 @@ catalog that can be searched when no Internet connection is available. First, de
|
||||||
the simple annotation, as the following example shows:
|
the simple annotation, as the following example shows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -315,22 +342,28 @@ the simple annotation, as the following example shows:
|
||||||
public @interface Offline {
|
public @interface Offline {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Qualifier
|
@Qualifier
|
||||||
annotation class Offline
|
annotation class Offline
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
Then add the annotation to the field or property to be autowired, as shown in the
|
Then add the annotation to the field or property to be autowired, as shown in the
|
||||||
following example:
|
following example:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -341,6 +374,7 @@ following example:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> This line adds the `@Offline` annotation.
|
<1> This line adds the `@Offline` annotation.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -379,8 +413,11 @@ all such attribute values to be considered an autowire candidate. As an example,
|
||||||
consider the following annotation definition:
|
consider the following annotation definition:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -392,41 +429,53 @@ consider the following annotation definition:
|
||||||
Format format();
|
Format format();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Qualifier
|
@Qualifier
|
||||||
annotation class MovieQualifier(val genre: String, val format: Format)
|
annotation class MovieQualifier(val genre: String, val format: Format)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
In this case `Format` is an enum, defined as follows:
|
In this case `Format` is an enum, defined as follows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public enum Format {
|
public enum Format {
|
||||||
VHS, DVD, BLURAY
|
VHS, DVD, BLURAY
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
enum class Format {
|
enum class Format {
|
||||||
VHS, DVD, BLURAY
|
VHS, DVD, BLURAY
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
The fields to be autowired are annotated with the custom qualifier and include values
|
The fields to be autowired are annotated with the custom qualifier and include values
|
||||||
for both attributes: `genre` and `format`, as the following example shows:
|
for both attributes: `genre` and `format`, as the following example shows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -449,8 +498,10 @@ for both attributes: `genre` and `format`, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -473,6 +524,7 @@ for both attributes: `genre` and `format`, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
Finally, the bean definitions should contain matching qualifier values. This example
|
Finally, the bean definitions should contain matching qualifier values. This example
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@ examples included in this section. See xref:core/beans/standard-annotations.adoc
|
||||||
|
|
||||||
You can apply the `@Autowired` annotation to constructors, as the following example shows:
|
You can apply the `@Autowired` annotation to constructors, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -24,12 +27,15 @@ You can apply the `@Autowired` annotation to constructors, as the following exam
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender @Autowired constructor(
|
class MovieRecommender @Autowired constructor(
|
||||||
private val customerPreferenceDao: CustomerPreferenceDao)
|
private val customerPreferenceDao: CustomerPreferenceDao)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -44,8 +50,11 @@ xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-cons
|
||||||
You can also apply the `@Autowired` annotation to _traditional_ setter methods,
|
You can also apply the `@Autowired` annotation to _traditional_ setter methods,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -59,8 +68,10 @@ as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -71,12 +82,16 @@ as the following example shows:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also apply the annotation to methods with arbitrary names and multiple
|
You can also apply the annotation to methods with arbitrary names and multiple
|
||||||
arguments, as the following example shows:
|
arguments, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -94,8 +109,10 @@ arguments, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -113,12 +130,16 @@ arguments, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can apply `@Autowired` to fields as well and even mix it with constructors, as the
|
You can apply `@Autowired` to fields as well and even mix it with constructors, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -135,8 +156,10 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender @Autowired constructor(
|
class MovieRecommender @Autowired constructor(
|
||||||
private val customerPreferenceDao: CustomerPreferenceDao) {
|
private val customerPreferenceDao: CustomerPreferenceDao) {
|
||||||
|
|
@ -147,6 +170,7 @@ following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
|
|
@ -166,8 +190,11 @@ You can also instruct Spring to provide all beans of a particular type from the
|
||||||
`ApplicationContext` by adding the `@Autowired` annotation to a field or method that
|
`ApplicationContext` by adding the `@Autowired` annotation to a field or method that
|
||||||
expects an array of that type, as the following example shows:
|
expects an array of that type, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -177,8 +204,10 @@ expects an array of that type, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -188,11 +217,15 @@ expects an array of that type, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The same applies for typed collections, as the following example shows:
|
The same applies for typed collections, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -206,8 +239,10 @@ The same applies for typed collections, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -217,6 +252,7 @@ The same applies for typed collections, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[beans-factory-ordered]]
|
[[beans-factory-ordered]]
|
||||||
[TIP]
|
[TIP]
|
||||||
|
|
@ -241,8 +277,11 @@ Even typed `Map` instances can be autowired as long as the expected key type is
|
||||||
The map values contain all beans of the expected type, and the keys contain the
|
The map values contain all beans of the expected type, and the keys contain the
|
||||||
corresponding bean names, as the following example shows:
|
corresponding bean names, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -256,8 +295,10 @@ corresponding bean names, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -267,6 +308,7 @@ corresponding bean names, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
By default, autowiring fails when no matching candidate beans are available for a given
|
By default, autowiring fails when no matching candidate beans are available for a given
|
||||||
injection point. In the case of a declared array, collection, or map, at least one
|
injection point. In the case of a declared array, collection, or map, at least one
|
||||||
|
|
@ -277,8 +319,11 @@ dependencies. You can change this behavior as demonstrated in the following exam
|
||||||
enabling the framework to skip a non-satisfiable injection point through marking it as
|
enabling the framework to skip a non-satisfiable injection point through marking it as
|
||||||
non-required (i.e., by setting the `required` attribute in `@Autowired` to `false`):
|
non-required (i.e., by setting the `required` attribute in `@Autowired` to `false`):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -292,8 +337,10 @@ non-required (i.e., by setting the `required` attribute in `@Autowired` to `fals
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -303,6 +350,7 @@ non-required (i.e., by setting the `required` attribute in `@Autowired` to `fals
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -317,8 +365,8 @@ that can be optionally overridden via dependency injection.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
[[beans-autowired-annotation-constructor-resolution]]
|
|
||||||
|
|
||||||
|
[[beans-autowired-annotation-constructor-resolution]]
|
||||||
Injected constructor and factory method arguments are a special case since the `required`
|
Injected constructor and factory method arguments are a special case since the `required`
|
||||||
attribute in `@Autowired` has a somewhat different meaning due to Spring's constructor
|
attribute in `@Autowired` has a somewhat different meaning due to Spring's constructor
|
||||||
resolution algorithm that may potentially deal with multiple constructors. Constructor
|
resolution algorithm that may potentially deal with multiple constructors. Constructor
|
||||||
|
|
@ -364,8 +412,11 @@ As of Spring Framework 5.0, you can also use a `@Nullable` annotation (of any ki
|
||||||
in any package -- for example, `javax.annotation.Nullable` from JSR-305) or just leverage
|
in any package -- for example, `javax.annotation.Nullable` from JSR-305) or just leverage
|
||||||
Kotlin built-in null-safety support:
|
Kotlin built-in null-safety support:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -375,8 +426,10 @@ Kotlin built-in null-safety support:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -386,6 +439,7 @@ Kotlin built-in null-safety support:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also use `@Autowired` for interfaces that are well-known resolvable
|
You can also use `@Autowired` for interfaces that are well-known resolvable
|
||||||
dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`,
|
dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`,
|
||||||
|
|
@ -394,8 +448,11 @@ interfaces, such as `ConfigurableApplicationContext` or `ResourcePatternResolver
|
||||||
automatically resolved, with no special setup necessary. The following example autowires
|
automatically resolved, with no special setup necessary. The following example autowires
|
||||||
an `ApplicationContext` object:
|
an `ApplicationContext` object:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -408,8 +465,10 @@ an `ApplicationContext` object:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender {
|
class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -419,6 +478,7 @@ class MovieRecommender {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ In addition to the `@Qualifier` annotation, you can use Java generic types
|
||||||
as an implicit form of qualification. For example, suppose you have the following
|
as an implicit form of qualification. For example, suppose you have the following
|
||||||
configuration:
|
configuration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MyConfiguration {
|
public class MyConfiguration {
|
||||||
|
|
@ -22,8 +25,10 @@ configuration:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class MyConfiguration {
|
class MyConfiguration {
|
||||||
|
|
@ -35,13 +40,17 @@ configuration:
|
||||||
fun integerStore() = IntegerStore()
|
fun integerStore() = IntegerStore()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Assuming that the preceding beans implement a generic interface, (that is, `Store<String>` and
|
Assuming that the preceding beans implement a generic interface, (that is, `Store<String>` and
|
||||||
`Store<Integer>`), you can `@Autowire` the `Store` interface and the generic is
|
`Store<Integer>`), you can `@Autowire` the `Store` interface and the generic is
|
||||||
used as a qualifier, as the following example shows:
|
used as a qualifier, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Autowired
|
@Autowired
|
||||||
private Store<String> s1; // <String> qualifier, injects the stringStore bean
|
private Store<String> s1; // <String> qualifier, injects the stringStore bean
|
||||||
|
|
@ -49,8 +58,10 @@ used as a qualifier, as the following example shows:
|
||||||
@Autowired
|
@Autowired
|
||||||
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
|
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var s1: Store<String> // <String> qualifier, injects the stringStore bean
|
private lateinit var s1: Store<String> // <String> qualifier, injects the stringStore bean
|
||||||
|
|
@ -58,26 +69,33 @@ used as a qualifier, as the following example shows:
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var s2: Store<Integer> // <Integer> qualifier, injects the integerStore bean
|
private lateinit var s2: Store<Integer> // <Integer> qualifier, injects the integerStore bean
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Generic qualifiers also apply when autowiring lists, `Map` instances and arrays. The
|
Generic qualifiers also apply when autowiring lists, `Map` instances and arrays. The
|
||||||
following example autowires a generic `List`:
|
following example autowires a generic `List`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// Inject all Store beans as long as they have an <Integer> generic
|
// Inject all Store beans as long as they have an <Integer> generic
|
||||||
// Store<String> beans will not appear in this list
|
// Store<String> beans will not appear in this list
|
||||||
@Autowired
|
@Autowired
|
||||||
private List<Store<Integer>> s;
|
private List<Store<Integer>> s;
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// Inject all Store beans as long as they have an <Integer> generic
|
// Inject all Store beans as long as they have an <Integer> generic
|
||||||
// Store<String> beans will not appear in this list
|
// Store<String> beans will not appear in this list
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var s: List<Store<Integer>>
|
private lateinit var s: List<Store<Integer>>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ as the corresponding Spring lifecycle interface method or explicitly declared ca
|
||||||
method. In the following example, the cache is pre-populated upon initialization and
|
method. In the following example, the cache is pre-populated upon initialization and
|
||||||
cleared upon destruction:
|
cleared upon destruction:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class CachingMovieLister {
|
public class CachingMovieLister {
|
||||||
|
|
||||||
|
|
@ -29,8 +32,10 @@ cleared upon destruction:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CachingMovieLister {
|
class CachingMovieLister {
|
||||||
|
|
||||||
|
|
@ -45,6 +50,7 @@ cleared upon destruction:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For details about the effects of combining various lifecycle mechanisms, see
|
For details about the effects of combining various lifecycle mechanisms, see
|
||||||
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-combined-effects[Combining Lifecycle Mechanisms].
|
xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-combined-effects[Combining Lifecycle Mechanisms].
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,11 @@ the bean name to be injected. In other words, it follows by-name semantics,
|
||||||
as demonstrated in the following example:
|
as demonstrated in the following example:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -24,6 +27,7 @@ as demonstrated in the following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> This line injects a `@Resource`.
|
<1> This line injects a `@Resource`.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -45,8 +49,11 @@ it takes the bean property name. The following example is going to have the bean
|
||||||
named `movieFinder` injected into its setter method:
|
named `movieFinder` injected into its setter method:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -58,8 +65,10 @@ named `movieFinder` injected into its setter method:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -68,6 +77,7 @@ named `movieFinder` injected into its setter method:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
NOTE: The name provided with the annotation is resolved as a bean name by the
|
NOTE: The name provided with the annotation is resolved as a bean name by the
|
||||||
|
|
@ -88,8 +98,11 @@ named "customerPreferenceDao" and then falls back to a primary type match for th
|
||||||
`CustomerPreferenceDao`:
|
`CustomerPreferenceDao`:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -105,6 +118,7 @@ named "customerPreferenceDao" and then falls back to a primary type match for th
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> The `context` field is injected based on the known resolvable dependency type:
|
<1> The `context` field is injected based on the known resolvable dependency type:
|
||||||
`ApplicationContext`.
|
`ApplicationContext`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
`@Value` is typically used to inject externalized properties:
|
`@Value` is typically used to inject externalized properties:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
@ -16,29 +19,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MovieRecommender(@Value("\${catalog.name}") private val catalog: String)
|
class MovieRecommender(@Value("\${catalog.name}") private val catalog: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
With the following configuration:
|
With the following configuration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:application.properties")
|
@PropertySource("classpath:application.properties")
|
||||||
public class AppConfig { }
|
public class AppConfig { }
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:application.properties")
|
@PropertySource("classpath:application.properties")
|
||||||
class AppConfig
|
class AppConfig
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
And the following `application.properties` file:
|
And the following `application.properties` file:
|
||||||
|
|
||||||
|
|
@ -55,8 +67,11 @@ will be injected as the value. If you want to maintain strict control over nonex
|
||||||
values, you should declare a `PropertySourcesPlaceholderConfigurer` bean, as the following
|
values, you should declare a `PropertySourcesPlaceholderConfigurer` bean, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -67,8 +82,10 @@ example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -77,6 +94,7 @@ example shows:
|
||||||
fun propertyPlaceholderConfigurer() = PropertySourcesPlaceholderConfigurer()
|
fun propertyPlaceholderConfigurer() = PropertySourcesPlaceholderConfigurer()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: When configuring a `PropertySourcesPlaceholderConfigurer` using JavaConfig, the
|
NOTE: When configuring a `PropertySourcesPlaceholderConfigurer` using JavaConfig, the
|
||||||
`@Bean` method must be `static`.
|
`@Bean` method must be `static`.
|
||||||
|
|
@ -95,8 +113,11 @@ automatically converted to `String` array without extra effort.
|
||||||
|
|
||||||
It is possible to provide a default value as following:
|
It is possible to provide a default value as following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
@ -108,20 +129,26 @@ It is possible to provide a default value as following:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MovieRecommender(@Value("\${catalog.name:defaultCatalog}") private val catalog: String)
|
class MovieRecommender(@Value("\${catalog.name:defaultCatalog}") private val catalog: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
A Spring `BeanPostProcessor` uses a `ConversionService` behind the scenes to handle the
|
A Spring `BeanPostProcessor` uses a `ConversionService` behind the scenes to handle the
|
||||||
process for converting the `String` value in `@Value` to the target type. If you want to
|
process for converting the `String` value in `@Value` to the target type. If you want to
|
||||||
provide conversion support for your own custom type, you can provide your own
|
provide conversion support for your own custom type, you can provide your own
|
||||||
`ConversionService` bean instance as the following example shows:
|
`ConversionService` bean instance as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -134,8 +161,10 @@ provide conversion support for your own custom type, you can provide your own
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -148,12 +177,16 @@ provide conversion support for your own custom type, you can provide your own
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When `@Value` contains a xref:core/expressions.adoc[`SpEL` expression] the value will be dynamically
|
When `@Value` contains a xref:core/expressions.adoc[`SpEL` expression] the value will be dynamically
|
||||||
computed at runtime as the following example shows:
|
computed at runtime as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
@ -165,18 +198,24 @@ computed at runtime as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MovieRecommender(
|
class MovieRecommender(
|
||||||
@Value("#{systemProperties['user.catalog'] + 'Catalog' }") private val catalog: String)
|
@Value("#{systemProperties['user.catalog'] + 'Catalog' }") private val catalog: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
SpEL also enables the use of more complex data structures:
|
SpEL also enables the use of more complex data structures:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
@ -189,12 +228,15 @@ SpEL also enables the use of more complex data structures:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MovieRecommender(
|
class MovieRecommender(
|
||||||
@Value("#{{'Thriller': 100, 'Comedy': 300}}") private val countOfMoviesPerCatalog: Map<String, Int>)
|
@Value("#{{'Thriller': 100, 'Comedy': 300}}") private val countOfMoviesPerCatalog: Map<String, Int>)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,16 +119,22 @@ supplied to an `ApplicationContext` constructor are resource strings that let
|
||||||
the container load configuration metadata from a variety of external resources, such
|
the container load configuration metadata from a variety of external resources, such
|
||||||
as the local file system, the Java `CLASSPATH`, and so on.
|
as the local file system, the Java `CLASSPATH`, and so on.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
|
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
|
||||||
----
|
----
|
||||||
.Kotlin
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
----
|
----
|
||||||
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
|
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -295,8 +301,11 @@ a registry of different beans and their dependencies. By using the method
|
||||||
The `ApplicationContext` lets you read bean definitions and access them, as the following
|
The `ApplicationContext` lets you read bean definitions and access them, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// create and configure beans
|
// create and configure beans
|
||||||
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
|
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
|
||||||
|
|
@ -307,7 +316,9 @@ example shows:
|
||||||
// use configured instance
|
// use configured instance
|
||||||
List<String> userList = service.getUsernameList();
|
List<String> userList = service.getUsernameList();
|
||||||
----
|
----
|
||||||
.Kotlin
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
@ -321,58 +332,77 @@ example shows:
|
||||||
// use configured instance
|
// use configured instance
|
||||||
var userList = service.getUsernameList()
|
var userList = service.getUsernameList()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
With Groovy configuration, bootstrapping looks very similar. It has a different context
|
With Groovy configuration, bootstrapping looks very similar. It has a different context
|
||||||
implementation class which is Groovy-aware (but also understands XML bean definitions).
|
implementation class which is Groovy-aware (but also understands XML bean definitions).
|
||||||
The following example shows Groovy configuration:
|
The following example shows Groovy configuration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
|
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
|
||||||
----
|
----
|
||||||
.Kotlin
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
----
|
----
|
||||||
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
|
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The most flexible variant is `GenericApplicationContext` in combination with reader
|
The most flexible variant is `GenericApplicationContext` in combination with reader
|
||||||
delegates -- for example, with `XmlBeanDefinitionReader` for XML files, as the following
|
delegates -- for example, with `XmlBeanDefinitionReader` for XML files, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
GenericApplicationContext context = new GenericApplicationContext();
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
|
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
|
||||||
context.refresh();
|
context.refresh();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val context = GenericApplicationContext()
|
val context = GenericApplicationContext()
|
||||||
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
|
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
|
||||||
context.refresh()
|
context.refresh()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also use the `GroovyBeanDefinitionReader` for Groovy files, as the following
|
You can also use the `GroovyBeanDefinitionReader` for Groovy files, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
GenericApplicationContext context = new GenericApplicationContext();
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
|
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
|
||||||
context.refresh();
|
context.refresh();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val context = GenericApplicationContext()
|
val context = GenericApplicationContext()
|
||||||
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
|
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
|
||||||
context.refresh()
|
context.refresh()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can mix and match such reader delegates on the same `ApplicationContext`,
|
You can mix and match such reader delegates on the same `ApplicationContext`,
|
||||||
reading bean definitions from diverse configuration sources.
|
reading bean definitions from diverse configuration sources.
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,11 @@ The following table lists features provided by the `BeanFactory` and
|
||||||
To explicitly register a bean post-processor with a `DefaultListableBeanFactory`,
|
To explicitly register a bean post-processor with a `DefaultListableBeanFactory`,
|
||||||
you need to programmatically call `addBeanPostProcessor`, as the following example shows:
|
you need to programmatically call `addBeanPostProcessor`, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||||
// populate the factory with bean definitions
|
// populate the factory with bean definitions
|
||||||
|
|
@ -98,8 +101,10 @@ you need to programmatically call `addBeanPostProcessor`, as the following examp
|
||||||
|
|
||||||
// now start using the factory
|
// now start using the factory
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val factory = DefaultListableBeanFactory()
|
val factory = DefaultListableBeanFactory()
|
||||||
// populate the factory with bean definitions
|
// populate the factory with bean definitions
|
||||||
|
|
@ -110,12 +115,16 @@ you need to programmatically call `addBeanPostProcessor`, as the following examp
|
||||||
|
|
||||||
// now start using the factory
|
// now start using the factory
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To apply a `BeanFactoryPostProcessor` to a plain `DefaultListableBeanFactory`,
|
To apply a `BeanFactoryPostProcessor` to a plain `DefaultListableBeanFactory`,
|
||||||
you need to call its `postProcessBeanFactory` method, as the following example shows:
|
you need to call its `postProcessBeanFactory` method, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
||||||
|
|
@ -128,8 +137,10 @@ you need to call its `postProcessBeanFactory` method, as the following example s
|
||||||
// now actually do the replacement
|
// now actually do the replacement
|
||||||
cfg.postProcessBeanFactory(factory);
|
cfg.postProcessBeanFactory(factory);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val factory = DefaultListableBeanFactory()
|
val factory = DefaultListableBeanFactory()
|
||||||
val reader = XmlBeanDefinitionReader(factory)
|
val reader = XmlBeanDefinitionReader(factory)
|
||||||
|
|
@ -142,6 +153,7 @@ you need to call its `postProcessBeanFactory` method, as the following example s
|
||||||
// now actually do the replacement
|
// now actually do the replacement
|
||||||
cfg.postProcessBeanFactory(factory)
|
cfg.postProcessBeanFactory(factory)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In both cases, the explicit registration steps are inconvenient, which is
|
In both cases, the explicit registration steps are inconvenient, which is
|
||||||
why the various `ApplicationContext` variants are preferred over a plain
|
why the various `ApplicationContext` variants are preferred over a plain
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,11 @@ own code. A meta-annotation is an annotation that can be applied to another anno
|
||||||
For example, the `@Service` annotation mentioned xref:core/beans/classpath-scanning.adoc#beans-stereotype-annotations[earlier]
|
For example, the `@Service` annotation mentioned xref:core/beans/classpath-scanning.adoc#beans-stereotype-annotations[earlier]
|
||||||
is meta-annotated with `@Component`, as the following example shows:
|
is meta-annotated with `@Component`, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -67,6 +70,7 @@ is meta-annotated with `@Component`, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
|
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -94,8 +98,11 @@ want to only expose a subset of the meta-annotation's attributes. For example, S
|
||||||
customization of the `proxyMode`. The following listing shows the definition of the
|
customization of the `proxyMode`. The following listing shows the definition of the
|
||||||
`SessionScope` annotation:
|
`SessionScope` annotation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -112,8 +119,10 @@ customization of the `proxyMode`. The following listing shows the definition of
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
|
@ -124,11 +133,15 @@ customization of the `proxyMode`. The following listing shows the definition of
|
||||||
val proxyMode: ScopedProxyMode = ScopedProxyMode.TARGET_CLASS
|
val proxyMode: ScopedProxyMode = ScopedProxyMode.TARGET_CLASS
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can then use `@SessionScope` without declaring the `proxyMode` as follows:
|
You can then use `@SessionScope` without declaring the `proxyMode` as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
@SessionScope
|
@SessionScope
|
||||||
|
|
@ -136,8 +149,10 @@ You can then use `@SessionScope` without declaring the `proxyMode` as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
@SessionScope
|
@SessionScope
|
||||||
|
|
@ -145,11 +160,15 @@ You can then use `@SessionScope` without declaring the `proxyMode` as follows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also override the value for the `proxyMode`, as the following example shows:
|
You can also override the value for the `proxyMode`, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
|
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
|
||||||
|
|
@ -157,8 +176,10 @@ You can also override the value for the `proxyMode`, as the following example sh
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
|
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
|
||||||
|
|
@ -166,6 +187,7 @@ You can also override the value for the `proxyMode`, as the following example sh
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For further details, see the
|
For further details, see the
|
||||||
https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]
|
https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]
|
||||||
|
|
@ -180,8 +202,11 @@ Spring can automatically detect stereotyped classes and register corresponding
|
||||||
`BeanDefinition` instances with the `ApplicationContext`. For example, the following two classes
|
`BeanDefinition` instances with the `ApplicationContext`. For example, the following two classes
|
||||||
are eligible for such autodetection:
|
are eligible for such autodetection:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
@ -193,29 +218,38 @@ are eligible for such autodetection:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
class SimpleMovieLister(private val movieFinder: MovieFinder)
|
class SimpleMovieLister(private val movieFinder: MovieFinder)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class JpaMovieFinder implements MovieFinder {
|
public class JpaMovieFinder implements MovieFinder {
|
||||||
// implementation elided for clarity
|
// implementation elided for clarity
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class JpaMovieFinder : MovieFinder {
|
class JpaMovieFinder : MovieFinder {
|
||||||
// implementation elided for clarity
|
// implementation elided for clarity
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
To autodetect these classes and register the corresponding beans, you need to add
|
To autodetect these classes and register the corresponding beans, you need to add
|
||||||
|
|
@ -223,8 +257,11 @@ To autodetect these classes and register the corresponding beans, you need to ad
|
||||||
is a common parent package for the two classes. (Alternatively, you can specify a
|
is a common parent package for the two classes. (Alternatively, you can specify a
|
||||||
comma- or semicolon- or space-separated list that includes the parent package of each class.)
|
comma- or semicolon- or space-separated list that includes the parent package of each class.)
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example")
|
@ComponentScan(basePackages = "org.example")
|
||||||
|
|
@ -232,8 +269,10 @@ comma- or semicolon- or space-separated list that includes the parent package of
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"])
|
@ComponentScan(basePackages = ["org.example"])
|
||||||
|
|
@ -241,6 +280,7 @@ comma- or semicolon- or space-separated list that includes the parent package of
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: For brevity, the preceding example could have used the `value` attribute of the
|
NOTE: For brevity, the preceding example could have used the `value` attribute of the
|
||||||
annotation (that is, `@ComponentScan("org.example")`).
|
annotation (that is, `@ComponentScan("org.example")`).
|
||||||
|
|
@ -335,8 +375,11 @@ The following table describes the filtering options:
|
||||||
The following example shows the configuration ignoring all `@Repository` annotations
|
The following example shows the configuration ignoring all `@Repository` annotations
|
||||||
and using "`stub`" repositories instead:
|
and using "`stub`" repositories instead:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example",
|
@ComponentScan(basePackages = "org.example",
|
||||||
|
|
@ -346,8 +389,10 @@ and using "`stub`" repositories instead:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"],
|
@ComponentScan(basePackages = ["org.example"],
|
||||||
|
|
@ -357,6 +402,7 @@ and using "`stub`" repositories instead:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following listing shows the equivalent XML:
|
The following listing shows the equivalent XML:
|
||||||
|
|
||||||
|
|
@ -387,8 +433,11 @@ Spring components can also contribute bean definition metadata to the container.
|
||||||
this with the same `@Bean` annotation used to define bean metadata within `@Configuration`
|
this with the same `@Bean` annotation used to define bean metadata within `@Configuration`
|
||||||
annotated classes. The following example shows how to do so:
|
annotated classes. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class FactoryMethodComponent {
|
public class FactoryMethodComponent {
|
||||||
|
|
@ -404,8 +453,10 @@ annotated classes. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class FactoryMethodComponent {
|
class FactoryMethodComponent {
|
||||||
|
|
@ -419,6 +470,7 @@ annotated classes. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding class is a Spring component that has application-specific code in its
|
The preceding class is a Spring component that has application-specific code in its
|
||||||
`doWork()` method. However, it also contributes a bean definition that has a factory
|
`doWork()` method. However, it also contributes a bean definition that has a factory
|
||||||
|
|
@ -436,8 +488,11 @@ with optional dependencies, we recommend `ObjectProvider<MyTargetBean>` instead.
|
||||||
Autowired fields and methods are supported, as previously discussed, with additional
|
Autowired fields and methods are supported, as previously discussed, with additional
|
||||||
support for autowiring of `@Bean` methods. The following example shows how to do so:
|
support for autowiring of `@Bean` methods. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class FactoryMethodComponent {
|
public class FactoryMethodComponent {
|
||||||
|
|
@ -473,8 +528,10 @@ support for autowiring of `@Bean` methods. The following example shows how to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class FactoryMethodComponent {
|
class FactoryMethodComponent {
|
||||||
|
|
@ -504,6 +561,7 @@ support for autowiring of `@Bean` methods. The following example shows how to do
|
||||||
fun requestScopedInstance() = TestBean("requestScopedInstance", 3)
|
fun requestScopedInstance() = TestBean("requestScopedInstance", 3)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The example autowires the `String` method parameter `country` to the value of the `age`
|
The example autowires the `String` method parameter `country` to the value of the `age`
|
||||||
property on another bean named `privateInstance`. A Spring Expression Language element
|
property on another bean named `privateInstance`. A Spring Expression Language element
|
||||||
|
|
@ -522,8 +580,11 @@ injection point that triggered the creation of a new bean instance in the given
|
||||||
You can use the provided injection point metadata with semantic care in such scenarios.
|
You can use the provided injection point metadata with semantic care in such scenarios.
|
||||||
The following example shows how to use `InjectionPoint`:
|
The following example shows how to use `InjectionPoint`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class FactoryMethodComponent {
|
public class FactoryMethodComponent {
|
||||||
|
|
@ -534,8 +595,10 @@ The following example shows how to use `InjectionPoint`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class FactoryMethodComponent {
|
class FactoryMethodComponent {
|
||||||
|
|
@ -546,6 +609,7 @@ The following example shows how to use `InjectionPoint`:
|
||||||
TestBean("prototypeInstance for ${injectionPoint.member}")
|
TestBean("prototypeInstance for ${injectionPoint.member}")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `@Bean` methods in a regular Spring component are processed differently than their
|
The `@Bean` methods in a regular Spring component are processed differently than their
|
||||||
counterparts inside a Spring `@Configuration` class. The difference is that `@Component`
|
counterparts inside a Spring `@Configuration` class. The difference is that `@Component`
|
||||||
|
|
@ -609,39 +673,51 @@ If such an annotation contains no name `value` or for any other detected compone
|
||||||
the uncapitalized non-qualified class name. For example, if the following component
|
the uncapitalized non-qualified class name. For example, if the following component
|
||||||
classes were detected, the names would be `myMovieLister` and `movieFinderImpl`:
|
classes were detected, the names would be `myMovieLister` and `movieFinderImpl`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Service("myMovieLister")
|
@Service("myMovieLister")
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Service("myMovieLister")
|
@Service("myMovieLister")
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class MovieFinderImpl implements MovieFinder {
|
public class MovieFinderImpl implements MovieFinder {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class MovieFinderImpl : MovieFinder {
|
class MovieFinderImpl : MovieFinder {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you do not want to rely on the default bean-naming strategy, you can provide a custom
|
If you do not want to rely on the default bean-naming strategy, you can provide a custom
|
||||||
bean-naming strategy. First, implement the
|
bean-naming strategy. First, implement the
|
||||||
|
|
@ -657,8 +733,11 @@ fully qualified class name for the generated bean name. As of Spring Framework 5
|
||||||
`FullyQualifiedAnnotationBeanNameGenerator` located in package
|
`FullyQualifiedAnnotationBeanNameGenerator` located in package
|
||||||
`org.springframework.context.annotation` can be used for such purposes.
|
`org.springframework.context.annotation` can be used for such purposes.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
|
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
|
||||||
|
|
@ -666,8 +745,10 @@ fully qualified class name for the generated bean name. As of Spring Framework 5
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
|
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
|
||||||
|
|
@ -675,6 +756,7 @@ fully qualified class name for the generated bean name. As of Spring Framework 5
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
@ -698,8 +780,11 @@ autodetected components is `singleton`. However, sometimes you need a different
|
||||||
that can be specified by the `@Scope` annotation. You can provide the name of the
|
that can be specified by the `@Scope` annotation. You can provide the name of the
|
||||||
scope within the annotation, as the following example shows:
|
scope within the annotation, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
@Repository
|
@Repository
|
||||||
|
|
@ -707,8 +792,10 @@ scope within the annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
@Repository
|
@Repository
|
||||||
|
|
@ -716,6 +803,7 @@ scope within the annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: `@Scope` annotations are only introspected on the concrete bean class (for annotated
|
NOTE: `@Scope` annotations are only introspected on the concrete bean class (for annotated
|
||||||
components) or the factory method (for `@Bean` methods). In contrast to XML bean
|
components) or the factory method (for `@Bean` methods). In contrast to XML bean
|
||||||
|
|
@ -735,8 +823,11 @@ interface. Be sure to include a default no-arg constructor. Then you can provide
|
||||||
fully qualified class name when configuring the scanner, as the following example of both
|
fully qualified class name when configuring the scanner, as the following example of both
|
||||||
an annotation and a bean definition shows:
|
an annotation and a bean definition shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
|
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
|
||||||
|
|
@ -744,8 +835,10 @@ an annotation and a bean definition shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
|
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
|
||||||
|
|
@ -753,6 +846,7 @@ an annotation and a bean definition shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
@ -767,8 +861,11 @@ For this purpose, a scoped-proxy attribute is available on the component-scan
|
||||||
element. The three possible values are: `no`, `interfaces`, and `targetClass`. For example,
|
element. The three possible values are: `no`, `interfaces`, and `targetClass`. For example,
|
||||||
the following configuration results in standard JDK dynamic proxies:
|
the following configuration results in standard JDK dynamic proxies:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
|
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
|
||||||
|
|
@ -776,8 +873,10 @@ the following configuration results in standard JDK dynamic proxies:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
|
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
|
||||||
|
|
@ -785,6 +884,7 @@ the following configuration results in standard JDK dynamic proxies:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
@ -808,8 +908,11 @@ auto-detection of components, you can provide the qualifier metadata with type-l
|
||||||
annotations on the candidate class. The following three examples demonstrate this
|
annotations on the candidate class. The following three examples demonstrate this
|
||||||
technique:
|
technique:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Qualifier("Action")
|
@Qualifier("Action")
|
||||||
|
|
@ -817,16 +920,22 @@ technique:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Qualifier("Action")
|
@Qualifier("Action")
|
||||||
class ActionMovieCatalog : MovieCatalog
|
class ActionMovieCatalog : MovieCatalog
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Genre("Action")
|
@Genre("Action")
|
||||||
|
|
@ -834,8 +943,10 @@ technique:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Genre("Action")
|
@Genre("Action")
|
||||||
|
|
@ -843,9 +954,13 @@ technique:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Offline
|
@Offline
|
||||||
|
|
@ -853,8 +968,10 @@ technique:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
@Offline
|
@Offline
|
||||||
|
|
@ -862,6 +979,7 @@ class CachingMovieCatalog : MovieCatalog {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: As with most annotation-based alternatives, keep in mind that the annotation metadata is
|
NOTE: As with most annotation-based alternatives, keep in mind that the annotation metadata is
|
||||||
bound to the class definition itself, while the use of XML allows for multiple beans
|
bound to the class definition itself, while the use of XML allows for multiple beans
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,11 @@ The next example shows a program to run the `MessageSource` functionality.
|
||||||
Remember that all `ApplicationContext` implementations are also `MessageSource`
|
Remember that all `ApplicationContext` implementations are also `MessageSource`
|
||||||
implementations and so can be cast to the `MessageSource` interface.
|
implementations and so can be cast to the `MessageSource` interface.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
||||||
|
|
@ -107,8 +110,10 @@ implementations and so can be cast to the `MessageSource` interface.
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val resources = ClassPathXmlApplicationContext("beans.xml")
|
val resources = ClassPathXmlApplicationContext("beans.xml")
|
||||||
|
|
@ -116,6 +121,7 @@ implementations and so can be cast to the `MessageSource` interface.
|
||||||
println(message)
|
println(message)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The resulting output from the above program is as follows:
|
The resulting output from the above program is as follows:
|
||||||
|
|
||||||
|
|
@ -151,8 +157,11 @@ converted into `String` objects and inserted into placeholders in the lookup mes
|
||||||
</beans>
|
</beans>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
|
|
@ -169,8 +178,10 @@ converted into `String` objects and inserted into placeholders in the lookup mes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Example {
|
class Example {
|
||||||
|
|
||||||
|
|
@ -183,6 +194,7 @@ converted into `String` objects and inserted into placeholders in the lookup mes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The resulting output from the invocation of the `execute()` method is as follows:
|
The resulting output from the invocation of the `execute()` method is as follows:
|
||||||
|
|
||||||
|
|
@ -208,8 +220,11 @@ resolved is specified manually:
|
||||||
argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
|
argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) {
|
||||||
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
||||||
|
|
@ -218,8 +233,10 @@ argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val resources = ClassPathXmlApplicationContext("beans.xml")
|
val resources = ClassPathXmlApplicationContext("beans.xml")
|
||||||
|
|
@ -228,6 +245,7 @@ argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
|
||||||
println(message)
|
println(message)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The resulting output from the running of the above program is as follows:
|
The resulting output from the running of the above program is as follows:
|
||||||
|
|
||||||
|
|
@ -322,8 +340,11 @@ The following table describes the standard events that Spring provides:
|
||||||
You can also create and publish your own custom events. The following example shows a
|
You can also create and publish your own custom events. The following example shows a
|
||||||
simple class that extends Spring's `ApplicationEvent` base class:
|
simple class that extends Spring's `ApplicationEvent` base class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class BlockedListEvent extends ApplicationEvent {
|
public class BlockedListEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
|
@ -339,21 +360,27 @@ simple class that extends Spring's `ApplicationEvent` base class:
|
||||||
// accessor and other methods...
|
// accessor and other methods...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class BlockedListEvent(source: Any,
|
class BlockedListEvent(source: Any,
|
||||||
val address: String,
|
val address: String,
|
||||||
val content: String) : ApplicationEvent(source)
|
val content: String) : ApplicationEvent(source)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To publish a custom `ApplicationEvent`, call the `publishEvent()` method on an
|
To publish a custom `ApplicationEvent`, call the `publishEvent()` method on an
|
||||||
`ApplicationEventPublisher`. Typically, this is done by creating a class that implements
|
`ApplicationEventPublisher`. Typically, this is done by creating a class that implements
|
||||||
`ApplicationEventPublisherAware` and registering it as a Spring bean. The following
|
`ApplicationEventPublisherAware` and registering it as a Spring bean. The following
|
||||||
example shows such a class:
|
example shows such a class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class EmailService implements ApplicationEventPublisherAware {
|
public class EmailService implements ApplicationEventPublisherAware {
|
||||||
|
|
||||||
|
|
@ -377,8 +404,10 @@ example shows such a class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class EmailService : ApplicationEventPublisherAware {
|
class EmailService : ApplicationEventPublisherAware {
|
||||||
|
|
||||||
|
|
@ -402,6 +431,7 @@ example shows such a class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
At configuration time, the Spring container detects that `EmailService` implements
|
At configuration time, the Spring container detects that `EmailService` implements
|
||||||
`ApplicationEventPublisherAware` and automatically calls
|
`ApplicationEventPublisherAware` and automatically calls
|
||||||
|
|
@ -413,8 +443,11 @@ To receive the custom `ApplicationEvent`, you can create a class that implements
|
||||||
`ApplicationListener` and register it as a Spring bean. The following example
|
`ApplicationListener` and register it as a Spring bean. The following example
|
||||||
shows such a class:
|
shows such a class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
|
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
|
||||||
|
|
||||||
|
|
@ -429,8 +462,10 @@ shows such a class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class BlockedListNotifier : ApplicationListener<BlockedListEvent> {
|
class BlockedListNotifier : ApplicationListener<BlockedListEvent> {
|
||||||
|
|
||||||
|
|
@ -441,6 +476,7 @@ shows such a class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Notice that `ApplicationListener` is generically parameterized with the type of your
|
Notice that `ApplicationListener` is generically parameterized with the type of your
|
||||||
custom event (`BlockedListEvent` in the preceding example). This means that the
|
custom event (`BlockedListEvent` in the preceding example). This means that the
|
||||||
|
|
@ -497,8 +533,11 @@ architectures that build upon the well-known Spring programming model.
|
||||||
You can register an event listener on any method of a managed bean by using the
|
You can register an event listener on any method of a managed bean by using the
|
||||||
`@EventListener` annotation. The `BlockedListNotifier` can be rewritten as follows:
|
`@EventListener` annotation. The `BlockedListNotifier` can be rewritten as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class BlockedListNotifier {
|
public class BlockedListNotifier {
|
||||||
|
|
||||||
|
|
@ -514,8 +553,10 @@ You can register an event listener on any method of a managed bean by using the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class BlockedListNotifier {
|
class BlockedListNotifier {
|
||||||
|
|
||||||
|
|
@ -527,6 +568,7 @@ You can register an event listener on any method of a managed bean by using the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The method signature once again declares the event type to which it listens,
|
The method signature once again declares the event type to which it listens,
|
||||||
but, this time, with a flexible name and without implementing a specific listener interface.
|
but, this time, with a flexible name and without implementing a specific listener interface.
|
||||||
|
|
@ -537,22 +579,28 @@ If your method should listen to several events or if you want to define it with
|
||||||
parameter at all, the event types can also be specified on the annotation itself. The
|
parameter at all, the event types can also be specified on the annotation itself. The
|
||||||
following example shows how to do so:
|
following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
|
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
|
||||||
public void handleContextStart() {
|
public void handleContextStart() {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener(ContextStartedEvent::class, ContextRefreshedEvent::class)
|
@EventListener(ContextStartedEvent::class, ContextRefreshedEvent::class)
|
||||||
fun handleContextStart() {
|
fun handleContextStart() {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
It is also possible to add additional runtime filtering by using the `condition` attribute
|
It is also possible to add additional runtime filtering by using the `condition` attribute
|
||||||
of the annotation that defines a xref:core/expressions.adoc[`SpEL` expression], which should match
|
of the annotation that defines a xref:core/expressions.adoc[`SpEL` expression], which should match
|
||||||
|
|
@ -561,22 +609,28 @@ to actually invoke the method for a particular event.
|
||||||
The following example shows how our notifier can be rewritten to be invoked only if the
|
The following example shows how our notifier can be rewritten to be invoked only if the
|
||||||
`content` attribute of the event is equal to `my-event`:
|
`content` attribute of the event is equal to `my-event`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener(condition = "#blEvent.content == 'my-event'")
|
@EventListener(condition = "#blEvent.content == 'my-event'")
|
||||||
public void processBlockedListEvent(BlockedListEvent blEvent) {
|
public void processBlockedListEvent(BlockedListEvent blEvent) {
|
||||||
// notify appropriate parties via notificationAddress...
|
// notify appropriate parties via notificationAddress...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener(condition = "#blEvent.content == 'my-event'")
|
@EventListener(condition = "#blEvent.content == 'my-event'")
|
||||||
fun processBlockedListEvent(blEvent: BlockedListEvent) {
|
fun processBlockedListEvent(blEvent: BlockedListEvent) {
|
||||||
// notify appropriate parties via notificationAddress...
|
// notify appropriate parties via notificationAddress...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Each `SpEL` expression evaluates against a dedicated context. The following table lists the
|
Each `SpEL` expression evaluates against a dedicated context. The following table lists the
|
||||||
items made available to the context so that you can use them for conditional event processing:
|
items made available to the context so that you can use them for conditional event processing:
|
||||||
|
|
@ -611,8 +665,11 @@ signature actually refers to an arbitrary object that was published.
|
||||||
If you need to publish an event as the result of processing another event, you can change the
|
If you need to publish an event as the result of processing another event, you can change the
|
||||||
method signature to return the event that should be published, as the following example shows:
|
method signature to return the event that should be published, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
public ListUpdateEvent handleBlockedListEvent(BlockedListEvent event) {
|
public ListUpdateEvent handleBlockedListEvent(BlockedListEvent event) {
|
||||||
|
|
@ -620,8 +677,10 @@ method signature to return the event that should be published, as the following
|
||||||
// then publish a ListUpdateEvent...
|
// then publish a ListUpdateEvent...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
fun handleBlockedListEvent(event: BlockedListEvent): ListUpdateEvent {
|
fun handleBlockedListEvent(event: BlockedListEvent): ListUpdateEvent {
|
||||||
|
|
@ -629,6 +688,7 @@ method signature to return the event that should be published, as the following
|
||||||
// then publish a ListUpdateEvent...
|
// then publish a ListUpdateEvent...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: This feature is not supported for
|
NOTE: This feature is not supported for
|
||||||
xref:core/beans/context-introduction.adoc#context-functionality-events-async[asynchronous listeners].
|
xref:core/beans/context-introduction.adoc#context-functionality-events-async[asynchronous listeners].
|
||||||
|
|
@ -645,8 +705,11 @@ If you want a particular listener to process events asynchronously, you can reus
|
||||||
xref:integration/scheduling.adoc#scheduling-annotation-support-async[regular `@Async` support].
|
xref:integration/scheduling.adoc#scheduling-annotation-support-async[regular `@Async` support].
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
@Async
|
@Async
|
||||||
|
|
@ -654,8 +717,10 @@ The following example shows how to do so:
|
||||||
// BlockedListEvent is processed in a separate thread
|
// BlockedListEvent is processed in a separate thread
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
@Async
|
@Async
|
||||||
|
|
@ -663,6 +728,7 @@ The following example shows how to do so:
|
||||||
// BlockedListEvent is processed in a separate thread
|
// BlockedListEvent is processed in a separate thread
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Be aware of the following limitations when using asynchronous events:
|
Be aware of the following limitations when using asynchronous events:
|
||||||
|
|
||||||
|
|
@ -682,8 +748,11 @@ Be aware of the following limitations when using asynchronous events:
|
||||||
If you need one listener to be invoked before another one, you can add the `@Order`
|
If you need one listener to be invoked before another one, you can add the `@Order`
|
||||||
annotation to the method declaration, as the following example shows:
|
annotation to the method declaration, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
@Order(42)
|
@Order(42)
|
||||||
|
|
@ -691,8 +760,10 @@ annotation to the method declaration, as the following example shows:
|
||||||
// notify appropriate parties via notificationAddress...
|
// notify appropriate parties via notificationAddress...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
@Order(42)
|
@Order(42)
|
||||||
|
|
@ -700,6 +771,7 @@ annotation to the method declaration, as the following example shows:
|
||||||
// notify appropriate parties via notificationAddress...
|
// notify appropriate parties via notificationAddress...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[context-functionality-events-generics]]
|
[[context-functionality-events-generics]]
|
||||||
|
|
@ -710,22 +782,28 @@ You can also use generics to further define the structure of your event. Conside
|
||||||
can create the following listener definition to receive only `EntityCreatedEvent` for a
|
can create the following listener definition to receive only `EntityCreatedEvent` for a
|
||||||
`Person`:
|
`Person`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
public void onPersonCreated(EntityCreatedEvent<Person> event) {
|
public void onPersonCreated(EntityCreatedEvent<Person> event) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@EventListener
|
@EventListener
|
||||||
fun onPersonCreated(event: EntityCreatedEvent<Person>) {
|
fun onPersonCreated(event: EntityCreatedEvent<Person>) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Due to type erasure, this works only if the event that is fired resolves the generic
|
Due to type erasure, this works only if the event that is fired resolves the generic
|
||||||
parameters on which the event listener filters (that is, something like
|
parameters on which the event listener filters (that is, something like
|
||||||
|
|
@ -736,8 +814,11 @@ structure (as should be the case for the event in the preceding example). In suc
|
||||||
you can implement `ResolvableTypeProvider` to guide the framework beyond what the runtime
|
you can implement `ResolvableTypeProvider` to guide the framework beyond what the runtime
|
||||||
environment provides. The following event shows how to do so:
|
environment provides. The following event shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
|
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
|
||||||
|
|
||||||
|
|
@ -751,8 +832,10 @@ environment provides. The following event shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class EntityCreatedEvent<T>(entity: T) : ApplicationEvent(entity), ResolvableTypeProvider {
|
class EntityCreatedEvent<T>(entity: T) : ApplicationEvent(entity), ResolvableTypeProvider {
|
||||||
|
|
||||||
|
|
@ -761,6 +844,7 @@ environment provides. The following event shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
TIP: This works not only for `ApplicationEvent` but any arbitrary object that you send as
|
TIP: This works not only for `ApplicationEvent` but any arbitrary object that you send as
|
||||||
an event.
|
an event.
|
||||||
|
|
@ -819,8 +903,11 @@ The `AbstractApplicationContext` (and its subclasses) is instrumented with an
|
||||||
|
|
||||||
Here is an example of instrumentation in the `AnnotationConfigApplicationContext`:
|
Here is an example of instrumentation in the `AnnotationConfigApplicationContext`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// create a startup step and start recording
|
// create a startup step and start recording
|
||||||
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan");
|
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan");
|
||||||
|
|
@ -831,8 +918,10 @@ Here is an example of instrumentation in the `AnnotationConfigApplicationContext
|
||||||
// end the current step
|
// end the current step
|
||||||
scanPackages.end();
|
scanPackages.end();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// create a startup step and start recording
|
// create a startup step and start recording
|
||||||
val scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
|
val scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
|
||||||
|
|
@ -843,6 +932,7 @@ Here is an example of instrumentation in the `AnnotationConfigApplicationContext
|
||||||
// end the current step
|
// end the current step
|
||||||
scanPackages.end()
|
scanPackages.end()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The application context is already instrumented with multiple steps.
|
The application context is already instrumented with multiple steps.
|
||||||
Once recorded, these startup steps can be collected, displayed and analyzed with specific tools.
|
Once recorded, these startup steps can be collected, displayed and analyzed with specific tools.
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,27 @@ loaded into the Java virtual machine (JVM).
|
||||||
To enable load-time weaving, you can add the `@EnableLoadTimeWeaving` to one of your
|
To enable load-time weaving, you can add the `@EnableLoadTimeWeaving` to one of your
|
||||||
`@Configuration` classes, as the following example shows:
|
`@Configuration` classes, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableLoadTimeWeaving
|
@EnableLoadTimeWeaving
|
||||||
class AppConfig
|
class AppConfig
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Alternatively, for XML configuration, you can use the `context:load-time-weaver` element:
|
Alternatively, for XML configuration, you can use the `context:load-time-weaver` element:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -260,8 +260,11 @@ specify a factory method:
|
||||||
|
|
||||||
The following example shows a class that would work with the preceding bean definition:
|
The following example shows a class that would work with the preceding bean definition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ClientService {
|
public class ClientService {
|
||||||
private static ClientService clientService = new ClientService();
|
private static ClientService clientService = new ClientService();
|
||||||
|
|
@ -272,8 +275,10 @@ The following example shows a class that would work with the preceding bean defi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ClientService private constructor() {
|
class ClientService private constructor() {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -283,6 +288,7 @@ The following example shows a class that would work with the preceding bean defi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For details about the mechanism for supplying (optional) arguments to the factory method
|
For details about the mechanism for supplying (optional) arguments to the factory method
|
||||||
and setting object instance properties after the object is returned from the factory,
|
and setting object instance properties after the object is returned from the factory,
|
||||||
|
|
@ -316,8 +322,11 @@ how to configure such a bean:
|
||||||
|
|
||||||
The following example shows the corresponding class:
|
The following example shows the corresponding class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class DefaultServiceLocator {
|
public class DefaultServiceLocator {
|
||||||
|
|
||||||
|
|
@ -328,8 +337,10 @@ The following example shows the corresponding class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DefaultServiceLocator {
|
class DefaultServiceLocator {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -340,6 +351,7 @@ The following example shows the corresponding class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
One factory class can also hold more than one factory method, as the following example shows:
|
One factory class can also hold more than one factory method, as the following example shows:
|
||||||
|
|
||||||
|
|
@ -360,8 +372,11 @@ One factory class can also hold more than one factory method, as the following e
|
||||||
|
|
||||||
The following example shows the corresponding class:
|
The following example shows the corresponding class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class DefaultServiceLocator {
|
public class DefaultServiceLocator {
|
||||||
|
|
||||||
|
|
@ -378,8 +393,10 @@ The following example shows the corresponding class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DefaultServiceLocator {
|
class DefaultServiceLocator {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -396,6 +413,7 @@ The following example shows the corresponding class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This approach shows that the factory bean itself can be managed and configured through
|
This approach shows that the factory bean itself can be managed and configured through
|
||||||
dependency injection (DI). See xref:core/beans/dependencies/factory-properties-detailed.adoc[Dependencies and Configuration in Detail]
|
dependency injection (DI). See xref:core/beans/dependencies/factory-properties-detailed.adoc[Dependencies and Configuration in Detail]
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@ treats arguments to a constructor and to a `static` factory method similarly. Th
|
||||||
following example shows a class that can only be dependency-injected with constructor
|
following example shows a class that can only be dependency-injected with constructor
|
||||||
injection:
|
injection:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -46,14 +49,17 @@ injection:
|
||||||
// business logic that actually uses the injected MovieFinder is omitted...
|
// business logic that actually uses the injected MovieFinder is omitted...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// a constructor so that the Spring container can inject a MovieFinder
|
// a constructor so that the Spring container can inject a MovieFinder
|
||||||
class SimpleMovieLister(private val movieFinder: MovieFinder) {
|
class SimpleMovieLister(private val movieFinder: MovieFinder) {
|
||||||
// business logic that actually uses the injected MovieFinder is omitted...
|
// business logic that actually uses the injected MovieFinder is omitted...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Notice that there is nothing special about this class. It is a POJO that
|
Notice that there is nothing special about this class. It is a POJO that
|
||||||
has no dependencies on container specific interfaces, base classes, or annotations.
|
has no dependencies on container specific interfaces, base classes, or annotations.
|
||||||
|
|
@ -67,8 +73,11 @@ order in which the constructor arguments are defined in a bean definition is the
|
||||||
in which those arguments are supplied to the appropriate constructor when the bean is
|
in which those arguments are supplied to the appropriate constructor when the bean is
|
||||||
being instantiated. Consider the following class:
|
being instantiated. Consider the following class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package x.y;
|
package x.y;
|
||||||
|
|
||||||
|
|
@ -79,13 +88,16 @@ being instantiated. Consider the following class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package x.y
|
package x.y
|
||||||
|
|
||||||
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
|
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Assuming that the `ThingTwo` and `ThingThree` classes are not related by inheritance, no
|
Assuming that the `ThingTwo` and `ThingThree` classes are not related by inheritance, no
|
||||||
potential ambiguity exists. Thus, the following configuration works fine, and you do not
|
potential ambiguity exists. Thus, the following configuration works fine, and you do not
|
||||||
|
|
@ -111,8 +123,11 @@ case with the preceding example). When a simple type is used, such as
|
||||||
`<value>true</value>`, Spring cannot determine the type of the value, and so cannot match
|
`<value>true</value>`, Spring cannot determine the type of the value, and so cannot match
|
||||||
by type without help. Consider the following class:
|
by type without help. Consider the following class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package examples;
|
package examples;
|
||||||
|
|
||||||
|
|
@ -130,8 +145,10 @@ by type without help. Consider the following class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package examples
|
package examples
|
||||||
|
|
||||||
|
|
@ -140,6 +157,7 @@ by type without help. Consider the following class:
|
||||||
private val ultimateAnswer: String // The Answer to Life, the Universe, and Everything
|
private val ultimateAnswer: String // The Answer to Life, the Universe, and Everything
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
.[[beans-factory-ctor-arguments-type]]Constructor argument type matching
|
.[[beans-factory-ctor-arguments-type]]Constructor argument type matching
|
||||||
--
|
--
|
||||||
|
|
@ -195,8 +213,11 @@ https://download.oracle.com/javase/8/docs/api/java/beans/ConstructorProperties.h
|
||||||
JDK annotation to explicitly name your constructor arguments. The sample class would
|
JDK annotation to explicitly name your constructor arguments. The sample class would
|
||||||
then have to look as follows:
|
then have to look as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package examples;
|
package examples;
|
||||||
|
|
||||||
|
|
@ -211,8 +232,10 @@ then have to look as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package examples
|
package examples
|
||||||
|
|
||||||
|
|
@ -220,6 +243,7 @@ then have to look as follows:
|
||||||
@ConstructorProperties("years", "ultimateAnswer")
|
@ConstructorProperties("years", "ultimateAnswer")
|
||||||
constructor(val years: Int, val ultimateAnswer: String)
|
constructor(val years: Int, val ultimateAnswer: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -234,8 +258,11 @@ The following example shows a class that can only be dependency-injected by usin
|
||||||
setter injection. This class is conventional Java. It is a POJO that has no dependencies
|
setter injection. This class is conventional Java. It is a POJO that has no dependencies
|
||||||
on container specific interfaces, base classes, or annotations.
|
on container specific interfaces, base classes, or annotations.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -250,8 +277,10 @@ on container specific interfaces, base classes, or annotations.
|
||||||
// business logic that actually uses the injected MovieFinder is omitted...
|
// business logic that actually uses the injected MovieFinder is omitted...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -261,6 +290,7 @@ class SimpleMovieLister {
|
||||||
// business logic that actually uses the injected MovieFinder is omitted...
|
// business logic that actually uses the injected MovieFinder is omitted...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
The `ApplicationContext` supports constructor-based and setter-based DI for the beans it
|
The `ApplicationContext` supports constructor-based and setter-based DI for the beans it
|
||||||
|
|
@ -403,8 +433,11 @@ part of a Spring XML configuration file specifies some bean definitions as follo
|
||||||
|
|
||||||
The following example shows the corresponding `ExampleBean` class:
|
The following example shows the corresponding `ExampleBean` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ExampleBean {
|
public class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -427,8 +460,10 @@ The following example shows the corresponding `ExampleBean` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ExampleBean {
|
class ExampleBean {
|
||||||
lateinit var beanOne: AnotherBean
|
lateinit var beanOne: AnotherBean
|
||||||
|
|
@ -436,6 +471,7 @@ class ExampleBean {
|
||||||
var i: Int = 0
|
var i: Int = 0
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example, setters are declared to match against the properties specified
|
In the preceding example, setters are declared to match against the properties specified
|
||||||
in the XML file. The following example uses constructor-based DI:
|
in the XML file. The following example uses constructor-based DI:
|
||||||
|
|
@ -460,8 +496,11 @@ in the XML file. The following example uses constructor-based DI:
|
||||||
|
|
||||||
The following example shows the corresponding `ExampleBean` class:
|
The following example shows the corresponding `ExampleBean` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ExampleBean {
|
public class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -479,14 +518,17 @@ The following example shows the corresponding `ExampleBean` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ExampleBean(
|
class ExampleBean(
|
||||||
private val beanOne: AnotherBean,
|
private val beanOne: AnotherBean,
|
||||||
private val beanTwo: YetAnotherBean,
|
private val beanTwo: YetAnotherBean,
|
||||||
private val i: Int)
|
private val i: Int)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The constructor arguments specified in the bean definition are used as arguments to
|
The constructor arguments specified in the bean definition are used as arguments to
|
||||||
the constructor of the `ExampleBean`.
|
the constructor of the `ExampleBean`.
|
||||||
|
|
@ -508,8 +550,11 @@ told to call a `static` factory method to return an instance of the object:
|
||||||
|
|
||||||
The following example shows the corresponding `ExampleBean` class:
|
The following example shows the corresponding `ExampleBean` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ExampleBean {
|
public class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -530,8 +575,10 @@ The following example shows the corresponding `ExampleBean` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ExampleBean private constructor() {
|
class ExampleBean private constructor() {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -547,6 +594,7 @@ The following example shows the corresponding `ExampleBean` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Arguments to the `static` factory method are supplied by `<constructor-arg/>` elements,
|
Arguments to the `static` factory method are supplied by `<constructor-arg/>` elements,
|
||||||
exactly the same as if a constructor had actually been used. The type of the class being
|
exactly the same as if a constructor had actually been used. The type of the class being
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,11 @@ and by xref:core/beans/basics.adoc#beans-factory-client[making a `getBean("B")`
|
||||||
typically new) bean B instance every time bean A needs it. The following example
|
typically new) bean B instance every time bean A needs it. The following example
|
||||||
shows this approach:
|
shows this approach:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package fiona.apple;
|
package fiona.apple;
|
||||||
|
|
||||||
|
|
@ -54,8 +57,10 @@ shows this approach:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package fiona.apple
|
package fiona.apple
|
||||||
|
|
||||||
|
|
@ -86,6 +91,7 @@ shows this approach:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding is not desirable, because the business code is aware of and coupled to the
|
The preceding is not desirable, because the business code is aware of and coupled to the
|
||||||
Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC
|
Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC
|
||||||
|
|
@ -127,8 +133,11 @@ Spring container dynamically overrides the implementation of the `createCommand(
|
||||||
method. The `CommandManager` class does not have any Spring dependencies, as
|
method. The `CommandManager` class does not have any Spring dependencies, as
|
||||||
the reworked example shows:
|
the reworked example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package fiona.apple;
|
package fiona.apple;
|
||||||
|
|
||||||
|
|
@ -148,8 +157,10 @@ the reworked example shows:
|
||||||
protected abstract Command createCommand();
|
protected abstract Command createCommand();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package fiona.apple
|
package fiona.apple
|
||||||
|
|
||||||
|
|
@ -169,6 +180,7 @@ the reworked example shows:
|
||||||
protected abstract fun createCommand(): Command
|
protected abstract fun createCommand(): Command
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the client class that contains the method to be injected (the `CommandManager` in this
|
In the client class that contains the method to be injected (the `CommandManager` in this
|
||||||
case), the method to be injected requires a signature of the following form:
|
case), the method to be injected requires a signature of the following form:
|
||||||
|
|
@ -204,8 +216,11 @@ bean is returned each time.
|
||||||
Alternatively, within the annotation-based component model, you can declare a lookup
|
Alternatively, within the annotation-based component model, you can declare a lookup
|
||||||
method through the `@Lookup` annotation, as the following example shows:
|
method through the `@Lookup` annotation, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public abstract class CommandManager {
|
public abstract class CommandManager {
|
||||||
|
|
||||||
|
|
@ -219,8 +234,10 @@ method through the `@Lookup` annotation, as the following example shows:
|
||||||
protected abstract Command createCommand();
|
protected abstract Command createCommand();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
abstract class CommandManager {
|
abstract class CommandManager {
|
||||||
|
|
||||||
|
|
@ -234,12 +251,16 @@ method through the `@Lookup` annotation, as the following example shows:
|
||||||
protected abstract fun createCommand(): Command
|
protected abstract fun createCommand(): Command
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Or, more idiomatically, you can rely on the target bean getting resolved against the
|
Or, more idiomatically, you can rely on the target bean getting resolved against the
|
||||||
declared return type of the lookup method:
|
declared return type of the lookup method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public abstract class CommandManager {
|
public abstract class CommandManager {
|
||||||
|
|
||||||
|
|
@ -253,8 +274,10 @@ declared return type of the lookup method:
|
||||||
protected abstract Command createCommand();
|
protected abstract Command createCommand();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
abstract class CommandManager {
|
abstract class CommandManager {
|
||||||
|
|
||||||
|
|
@ -268,6 +291,7 @@ declared return type of the lookup method:
|
||||||
protected abstract fun createCommand(): Command
|
protected abstract fun createCommand(): Command
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Note that you should typically declare such annotated lookup methods with a concrete
|
Note that you should typically declare such annotated lookup methods with a concrete
|
||||||
stub implementation, in order for them to be compatible with Spring's component
|
stub implementation, in order for them to be compatible with Spring's component
|
||||||
|
|
@ -296,8 +320,11 @@ With XML-based configuration metadata, you can use the `replaced-method` element
|
||||||
replace an existing method implementation with another, for a deployed bean. Consider
|
replace an existing method implementation with another, for a deployed bean. Consider
|
||||||
the following class, which has a method called `computeValue` that we want to override:
|
the following class, which has a method called `computeValue` that we want to override:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MyValueCalculator {
|
public class MyValueCalculator {
|
||||||
|
|
||||||
|
|
@ -308,8 +335,10 @@ the following class, which has a method called `computeValue` that we want to ov
|
||||||
// some other methods...
|
// some other methods...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MyValueCalculator {
|
class MyValueCalculator {
|
||||||
|
|
||||||
|
|
@ -320,12 +349,16 @@ the following class, which has a method called `computeValue` that we want to ov
|
||||||
// some other methods...
|
// some other methods...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
A class that implements the `org.springframework.beans.factory.support.MethodReplacer`
|
A class that implements the `org.springframework.beans.factory.support.MethodReplacer`
|
||||||
interface provides the new method definition, as the following example shows:
|
interface provides the new method definition, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
/**
|
/**
|
||||||
* meant to be used to override the existing computeValue(String)
|
* meant to be used to override the existing computeValue(String)
|
||||||
|
|
@ -341,8 +374,10 @@ interface provides the new method definition, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
/**
|
/**
|
||||||
* meant to be used to override the existing computeValue(String)
|
* meant to be used to override the existing computeValue(String)
|
||||||
|
|
@ -358,6 +393,7 @@ interface provides the new method definition, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,8 +350,11 @@ type-conversion support such that the elements of your strongly-typed `Collectio
|
||||||
instances are converted to the appropriate type prior to being added to the `Collection`.
|
instances are converted to the appropriate type prior to being added to the `Collection`.
|
||||||
The following Java class and bean definition show how to do so:
|
The following Java class and bean definition show how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SomeClass {
|
public class SomeClass {
|
||||||
|
|
||||||
|
|
@ -362,13 +365,16 @@ The following Java class and bean definition show how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
lateinit var accounts: Map<String, Float>
|
lateinit var accounts: Map<String, Float>
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
@ -408,16 +414,22 @@ following XML-based configuration metadata snippet sets the `email` property to
|
||||||
|
|
||||||
The preceding example is equivalent to the following Java code:
|
The preceding example is equivalent to the following Java code:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
exampleBean.setEmail("");
|
exampleBean.setEmail("");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
exampleBean.email = ""
|
exampleBean.email = ""
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
The `<null/>` element handles `null` values. The following listing shows an example:
|
The `<null/>` element handles `null` values. The following listing shows an example:
|
||||||
|
|
@ -433,16 +445,22 @@ The `<null/>` element handles `null` values. The following listing shows an exam
|
||||||
|
|
||||||
The preceding configuration is equivalent to the following Java code:
|
The preceding configuration is equivalent to the following Java code:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
exampleBean.setEmail(null);
|
exampleBean.setEmail(null);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
exampleBean.email = null
|
exampleBean.email = null
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-p-namespace]]
|
[[beans-p-namespace]]
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,11 @@ B deployments.
|
||||||
Consider the first use case in a practical application that requires a
|
Consider the first use case in a practical application that requires a
|
||||||
`DataSource`. In a test environment, the configuration might resemble the following:
|
`DataSource`. In a test environment, the configuration might resemble the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
public DataSource dataSource() {
|
public DataSource dataSource() {
|
||||||
|
|
@ -51,8 +54,10 @@ Consider the first use case in a practical application that requires a
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
fun dataSource(): DataSource {
|
fun dataSource(): DataSource {
|
||||||
|
|
@ -63,14 +68,18 @@ Consider the first use case in a practical application that requires a
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now consider how this application can be deployed into a QA or production
|
Now consider how this application can be deployed into a QA or production
|
||||||
environment, assuming that the datasource for the application is registered
|
environment, assuming that the datasource for the application is registered
|
||||||
with the production application server's JNDI directory. Our `dataSource` bean
|
with the production application server's JNDI directory. Our `dataSource` bean
|
||||||
now looks like the following listing:
|
now looks like the following listing:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Bean(destroyMethod = "")
|
@Bean(destroyMethod = "")
|
||||||
public DataSource dataSource() throws Exception {
|
public DataSource dataSource() throws Exception {
|
||||||
|
|
@ -78,8 +87,10 @@ now looks like the following listing:
|
||||||
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
|
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Bean(destroyMethod = "")
|
@Bean(destroyMethod = "")
|
||||||
fun dataSource(): DataSource {
|
fun dataSource(): DataSource {
|
||||||
|
|
@ -87,6 +98,7 @@ now looks like the following listing:
|
||||||
return ctx.lookup("java:comp/env/jdbc/datasource") as DataSource
|
return ctx.lookup("java:comp/env/jdbc/datasource") as DataSource
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The problem is how to switch between using these two variations based on the
|
The problem is how to switch between using these two variations based on the
|
||||||
current environment. Over time, Spring users have devised a number of ways to
|
current environment. Over time, Spring users have devised a number of ways to
|
||||||
|
|
@ -112,8 +124,11 @@ when one or more specified profiles are active. Using our preceding example, we
|
||||||
can rewrite the `dataSource` configuration as follows:
|
can rewrite the `dataSource` configuration as follows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@Profile("development")
|
@Profile("development")
|
||||||
|
|
@ -129,8 +144,10 @@ can rewrite the `dataSource` configuration as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@Profile("development")
|
@Profile("development")
|
||||||
|
|
@ -146,11 +163,15 @@ can rewrite the `dataSource` configuration as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@Profile("production")
|
@Profile("production")
|
||||||
|
|
@ -163,6 +184,7 @@ can rewrite the `dataSource` configuration as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> `@Bean(destroyMethod = "")` disables default destroy method inference.
|
<1> `@Bean(destroyMethod = "")` disables default destroy method inference.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -206,8 +228,11 @@ of creating a custom composed annotation. The following example defines a custom
|
||||||
`@Profile("production")`:
|
`@Profile("production")`:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -215,14 +240,17 @@ of creating a custom composed annotation. The following example defines a custom
|
||||||
public @interface Production {
|
public @interface Production {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Profile("production")
|
@Profile("production")
|
||||||
annotation class Production
|
annotation class Production
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
TIP: If a `@Configuration` class is marked with `@Profile`, all of the `@Bean` methods and
|
TIP: If a `@Configuration` class is marked with `@Profile`, all of the `@Bean` methods and
|
||||||
|
|
@ -239,8 +267,11 @@ of a configuration class (for example, for alternative variants of a particular
|
||||||
the following example shows:
|
the following example shows:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -263,6 +294,7 @@ the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> The `standaloneDataSource` method is available only in the `development` profile.
|
<1> The `standaloneDataSource` method is available only in the `development` profile.
|
||||||
<2> The `jndiDataSource` method is available only in the `production` profile.
|
<2> The `jndiDataSource` method is available only in the `production` profile.
|
||||||
|
|
||||||
|
|
@ -416,16 +448,21 @@ Activating a profile can be done in several ways, but the most straightforward i
|
||||||
it programmatically against the `Environment` API which is available through an
|
it programmatically against the `Environment` API which is available through an
|
||||||
`ApplicationContext`. The following example shows how to do so:
|
`ApplicationContext`. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.getEnvironment().setActiveProfiles("development");
|
ctx.getEnvironment().setActiveProfiles("development");
|
||||||
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
|
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = AnnotationConfigApplicationContext().apply {
|
val ctx = AnnotationConfigApplicationContext().apply {
|
||||||
environment.setActiveProfiles("development")
|
environment.setActiveProfiles("development")
|
||||||
|
|
@ -433,6 +470,7 @@ it programmatically against the `Environment` API which is available through an
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In addition, you can also declaratively activate profiles through the
|
In addition, you can also declaratively activate profiles through the
|
||||||
`spring.profiles.active` property, which may be specified through system environment
|
`spring.profiles.active` property, which may be specified through system environment
|
||||||
|
|
@ -447,16 +485,22 @@ profiles at once. Programmatically, you can provide multiple profile names to th
|
||||||
`setActiveProfiles()` method, which accepts `String...` varargs. The following example
|
`setActiveProfiles()` method, which accepts `String...` varargs. The following example
|
||||||
activates multiple profiles:
|
activates multiple profiles:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
|
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
ctx.getEnvironment().setActiveProfiles("profile1", "profile2")
|
ctx.getEnvironment().setActiveProfiles("profile1", "profile2")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Declaratively, `spring.profiles.active` may accept a comma-separated list of profile names,
|
Declaratively, `spring.profiles.active` may accept a comma-separated list of profile names,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
@ -473,8 +517,11 @@ as the following example shows:
|
||||||
The default profile represents the profile that is enabled by default. Consider the
|
The default profile represents the profile that is enabled by default. Consider the
|
||||||
following example:
|
following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@Profile("default")
|
@Profile("default")
|
||||||
|
|
@ -489,8 +536,10 @@ following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@Profile("default")
|
@Profile("default")
|
||||||
|
|
@ -505,6 +554,7 @@ following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If no profile is active, the `dataSource` is created. You can see this
|
If no profile is active, the `dataSource` is created. You can see this
|
||||||
as a way to provide a default definition for one or more beans. If any
|
as a way to provide a default definition for one or more beans. If any
|
||||||
|
|
@ -521,22 +571,28 @@ the `Environment` or, declaratively, by using the `spring.profiles.default` prop
|
||||||
Spring's `Environment` abstraction provides search operations over a configurable
|
Spring's `Environment` abstraction provides search operations over a configurable
|
||||||
hierarchy of property sources. Consider the following listing:
|
hierarchy of property sources. Consider the following listing:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx = new GenericApplicationContext();
|
ApplicationContext ctx = new GenericApplicationContext();
|
||||||
Environment env = ctx.getEnvironment();
|
Environment env = ctx.getEnvironment();
|
||||||
boolean containsMyProperty = env.containsProperty("my-property");
|
boolean containsMyProperty = env.containsProperty("my-property");
|
||||||
System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
|
System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = GenericApplicationContext()
|
val ctx = GenericApplicationContext()
|
||||||
val env = ctx.environment
|
val env = ctx.environment
|
||||||
val containsMyProperty = env.containsProperty("my-property")
|
val containsMyProperty = env.containsProperty("my-property")
|
||||||
println("Does my environment contain the 'my-property' property? $containsMyProperty")
|
println("Does my environment contain the 'my-property' property? $containsMyProperty")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding snippet, we see a high-level way of asking Spring whether the `my-property` property is
|
In the preceding snippet, we see a high-level way of asking Spring whether the `my-property` property is
|
||||||
defined for the current environment. To answer this question, the `Environment` object performs
|
defined for the current environment. To answer this question, the `Environment` object performs
|
||||||
|
|
@ -580,20 +636,26 @@ of properties that you want to integrate into this search. To do so, implement
|
||||||
and instantiate your own `PropertySource` and add it to the set of `PropertySources` for the
|
and instantiate your own `PropertySource` and add it to the set of `PropertySources` for the
|
||||||
current `Environment`. The following example shows how to do so:
|
current `Environment`. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ConfigurableApplicationContext ctx = new GenericApplicationContext();
|
ConfigurableApplicationContext ctx = new GenericApplicationContext();
|
||||||
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
|
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
|
||||||
sources.addFirst(new MyPropertySource());
|
sources.addFirst(new MyPropertySource());
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = GenericApplicationContext()
|
val ctx = GenericApplicationContext()
|
||||||
val sources = ctx.environment.propertySources
|
val sources = ctx.environment.propertySources
|
||||||
sources.addFirst(MyPropertySource())
|
sources.addFirst(MyPropertySource())
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding code, `MyPropertySource` has been added with highest precedence in the
|
In the preceding code, `MyPropertySource` has been added with highest precedence in the
|
||||||
search. If it contains a `my-property` property, the property is detected and returned, in favor of
|
search. If it contains a `my-property` property, the property is detected and returned, in favor of
|
||||||
|
|
@ -615,8 +677,11 @@ Given a file called `app.properties` that contains the key-value pair `testbean.
|
||||||
the following `@Configuration` class uses `@PropertySource` in such a way that
|
the following `@Configuration` class uses `@PropertySource` in such a way that
|
||||||
a call to `testBean.getName()` returns `myTestBean`:
|
a call to `testBean.getName()` returns `myTestBean`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:/com/myco/app.properties")
|
@PropertySource("classpath:/com/myco/app.properties")
|
||||||
|
|
@ -633,8 +698,10 @@ a call to `testBean.getName()` returns `myTestBean`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:/com/myco/app.properties")
|
@PropertySource("classpath:/com/myco/app.properties")
|
||||||
|
|
@ -649,13 +716,17 @@ a call to `testBean.getName()` returns `myTestBean`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Any `${...}` placeholders present in a `@PropertySource` resource location are
|
Any `${...}` placeholders present in a `@PropertySource` resource location are
|
||||||
resolved against the set of property sources already registered against the
|
resolved against the set of property sources already registered against the
|
||||||
environment, as the following example shows:
|
environment, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
|
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
|
||||||
|
|
@ -672,8 +743,10 @@ environment, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@PropertySource("classpath:/com/\${my.placeholder:default/path}/app.properties")
|
@PropertySource("classpath:/com/\${my.placeholder:default/path}/app.properties")
|
||||||
|
|
@ -688,6 +761,7 @@ environment, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Assuming that `my.placeholder` is present in one of the property sources already
|
Assuming that `my.placeholder` is present in one of the property sources already
|
||||||
registered (for example, system properties or environment variables), the placeholder is
|
registered (for example, system properties or environment variables), the placeholder is
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,11 @@ it is created by the container and prints the resulting string to the system con
|
||||||
|
|
||||||
The following listing shows the custom `BeanPostProcessor` implementation class definition:
|
The following listing shows the custom `BeanPostProcessor` implementation class definition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package scripting;
|
package scripting;
|
||||||
|
|
||||||
|
|
@ -140,8 +143,10 @@ The following listing shows the custom `BeanPostProcessor` implementation class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package scripting
|
package scripting
|
||||||
|
|
||||||
|
|
@ -160,6 +165,7 @@ The following listing shows the custom `BeanPostProcessor` implementation class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
|
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
|
||||||
|
|
||||||
|
|
@ -196,8 +202,11 @@ xref:languages/dynamic.adoc[Dynamic Language Support].)
|
||||||
|
|
||||||
The following Java application runs the preceding code and configuration:
|
The following Java application runs the preceding code and configuration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
@ -213,8 +222,10 @@ The following Java application runs the preceding code and configuration:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -224,6 +235,7 @@ The following Java application runs the preceding code and configuration:
|
||||||
println(messenger)
|
println(messenger)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The output of the preceding application resembles the following:
|
The output of the preceding application resembles the following:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,11 @@ no-argument signature. With Java configuration, you can use the `initMethod` att
|
||||||
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
|
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ExampleBean {
|
public class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -77,8 +80,10 @@ no-argument signature. With Java configuration, you can use the `initMethod` att
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ExampleBean {
|
class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -87,6 +92,7 @@ no-argument signature. With Java configuration, you can use the `initMethod` att
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding example has almost exactly the same effect as the following example
|
The preceding example has almost exactly the same effect as the following example
|
||||||
(which consists of two listings):
|
(which consists of two listings):
|
||||||
|
|
@ -96,8 +102,11 @@ The preceding example has almost exactly the same effect as the following exampl
|
||||||
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
|
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class AnotherExampleBean implements InitializingBean {
|
public class AnotherExampleBean implements InitializingBean {
|
||||||
|
|
||||||
|
|
@ -107,8 +116,10 @@ The preceding example has almost exactly the same effect as the following exampl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class AnotherExampleBean : InitializingBean {
|
class AnotherExampleBean : InitializingBean {
|
||||||
|
|
||||||
|
|
@ -117,6 +128,7 @@ The preceding example has almost exactly the same effect as the following exampl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
However, the first of the two preceding examples does not couple the code to Spring.
|
However, the first of the two preceding examples does not couple the code to Spring.
|
||||||
|
|
||||||
|
|
@ -146,8 +158,11 @@ xref:core/beans/java/bean-annotation.adoc#beans-java-lifecycle-callbacks[Receivi
|
||||||
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
|
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ExampleBean {
|
public class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -156,8 +171,10 @@ xref:core/beans/java/bean-annotation.adoc#beans-java-lifecycle-callbacks[Receivi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ExampleBean {
|
class ExampleBean {
|
||||||
|
|
||||||
|
|
@ -166,6 +183,7 @@ xref:core/beans/java/bean-annotation.adoc#beans-java-lifecycle-callbacks[Receivi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding definition has almost exactly the same effect as the following definition:
|
The preceding definition has almost exactly the same effect as the following definition:
|
||||||
|
|
||||||
|
|
@ -174,8 +192,11 @@ The preceding definition has almost exactly the same effect as the following def
|
||||||
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
|
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class AnotherExampleBean implements DisposableBean {
|
public class AnotherExampleBean implements DisposableBean {
|
||||||
|
|
||||||
|
|
@ -185,8 +206,10 @@ The preceding definition has almost exactly the same effect as the following def
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class AnotherExampleBean : DisposableBean {
|
class AnotherExampleBean : DisposableBean {
|
||||||
|
|
||||||
|
|
@ -195,6 +218,7 @@ The preceding definition has almost exactly the same effect as the following def
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
However, the first of the two preceding definitions does not couple the code to Spring.
|
However, the first of the two preceding definitions does not couple the code to Spring.
|
||||||
|
|
||||||
|
|
@ -229,8 +253,11 @@ Suppose that your initialization callback methods are named `init()` and your de
|
||||||
callback methods are named `destroy()`. Your class then resembles the class in the
|
callback methods are named `destroy()`. Your class then resembles the class in the
|
||||||
following example:
|
following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class DefaultBlogService implements BlogService {
|
public class DefaultBlogService implements BlogService {
|
||||||
|
|
||||||
|
|
@ -248,8 +275,10 @@ following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DefaultBlogService : BlogService {
|
class DefaultBlogService : BlogService {
|
||||||
|
|
||||||
|
|
@ -263,6 +292,7 @@ following example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You could then use that class in a bean resembling the following:
|
You could then use that class in a bean resembling the following:
|
||||||
|
|
||||||
|
|
@ -478,8 +508,11 @@ and implement these destroy callbacks correctly.
|
||||||
To register a shutdown hook, call the `registerShutdownHook()` method that is
|
To register a shutdown hook, call the `registerShutdownHook()` method that is
|
||||||
declared on the `ConfigurableApplicationContext` interface, as the following example shows:
|
declared on the `ConfigurableApplicationContext` interface, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
@ -498,8 +531,10 @@ declared on the `ConfigurableApplicationContext` interface, as the following exa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext
|
import org.springframework.context.support.ClassPathXmlApplicationContext
|
||||||
|
|
||||||
|
|
@ -514,6 +549,7 @@ declared on the `ConfigurableApplicationContext` interface, as the following exa
|
||||||
// main method exits, hook is called prior to the app shutting down...
|
// main method exits, hook is called prior to the app shutting down...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,8 +247,11 @@ When using annotation-driven components or Java configuration, the `@RequestScop
|
||||||
can be used to assign a component to the `request` scope. The following example shows how
|
can be used to assign a component to the `request` scope. The following example shows how
|
||||||
to do so:
|
to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@RequestScope
|
@RequestScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -256,8 +259,10 @@ to do so:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@RequestScope
|
@RequestScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -265,6 +270,7 @@ to do so:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -291,8 +297,11 @@ HTTP `Session` is eventually discarded, the bean that is scoped to that particul
|
||||||
When using annotation-driven components or Java configuration, you can use the
|
When using annotation-driven components or Java configuration, you can use the
|
||||||
`@SessionScope` annotation to assign a component to the `session` scope.
|
`@SessionScope` annotation to assign a component to the `session` scope.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@SessionScope
|
@SessionScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -300,8 +309,10 @@ When using annotation-driven components or Java configuration, you can use the
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@SessionScope
|
@SessionScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -309,6 +320,7 @@ When using annotation-driven components or Java configuration, you can use the
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -335,8 +347,11 @@ When using annotation-driven components or Java configuration, you can use the
|
||||||
`@ApplicationScope` annotation to assign a component to the `application` scope. The
|
`@ApplicationScope` annotation to assign a component to the `application` scope. The
|
||||||
following example shows how to do so:
|
following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@ApplicationScope
|
@ApplicationScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -344,8 +359,10 @@ following example shows how to do so:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@ApplicationScope
|
@ApplicationScope
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -353,6 +370,7 @@ following example shows how to do so:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -551,62 +569,86 @@ does not exist, the method returns a new instance of the bean, after having boun
|
||||||
the session for future reference). The following method returns the object from the
|
the session for future reference). The following method returns the object from the
|
||||||
underlying scope:
|
underlying scope:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Object get(String name, ObjectFactory<?> objectFactory)
|
Object get(String name, ObjectFactory<?> objectFactory)
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun get(name: String, objectFactory: ObjectFactory<*>): Any
|
fun get(name: String, objectFactory: ObjectFactory<*>): Any
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The session scope implementation, for example, removes the session-scoped bean from the
|
The session scope implementation, for example, removes the session-scoped bean from the
|
||||||
underlying session. The object should be returned, but you can return `null` if the
|
underlying session. The object should be returned, but you can return `null` if the
|
||||||
object with the specified name is not found. The following method removes the object from
|
object with the specified name is not found. The following method removes the object from
|
||||||
the underlying scope:
|
the underlying scope:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Object remove(String name)
|
Object remove(String name)
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun remove(name: String): Any
|
fun remove(name: String): Any
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following method registers a callback that the scope should invoke when it is
|
The following method registers a callback that the scope should invoke when it is
|
||||||
destroyed or when the specified object in the scope is destroyed:
|
destroyed or when the specified object in the scope is destroyed:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
void registerDestructionCallback(String name, Runnable destructionCallback)
|
void registerDestructionCallback(String name, Runnable destructionCallback)
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
|
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the {api-spring-framework}/beans/factory/config/Scope.html#registerDestructionCallback[javadoc]
|
See the {api-spring-framework}/beans/factory/config/Scope.html#registerDestructionCallback[javadoc]
|
||||||
or a Spring scope implementation for more information on destruction callbacks.
|
or a Spring scope implementation for more information on destruction callbacks.
|
||||||
|
|
||||||
The following method obtains the conversation identifier for the underlying scope:
|
The following method obtains the conversation identifier for the underlying scope:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
String getConversationId()
|
String getConversationId()
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun getConversationId(): String
|
fun getConversationId(): String
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This identifier is different for each scope. For a session scoped implementation, this
|
This identifier is different for each scope. For a session scoped implementation, this
|
||||||
identifier can be the session identifier.
|
identifier can be the session identifier.
|
||||||
|
|
@ -620,16 +662,22 @@ After you write and test one or more custom `Scope` implementations, you need to
|
||||||
the Spring container aware of your new scopes. The following method is the central
|
the Spring container aware of your new scopes. The following method is the central
|
||||||
method to register a new `Scope` with the Spring container:
|
method to register a new `Scope` with the Spring container:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
void registerScope(String scopeName, Scope scope);
|
void registerScope(String scopeName, Scope scope);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun registerScope(scopeName: String, scope: Scope)
|
fun registerScope(scopeName: String, scope: Scope)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This method is declared on the `ConfigurableBeanFactory` interface, which is available
|
This method is declared on the `ConfigurableBeanFactory` interface, which is available
|
||||||
through the `BeanFactory` property on most of the concrete `ApplicationContext`
|
through the `BeanFactory` property on most of the concrete `ApplicationContext`
|
||||||
|
|
@ -647,18 +695,24 @@ NOTE: The next example uses `SimpleThreadScope`, which is included with Spring b
|
||||||
registered by default. The instructions would be the same for your own custom `Scope`
|
registered by default. The instructions would be the same for your own custom `Scope`
|
||||||
implementations.
|
implementations.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Scope threadScope = new SimpleThreadScope();
|
Scope threadScope = new SimpleThreadScope();
|
||||||
beanFactory.registerScope("thread", threadScope);
|
beanFactory.registerScope("thread", threadScope);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val threadScope = SimpleThreadScope()
|
val threadScope = SimpleThreadScope()
|
||||||
beanFactory.registerScope("thread", threadScope)
|
beanFactory.registerScope("thread", threadScope)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can then create bean definitions that adhere to the scoping rules of your custom
|
You can then create bean definitions that adhere to the scoping rules of your custom
|
||||||
`Scope`, as follows:
|
`Scope`, as follows:
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@ source of bean definitions. Furthermore, `@Configuration` classes let inter-bean
|
||||||
dependencies be defined by calling other `@Bean` methods in the same class.
|
dependencies be defined by calling other `@Bean` methods in the same class.
|
||||||
The simplest possible `@Configuration` class reads as follows:
|
The simplest possible `@Configuration` class reads as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -27,8 +30,10 @@ The simplest possible `@Configuration` class reads as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -39,6 +44,7 @@ The simplest possible `@Configuration` class reads as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding `AppConfig` class is equivalent to the following Spring `<beans/>` XML:
|
The preceding `AppConfig` class is equivalent to the following Spring `<beans/>` XML:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,11 @@ method to register a bean definition within an `ApplicationContext` of the type
|
||||||
specified as the method's return value. By default, the bean name is the same as
|
specified as the method's return value. By default, the bean name is the same as
|
||||||
the method name. The following example shows a `@Bean` method declaration:
|
the method name. The following example shows a `@Bean` method declaration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -33,8 +36,10 @@ the method name. The following example shows a `@Bean` method declaration:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -43,6 +48,7 @@ the method name. The following example shows a `@Bean` method declaration:
|
||||||
fun transferService() = TransferServiceImpl()
|
fun transferService() = TransferServiceImpl()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding configuration is exactly equivalent to the following Spring XML:
|
The preceding configuration is exactly equivalent to the following Spring XML:
|
||||||
|
|
||||||
|
|
@ -65,8 +71,11 @@ transferService -> com.acme.TransferServiceImpl
|
||||||
You can also use default methods to define beans. This allows composition of bean
|
You can also use default methods to define beans. This allows composition of bean
|
||||||
configurations by implementing interfaces with bean definitions on default methods.
|
configurations by implementing interfaces with bean definitions on default methods.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public interface BaseConfig {
|
public interface BaseConfig {
|
||||||
|
|
||||||
|
|
@ -81,12 +90,16 @@ configurations by implementing interfaces with bean definitions on default metho
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also declare your `@Bean` method with an interface (or base class)
|
You can also declare your `@Bean` method with an interface (or base class)
|
||||||
return type, as the following example shows:
|
return type, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -97,8 +110,10 @@ return type, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -109,6 +124,7 @@ return type, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
However, this limits the visibility for advance type prediction to the specified
|
However, this limits the visibility for advance type prediction to the specified
|
||||||
interface type (`TransferService`). Then, with the full type (`TransferServiceImpl`)
|
interface type (`TransferService`). Then, with the full type (`TransferServiceImpl`)
|
||||||
|
|
@ -133,8 +149,11 @@ dependencies required to build that bean. For instance, if our `TransferService`
|
||||||
requires an `AccountRepository`, we can materialize that dependency with a method
|
requires an `AccountRepository`, we can materialize that dependency with a method
|
||||||
parameter, as the following example shows:
|
parameter, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -145,8 +164,10 @@ parameter, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -157,6 +178,7 @@ parameter, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
The resolution mechanism is pretty much identical to constructor-based dependency
|
The resolution mechanism is pretty much identical to constructor-based dependency
|
||||||
|
|
@ -184,8 +206,11 @@ The `@Bean` annotation supports specifying arbitrary initialization and destruct
|
||||||
callback methods, much like Spring XML's `init-method` and `destroy-method` attributes
|
callback methods, much like Spring XML's `init-method` and `destroy-method` attributes
|
||||||
on the `bean` element, as the following example shows:
|
on the `bean` element, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class BeanOne {
|
public class BeanOne {
|
||||||
|
|
||||||
|
|
@ -215,8 +240,10 @@ on the `bean` element, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class BeanOne {
|
class BeanOne {
|
||||||
|
|
||||||
|
|
@ -242,6 +269,7 @@ class AppConfig {
|
||||||
fun beanTwo() = BeanTwo()
|
fun beanTwo() = BeanTwo()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
=====
|
=====
|
||||||
|
|
@ -258,22 +286,28 @@ for a `DataSource`, as it is known to be problematic on Jakarta EE application s
|
||||||
The following example shows how to prevent an automatic destruction callback for a
|
The following example shows how to prevent an automatic destruction callback for a
|
||||||
`DataSource`:
|
`DataSource`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Bean(destroyMethod = "")
|
@Bean(destroyMethod = "")
|
||||||
public DataSource dataSource() throws NamingException {
|
public DataSource dataSource() throws NamingException {
|
||||||
return (DataSource) jndiTemplate.lookup("MyDS");
|
return (DataSource) jndiTemplate.lookup("MyDS");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Bean(destroyMethod = "")
|
@Bean(destroyMethod = "")
|
||||||
fun dataSource(): DataSource {
|
fun dataSource(): DataSource {
|
||||||
return jndiTemplate.lookup("MyDS") as DataSource
|
return jndiTemplate.lookup("MyDS") as DataSource
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Also, with `@Bean` methods, you typically use programmatic JNDI lookups, either by
|
Also, with `@Bean` methods, you typically use programmatic JNDI lookups, either by
|
||||||
using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI
|
using Spring's `JndiTemplate` or `JndiLocatorDelegate` helpers or straight JNDI
|
||||||
|
|
@ -286,8 +320,11 @@ intend to refer to the provided resource here).
|
||||||
In the case of `BeanOne` from the example above the preceding note, it would be equally valid to call the `init()`
|
In the case of `BeanOne` from the example above the preceding note, it would be equally valid to call the `init()`
|
||||||
method directly during construction, as the following example shows:
|
method directly during construction, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -302,8 +339,10 @@ method directly during construction, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -316,6 +355,7 @@ method directly during construction, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
TIP: When you work directly in Java, you can do anything you like with your objects and do
|
TIP: When you work directly in Java, you can do anything you like with your objects and do
|
||||||
not always need to rely on the container lifecycle.
|
not always need to rely on the container lifecycle.
|
||||||
|
|
@ -336,8 +376,11 @@ xref:core/beans/factory-scopes.adoc[Bean Scopes] section.
|
||||||
The default scope is `singleton`, but you can override this with the `@Scope` annotation,
|
The default scope is `singleton`, but you can override this with the `@Scope` annotation,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MyConfiguration {
|
public class MyConfiguration {
|
||||||
|
|
@ -349,8 +392,10 @@ as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class MyConfiguration {
|
class MyConfiguration {
|
||||||
|
|
@ -362,6 +407,7 @@ as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[beans-java-scoped-proxy]]
|
[[beans-java-scoped-proxy]]
|
||||||
=== `@Scope` and `scoped-proxy`
|
=== `@Scope` and `scoped-proxy`
|
||||||
|
|
@ -379,8 +425,11 @@ If you port the scoped proxy example from the XML reference documentation (see
|
||||||
xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other-injection[scoped proxies]) to our `@Bean` using Java,
|
xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other-injection[scoped proxies]) to our `@Bean` using Java,
|
||||||
it resembles the following:
|
it resembles the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// an HTTP Session-scoped bean exposed as a proxy
|
// an HTTP Session-scoped bean exposed as a proxy
|
||||||
@Bean
|
@Bean
|
||||||
|
|
@ -397,8 +446,10 @@ it resembles the following:
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// an HTTP Session-scoped bean exposed as a proxy
|
// an HTTP Session-scoped bean exposed as a proxy
|
||||||
@Bean
|
@Bean
|
||||||
|
|
@ -413,6 +464,7 @@ it resembles the following:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[beans-java-customizing-bean-naming]]
|
[[beans-java-customizing-bean-naming]]
|
||||||
== Customizing Bean Naming
|
== Customizing Bean Naming
|
||||||
|
|
@ -421,8 +473,11 @@ By default, configuration classes use a `@Bean` method's name as the name of the
|
||||||
resulting bean. This functionality can be overridden, however, with the `name` attribute,
|
resulting bean. This functionality can be overridden, however, with the `name` attribute,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -433,8 +488,10 @@ as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -443,6 +500,7 @@ as the following example shows:
|
||||||
fun thing() = Thing()
|
fun thing() = Thing()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-java-bean-aliasing]]
|
[[beans-java-bean-aliasing]]
|
||||||
|
|
@ -453,8 +511,11 @@ multiple names, otherwise known as bean aliasing. The `name` attribute of the `@
|
||||||
annotation accepts a String array for this purpose. The following example shows how to set
|
annotation accepts a String array for this purpose. The following example shows how to set
|
||||||
a number of aliases for a bean:
|
a number of aliases for a bean:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -465,8 +526,10 @@ a number of aliases for a bean:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -477,6 +540,7 @@ a number of aliases for a bean:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-java-bean-description]]
|
[[beans-java-bean-description]]
|
||||||
|
|
@ -489,8 +553,11 @@ To add a description to a `@Bean`, you can use the
|
||||||
{api-spring-framework}/context/annotation/Description.html[`@Description`]
|
{api-spring-framework}/context/annotation/Description.html[`@Description`]
|
||||||
annotation, as the following example shows:
|
annotation, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -502,8 +569,10 @@ annotation, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -513,6 +582,7 @@ annotation, as the following example shows:
|
||||||
fun thing() = Thing()
|
fun thing() = Thing()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,11 @@ Much as the `<import/>` element is used within Spring XML files to aid in modula
|
||||||
configurations, the `@Import` annotation allows for loading `@Bean` definitions from
|
configurations, the `@Import` annotation allows for loading `@Bean` definitions from
|
||||||
another configuration class, as the following example shows:
|
another configuration class, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ConfigA {
|
public class ConfigA {
|
||||||
|
|
@ -34,8 +37,10 @@ another configuration class, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class ConfigA {
|
class ConfigA {
|
||||||
|
|
@ -52,13 +57,17 @@ another configuration class, as the following example shows:
|
||||||
fun b() = B()
|
fun b() = B()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now, rather than needing to specify both `ConfigA.class` and `ConfigB.class` when
|
Now, rather than needing to specify both `ConfigA.class` and `ConfigB.class` when
|
||||||
instantiating the context, only `ConfigB` needs to be supplied explicitly, as the
|
instantiating the context, only `ConfigB` needs to be supplied explicitly, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
|
||||||
|
|
@ -68,8 +77,10 @@ following example shows:
|
||||||
B b = ctx.getBean(B.class);
|
B b = ctx.getBean(B.class);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -81,6 +92,7 @@ following example shows:
|
||||||
val b = ctx.getBean<B>()
|
val b = ctx.getBean<B>()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This approach simplifies container instantiation, as only one class needs to be dealt
|
This approach simplifies container instantiation, as only one class needs to be dealt
|
||||||
with, rather than requiring you to remember a potentially large number of
|
with, rather than requiring you to remember a potentially large number of
|
||||||
|
|
@ -106,8 +118,11 @@ a `@Bean` method can have an arbitrary number of parameters that describe the be
|
||||||
dependencies. Consider the following more real-world scenario with several `@Configuration`
|
dependencies. Consider the following more real-world scenario with several `@Configuration`
|
||||||
classes, each depending on beans declared in the others:
|
classes, each depending on beans declared in the others:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ServiceConfig {
|
public class ServiceConfig {
|
||||||
|
|
@ -144,8 +159,10 @@ classes, each depending on beans declared in the others:
|
||||||
transferService.transfer(100.00, "A123", "C456");
|
transferService.transfer(100.00, "A123", "C456");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -185,6 +202,7 @@ classes, each depending on beans declared in the others:
|
||||||
transferService.transfer(100.00, "A123", "C456")
|
transferService.transfer(100.00, "A123", "C456")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
There is another way to achieve the same result. Remember that `@Configuration` classes are
|
There is another way to achieve the same result. Remember that `@Configuration` classes are
|
||||||
|
|
@ -207,8 +225,11 @@ work on the configuration class itself, since it is possible to create it as a b
|
||||||
|
|
||||||
The following example shows how one bean can be autowired to another bean:
|
The following example shows how one bean can be autowired to another bean:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ServiceConfig {
|
public class ServiceConfig {
|
||||||
|
|
@ -254,8 +275,10 @@ The following example shows how one bean can be autowired to another bean:
|
||||||
transferService.transfer(100.00, "A123", "C456");
|
transferService.transfer(100.00, "A123", "C456");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -297,6 +320,7 @@ The following example shows how one bean can be autowired to another bean:
|
||||||
transferService.transfer(100.00, "A123", "C456")
|
transferService.transfer(100.00, "A123", "C456")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
TIP: Constructor injection in `@Configuration` classes is only supported as of Spring
|
TIP: Constructor injection in `@Configuration` classes is only supported as of Spring
|
||||||
Framework 4.3. Note also that there is no need to specify `@Autowired` if the target
|
Framework 4.3. Note also that there is no need to specify `@Autowired` if the target
|
||||||
|
|
@ -318,8 +342,11 @@ In cases where this ambiguity is not acceptable and you wish to have direct navi
|
||||||
from within your IDE from one `@Configuration` class to another, consider autowiring the
|
from within your IDE from one `@Configuration` class to another, consider autowiring the
|
||||||
configuration classes themselves. The following example shows how to do so:
|
configuration classes themselves. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ServiceConfig {
|
public class ServiceConfig {
|
||||||
|
|
@ -334,8 +361,10 @@ configuration classes themselves. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class ServiceConfig {
|
class ServiceConfig {
|
||||||
|
|
@ -350,14 +379,18 @@ class ServiceConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding situation, where `AccountRepository` is defined is completely explicit.
|
In the preceding situation, where `AccountRepository` is defined is completely explicit.
|
||||||
However, `ServiceConfig` is now tightly coupled to `RepositoryConfig`. That is the
|
However, `ServiceConfig` is now tightly coupled to `RepositoryConfig`. That is the
|
||||||
tradeoff. This tight coupling can be somewhat mitigated by using interface-based or
|
tradeoff. This tight coupling can be somewhat mitigated by using interface-based or
|
||||||
abstract class-based `@Configuration` classes. Consider the following example:
|
abstract class-based `@Configuration` classes. Consider the following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ServiceConfig {
|
public class ServiceConfig {
|
||||||
|
|
@ -404,8 +437,10 @@ abstract class-based `@Configuration` classes. Consider the following example:
|
||||||
transferService.transfer(100.00, "A123", "C456");
|
transferService.transfer(100.00, "A123", "C456");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -454,6 +489,7 @@ abstract class-based `@Configuration` classes. Consider the following example:
|
||||||
transferService.transfer(100.00, "A123", "C456")
|
transferService.transfer(100.00, "A123", "C456")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now `ServiceConfig` is loosely coupled with respect to the concrete
|
Now `ServiceConfig` is loosely coupled with respect to the concrete
|
||||||
`DefaultRepositoryConfig`, and built-in IDE tooling is still useful: You can easily
|
`DefaultRepositoryConfig`, and built-in IDE tooling is still useful: You can easily
|
||||||
|
|
@ -487,8 +523,11 @@ Implementations of the `Condition` interface provide a `matches(...)`
|
||||||
method that returns `true` or `false`. For example, the following listing shows the actual
|
method that returns `true` or `false`. For example, the following listing shows the actual
|
||||||
`Condition` implementation used for `@Profile`:
|
`Condition` implementation used for `@Profile`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
|
@ -505,8 +544,10 @@ method that returns `true` or `false`. For example, the following listing shows
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean {
|
override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean {
|
||||||
// Read the @Profile annotation attributes
|
// Read the @Profile annotation attributes
|
||||||
|
|
@ -522,6 +563,7 @@ method that returns `true` or `false`. For example, the following listing shows
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the {api-spring-framework}/context/annotation/Conditional.html[`@Conditional`]
|
See the {api-spring-framework}/context/annotation/Conditional.html[`@Conditional`]
|
||||||
javadoc for more detail.
|
javadoc for more detail.
|
||||||
|
|
@ -558,8 +600,11 @@ properly.
|
||||||
|
|
||||||
The following example shows an ordinary configuration class in Java:
|
The following example shows an ordinary configuration class in Java:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -578,8 +623,10 @@ The following example shows an ordinary configuration class in Java:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -596,6 +643,7 @@ The following example shows an ordinary configuration class in Java:
|
||||||
fun transferService() = TransferService(accountRepository())
|
fun transferService() = TransferService(accountRepository())
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows part of a sample `system-test-config.xml` file:
|
The following example shows part of a sample `system-test-config.xml` file:
|
||||||
|
|
||||||
|
|
@ -625,8 +673,11 @@ jdbc.username=sa
|
||||||
jdbc.password=
|
jdbc.password=
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
|
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
|
||||||
|
|
@ -634,8 +685,10 @@ jdbc.password=
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val ctx = ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml")
|
val ctx = ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml")
|
||||||
|
|
@ -643,6 +696,7 @@ jdbc.password=
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
NOTE: In `system-test-config.xml` file, the `AppConfig` `<bean/>` does not declare an `id`
|
NOTE: In `system-test-config.xml` file, the `AppConfig` `<bean/>` does not declare an `id`
|
||||||
|
|
@ -691,8 +745,11 @@ that defines a bean, a properties file, and the `main` class) shows how to use
|
||||||
the `@ImportResource` annotation to achieve "`Java-centric`" configuration that uses XML
|
the `@ImportResource` annotation to achieve "`Java-centric`" configuration that uses XML
|
||||||
as needed:
|
as needed:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ImportResource("classpath:/com/acme/properties-config.xml")
|
@ImportResource("classpath:/com/acme/properties-config.xml")
|
||||||
|
|
@ -713,8 +770,10 @@ as needed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ImportResource("classpath:/com/acme/properties-config.xml")
|
@ImportResource("classpath:/com/acme/properties-config.xml")
|
||||||
|
|
@ -735,6 +794,7 @@ as needed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
@ -752,8 +812,11 @@ jdbc.username=sa
|
||||||
jdbc.password=
|
jdbc.password=
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||||
|
|
@ -761,8 +824,10 @@ jdbc.password=
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -772,6 +837,7 @@ jdbc.password=
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ inter-bean dependencies. See xref:core/beans/java/basic-concepts.adoc[Basic Conc
|
||||||
When beans have dependencies on one another, expressing that dependency is as simple
|
When beans have dependencies on one another, expressing that dependency is as simple
|
||||||
as having one bean method call another, as the following example shows:
|
as having one bean method call another, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -30,8 +33,10 @@ as having one bean method call another, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -43,6 +48,7 @@ as having one bean method call another, as the following example shows:
|
||||||
fun beanTwo() = BeanTwo()
|
fun beanTwo() = BeanTwo()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example, `beanOne` receives a reference to `beanTwo` through constructor
|
In the preceding example, `beanOne` receives a reference to `beanTwo` through constructor
|
||||||
injection.
|
injection.
|
||||||
|
|
@ -62,8 +68,11 @@ singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java fo
|
||||||
type of configuration provides a natural means for implementing this pattern. The
|
type of configuration provides a natural means for implementing this pattern. The
|
||||||
following example shows how to use lookup method injection:
|
following example shows how to use lookup method injection:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public abstract class CommandManager {
|
public abstract class CommandManager {
|
||||||
public Object process(Object commandState) {
|
public Object process(Object commandState) {
|
||||||
|
|
@ -78,8 +87,10 @@ following example shows how to use lookup method injection:
|
||||||
protected abstract Command createCommand();
|
protected abstract Command createCommand();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
abstract class CommandManager {
|
abstract class CommandManager {
|
||||||
fun process(commandState: Any): Any {
|
fun process(commandState: Any): Any {
|
||||||
|
|
@ -94,13 +105,17 @@ following example shows how to use lookup method injection:
|
||||||
protected abstract fun createCommand(): Command
|
protected abstract fun createCommand(): Command
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
By using Java configuration, you can create a subclass of `CommandManager` where
|
By using Java configuration, you can create a subclass of `CommandManager` where
|
||||||
the abstract `createCommand()` method is overridden in such a way that it looks up a new
|
the abstract `createCommand()` method is overridden in such a way that it looks up a new
|
||||||
(prototype) command object. The following example shows how to do so:
|
(prototype) command object. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
|
|
@ -121,8 +136,10 @@ the abstract `createCommand()` method is overridden in such a way that it looks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
|
|
@ -143,6 +160,7 @@ the abstract `createCommand()` method is overridden in such a way that it looks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-java-further-information-java-config]]
|
[[beans-java-further-information-java-config]]
|
||||||
|
|
@ -150,8 +168,11 @@ the abstract `createCommand()` method is overridden in such a way that it looks
|
||||||
|
|
||||||
Consider the following example, which shows a `@Bean` annotated method being called twice:
|
Consider the following example, which shows a `@Bean` annotated method being called twice:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -176,8 +197,10 @@ Consider the following example, which shows a `@Bean` annotated method being cal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -202,6 +225,7 @@ Consider the following example, which shows a `@Bean` annotated method being cal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`clientDao()` has been called once in `clientService1()` and once in `clientService2()`.
|
`clientDao()` has been called once in `clientService1()` and once in `clientService2()`.
|
||||||
Since this method creates a new instance of `ClientDaoImpl` and returns it, you would
|
Since this method creates a new instance of `ClientDaoImpl` and returns it, you would
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,11 @@ In much the same way that Spring XML files are used as input when instantiating
|
||||||
instantiating an `AnnotationConfigApplicationContext`. This allows for completely
|
instantiating an `AnnotationConfigApplicationContext`. This allows for completely
|
||||||
XML-free usage of the Spring container, as the following example shows:
|
XML-free usage of the Spring container, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||||
|
|
@ -32,8 +35,10 @@ XML-free usage of the Spring container, as the following example shows:
|
||||||
myService.doStuff();
|
myService.doStuff();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -43,13 +48,17 @@ XML-free usage of the Spring container, as the following example shows:
|
||||||
myService.doStuff()
|
myService.doStuff()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
As mentioned earlier, `AnnotationConfigApplicationContext` is not limited to working only
|
As mentioned earlier, `AnnotationConfigApplicationContext` is not limited to working only
|
||||||
with `@Configuration` classes. Any `@Component` or JSR-330 annotated class may be supplied
|
with `@Configuration` classes. Any `@Component` or JSR-330 annotated class may be supplied
|
||||||
as input to the constructor, as the following example shows:
|
as input to the constructor, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
|
||||||
|
|
@ -57,8 +66,10 @@ as input to the constructor, as the following example shows:
|
||||||
myService.doStuff();
|
myService.doStuff();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -68,6 +79,7 @@ as input to the constructor, as the following example shows:
|
||||||
myService.doStuff()
|
myService.doStuff()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding example assumes that `MyServiceImpl`, `Dependency1`, and `Dependency2` use Spring
|
The preceding example assumes that `MyServiceImpl`, `Dependency1`, and `Dependency2` use Spring
|
||||||
dependency injection annotations such as `@Autowired`.
|
dependency injection annotations such as `@Autowired`.
|
||||||
|
|
@ -81,8 +93,11 @@ and then configure it by using the `register()` method. This approach is particu
|
||||||
when programmatically building an `AnnotationConfigApplicationContext`. The following
|
when programmatically building an `AnnotationConfigApplicationContext`. The following
|
||||||
example shows how to do so:
|
example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
|
@ -93,8 +108,10 @@ example shows how to do so:
|
||||||
myService.doStuff();
|
myService.doStuff();
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -107,6 +124,7 @@ example shows how to do so:
|
||||||
myService.doStuff()
|
myService.doStuff()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-java-instantiating-container-scan]]
|
[[beans-java-instantiating-container-scan]]
|
||||||
|
|
@ -114,8 +132,11 @@ example shows how to do so:
|
||||||
|
|
||||||
To enable component scanning, you can annotate your `@Configuration` class as follows:
|
To enable component scanning, you can annotate your `@Configuration` class as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "com.acme") // <1>
|
@ComponentScan(basePackages = "com.acme") // <1>
|
||||||
|
|
@ -123,6 +144,7 @@ To enable component scanning, you can annotate your `@Configuration` class as fo
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> This annotation enables component scanning.
|
<1> This annotation enables component scanning.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -156,8 +178,11 @@ definitions within the container. `AnnotationConfigApplicationContext` exposes t
|
||||||
`scan(String...)` method to allow for the same component-scanning functionality, as the
|
`scan(String...)` method to allow for the same component-scanning functionality, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
|
@ -166,8 +191,10 @@ following example shows:
|
||||||
MyService myService = ctx.getBean(MyService.class);
|
MyService myService = ctx.getBean(MyService.class);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun main() {
|
fun main() {
|
||||||
val ctx = AnnotationConfigApplicationContext()
|
val ctx = AnnotationConfigApplicationContext()
|
||||||
|
|
@ -176,6 +203,7 @@ following example shows:
|
||||||
val myService = ctx.getBean<MyService>()
|
val myService = ctx.getBean<MyService>()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: Remember that `@Configuration` classes are xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[meta-annotated]
|
NOTE: Remember that `@Configuration` classes are xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[meta-annotated]
|
||||||
with `@Component`, so they are candidates for component-scanning. In the preceding example,
|
with `@Component`, so they are candidates for component-scanning. In the preceding example,
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,11 @@ You can add the following dependency to your file pom.xml:
|
||||||
|
|
||||||
Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
|
Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
|
@ -49,8 +52,10 @@ Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
|
|
||||||
|
|
@ -66,6 +71,7 @@ Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
As with `@Autowired`, you can use `@Inject` at the field level, method level
|
As with `@Autowired`, you can use `@Inject` at the field level, method level
|
||||||
and constructor-argument level. Furthermore, you may declare your injection point as a
|
and constructor-argument level. Furthermore, you may declare your injection point as a
|
||||||
|
|
@ -73,8 +79,11 @@ and constructor-argument level. Furthermore, you may declare your injection poin
|
||||||
other beans through a `Provider.get()` call. The following example offers a variant of the
|
other beans through a `Provider.get()` call. The following example offers a variant of the
|
||||||
preceding example:
|
preceding example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Provider;
|
import jakarta.inject.Provider;
|
||||||
|
|
@ -94,8 +103,10 @@ preceding example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
|
|
||||||
|
|
@ -111,12 +122,16 @@ preceding example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you would like to use a qualified name for the dependency that should be injected,
|
If you would like to use a qualified name for the dependency that should be injected,
|
||||||
you should use the `@Named` annotation, as the following example shows:
|
you should use the `@Named` annotation, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Named;
|
import jakarta.inject.Named;
|
||||||
|
|
@ -133,8 +148,10 @@ you should use the `@Named` annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
import jakarta.inject.Named
|
import jakarta.inject.Named
|
||||||
|
|
@ -151,6 +168,7 @@ you should use the `@Named` annotation, as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
As with `@Autowired`, `@Inject` can also be used with `java.util.Optional` or
|
As with `@Autowired`, `@Inject` can also be used with `java.util.Optional` or
|
||||||
`@Nullable`. This is even more applicable here, since `@Inject` does not have
|
`@Nullable`. This is even more applicable here, since `@Inject` does not have
|
||||||
|
|
@ -168,8 +186,11 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -179,8 +200,10 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -188,6 +211,7 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
|
||||||
var movieFinder: MovieFinder? = null
|
var movieFinder: MovieFinder? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -197,8 +221,11 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
|
||||||
Instead of `@Component`, you can use `@jakarta.inject.Named` or `jakarta.annotation.ManagedBean`,
|
Instead of `@Component`, you can use `@jakarta.inject.Named` or `jakarta.annotation.ManagedBean`,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Named;
|
import jakarta.inject.Named;
|
||||||
|
|
@ -216,8 +243,10 @@ as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
import jakarta.inject.Named
|
import jakarta.inject.Named
|
||||||
|
|
@ -231,12 +260,16 @@ as the following example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
It is very common to use `@Component` without specifying a name for the component.
|
It is very common to use `@Component` without specifying a name for the component.
|
||||||
`@Named` can be used in a similar fashion, as the following example shows:
|
`@Named` can be used in a similar fashion, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Named;
|
import jakarta.inject.Named;
|
||||||
|
|
@ -254,8 +287,10 @@ It is very common to use `@Component` without specifying a name for the componen
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
import jakarta.inject.Named
|
import jakarta.inject.Named
|
||||||
|
|
@ -269,12 +304,16 @@ It is very common to use `@Component` without specifying a name for the componen
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When you use `@Named` or `@ManagedBean`, you can use component scanning in the
|
When you use `@Named` or `@ManagedBean`, you can use component scanning in the
|
||||||
exact same way as when you use Spring annotations, as the following example shows:
|
exact same way as when you use Spring annotations, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "org.example")
|
@ComponentScan(basePackages = "org.example")
|
||||||
|
|
@ -282,8 +321,10 @@ exact same way as when you use Spring annotations, as the following example show
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = ["org.example"])
|
@ComponentScan(basePackages = ["org.example"])
|
||||||
|
|
@ -291,6 +332,7 @@ exact same way as when you use Spring annotations, as the following example show
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: In contrast to `@Component`, the JSR-330 `@Named` and the JSR-250 `@ManagedBean`
|
NOTE: In contrast to `@Component`, the JSR-330 `@Named` and the JSR-250 `@ManagedBean`
|
||||||
annotations are not composable. You should use Spring's stereotype model for building
|
annotations are not composable. You should use Spring's stereotype model for building
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,11 @@ An `Encoder` allocates data buffers that others must read (and release). So an `
|
||||||
doesn't have much to do. However an `Encoder` must take care to release a data buffer if
|
doesn't have much to do. However an `Encoder` must take care to release a data buffer if
|
||||||
a serialization error occurs while populating the buffer with data. For example:
|
a serialization error occurs while populating the buffer with data. For example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DataBuffer buffer = factory.allocateBuffer();
|
DataBuffer buffer = factory.allocateBuffer();
|
||||||
boolean release = true;
|
boolean release = true;
|
||||||
|
|
@ -156,8 +159,10 @@ a serialization error occurs while populating the buffer with data. For example:
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val buffer = factory.allocateBuffer()
|
val buffer = factory.allocateBuffer()
|
||||||
var release = true
|
var release = true
|
||||||
|
|
@ -171,6 +176,7 @@ a serialization error occurs while populating the buffer with data. For example:
|
||||||
}
|
}
|
||||||
return buffer
|
return buffer
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The consumer of an `Encoder` is responsible for releasing the data buffers it receives.
|
The consumer of an `Encoder` is responsible for releasing the data buffers it receives.
|
||||||
In a WebFlux application, the output of the `Encoder` is used to write to the HTTP server
|
In a WebFlux application, the output of the `Encoder` is used to write to the HTTP server
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,11 @@ and method or constructor parameters.
|
||||||
|
|
||||||
The following example sets the default value of a field:
|
The following example sets the default value of a field:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class FieldValueTestBean {
|
public class FieldValueTestBean {
|
||||||
|
|
||||||
|
|
@ -84,8 +87,10 @@ The following example sets the default value of a field:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class FieldValueTestBean {
|
class FieldValueTestBean {
|
||||||
|
|
||||||
|
|
@ -93,11 +98,15 @@ The following example sets the default value of a field:
|
||||||
var defaultLocale: String? = null
|
var defaultLocale: String? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows the equivalent but on a property setter method:
|
The following example shows the equivalent but on a property setter method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class PropertyValueTestBean {
|
public class PropertyValueTestBean {
|
||||||
|
|
||||||
|
|
@ -113,8 +122,10 @@ The following example shows the equivalent but on a property setter method:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class PropertyValueTestBean {
|
class PropertyValueTestBean {
|
||||||
|
|
||||||
|
|
@ -122,12 +133,16 @@ The following example shows the equivalent but on a property setter method:
|
||||||
var defaultLocale: String? = null
|
var defaultLocale: String? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Autowired methods and constructors can also use the `@Value` annotation, as the following
|
Autowired methods and constructors can also use the `@Value` annotation, as the following
|
||||||
examples show:
|
examples show:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleMovieLister {
|
public class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -144,8 +159,10 @@ examples show:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleMovieLister {
|
class SimpleMovieLister {
|
||||||
|
|
||||||
|
|
@ -162,9 +179,13 @@ examples show:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MovieRecommender {
|
public class MovieRecommender {
|
||||||
|
|
||||||
|
|
@ -181,14 +202,17 @@ examples show:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MovieRecommender(private val customerPreferenceDao: CustomerPreferenceDao,
|
class MovieRecommender(private val customerPreferenceDao: CustomerPreferenceDao,
|
||||||
@Value("#{systemProperties['user.country']}") private val defaultLocale: String) {
|
@Value("#{systemProperties['user.country']}") private val defaultLocale: String) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,17 @@ xref:core/expressions/language-ref.adoc[Language Reference].
|
||||||
The following code introduces the SpEL API to evaluate the literal string expression,
|
The following code introduces the SpEL API to evaluate the literal string expression,
|
||||||
`Hello World`.
|
`Hello World`.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
Expression exp = parser.parseExpression("'Hello World'"); // <1>
|
Expression exp = parser.parseExpression("'Hello World'"); // <1>
|
||||||
String message = (String) exp.getValue();
|
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'`.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -42,13 +46,17 @@ and calling constructors.
|
||||||
|
|
||||||
In the following example of method invocation, we call the `concat` method on the string literal:
|
In the following example of method invocation, we call the `concat` method on the string literal:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
|
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
|
||||||
String message = (String) exp.getValue();
|
String message = (String) exp.getValue();
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> The value of `message` is now 'Hello World!'.
|
<1> The value of `message` is now 'Hello World!'.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -62,8 +70,11 @@ In the following example of method invocation, we call the `concat` method on th
|
||||||
|
|
||||||
The following example of calling a JavaBean property calls the `String` property `Bytes`:
|
The following example of calling a JavaBean property calls the `String` property `Bytes`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
|
@ -71,6 +82,7 @@ The following example of calling a JavaBean property calls the `String` property
|
||||||
Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1>
|
Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1>
|
||||||
byte[] bytes = (byte[]) exp.getValue();
|
byte[] bytes = (byte[]) exp.getValue();
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> This line converts the literal to a byte array.
|
<1> This line converts the literal to a byte array.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -90,8 +102,11 @@ Public fields may also be accessed.
|
||||||
|
|
||||||
The following example shows how to use dot notation to get the length of a literal:
|
The following example shows how to use dot notation to get the length of a literal:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
|
@ -99,6 +114,7 @@ The following example shows how to use dot notation to get the length of a liter
|
||||||
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1>
|
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1>
|
||||||
int length = (Integer) exp.getValue();
|
int length = (Integer) exp.getValue();
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> `'Hello World'.bytes.length` gives the length of the literal.
|
<1> `'Hello World'.bytes.length` gives the length of the literal.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -115,13 +131,17 @@ The following example shows how to use dot notation to get the length of a liter
|
||||||
The String's constructor can be called instead of using a string literal, as the following
|
The String's constructor can be called instead of using a string literal, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
|
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
|
||||||
String message = exp.getValue(String.class);
|
String message = exp.getValue(String.class);
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> Construct a new `String` from the literal and make it be upper case.
|
<1> Construct a new `String` from the literal and make it be upper case.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -144,8 +164,11 @@ against a specific object instance (called the root object). The following examp
|
||||||
how to retrieve the `name` property from an instance of the `Inventor` class or
|
how to retrieve the `name` property from an instance of the `Inventor` class or
|
||||||
create a boolean condition:
|
create a boolean condition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// Create and set a calendar
|
// Create and set a calendar
|
||||||
GregorianCalendar c = new GregorianCalendar();
|
GregorianCalendar c = new GregorianCalendar();
|
||||||
|
|
@ -164,8 +187,10 @@ create a boolean condition:
|
||||||
boolean result = exp.getValue(tesla, Boolean.class);
|
boolean result = exp.getValue(tesla, Boolean.class);
|
||||||
// result == true
|
// result == true
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// Create and set a calendar
|
// Create and set a calendar
|
||||||
val c = GregorianCalendar()
|
val c = GregorianCalendar()
|
||||||
|
|
@ -184,6 +209,7 @@ create a boolean condition:
|
||||||
val result = exp.getValue(tesla, Boolean::class.java)
|
val result = exp.getValue(tesla, Boolean::class.java)
|
||||||
// result == true
|
// result == true
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -232,8 +258,11 @@ to set a `List` property. The type of the property is actually `List<Boolean>`.
|
||||||
recognizes that the elements of the list need to be converted to `Boolean` before
|
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]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
class Simple {
|
class Simple {
|
||||||
public List<Boolean> booleanList = new ArrayList<>();
|
public List<Boolean> booleanList = new ArrayList<>();
|
||||||
|
|
@ -251,8 +280,10 @@ being placed in it. The following example shows how to do so:
|
||||||
// b is false
|
// b is false
|
||||||
Boolean b = simple.booleanList.get(0);
|
Boolean b = simple.booleanList.get(0);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Simple {
|
class Simple {
|
||||||
var booleanList: MutableList<Boolean> = ArrayList()
|
var booleanList: MutableList<Boolean> = ArrayList()
|
||||||
|
|
@ -270,6 +301,7 @@ being placed in it. The following example shows how to do so:
|
||||||
// b is false
|
// b is false
|
||||||
val b = simple.booleanList[0]
|
val b = simple.booleanList[0]
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[expressions-parser-configuration]]
|
[[expressions-parser-configuration]]
|
||||||
|
|
@ -290,8 +322,11 @@ or custom converter that knows how to set the value, `null` will remain in the a
|
||||||
list at the specified index. The following example demonstrates how to automatically grow
|
list at the specified index. The following example demonstrates how to automatically grow
|
||||||
the list:
|
the list:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
class Demo {
|
class Demo {
|
||||||
public List<String> list;
|
public List<String> list;
|
||||||
|
|
@ -313,8 +348,10 @@ the list:
|
||||||
// demo.list will now be a real collection of 4 entries
|
// demo.list will now be a real collection of 4 entries
|
||||||
// Each entry is a new empty String
|
// Each entry is a new empty String
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Demo {
|
class Demo {
|
||||||
var list: List<String>? = null
|
var list: List<String>? = null
|
||||||
|
|
@ -336,6 +373,7 @@ the list:
|
||||||
// demo.list will now be a real collection of 4 entries
|
// demo.list will now be a real collection of 4 entries
|
||||||
// Each entry is a new empty String
|
// Each entry is a new empty String
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -404,8 +442,11 @@ since part of the expression may be running twice.
|
||||||
After selecting a mode, use the `SpelParserConfiguration` to configure the parser. The
|
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]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
|
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
|
||||||
this.getClass().getClassLoader());
|
this.getClass().getClassLoader());
|
||||||
|
|
@ -418,8 +459,10 @@ following example shows how to do so:
|
||||||
|
|
||||||
Object payload = expr.getValue(message);
|
Object payload = expr.getValue(message);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val config = SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
|
val config = SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
|
||||||
this.javaClass.classLoader)
|
this.javaClass.classLoader)
|
||||||
|
|
@ -432,6 +475,7 @@ following example shows how to do so:
|
||||||
|
|
||||||
val payload = expr.getValue(message)
|
val payload = expr.getValue(message)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When you specify the compiler mode, you can also specify a classloader (passing null is allowed).
|
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.
|
Compiled expressions are defined in a child classloader created under any that is supplied.
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
This section lists the classes used in the examples throughout this chapter.
|
This section lists the classes used in the examples throughout this chapter.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Inventor.Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Inventor.Java
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor;
|
package org.spring.samples.spel.inventor;
|
||||||
|
|
||||||
|
|
@ -76,8 +79,10 @@ This section lists the classes used in the examples throughout this chapter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Inventor.kt::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Inventor.kt
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor
|
package org.spring.samples.spel.inventor
|
||||||
|
|
||||||
|
|
@ -88,9 +93,13 @@ This section lists the classes used in the examples throughout this chapter.
|
||||||
var birthdate: Date = GregorianCalendar().time,
|
var birthdate: Date = GregorianCalendar().time,
|
||||||
var placeOfBirth: PlaceOfBirth? = null)
|
var placeOfBirth: PlaceOfBirth? = null)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
PlaceOfBirth.java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.PlaceOfBirth.java
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor;
|
package org.spring.samples.spel.inventor;
|
||||||
|
|
||||||
|
|
@ -125,16 +134,22 @@ This section lists the classes used in the examples throughout this chapter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
PlaceOfBirth.kt::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.PlaceOfBirth.kt
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor
|
package org.spring.samples.spel.inventor
|
||||||
|
|
||||||
class PlaceOfBirth(var city: String, var country: String? = null) {
|
class PlaceOfBirth(var city: String, var country: String? = null) {
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Society.java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Society.java
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor;
|
package org.spring.samples.spel.inventor;
|
||||||
|
|
||||||
|
|
@ -176,8 +191,10 @@ This section lists the classes used in the examples throughout this chapter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Society.kt::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Society.kt
|
|
||||||
----
|
----
|
||||||
package org.spring.samples.spel.inventor
|
package org.spring.samples.spel.inventor
|
||||||
|
|
||||||
|
|
@ -203,3 +220,4 @@ This section lists the classes used in the examples throughout this chapter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@
|
||||||
You can build arrays by using the familiar Java syntax, optionally supplying an initializer
|
You can build arrays by using the familiar Java syntax, optionally supplying an initializer
|
||||||
to have the array populated at construction time. The following example shows how to do so:
|
to have the array populated at construction time. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
|
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
|
||||||
|
|
||||||
|
|
@ -15,8 +18,10 @@ to have the array populated at construction time. The following example shows ho
|
||||||
// Multi dimensional array
|
// Multi dimensional array
|
||||||
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
|
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val numbers1 = parser.parseExpression("new int[4]").getValue(context) as IntArray
|
val numbers1 = parser.parseExpression("new int[4]").getValue(context) as IntArray
|
||||||
|
|
||||||
|
|
@ -26,6 +31,7 @@ to have the array populated at construction time. The following example shows ho
|
||||||
// Multi dimensional array
|
// Multi dimensional array
|
||||||
val numbers3 = parser.parseExpression("new int[4][5]").getValue(context) as Array<IntArray>
|
val numbers3 = parser.parseExpression("new int[4][5]").getValue(context) as Array<IntArray>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You cannot currently supply an initializer when you construct a multi-dimensional array.
|
You cannot currently supply an initializer when you construct a multi-dimensional array.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ If the evaluation context has been configured with a bean resolver, you can
|
||||||
look up beans from an expression by using the `@` symbol. The following example shows how
|
look up beans from an expression by using the `@` symbol. The following example shows how
|
||||||
to do so:
|
to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||||
|
|
@ -15,8 +18,10 @@ to do so:
|
||||||
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
|
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
|
||||||
Object bean = parser.parseExpression("@something").getValue(context);
|
Object bean = parser.parseExpression("@something").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
val context = StandardEvaluationContext()
|
val context = StandardEvaluationContext()
|
||||||
|
|
@ -25,12 +30,16 @@ to do so:
|
||||||
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
|
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
|
||||||
val bean = parser.parseExpression("@something").getValue(context)
|
val bean = parser.parseExpression("@something").getValue(context)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To access a factory bean itself, you should instead prefix the bean name with an `&` symbol.
|
To access a factory bean itself, you should instead prefix the bean name with an `&` symbol.
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||||
|
|
@ -39,8 +48,10 @@ The following example shows how to do so:
|
||||||
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
|
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
|
||||||
Object bean = parser.parseExpression("&foo").getValue(context);
|
Object bean = parser.parseExpression("&foo").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
val context = StandardEvaluationContext()
|
val context = StandardEvaluationContext()
|
||||||
|
|
@ -49,5 +60,6 @@ The following example shows how to do so:
|
||||||
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
|
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
|
||||||
val bean = parser.parseExpression("&foo").getValue(context)
|
val bean = parser.parseExpression("&foo").getValue(context)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,24 @@ suppose we have a list of inventors but want the list of cities where they were
|
||||||
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:
|
list. The following example uses projection to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// returns ['Smiljan', 'Idvor' ]
|
// returns ['Smiljan', 'Idvor' ]
|
||||||
List placesOfBirth = (List)parser.parseExpression("members.![placeOfBirth.city]");
|
List placesOfBirth = (List)parser.parseExpression("members.![placeOfBirth.city]");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// returns ['Smiljan', 'Idvor' ]
|
// returns ['Smiljan', 'Idvor' ]
|
||||||
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") as List<*>
|
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") as List<*>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Projection is supported for arrays and anything that implements `java.lang.Iterable` or
|
Projection is supported for arrays and anything that implements `java.lang.Iterable` or
|
||||||
`java.util.Map`. When using a map to drive projection, the projection expression is
|
`java.util.Map`. When using a map to drive projection, the projection expression is
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,24 @@ Selection uses a syntax of `.?[selectionExpression]`. It filters the collection
|
||||||
returns a new collection that contains a subset of the original elements. For example,
|
returns a new collection that contains a subset of the original elements. For example,
|
||||||
selection lets us easily get a list of Serbian inventors, as the following example shows:
|
selection lets us easily get a list of Serbian inventors, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
List<Inventor> list = (List<Inventor>) parser.parseExpression(
|
List<Inventor> list = (List<Inventor>) parser.parseExpression(
|
||||||
"members.?[nationality == 'Serbian']").getValue(societyContext);
|
"members.?[nationality == 'Serbian']").getValue(societyContext);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val list = parser.parseExpression(
|
val list = parser.parseExpression(
|
||||||
"members.?[nationality == 'Serbian']").getValue(societyContext) as List<Inventor>
|
"members.?[nationality == 'Serbian']").getValue(societyContext) as List<Inventor>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Selection is supported for arrays and anything that implements `java.lang.Iterable` or
|
Selection is supported for arrays and anything that implements `java.lang.Iterable` or
|
||||||
`java.util.Map`. For a list or array, the selection criteria is evaluated against each
|
`java.util.Map`. For a list or array, the selection criteria is evaluated against each
|
||||||
|
|
@ -30,16 +36,22 @@ accessible as properties for use in the selection.
|
||||||
The following expression returns a new map that consists of those elements of the
|
The following expression returns a new map that consists of those elements of the
|
||||||
original map where the entry's value is less than 27:
|
original map where the entry's value is less than 27:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
|
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val newMap = parser.parseExpression("map.?[value<27]").getValue()
|
val newMap = parser.parseExpression("map.?[value<27]").getValue()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In addition to returning all the selected elements, you can retrieve only the first or
|
In addition to returning all the selected elements, you can retrieve only the first or
|
||||||
the last element. To obtain the first element matching the selection, the syntax is
|
the last element. To obtain the first element matching the selection, the syntax is
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ qualified class name for all types except those located in the `java.lang` packa
|
||||||
(`Integer`, `Float`, `String`, and so on). The following example shows how to use the
|
(`Integer`, `Float`, `String`, and so on). The following example shows how to use the
|
||||||
`new` operator to invoke constructors:
|
`new` operator to invoke constructors:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Inventor einstein = p.parseExpression(
|
Inventor einstein = p.parseExpression(
|
||||||
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
|
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
|
||||||
|
|
@ -18,8 +21,10 @@ qualified class name for all types except those located in the `java.lang` packa
|
||||||
"Members.add(new org.spring.samples.spel.inventor.Inventor(
|
"Members.add(new org.spring.samples.spel.inventor.Inventor(
|
||||||
'Albert Einstein', 'German'))").getValue(societyContext);
|
'Albert Einstein', 'German'))").getValue(societyContext);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val einstein = p.parseExpression(
|
val einstein = p.parseExpression(
|
||||||
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
|
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
|
||||||
|
|
@ -30,6 +35,7 @@ qualified class name for all types except those located in the `java.lang` packa
|
||||||
"Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German'))")
|
"Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German'))")
|
||||||
.getValue(societyContext)
|
.getValue(societyContext)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,36 @@ You can extend SpEL by registering user-defined functions that can be called wit
|
||||||
expression string. The function is registered through the `EvaluationContext`. The
|
expression string. The function is registered through the `EvaluationContext`. The
|
||||||
following example shows how to register a user-defined function:
|
following example shows how to register a user-defined function:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Method method = ...;
|
Method method = ...;
|
||||||
|
|
||||||
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||||||
context.setVariable("myFunction", method);
|
context.setVariable("myFunction", method);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val method: Method = ...
|
val method: Method = ...
|
||||||
|
|
||||||
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
||||||
context.setVariable("myFunction", method)
|
context.setVariable("myFunction", method)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For example, consider the following utility method that reverses a string:
|
For example, consider the following utility method that reverses a string:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public abstract class StringUtils {
|
public abstract class StringUtils {
|
||||||
|
|
||||||
|
|
@ -38,8 +47,10 @@ For example, consider the following utility method that reverses a string:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun reverseString(input: String): String {
|
fun reverseString(input: String): String {
|
||||||
val backwards = StringBuilder(input.length)
|
val backwards = StringBuilder(input.length)
|
||||||
|
|
@ -49,11 +60,15 @@ For example, consider the following utility method that reverses a string:
|
||||||
return backwards.toString()
|
return backwards.toString()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can then register and use the preceding method, as the following example shows:
|
You can then register and use the preceding method, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
|
@ -64,8 +79,10 @@ You can then register and use the preceding method, as the following example sho
|
||||||
String helloWorldReversed = parser.parseExpression(
|
String helloWorldReversed = parser.parseExpression(
|
||||||
"#reverseString('hello')").getValue(context, String.class);
|
"#reverseString('hello')").getValue(context, String.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
|
|
||||||
|
|
@ -75,6 +92,7 @@ You can then register and use the preceding method, as the following example sho
|
||||||
val helloWorldReversed = parser.parseExpression(
|
val helloWorldReversed = parser.parseExpression(
|
||||||
"#reverseString('hello')").getValue(context, String::class.java)
|
"#reverseString('hello')").getValue(context, String::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,28 @@
|
||||||
|
|
||||||
You can directly express lists in an expression by using `{}` notation.
|
You can directly express lists in an expression by using `{}` notation.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// evaluates to a Java list containing the four numbers
|
// evaluates to a Java list containing the four numbers
|
||||||
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
|
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
|
||||||
|
|
||||||
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
|
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// evaluates to a Java list containing the four numbers
|
// evaluates to a Java list containing the four numbers
|
||||||
val numbers = parser.parseExpression("{1,2,3,4}").getValue(context) as List<*>
|
val numbers = parser.parseExpression("{1,2,3,4}").getValue(context) as List<*>
|
||||||
|
|
||||||
val listOfLists = parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context) as List<*>
|
val listOfLists = parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context) as List<*>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`{}` by itself means an empty list. For performance reasons, if the list is itself
|
`{}` by itself means an empty list. For performance reasons, if the list is itself
|
||||||
entirely composed of fixed literals, a constant list is created to represent the
|
entirely composed of fixed literals, a constant list is created to represent the
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,28 @@
|
||||||
You can also directly express maps in an expression by using `{key:value}` notation. The
|
You can also directly express maps in an expression by using `{key:value}` notation. The
|
||||||
following example shows how to do so:
|
following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// evaluates to a Java map containing the two entries
|
// evaluates to a Java map containing the two entries
|
||||||
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
|
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
|
||||||
|
|
||||||
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
|
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// evaluates to a Java map containing the two entries
|
// evaluates to a Java map containing the two entries
|
||||||
val inventorInfo = parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context) as Map<*, *>
|
val inventorInfo = parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context) as Map<*, *>
|
||||||
|
|
||||||
val mapOfMaps = parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context) as Map<*, *>
|
val mapOfMaps = parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context) as Map<*, *>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`{:}` by itself means an empty map. For performance reasons, if the map is itself
|
`{:}` by itself means an empty map. For performance reasons, if the map is itself
|
||||||
composed of fixed literals or other nested constant structures (lists or maps), a
|
composed of fixed literals or other nested constant structures (lists or maps), a
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,11 @@ isolation like this but, rather, as part of a more complex expression -- for exa
|
||||||
using a literal on one side of a logical comparison operator or as an argument to a
|
using a literal on one side of a logical comparison operator or as an argument to a
|
||||||
method.
|
method.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
|
@ -43,8 +46,10 @@ method.
|
||||||
|
|
||||||
Object nullValue = parser.parseExpression("null").getValue();
|
Object nullValue = parser.parseExpression("null").getValue();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
|
|
||||||
|
|
@ -63,6 +68,7 @@ method.
|
||||||
|
|
||||||
val nullValue = parser.parseExpression("null").value
|
val nullValue = parser.parseExpression("null").value
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ You can invoke methods by using typical Java programming syntax. You can also in
|
||||||
on literals. Variable arguments are also supported. The following examples show how to
|
on literals. Variable arguments are also supported. The following examples show how to
|
||||||
invoke methods:
|
invoke methods:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// string literal, evaluates to "bc"
|
// string literal, evaluates to "bc"
|
||||||
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
|
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
|
||||||
|
|
@ -15,8 +18,10 @@ invoke methods:
|
||||||
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
|
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
|
||||||
societyContext, Boolean.class);
|
societyContext, Boolean.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// string literal, evaluates to "bc"
|
// string literal, evaluates to "bc"
|
||||||
val bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String::class.java)
|
val bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String::class.java)
|
||||||
|
|
@ -25,5 +30,6 @@ invoke methods:
|
||||||
val isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
|
val isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
|
||||||
societyContext, Boolean::class.java)
|
societyContext, Boolean::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,27 +15,36 @@ following example shows:
|
||||||
Instead, you can use the Elvis operator (named for the resemblance to Elvis' hair style).
|
Instead, you can use the Elvis operator (named for the resemblance to Elvis' hair style).
|
||||||
The following example shows how to use the Elvis operator:
|
The following example shows how to use the Elvis operator:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
String name = parser.parseExpression("name?:'Unknown'").getValue(new Inventor(), String.class);
|
String name = parser.parseExpression("name?:'Unknown'").getValue(new Inventor(), String.class);
|
||||||
System.out.println(name); // 'Unknown'
|
System.out.println(name); // 'Unknown'
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
|
|
||||||
val name = parser.parseExpression("name?:'Unknown'").getValue(Inventor(), String::class.java)
|
val name = parser.parseExpression("name?:'Unknown'").getValue(Inventor(), String::class.java)
|
||||||
println(name) // 'Unknown'
|
println(name) // 'Unknown'
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following listing shows a more complex example:
|
The following listing shows a more complex example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||||||
|
|
@ -48,8 +57,10 @@ The following listing shows a more complex example:
|
||||||
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String.class);
|
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String.class);
|
||||||
System.out.println(name); // Elvis Presley
|
System.out.println(name); // Elvis Presley
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
||||||
|
|
@ -62,6 +73,7 @@ The following listing shows a more complex example:
|
||||||
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String::class.java)
|
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String::class.java)
|
||||||
println(name) // Elvis Presley
|
println(name) // Elvis Presley
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
=====
|
=====
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,11 @@ it is not null before accessing methods or properties of the object. To avoid th
|
||||||
safe navigation operator returns null instead of throwing an exception. The following
|
safe navigation operator returns null instead of throwing an exception. The following
|
||||||
example shows how to use the safe navigation operator:
|
example shows how to use the safe navigation operator:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||||||
|
|
@ -24,8 +27,10 @@ example shows how to use the safe navigation operator:
|
||||||
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String.class);
|
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String.class);
|
||||||
System.out.println(city); // null - does not throw NullPointerException!!!
|
System.out.println(city); // null - does not throw NullPointerException!!!
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
||||||
|
|
@ -40,6 +45,7 @@ example shows how to use the safe navigation operator:
|
||||||
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String::class.java)
|
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String::class.java)
|
||||||
println(city) // null - does not throw NullPointerException!!!
|
println(city) // null - does not throw NullPointerException!!!
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,33 @@
|
||||||
You can use the ternary operator for performing if-then-else conditional logic inside
|
You can use the ternary operator for performing if-then-else conditional logic inside
|
||||||
the expression. The following listing shows a minimal example:
|
the expression. The following listing shows a minimal example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
String falseString = parser.parseExpression(
|
String falseString = parser.parseExpression(
|
||||||
"false ? 'trueExp' : 'falseExp'").getValue(String.class);
|
"false ? 'trueExp' : 'falseExp'").getValue(String.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val falseString = parser.parseExpression(
|
val falseString = parser.parseExpression(
|
||||||
"false ? 'trueExp' : 'falseExp'").getValue(String::class.java)
|
"false ? 'trueExp' : 'falseExp'").getValue(String::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In this case, the boolean `false` results in returning the string value `'falseExp'`. A more
|
In this case, the boolean `false` results in returning the string value `'falseExp'`. A more
|
||||||
realistic example follows:
|
realistic example follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
parser.parseExpression("name").setValue(societyContext, "IEEE");
|
parser.parseExpression("name").setValue(societyContext, "IEEE");
|
||||||
societyContext.setVariable("queryName", "Nikola Tesla");
|
societyContext.setVariable("queryName", "Nikola Tesla");
|
||||||
|
|
@ -33,8 +42,10 @@ realistic example follows:
|
||||||
.getValue(societyContext, String.class);
|
.getValue(societyContext, String.class);
|
||||||
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
parser.parseExpression("name").setValue(societyContext, "IEEE")
|
parser.parseExpression("name").setValue(societyContext, "IEEE")
|
||||||
societyContext.setVariable("queryName", "Nikola Tesla")
|
societyContext.setVariable("queryName", "Nikola Tesla")
|
||||||
|
|
@ -45,6 +56,7 @@ realistic example follows:
|
||||||
.getValue(societyContext, String::class.java)
|
.getValue(societyContext, String::class.java)
|
||||||
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the next section on the Elvis operator for an even shorter syntax for the
|
See the next section on the Elvis operator for an even shorter syntax for the
|
||||||
ternary operator.
|
ternary operator.
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,11 @@ and greater than or equal) are supported by using standard operator notation.
|
||||||
These operators work on `Number` types as well as types implementing `Comparable`.
|
These operators work on `Number` types as well as types implementing `Comparable`.
|
||||||
The following listing shows a few examples of operators:
|
The following listing shows a few examples of operators:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// evaluates to true
|
// evaluates to true
|
||||||
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
|
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
|
||||||
|
|
@ -32,8 +35,10 @@ The following listing shows a few examples of operators:
|
||||||
// uses CustomValue:::compareTo
|
// uses CustomValue:::compareTo
|
||||||
boolean trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean.class);
|
boolean trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// evaluates to true
|
// evaluates to true
|
||||||
val trueValue = parser.parseExpression("2 == 2").getValue(Boolean::class.java)
|
val trueValue = parser.parseExpression("2 == 2").getValue(Boolean::class.java)
|
||||||
|
|
@ -47,6 +52,7 @@ The following listing shows a few examples of operators:
|
||||||
// uses CustomValue:::compareTo
|
// uses CustomValue:::compareTo
|
||||||
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java);
|
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java);
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -62,8 +68,11 @@ in favor of comparisons against zero (for example, `X > 0` or `X < 0`).
|
||||||
In addition to the standard relational operators, SpEL supports the `instanceof` and regular
|
In addition to the standard relational operators, SpEL supports the `instanceof` and regular
|
||||||
expression-based `matches` operator. The following listing shows examples of both:
|
expression-based `matches` operator. The following listing shows examples of both:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// evaluates to false
|
// evaluates to false
|
||||||
boolean falseValue = parser.parseExpression(
|
boolean falseValue = parser.parseExpression(
|
||||||
|
|
@ -77,8 +86,10 @@ expression-based `matches` operator. The following listing shows examples of bot
|
||||||
boolean falseValue = parser.parseExpression(
|
boolean falseValue = parser.parseExpression(
|
||||||
"'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
"'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// evaluates to false
|
// evaluates to false
|
||||||
val falseValue = parser.parseExpression(
|
val falseValue = parser.parseExpression(
|
||||||
|
|
@ -92,6 +103,7 @@ expression-based `matches` operator. The following listing shows examples of bot
|
||||||
val falseValue = parser.parseExpression(
|
val falseValue = parser.parseExpression(
|
||||||
"'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean::class.java)
|
"'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
CAUTION: Be careful with primitive types, as they are immediately boxed up to their
|
CAUTION: Be careful with primitive types, as they are immediately boxed up to their
|
||||||
wrapper types. For example, `1 instanceof T(int)` evaluates to `false`, while
|
wrapper types. For example, `1 instanceof T(int)` evaluates to `false`, while
|
||||||
|
|
@ -125,8 +137,11 @@ SpEL supports the following logical operators:
|
||||||
|
|
||||||
The following example shows how to use the logical operators:
|
The following example shows how to use the logical operators:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// -- AND --
|
// -- AND --
|
||||||
|
|
||||||
|
|
@ -155,8 +170,10 @@ The following example shows how to use the logical operators:
|
||||||
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
|
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
|
||||||
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// -- AND --
|
// -- AND --
|
||||||
|
|
||||||
|
|
@ -185,6 +202,7 @@ The following example shows how to use the logical operators:
|
||||||
val expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')"
|
val expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')"
|
||||||
val falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean::class.java)
|
val falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[expressions-operators-mathematical]]
|
[[expressions-operators-mathematical]]
|
||||||
|
|
@ -196,8 +214,11 @@ You can also use the modulus (`%`) and exponential power (`^`) operators on numb
|
||||||
Standard operator precedence is enforced. The following example shows the mathematical
|
Standard operator precedence is enforced. The following example shows the mathematical
|
||||||
operators in use:
|
operators in use:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// Addition
|
// Addition
|
||||||
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
|
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
|
||||||
|
|
@ -228,8 +249,10 @@ operators in use:
|
||||||
// Operator precedence
|
// Operator precedence
|
||||||
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
|
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// Addition
|
// Addition
|
||||||
val two = parser.parseExpression("1 + 1").getValue(Int::class.java) // 2
|
val two = parser.parseExpression("1 + 1").getValue(Int::class.java) // 2
|
||||||
|
|
@ -260,6 +283,7 @@ operators in use:
|
||||||
// Operator precedence
|
// Operator precedence
|
||||||
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
|
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[expressions-assignment]]
|
[[expressions-assignment]]
|
||||||
|
|
@ -269,8 +293,11 @@ To set a property, use the assignment operator (`=`). This is typically done wit
|
||||||
call to `setValue` but can also be done inside a call to `getValue`. The following
|
call to `setValue` but can also be done inside a call to `getValue`. The following
|
||||||
listing shows both ways to use the assignment operator:
|
listing shows both ways to use the assignment operator:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Inventor inventor = new Inventor();
|
Inventor inventor = new Inventor();
|
||||||
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
|
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
|
||||||
|
|
@ -281,8 +308,10 @@ listing shows both ways to use the assignment operator:
|
||||||
String aleks = parser.parseExpression(
|
String aleks = parser.parseExpression(
|
||||||
"name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);
|
"name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val inventor = Inventor()
|
val inventor = Inventor()
|
||||||
val context = SimpleEvaluationContext.forReadWriteDataBinding().build()
|
val context = SimpleEvaluationContext.forReadWriteDataBinding().build()
|
||||||
|
|
@ -293,5 +322,6 @@ listing shows both ways to use the assignment operator:
|
||||||
val aleks = parser.parseExpression(
|
val aleks = parser.parseExpression(
|
||||||
"name = 'Aleksandar Seovic'").getValue(context, inventor, String::class.java)
|
"name = 'Aleksandar Seovic'").getValue(context, inventor, String::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,28 @@ populated with data listed in the xref:core/expressions/example-classes.adoc[Cla
|
||||||
section. To navigate "down" the object graph and get Tesla's year of birth and
|
section. To navigate "down" the object graph and get Tesla's year of birth and
|
||||||
Pupin's city of birth, we use the following expressions:
|
Pupin's city of birth, we use the following expressions:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// evaluates to 1856
|
// evaluates to 1856
|
||||||
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
|
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
|
||||||
|
|
||||||
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
|
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// evaluates to 1856
|
// evaluates to 1856
|
||||||
val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int
|
val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int
|
||||||
|
|
||||||
val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String
|
val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
@ -36,8 +42,11 @@ method invocations -- for example, `getPlaceOfBirth().getCity()` instead of
|
||||||
The contents of arrays and lists are obtained by using square bracket notation, as the
|
The contents of arrays and lists are obtained by using square bracket notation, as the
|
||||||
following example shows:
|
following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||||||
|
|
@ -59,8 +68,10 @@ following example shows:
|
||||||
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
|
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
|
||||||
context, ieee, String.class);
|
context, ieee, String.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val parser = SpelExpressionParser()
|
val parser = SpelExpressionParser()
|
||||||
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
|
||||||
|
|
@ -82,13 +93,17 @@ following example shows:
|
||||||
val invention = parser.parseExpression("members[0].inventions[6]").getValue(
|
val invention = parser.parseExpression("members[0].inventions[6]").getValue(
|
||||||
context, ieee, String::class.java)
|
context, ieee, String::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The contents of maps are obtained by specifying the literal key value within the
|
The contents of maps are obtained by specifying the literal key value within the
|
||||||
brackets. In the following example, because keys for the `officers` map are strings, we can specify
|
brackets. In the following example, because keys for the `officers` map are strings, we can specify
|
||||||
string literals:
|
string literals:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// Officer's Dictionary
|
// Officer's Dictionary
|
||||||
|
|
||||||
|
|
@ -103,8 +118,10 @@ string literals:
|
||||||
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
|
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
|
||||||
societyContext, "Croatia");
|
societyContext, "Croatia");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// Officer's Dictionary
|
// Officer's Dictionary
|
||||||
|
|
||||||
|
|
@ -119,6 +136,7 @@ string literals:
|
||||||
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
|
parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
|
||||||
societyContext, "Croatia")
|
societyContext, "Croatia")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ Each evaluation block is delimited with prefix and suffix characters that you ca
|
||||||
define. A common choice is to use `#{ }` as the delimiters, as the following example
|
define. A common choice is to use `#{ }` as the delimiters, as the following example
|
||||||
shows:
|
shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
String randomPhrase = parser.parseExpression(
|
String randomPhrase = parser.parseExpression(
|
||||||
"random number is #{T(java.lang.Math).random()}",
|
"random number is #{T(java.lang.Math).random()}",
|
||||||
|
|
@ -15,8 +18,10 @@ shows:
|
||||||
|
|
||||||
// evaluates to "random number is 0.7038186818312008"
|
// evaluates to "random number is 0.7038186818312008"
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val randomPhrase = parser.parseExpression(
|
val randomPhrase = parser.parseExpression(
|
||||||
"random number is #{T(java.lang.Math).random()}",
|
"random number is #{T(java.lang.Math).random()}",
|
||||||
|
|
@ -24,6 +29,7 @@ shows:
|
||||||
|
|
||||||
// evaluates to "random number is 0.7038186818312008"
|
// evaluates to "random number is 0.7038186818312008"
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The string is evaluated by concatenating the literal text `'random number is '` with the
|
The string is evaluated by concatenating the literal text `'random number is '` with the
|
||||||
result of evaluating the expression inside the `#{ }` delimiter (in this case, the result
|
result of evaluating the expression inside the `#{ }` delimiter (in this case, the result
|
||||||
|
|
@ -32,8 +38,11 @@ is of the type `ParserContext`. The `ParserContext` interface is used to influen
|
||||||
the expression is parsed in order to support the expression templating functionality.
|
the expression is parsed in order to support the expression templating functionality.
|
||||||
The definition of `TemplateParserContext` follows:
|
The definition of `TemplateParserContext` follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class TemplateParserContext implements ParserContext {
|
public class TemplateParserContext implements ParserContext {
|
||||||
|
|
||||||
|
|
@ -50,8 +59,10 @@ The definition of `TemplateParserContext` follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TemplateParserContext : ParserContext {
|
class TemplateParserContext : ParserContext {
|
||||||
|
|
||||||
|
|
@ -68,5 +79,6 @@ The definition of `TemplateParserContext` follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@ type). Static methods are invoked by using this operator as well. The
|
||||||
package do not need to be fully qualified, but all other type references must be. The
|
package do not need to be fully qualified, but all other type references must be. The
|
||||||
following example shows how to use the `T` operator:
|
following example shows how to use the `T` operator:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
|
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
|
||||||
|
|
||||||
|
|
@ -20,8 +23,10 @@ following example shows how to use the `T` operator:
|
||||||
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
||||||
.getValue(Boolean.class);
|
.getValue(Boolean.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class::class.java)
|
val dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class::class.java)
|
||||||
|
|
||||||
|
|
@ -31,6 +36,7 @@ following example shows how to use the `T` operator:
|
||||||
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
||||||
.getValue(Boolean::class.java)
|
.getValue(Boolean::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,11 @@ characters.
|
||||||
|
|
||||||
The following example shows how to use variables.
|
The following example shows how to use variables.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||||||
|
|
||||||
|
|
@ -28,8 +31,10 @@ The following example shows how to use variables.
|
||||||
parser.parseExpression("name = #newName").getValue(context, tesla);
|
parser.parseExpression("name = #newName").getValue(context, tesla);
|
||||||
System.out.println(tesla.getName()) // "Mike Tesla"
|
System.out.println(tesla.getName()) // "Mike Tesla"
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val tesla = Inventor("Nikola Tesla", "Serbian")
|
val tesla = Inventor("Nikola Tesla", "Serbian")
|
||||||
|
|
||||||
|
|
@ -39,6 +44,7 @@ The following example shows how to use variables.
|
||||||
parser.parseExpression("name = #newName").getValue(context, tesla)
|
parser.parseExpression("name = #newName").getValue(context, tesla)
|
||||||
println(tesla.name) // "Mike Tesla"
|
println(tesla.name) // "Mike Tesla"
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[expressions-this-root]]
|
[[expressions-this-root]]
|
||||||
|
|
@ -50,8 +56,11 @@ defined and refers to the root context object. Although `#this` may vary as comp
|
||||||
an expression are evaluated, `#root` always refers to the root. The following examples
|
an expression are evaluated, `#root` always refers to the root. The following examples
|
||||||
show how to use the `#this` and `#root` variables:
|
show how to use the `#this` and `#root` variables:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// create an array of integers
|
// create an array of integers
|
||||||
List<Integer> primes = new ArrayList<>();
|
List<Integer> primes = new ArrayList<>();
|
||||||
|
|
@ -67,8 +76,10 @@ show how to use the `#this` and `#root` variables:
|
||||||
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
|
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
|
||||||
"#primes.?[#this>10]").getValue(context);
|
"#primes.?[#this>10]").getValue(context);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// create an array of integers
|
// create an array of integers
|
||||||
val primes = ArrayList<Int>()
|
val primes = ArrayList<Int>()
|
||||||
|
|
@ -84,6 +95,7 @@ show how to use the `#this` and `#root` variables:
|
||||||
val primesGreaterThanTen = parser.parseExpression(
|
val primesGreaterThanTen = parser.parseExpression(
|
||||||
"#primes.?[#this>10]").getValue(context) as List<Int>
|
"#primes.?[#this>10]").getValue(context) as List<Int>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -276,16 +276,22 @@ specified doesn't have a specific prefix, you get back a `Resource` type that is
|
||||||
appropriate to that particular application context. For example, assume the following
|
appropriate to that particular application context. For example, assume the following
|
||||||
snippet of code was run against a `ClassPathXmlApplicationContext` instance:
|
snippet of code was run against a `ClassPathXmlApplicationContext` instance:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
|
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val template = ctx.getResource("some/resource/path/myTemplate.txt")
|
val template = ctx.getResource("some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Against a `ClassPathXmlApplicationContext`, that code returns a `ClassPathResource`. If
|
Against a `ClassPathXmlApplicationContext`, that code returns a `ClassPathResource`. If
|
||||||
the same method were run against a `FileSystemXmlApplicationContext` instance, it would
|
the same method were run against a `FileSystemXmlApplicationContext` instance, it would
|
||||||
|
|
@ -299,41 +305,59 @@ On the other hand, you may also force `ClassPathResource` to be used, regardless
|
||||||
application context type, by specifying the special `classpath:` prefix, as the following
|
application context type, by specifying the special `classpath:` prefix, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
|
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val template = ctx.getResource("classpath:some/resource/path/myTemplate.txt")
|
val template = ctx.getResource("classpath:some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Similarly, you can force a `UrlResource` to be used by specifying any of the standard
|
Similarly, you can force a `UrlResource` to be used by specifying any of the standard
|
||||||
`java.net.URL` prefixes. The following examples use the `file` and `https` prefixes:
|
`java.net.URL` prefixes. The following examples use the `file` and `https` prefixes:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
|
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val template = ctx.getResource("file:///some/resource/path/myTemplate.txt")
|
val template = ctx.getResource("file:///some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
|
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt")
|
val template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following table summarizes the strategy for converting `String` objects to `Resource`
|
The following table summarizes the strategy for converting `String` objects to `Resource`
|
||||||
objects:
|
objects:
|
||||||
|
|
@ -477,8 +501,11 @@ register and use a special JavaBeans `PropertyEditor`, which can convert `String
|
||||||
to `Resource` objects. For example, the following `MyBean` class has a `template`
|
to `Resource` objects. For example, the following `MyBean` class has a `template`
|
||||||
property of type `Resource`.
|
property of type `Resource`.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
|
@ -493,11 +520,14 @@ property of type `Resource`.
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MyBean(var template: Resource)
|
class MyBean(var template: Resource)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In an XML configuration file, the `template` property can be configured with a simple
|
In an XML configuration file, the `template` property can be configured with a simple
|
||||||
string for that resource, as the following example shows:
|
string for that resource, as the following example shows:
|
||||||
|
|
@ -537,8 +567,11 @@ retrieve the value of the template path as a string, and a special `PropertyEdit
|
||||||
convert the string to a `Resource` object to be injected into the `MyBean` constructor.
|
convert the string to a `Resource` object to be injected into the `MyBean` constructor.
|
||||||
The following example demonstrates how to achieve this.
|
The following example demonstrates how to achieve this.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MyBean {
|
public class MyBean {
|
||||||
|
|
@ -552,12 +585,15 @@ The following example demonstrates how to achieve this.
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MyBean(@Value("\${template.path}") private val template: Resource)
|
class MyBean(@Value("\${template.path}") private val template: Resource)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If we want to support multiple templates discovered under the same path in multiple
|
If we want to support multiple templates discovered under the same path in multiple
|
||||||
locations in the classpath -- for example, in multiple jars in the classpath -- we can
|
locations in the classpath -- for example, in multiple jars in the classpath -- we can
|
||||||
|
|
@ -566,8 +602,11 @@ use the special `classpath*:` prefix and wildcarding to define a `templates.path
|
||||||
Spring will convert the template path pattern into an array of `Resource` objects that
|
Spring will convert the template path pattern into an array of `Resource` objects that
|
||||||
can be injected into the `MyBean` constructor.
|
can be injected into the `MyBean` constructor.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MyBean {
|
public class MyBean {
|
||||||
|
|
@ -581,12 +620,15 @@ can be injected into the `MyBean` constructor.
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MyBean(@Value("\${templates.path}") private val templates: Resource[])
|
class MyBean(@Value("\${templates.path}") private val templates: Resource[])
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -611,31 +653,43 @@ that path and used to load the bean definitions depends on and is appropriate to
|
||||||
specific application context. For example, consider the following example, which creates a
|
specific application context. For example, consider the following example, which creates a
|
||||||
`ClassPathXmlApplicationContext`:
|
`ClassPathXmlApplicationContext`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
|
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = ClassPathXmlApplicationContext("conf/appContext.xml")
|
val ctx = ClassPathXmlApplicationContext("conf/appContext.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The bean definitions are loaded from the classpath, because a `ClassPathResource` is
|
The bean definitions are loaded from the classpath, because a `ClassPathResource` is
|
||||||
used. However, consider the following example, which creates a `FileSystemXmlApplicationContext`:
|
used. However, consider the following example, which creates a `FileSystemXmlApplicationContext`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new FileSystemXmlApplicationContext("conf/appContext.xml");
|
new FileSystemXmlApplicationContext("conf/appContext.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = FileSystemXmlApplicationContext("conf/appContext.xml")
|
val ctx = FileSystemXmlApplicationContext("conf/appContext.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Now the bean definitions are loaded from a filesystem location (in this case, relative to
|
Now the bean definitions are loaded from a filesystem location (in this case, relative to
|
||||||
the current working directory).
|
the current working directory).
|
||||||
|
|
@ -644,17 +698,23 @@ Note that the use of the special `classpath` prefix or a standard URL prefix on
|
||||||
location path overrides the default type of `Resource` created to load the bean
|
location path overrides the default type of `Resource` created to load the bean
|
||||||
definitions. Consider the following example:
|
definitions. Consider the following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
|
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = FileSystemXmlApplicationContext("classpath:conf/appContext.xml")
|
val ctx = FileSystemXmlApplicationContext("classpath:conf/appContext.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Using `FileSystemXmlApplicationContext` loads the bean definitions from the classpath.
|
Using `FileSystemXmlApplicationContext` loads the bean definitions from the classpath.
|
||||||
However, it is still a `FileSystemXmlApplicationContext`. If it is subsequently used as a
|
However, it is still a `FileSystemXmlApplicationContext`. If it is subsequently used as a
|
||||||
|
|
@ -685,17 +745,23 @@ The following example shows how a `ClassPathXmlApplicationContext` instance comp
|
||||||
the beans defined in files named `services.xml` and `repositories.xml` (which are on the
|
the beans defined in files named `services.xml` and `repositories.xml` (which are on the
|
||||||
classpath) can be instantiated:
|
classpath) can be instantiated:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||||
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
|
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = ClassPathXmlApplicationContext(arrayOf("services.xml", "repositories.xml"), MessengerService::class.java)
|
val ctx = ClassPathXmlApplicationContext(arrayOf("services.xml", "repositories.xml"), MessengerService::class.java)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the {api-spring-framework}/context/support/ClassPathXmlApplicationContext.html[`ClassPathXmlApplicationContext`]
|
See the {api-spring-framework}/context/support/ClassPathXmlApplicationContext.html[`ClassPathXmlApplicationContext`]
|
||||||
javadoc for details on the various constructors.
|
javadoc for details on the various constructors.
|
||||||
|
|
@ -773,17 +839,23 @@ coming from jars be thoroughly tested in your specific environment before you re
|
||||||
When constructing an XML-based application context, a location string may use the
|
When constructing an XML-based application context, a location string may use the
|
||||||
special `classpath*:` prefix, as the following example shows:
|
special `classpath*:` prefix, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
|
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = ClassPathXmlApplicationContext("classpath*:conf/appContext.xml")
|
val ctx = ClassPathXmlApplicationContext("classpath*:conf/appContext.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This special prefix specifies that all classpath resources that match the given name
|
This special prefix specifies that all classpath resources that match the given name
|
||||||
must be obtained (internally, this essentially happens through a call to
|
must be obtained (internally, this essentially happens through a call to
|
||||||
|
|
@ -879,87 +951,123 @@ For backwards compatibility (historical) reasons however, this changes when the
|
||||||
to treat all location paths as relative, whether they start with a leading slash or not.
|
to treat all location paths as relative, whether they start with a leading slash or not.
|
||||||
In practice, this means the following examples are equivalent:
|
In practice, this means the following examples are equivalent:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new FileSystemXmlApplicationContext("conf/context.xml");
|
new FileSystemXmlApplicationContext("conf/context.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = FileSystemXmlApplicationContext("conf/context.xml")
|
val ctx = FileSystemXmlApplicationContext("conf/context.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new FileSystemXmlApplicationContext("/conf/context.xml");
|
new FileSystemXmlApplicationContext("/conf/context.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx = FileSystemXmlApplicationContext("/conf/context.xml")
|
val ctx = FileSystemXmlApplicationContext("/conf/context.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following examples are also equivalent (even though it would make sense for them to be different, as one
|
The following examples are also equivalent (even though it would make sense for them to be different, as one
|
||||||
case is relative and the other absolute):
|
case is relative and the other absolute):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
FileSystemXmlApplicationContext ctx = ...;
|
FileSystemXmlApplicationContext ctx = ...;
|
||||||
ctx.getResource("some/resource/path/myTemplate.txt");
|
ctx.getResource("some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx: FileSystemXmlApplicationContext = ...
|
val ctx: FileSystemXmlApplicationContext = ...
|
||||||
ctx.getResource("some/resource/path/myTemplate.txt")
|
ctx.getResource("some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
FileSystemXmlApplicationContext ctx = ...;
|
FileSystemXmlApplicationContext ctx = ...;
|
||||||
ctx.getResource("/some/resource/path/myTemplate.txt");
|
ctx.getResource("/some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val ctx: FileSystemXmlApplicationContext = ...
|
val ctx: FileSystemXmlApplicationContext = ...
|
||||||
ctx.getResource("/some/resource/path/myTemplate.txt")
|
ctx.getResource("/some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In practice, if you need true absolute filesystem paths, you should avoid using
|
In practice, if you need true absolute filesystem paths, you should avoid using
|
||||||
absolute paths with `FileSystemResource` or `FileSystemXmlApplicationContext` and
|
absolute paths with `FileSystemResource` or `FileSystemXmlApplicationContext` and
|
||||||
force the use of a `UrlResource` by using the `file:` URL prefix. The following examples
|
force the use of a `UrlResource` by using the `file:` URL prefix. The following examples
|
||||||
show how to do so:
|
show how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// actual context type doesn't matter, the Resource will always be UrlResource
|
// actual context type doesn't matter, the Resource will always be UrlResource
|
||||||
ctx.getResource("file:///some/resource/path/myTemplate.txt");
|
ctx.getResource("file:///some/resource/path/myTemplate.txt");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// actual context type doesn't matter, the Resource will always be UrlResource
|
// actual context type doesn't matter, the Resource will always be UrlResource
|
||||||
ctx.getResource("file:///some/resource/path/myTemplate.txt")
|
ctx.getResource("file:///some/resource/path/myTemplate.txt")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
|
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
|
||||||
ApplicationContext ctx =
|
ApplicationContext ctx =
|
||||||
new FileSystemXmlApplicationContext("file:///conf/context.xml");
|
new FileSystemXmlApplicationContext("file:///conf/context.xml");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
|
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
|
||||||
val ctx = FileSystemXmlApplicationContext("file:///conf/context.xml")
|
val ctx = FileSystemXmlApplicationContext("file:///conf/context.xml")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,25 @@ For logging needs within application code, prefer direct use of Log4j 2.x, SLF4J
|
||||||
A `Log` implementation may be retrieved via `org.apache.commons.logging.LogFactory` as in
|
A `Log` implementation may be retrieved via `org.apache.commons.logging.LogFactory` as in
|
||||||
the following example.
|
the following example.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MyBean {
|
public class MyBean {
|
||||||
private final Log log = LogFactory.getLog(getClass());
|
private final Log log = LogFactory.getLog(getClass());
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MyBean {
|
class MyBean {
|
||||||
private val log = LogFactory.getLog(javaClass)
|
private val log = LogFactory.getLog(javaClass)
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,11 @@ xref:core/validation/beans-beans.adoc#beans-beans-conversion[section on `Propert
|
||||||
The following two example classes use the `BeanWrapper` to get and set
|
The following two example classes use the `BeanWrapper` to get and set
|
||||||
properties:
|
properties:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Company {
|
public class Company {
|
||||||
|
|
||||||
|
|
@ -87,17 +90,23 @@ properties:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Company {
|
class Company {
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
var managingDirector: Employee? = null
|
var managingDirector: Employee? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Employee {
|
public class Employee {
|
||||||
|
|
||||||
|
|
@ -122,20 +131,26 @@ properties:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Employee {
|
class Employee {
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
var salary: Float? = null
|
var salary: Float? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following code snippets show some examples of how to retrieve and manipulate some of
|
The following code snippets show some examples of how to retrieve and manipulate some of
|
||||||
the properties of instantiated ``Company``s and ``Employee``s:
|
the properties of instantiated ``Company``s and ``Employee``s:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
BeanWrapper company = new BeanWrapperImpl(new Company());
|
BeanWrapper company = new BeanWrapperImpl(new Company());
|
||||||
// setting the company name..
|
// setting the company name..
|
||||||
|
|
@ -152,8 +167,10 @@ the properties of instantiated ``Company``s and ``Employee``s:
|
||||||
// retrieving the salary of the managingDirector through the company
|
// retrieving the salary of the managingDirector through the company
|
||||||
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
|
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val company = BeanWrapperImpl(Company())
|
val company = BeanWrapperImpl(Company())
|
||||||
// setting the company name..
|
// setting the company name..
|
||||||
|
|
@ -170,6 +187,7 @@ the properties of instantiated ``Company``s and ``Employee``s:
|
||||||
// retrieving the salary of the managingDirector through the company
|
// retrieving the salary of the managingDirector through the company
|
||||||
val salary = company.getPropertyValue("managingDirector.salary") as Float?
|
val salary = company.getPropertyValue("managingDirector.salary") as Float?
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -308,8 +326,11 @@ com
|
||||||
The following Java source code for the referenced `SomethingBeanInfo` class
|
The following Java source code for the referenced `SomethingBeanInfo` class
|
||||||
associates a `CustomNumberEditor` with the `age` property of the `Something` class:
|
associates a `CustomNumberEditor` with the `age` property of the `Something` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SomethingBeanInfo extends SimpleBeanInfo {
|
public class SomethingBeanInfo extends SimpleBeanInfo {
|
||||||
|
|
||||||
|
|
@ -330,8 +351,10 @@ associates a `CustomNumberEditor` with the `age` property of the `Something` cla
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SomethingBeanInfo : SimpleBeanInfo() {
|
class SomethingBeanInfo : SimpleBeanInfo() {
|
||||||
|
|
||||||
|
|
@ -351,6 +374,7 @@ associates a `CustomNumberEditor` with the `age` property of the `Something` cla
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[beans-beans-conversion-customeditor-registration]]
|
[[beans-beans-conversion-customeditor-registration]]
|
||||||
|
|
@ -390,8 +414,11 @@ support for additional `PropertyEditor` instances to an `ApplicationContext`.
|
||||||
Consider the following example, which defines a user class called `ExoticType` and
|
Consider the following example, which defines a user class called `ExoticType` and
|
||||||
another class called `DependsOnExoticType`, which needs `ExoticType` set as a property:
|
another class called `DependsOnExoticType`, which needs `ExoticType` set as a property:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
|
@ -413,8 +440,10 @@ another class called `DependsOnExoticType`, which needs `ExoticType` set as a pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package example
|
package example
|
||||||
|
|
||||||
|
|
@ -425,6 +454,7 @@ another class called `DependsOnExoticType`, which needs `ExoticType` set as a pr
|
||||||
var type: ExoticType? = null
|
var type: ExoticType? = null
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
When things are properly set up, we want to be able to assign the type property as a
|
When things are properly set up, we want to be able to assign the type property as a
|
||||||
string, which a `PropertyEditor` converts into an actual
|
string, which a `PropertyEditor` converts into an actual
|
||||||
|
|
@ -439,8 +469,11 @@ string, which a `PropertyEditor` converts into an actual
|
||||||
|
|
||||||
The `PropertyEditor` implementation could look similar to the following:
|
The `PropertyEditor` implementation could look similar to the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
|
@ -454,8 +487,10 @@ The `PropertyEditor` implementation could look similar to the following:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package example
|
package example
|
||||||
|
|
||||||
|
|
@ -469,6 +504,7 @@ The `PropertyEditor` implementation could look similar to the following:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Finally, the following example shows how to use `CustomEditorConfigurer` to register the new `PropertyEditor` with the
|
Finally, the following example shows how to use `CustomEditorConfigurer` to register the new `PropertyEditor` with the
|
||||||
`ApplicationContext`, which will then be able to use it as needed:
|
`ApplicationContext`, which will then be able to use it as needed:
|
||||||
|
|
@ -504,8 +540,11 @@ instances for each bean creation attempt.
|
||||||
|
|
||||||
The following example shows how to create your own `PropertyEditorRegistrar` implementation:
|
The following example shows how to create your own `PropertyEditorRegistrar` implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package com.foo.editors.spring;
|
package com.foo.editors.spring;
|
||||||
|
|
||||||
|
|
@ -520,8 +559,10 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package com.foo.editors.spring
|
package com.foo.editors.spring
|
||||||
|
|
||||||
|
|
@ -539,6 +580,7 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example
|
See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example
|
||||||
`PropertyEditorRegistrar` implementation. Notice how in its implementation of the
|
`PropertyEditorRegistrar` implementation. Notice how in its implementation of the
|
||||||
|
|
@ -566,8 +608,11 @@ using xref:web/webmvc.adoc#mvc[Spring's MVC web framework], using a `PropertyEdi
|
||||||
conjunction with data-binding web controllers can be very convenient. The following
|
conjunction with data-binding web controllers can be very convenient. The following
|
||||||
example uses a `PropertyEditorRegistrar` in the implementation of an `@InitBinder` method:
|
example uses a `PropertyEditorRegistrar` in the implementation of an `@InitBinder` method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Controller
|
@Controller
|
||||||
public class RegisterUserController {
|
public class RegisterUserController {
|
||||||
|
|
@ -586,8 +631,10 @@ example uses a `PropertyEditorRegistrar` in the implementation of an `@InitBinde
|
||||||
// other methods related to registering a User
|
// other methods related to registering a User
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Controller
|
@Controller
|
||||||
class RegisterUserController(
|
class RegisterUserController(
|
||||||
|
|
@ -601,6 +648,7 @@ example uses a `PropertyEditorRegistrar` in the implementation of an `@InitBinde
|
||||||
// other methods related to registering a User
|
// other methods related to registering a User
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This style of `PropertyEditor` registration can lead to concise code (the implementation
|
This style of `PropertyEditor` registration can lead to concise code (the implementation
|
||||||
of the `@InitBinder` method is only one line long) and lets common `PropertyEditor`
|
of the `@InitBinder` method is only one line long) and lets common `PropertyEditor`
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,36 @@ built-in constraints, and you can also define your own custom constraints.
|
||||||
|
|
||||||
Consider the following example, which shows a simple `PersonForm` model with two properties:
|
Consider the following example, which shows a simple `PersonForm` model with two properties:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class PersonForm {
|
public class PersonForm {
|
||||||
private String name;
|
private String name;
|
||||||
private int age;
|
private int age;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class PersonForm(
|
class PersonForm(
|
||||||
private val name: String,
|
private val name: String,
|
||||||
private val age: Int
|
private val age: Int
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Bean Validation lets you declare constraints as the following example shows:
|
Bean Validation lets you declare constraints as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class PersonForm {
|
public class PersonForm {
|
||||||
|
|
||||||
|
|
@ -48,8 +57,10 @@ Bean Validation lets you declare constraints as the following example shows:
|
||||||
private int age;
|
private int age;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class PersonForm(
|
class PersonForm(
|
||||||
@get:NotNull @get:Size(max=64)
|
@get:NotNull @get:Size(max=64)
|
||||||
|
|
@ -58,6 +69,7 @@ Bean Validation lets you declare constraints as the following example shows:
|
||||||
private val age: Int
|
private val age: Int
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
A Bean Validation validator then validates instances of this class based on the declared
|
A Bean Validation validator then validates instances of this class based on the declared
|
||||||
constraints. See https://beanvalidation.org/[Bean Validation] for general information about
|
constraints. See https://beanvalidation.org/[Bean Validation] for general information about
|
||||||
|
|
@ -78,8 +90,11 @@ is needed in your application.
|
||||||
You can use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring
|
You can use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring
|
||||||
bean, as the following example shows:
|
bean, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
|
|
@ -92,12 +107,15 @@ bean, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
XML::
|
||||||
|
+
|
||||||
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.XML
|
|
||||||
----
|
----
|
||||||
<bean id="validator"
|
<bean id="validator"
|
||||||
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The basic configuration in the preceding example triggers bean validation to initialize by
|
The basic configuration in the preceding example triggers bean validation to initialize by
|
||||||
using its default bootstrap mechanism. A Bean Validation provider, such as the Hibernate
|
using its default bootstrap mechanism. A Bean Validation provider, such as the Hibernate
|
||||||
|
|
@ -115,8 +133,11 @@ validation logic.
|
||||||
You can inject a reference to `jakarta.validation.Validator` if you prefer to work with the Bean
|
You can inject a reference to `jakarta.validation.Validator` if you prefer to work with the Bean
|
||||||
Validation API directly, as the following example shows:
|
Validation API directly, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
|
|
||||||
|
|
@ -127,20 +148,26 @@ Validation API directly, as the following example shows:
|
||||||
private Validator validator;
|
private Validator validator;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class MyService(@Autowired private val validator: Validator)
|
class MyService(@Autowired private val validator: Validator)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can inject a reference to `org.springframework.validation.Validator` if your bean
|
You can inject a reference to `org.springframework.validation.Validator` if your bean
|
||||||
requires the Spring Validation API, as the following example shows:
|
requires the Spring Validation API, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.springframework.validation.Validator;
|
import org.springframework.validation.Validator;
|
||||||
|
|
||||||
|
|
@ -151,14 +178,17 @@ requires the Spring Validation API, as the following example shows:
|
||||||
private Validator validator;
|
private Validator validator;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.validation.Validator
|
import org.springframework.validation.Validator
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class MyService(@Autowired private val validator: Validator)
|
class MyService(@Autowired private val validator: Validator)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[validation-beanvalidation-spring-constraints]]
|
[[validation-beanvalidation-spring-constraints]]
|
||||||
|
|
@ -182,8 +212,11 @@ that uses Spring to create `ConstraintValidator` instances. This lets your custo
|
||||||
The following example shows a custom `@Constraint` declaration followed by an associated
|
The following example shows a custom `@Constraint` declaration followed by an associated
|
||||||
`ConstraintValidator` implementation that uses Spring for dependency injection:
|
`ConstraintValidator` implementation that uses Spring for dependency injection:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -191,17 +224,23 @@ The following example shows a custom `@Constraint` declaration followed by an as
|
||||||
public @interface MyConstraint {
|
public @interface MyConstraint {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Constraint(validatedBy = MyConstraintValidator::class)
|
@Constraint(validatedBy = MyConstraintValidator::class)
|
||||||
annotation class MyConstraint
|
annotation class MyConstraint
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import jakarta.validation.ConstraintValidator;
|
import jakarta.validation.ConstraintValidator;
|
||||||
|
|
||||||
|
|
@ -213,8 +252,10 @@ The following example shows a custom `@Constraint` declaration followed by an as
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import jakarta.validation.ConstraintValidator
|
import jakarta.validation.ConstraintValidator
|
||||||
|
|
||||||
|
|
@ -223,6 +264,7 @@ The following example shows a custom `@Constraint` declaration followed by an as
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
As the preceding example shows, a `ConstraintValidator` implementation can have its dependencies
|
As the preceding example shows, a `ConstraintValidator` implementation can have its dependencies
|
||||||
|
|
@ -236,8 +278,11 @@ You can integrate the method validation feature supported by Bean Validation 1.1
|
||||||
a custom extension, also by Hibernate Validator 4.3) into a Spring context through a
|
a custom extension, also by Hibernate Validator 4.3) into a Spring context through a
|
||||||
`MethodValidationPostProcessor` bean definition:
|
`MethodValidationPostProcessor` bean definition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||||
|
|
||||||
|
|
@ -251,11 +296,14 @@ a custom extension, also by Hibernate Validator 4.3) into a Spring context throu
|
||||||
}
|
}
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
XML::
|
||||||
|
+
|
||||||
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.XML
|
|
||||||
----
|
----
|
||||||
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
|
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To be eligible for Spring-driven method validation, all target classes need to be annotated
|
To be eligible for Spring-driven method validation, all target classes need to be annotated
|
||||||
with Spring's `@Validated` annotation, which can optionally also declare the validation
|
with Spring's `@Validated` annotation, which can optionally also declare the validation
|
||||||
|
|
@ -296,8 +344,11 @@ automatically added to the binder's `BindingResult`.
|
||||||
The following example shows how to use a `DataBinder` programmatically to invoke validation
|
The following example shows how to use a `DataBinder` programmatically to invoke validation
|
||||||
logic after binding to a target object:
|
logic after binding to a target object:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Foo target = new Foo();
|
Foo target = new Foo();
|
||||||
DataBinder binder = new DataBinder(target);
|
DataBinder binder = new DataBinder(target);
|
||||||
|
|
@ -312,8 +363,10 @@ logic after binding to a target object:
|
||||||
// get BindingResult that includes any validation errors
|
// get BindingResult that includes any validation errors
|
||||||
BindingResult results = binder.getBindingResult();
|
BindingResult results = binder.getBindingResult();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val target = Foo()
|
val target = Foo()
|
||||||
val binder = DataBinder(target)
|
val binder = DataBinder(target)
|
||||||
|
|
@ -328,6 +381,7 @@ logic after binding to a target object:
|
||||||
// get BindingResult that includes any validation errors
|
// get BindingResult that includes any validation errors
|
||||||
val results = binder.bindingResult
|
val results = binder.bindingResult
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can also configure a `DataBinder` with multiple `Validator` instances through
|
You can also configure a `DataBinder` with multiple `Validator` instances through
|
||||||
`dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when
|
`dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when
|
||||||
|
|
|
||||||
|
|
@ -259,8 +259,11 @@ xref:core/validation/format.adoc#format-FormatterRegistry-SPI[The `FormatterRegi
|
||||||
To work with a `ConversionService` instance programmatically, you can inject a reference to
|
To work with a `ConversionService` instance programmatically, you can inject a reference to
|
||||||
it like you would for any other bean. The following example shows how to do so:
|
it like you would for any other bean. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
public class MyService {
|
public class MyService {
|
||||||
|
|
@ -274,8 +277,10 @@ it like you would for any other bean. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Service
|
@Service
|
||||||
class MyService(private val conversionService: ConversionService) {
|
class MyService(private val conversionService: ConversionService) {
|
||||||
|
|
@ -285,6 +290,7 @@ it like you would for any other bean. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For most use cases, you can use the `convert` method that specifies the `targetType`, but it
|
For most use cases, you can use the `convert` method that specifies the `targetType`, but it
|
||||||
does not work with more complex types, such as a collection of a parameterized element.
|
does not work with more complex types, such as a collection of a parameterized element.
|
||||||
|
|
@ -294,8 +300,11 @@ you need to provide a formal definition of the source and target types.
|
||||||
Fortunately, `TypeDescriptor` provides various options to make doing so straightforward,
|
Fortunately, `TypeDescriptor` provides various options to make doing so straightforward,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DefaultConversionService cs = new DefaultConversionService();
|
DefaultConversionService cs = new DefaultConversionService();
|
||||||
|
|
||||||
|
|
@ -304,8 +313,10 @@ as the following example shows:
|
||||||
TypeDescriptor.forObject(input), // List<Integer> type descriptor
|
TypeDescriptor.forObject(input), // List<Integer> type descriptor
|
||||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
|
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val cs = DefaultConversionService()
|
val cs = DefaultConversionService()
|
||||||
|
|
||||||
|
|
@ -314,6 +325,7 @@ as the following example shows:
|
||||||
TypeDescriptor.forObject(input), // List<Integer> type descriptor
|
TypeDescriptor.forObject(input), // List<Integer> type descriptor
|
||||||
TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(String::class.java)))
|
TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(String::class.java)))
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Note that `DefaultConversionService` automatically registers converters that are
|
Note that `DefaultConversionService` automatically registers converters that are
|
||||||
appropriate for most environments. This includes collection converters, scalar
|
appropriate for most environments. This includes collection converters, scalar
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ formatters manually with the help of:
|
||||||
|
|
||||||
For example, the following Java configuration registers a global `yyyyMMdd` format:
|
For example, the following Java configuration registers a global `yyyyMMdd` format:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
@ -44,8 +47,10 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
@ -71,6 +76,7 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you prefer XML-based configuration, you can use a
|
If you prefer XML-based configuration, you can use a
|
||||||
`FormattingConversionServiceFactoryBean`. The following example shows how to do so:
|
`FormattingConversionServiceFactoryBean`. The following example shows how to do so:
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,11 @@ a `java.text.DateFormat`.
|
||||||
|
|
||||||
The following `DateFormatter` is an example `Formatter` implementation:
|
The following `DateFormatter` is an example `Formatter` implementation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package org.springframework.format.datetime;
|
package org.springframework.format.datetime;
|
||||||
|
|
||||||
|
|
@ -112,8 +115,10 @@ The following `DateFormatter` is an example `Formatter` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DateFormatter(private val pattern: String) : Formatter<Date> {
|
class DateFormatter(private val pattern: String) : Formatter<Date> {
|
||||||
|
|
||||||
|
|
@ -131,6 +136,7 @@ The following `DateFormatter` is an example `Formatter` implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The Spring team welcomes community-driven `Formatter` contributions. See
|
The Spring team welcomes community-driven `Formatter` contributions. See
|
||||||
https://github.com/spring-projects/spring-framework/issues[GitHub Issues] to contribute.
|
https://github.com/spring-projects/spring-framework/issues[GitHub Issues] to contribute.
|
||||||
|
|
@ -169,8 +175,11 @@ formatting logic -- for example `org.springframework.format.annotation.DateTime
|
||||||
The following example `AnnotationFormatterFactory` implementation binds the `@NumberFormat`
|
The following example `AnnotationFormatterFactory` implementation binds the `@NumberFormat`
|
||||||
annotation to a formatter to let a number style or pattern be specified:
|
annotation to a formatter to let a number style or pattern be specified:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public final class NumberFormatAnnotationFormatterFactory
|
public final class NumberFormatAnnotationFormatterFactory
|
||||||
implements AnnotationFormatterFactory<NumberFormat> {
|
implements AnnotationFormatterFactory<NumberFormat> {
|
||||||
|
|
@ -204,8 +213,10 @@ annotation to a formatter to let a number style or pattern be specified:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class NumberFormatAnnotationFormatterFactory : AnnotationFormatterFactory<NumberFormat> {
|
class NumberFormatAnnotationFormatterFactory : AnnotationFormatterFactory<NumberFormat> {
|
||||||
|
|
||||||
|
|
@ -235,12 +246,16 @@ annotation to a formatter to let a number style or pattern be specified:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To trigger formatting, you can annotate fields with `@NumberFormat`, as the following
|
To trigger formatting, you can annotate fields with `@NumberFormat`, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MyModel {
|
public class MyModel {
|
||||||
|
|
||||||
|
|
@ -248,13 +263,16 @@ example shows:
|
||||||
private BigDecimal decimal;
|
private BigDecimal decimal;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MyModel(
|
class MyModel(
|
||||||
@field:NumberFormat(style = Style.CURRENCY) private val decimal: BigDecimal
|
@field:NumberFormat(style = Style.CURRENCY) private val decimal: BigDecimal
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[format-annotations-api]]
|
[[format-annotations-api]]
|
||||||
|
|
@ -268,8 +286,11 @@ package. You can use `@NumberFormat` to format `Number` fields such as `Double`
|
||||||
The following example uses `@DateTimeFormat` to format a `java.util.Date` as an ISO Date
|
The following example uses `@DateTimeFormat` to format a `java.util.Date` as an ISO Date
|
||||||
(yyyy-MM-dd):
|
(yyyy-MM-dd):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class MyModel {
|
public class MyModel {
|
||||||
|
|
||||||
|
|
@ -277,13 +298,16 @@ The following example uses `@DateTimeFormat` to format a `java.util.Date` as an
|
||||||
private Date date;
|
private Date date;
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class MyModel(
|
class MyModel(
|
||||||
@DateTimeFormat(iso=ISO.DATE) private val date: Date
|
@DateTimeFormat(iso=ISO.DATE) private val date: Date
|
||||||
)
|
)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[format-FormatterRegistry-SPI]]
|
[[format-FormatterRegistry-SPI]]
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@ validators can report validation failures to the `Errors` object.
|
||||||
|
|
||||||
Consider the following example of a small data object:
|
Consider the following example of a small data object:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Person {
|
public class Person {
|
||||||
|
|
||||||
|
|
@ -18,11 +21,14 @@ Consider the following example of a small data object:
|
||||||
// the usual getters and setters...
|
// the usual getters and setters...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Person(val name: String, val age: Int)
|
class Person(val name: String, val age: Int)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The next example provides validation behavior for the `Person` class by implementing the
|
The next example provides validation behavior for the `Person` class by implementing the
|
||||||
following two methods of the `org.springframework.validation.Validator` interface:
|
following two methods of the `org.springframework.validation.Validator` interface:
|
||||||
|
|
@ -35,8 +41,11 @@ Implementing a `Validator` is fairly straightforward, especially when you know o
|
||||||
`ValidationUtils` helper class that the Spring Framework also provides. The following
|
`ValidationUtils` helper class that the Spring Framework also provides. The following
|
||||||
example implements `Validator` for `Person` instances:
|
example implements `Validator` for `Person` instances:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class PersonValidator implements Validator {
|
public class PersonValidator implements Validator {
|
||||||
|
|
||||||
|
|
@ -58,8 +67,10 @@ example implements `Validator` for `Person` instances:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class PersonValidator : Validator {
|
class PersonValidator : Validator {
|
||||||
|
|
||||||
|
|
@ -81,6 +92,7 @@ example implements `Validator` for `Person` instances:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class is used to
|
The `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class is used to
|
||||||
reject the `name` property if it is `null` or the empty string. Have a look at the
|
reject the `name` property if it is `null` or the empty string. Have a look at the
|
||||||
|
|
@ -98,8 +110,11 @@ within the `AddressValidator` class without resorting to copy-and-paste, you can
|
||||||
dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`,
|
dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class CustomerValidator implements Validator {
|
public class CustomerValidator implements Validator {
|
||||||
|
|
||||||
|
|
@ -137,8 +152,10 @@ as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CustomerValidator(private val addressValidator: Validator) : Validator {
|
class CustomerValidator(private val addressValidator: Validator) : Validator {
|
||||||
|
|
||||||
|
|
@ -171,6 +188,7 @@ as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Validation errors are reported to the `Errors` object passed to the validator. In the case
|
Validation errors are reported to the `Errors` object passed to the validator. In the case
|
||||||
of Spring Web MVC, you can use the `<spring:bind/>` tag to inspect the error messages, but
|
of Spring Web MVC, you can use the `<spring:bind/>` tag to inspect the error messages, but
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,18 @@ lets the component scanning support find and configure your DAOs and repositorie
|
||||||
without having to provide XML configuration entries for them. The following example shows
|
without having to provide XML configuration entries for them. The following example shows
|
||||||
how to use the `@Repository` annotation:
|
how to use the `@Repository` annotation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository // <1>
|
@Repository // <1>
|
||||||
public class SomeMovieFinder implements MovieFinder {
|
public class SomeMovieFinder implements MovieFinder {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> The `@Repository` annotation.
|
<1> The `@Repository` annotation.
|
||||||
|
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
|
@ -80,8 +84,11 @@ needs access to a JDBC `DataSource`, and a JPA-based repository needs access to
|
||||||
injected by using one of the `@Autowired`, `@Inject`, `@Resource` or `@PersistenceContext`
|
injected by using one of the `@Autowired`, `@Inject`, `@Resource` or `@PersistenceContext`
|
||||||
annotations. The following example works for a JPA repository:
|
annotations. The following example works for a JPA repository:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class JpaMovieFinder implements MovieFinder {
|
public class JpaMovieFinder implements MovieFinder {
|
||||||
|
|
@ -93,8 +100,9 @@ annotations. The following example works for a JPA repository:
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class JpaMovieFinder : MovieFinder {
|
class JpaMovieFinder : MovieFinder {
|
||||||
|
|
@ -105,13 +113,17 @@ annotations. The following example works for a JPA repository:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
If you use the classic Hibernate APIs, you can inject `SessionFactory`, as the following
|
If you use the classic Hibernate APIs, you can inject `SessionFactory`, as the following
|
||||||
example shows:
|
example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class HibernateMovieFinder implements MovieFinder {
|
public class HibernateMovieFinder implements MovieFinder {
|
||||||
|
|
@ -126,22 +138,28 @@ example shows:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class HibernateMovieFinder(private val sessionFactory: SessionFactory) : MovieFinder {
|
class HibernateMovieFinder(private val sessionFactory: SessionFactory) : MovieFinder {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The last example we show here is for typical JDBC support. You could have the
|
The last example we show here is for typical JDBC support. You could have the
|
||||||
`DataSource` injected into an initialization method or a constructor, where you would create a
|
`DataSource` injected into an initialization method or a constructor, where you would create a
|
||||||
`JdbcTemplate` and other data access support classes (such as `SimpleJdbcCall` and others) by using
|
`JdbcTemplate` and other data access support classes (such as `SimpleJdbcCall` and others) by using
|
||||||
this `DataSource`. The following example autowires a `DataSource`:
|
this `DataSource`. The following example autowires a `DataSource`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class JdbcMovieFinder implements MovieFinder {
|
public class JdbcMovieFinder implements MovieFinder {
|
||||||
|
|
@ -156,8 +174,10 @@ this `DataSource`. The following example autowires a `DataSource`:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class JdbcMovieFinder(dataSource: DataSource) : MovieFinder {
|
class JdbcMovieFinder(dataSource: DataSource) : MovieFinder {
|
||||||
|
|
@ -167,6 +187,7 @@ this `DataSource`. The following example autowires a `DataSource`:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: See the specific coverage of each persistence technology for details on how to
|
NOTE: See the specific coverage of each persistence technology for details on how to
|
||||||
configure the application context to take advantage of these annotations.
|
configure the application context to take advantage of these annotations.
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,11 @@ the prepared statement. This method is called the number of times that you
|
||||||
specified in the `getBatchSize` call. The following example updates the `t_actor` table
|
specified in the `getBatchSize` call. The following example updates the `t_actor` table
|
||||||
based on entries in a list, and the entire list is used as the batch:
|
based on entries in a list, and the entire list is used as the batch:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -47,8 +50,10 @@ based on entries in a list, and the entire list is used as the batch:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -71,6 +76,7 @@ based on entries in a list, and the entire list is used as the batch:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you process a stream of updates or reading from a file, you might have a
|
If you process a stream of updates or reading from a file, you might have a
|
||||||
preferred batch size, but the last batch might not have that number of entries. In this
|
preferred batch size, but the last batch might not have that number of entries. In this
|
||||||
|
|
@ -94,8 +100,11 @@ in an array of bean-style objects (with getter methods corresponding to paramete
|
||||||
|
|
||||||
The following example shows a batch update using named parameters:
|
The following example shows a batch update using named parameters:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -114,8 +123,10 @@ The following example shows a batch update using named parameters:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -130,6 +141,7 @@ The following example shows a batch update using named parameters:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
For an SQL statement that uses the classic `?` placeholders, you pass in a list
|
For an SQL statement that uses the classic `?` placeholders, you pass in a list
|
||||||
containing an object array with the update values. This object array must have one entry
|
containing an object array with the update values. This object array must have one entry
|
||||||
|
|
@ -139,8 +151,11 @@ defined in the SQL statement.
|
||||||
The following example is the same as the preceding example, except that it uses classic
|
The following example is the same as the preceding example, except that it uses classic
|
||||||
JDBC `?` placeholders:
|
JDBC `?` placeholders:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -165,8 +180,10 @@ JDBC `?` placeholders:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -184,6 +201,7 @@ JDBC `?` placeholders:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
All of the batch update methods that we described earlier return an `int` array
|
All of the batch update methods that we described earlier return an `int` array
|
||||||
containing the number of affected rows for each batch entry. This count is reported by
|
containing the number of affected rows for each batch entry. This count is reported by
|
||||||
|
|
@ -223,8 +241,11 @@ update calls into batches of the size specified.
|
||||||
|
|
||||||
The following example shows a batch update that uses a batch size of 100:
|
The following example shows a batch update that uses a batch size of 100:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -250,8 +271,10 @@ The following example shows a batch update that uses a batch size of 100:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -270,6 +293,7 @@ The following example shows a batch update that uses a batch size of 100:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The batch update method for this call returns an array of `int` arrays that contains an
|
The batch update method for this call returns an array of `int` arrays that contains an
|
||||||
array entry for each batch with an array of the number of affected rows for each update.
|
array entry for each batch with an array of the number of affected rows for each update.
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,11 @@ To configure a `DriverManagerDataSource`:
|
||||||
|
|
||||||
The following example shows how to configure a `DriverManagerDataSource` in Java:
|
The following example shows how to configure a `DriverManagerDataSource` in Java:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||||
|
|
@ -57,8 +60,10 @@ The following example shows how to configure a `DriverManagerDataSource` in Java
|
||||||
dataSource.setUsername("sa");
|
dataSource.setUsername("sa");
|
||||||
dataSource.setPassword("");
|
dataSource.setPassword("");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val dataSource = DriverManagerDataSource().apply {
|
val dataSource = DriverManagerDataSource().apply {
|
||||||
setDriverClassName("org.hsqldb.jdbcDriver")
|
setDriverClassName("org.hsqldb.jdbcDriver")
|
||||||
|
|
@ -67,6 +72,7 @@ The following example shows how to configure a `DriverManagerDataSource` in Java
|
||||||
password = ""
|
password = ""
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows the corresponding XML configuration:
|
The following example shows the corresponding XML configuration:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,54 +57,75 @@ See the attendant {api-spring-framework}/jdbc/core/JdbcTemplate.html[javadoc] fo
|
||||||
|
|
||||||
The following query gets the number of rows in a relation:
|
The following query gets the number of rows in a relation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
|
int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val rowCount = jdbcTemplate.queryForObject<Int>("select count(*) from t_actor")!!
|
val rowCount = jdbcTemplate.queryForObject<Int>("select count(*) from t_actor")!!
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following query uses a bind variable:
|
The following query uses a bind variable:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
|
int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
|
||||||
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
|
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val countOfActorsNamedJoe = jdbcTemplate.queryForObject<Int>(
|
val countOfActorsNamedJoe = jdbcTemplate.queryForObject<Int>(
|
||||||
"select count(*) from t_actor where first_name = ?", arrayOf("Joe"))!!
|
"select count(*) from t_actor where first_name = ?", arrayOf("Joe"))!!
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
The following query looks for a `String`:
|
The following query looks for a `String`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
String lastName = this.jdbcTemplate.queryForObject(
|
String lastName = this.jdbcTemplate.queryForObject(
|
||||||
"select last_name from t_actor where id = ?",
|
"select last_name from t_actor where id = ?",
|
||||||
String.class, 1212L);
|
String.class, 1212L);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val lastName = this.jdbcTemplate.queryForObject<String>(
|
val lastName = this.jdbcTemplate.queryForObject<String>(
|
||||||
"select last_name from t_actor where id = ?",
|
"select last_name from t_actor where id = ?",
|
||||||
arrayOf(1212L))!!
|
arrayOf(1212L))!!
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following query finds and populates a single domain object:
|
The following query finds and populates a single domain object:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Actor actor = jdbcTemplate.queryForObject(
|
Actor actor = jdbcTemplate.queryForObject(
|
||||||
"select first_name, last_name from t_actor where id = ?",
|
"select first_name, last_name from t_actor where id = ?",
|
||||||
|
|
@ -116,8 +137,10 @@ The following query finds and populates a single domain object:
|
||||||
},
|
},
|
||||||
1212L);
|
1212L);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val actor = jdbcTemplate.queryForObject(
|
val actor = jdbcTemplate.queryForObject(
|
||||||
"select first_name, last_name from t_actor where id = ?",
|
"select first_name, last_name from t_actor where id = ?",
|
||||||
|
|
@ -125,11 +148,15 @@ The following query finds and populates a single domain object:
|
||||||
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following query finds and populates a list of domain objects:
|
The following query finds and populates a list of domain objects:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
List<Actor> actors = this.jdbcTemplate.query(
|
List<Actor> actors = this.jdbcTemplate.query(
|
||||||
"select first_name, last_name from t_actor",
|
"select first_name, last_name from t_actor",
|
||||||
|
|
@ -140,20 +167,26 @@ The following query finds and populates a list of domain objects:
|
||||||
return actor;
|
return actor;
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val actors = jdbcTemplate.query("select first_name, last_name from t_actor") { rs, _ ->
|
val actors = jdbcTemplate.query("select first_name, last_name from t_actor") { rs, _ ->
|
||||||
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If the last two snippets of code actually existed in the same application, it would make
|
If the last two snippets of code actually existed in the same application, it would make
|
||||||
sense to remove the duplication present in the two `RowMapper` lambda expressions and
|
sense to remove the duplication present in the two `RowMapper` lambda expressions and
|
||||||
extract them out into a single field that could then be referenced by DAO methods as needed.
|
extract them out into a single field that could then be referenced by DAO methods as needed.
|
||||||
For example, it may be better to write the preceding code snippet as follows:
|
For example, it may be better to write the preceding code snippet as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
|
private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
|
||||||
Actor actor = new Actor();
|
Actor actor = new Actor();
|
||||||
|
|
@ -166,8 +199,10 @@ For example, it may be better to write the preceding code snippet as follows:
|
||||||
return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);
|
return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val actorMapper = RowMapper<Actor> { rs: ResultSet, rowNum: Int ->
|
val actorMapper = RowMapper<Actor> { rs: ResultSet, rowNum: Int ->
|
||||||
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
Actor(rs.getString("first_name"), rs.getString("last_name"))
|
||||||
|
|
@ -177,6 +212,7 @@ For example, it may be better to write the preceding code snippet as follows:
|
||||||
return jdbcTemplate.query("select first_name, last_name from t_actor", actorMapper)
|
return jdbcTemplate.query("select first_name, last_name from t_actor", actorMapper)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[jdbc-JdbcTemplate-examples-update]]
|
[[jdbc-JdbcTemplate-examples-update]]
|
||||||
=== Updating (`INSERT`, `UPDATE`, and `DELETE`) with `JdbcTemplate`
|
=== Updating (`INSERT`, `UPDATE`, and `DELETE`) with `JdbcTemplate`
|
||||||
|
|
@ -186,52 +222,70 @@ Parameter values are usually provided as variable arguments or, alternatively, a
|
||||||
|
|
||||||
The following example inserts a new entry:
|
The following example inserts a new entry:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
this.jdbcTemplate.update(
|
this.jdbcTemplate.update(
|
||||||
"insert into t_actor (first_name, last_name) values (?, ?)",
|
"insert into t_actor (first_name, last_name) values (?, ?)",
|
||||||
"Leonor", "Watling");
|
"Leonor", "Watling");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
jdbcTemplate.update(
|
jdbcTemplate.update(
|
||||||
"insert into t_actor (first_name, last_name) values (?, ?)",
|
"insert into t_actor (first_name, last_name) values (?, ?)",
|
||||||
"Leonor", "Watling")
|
"Leonor", "Watling")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example updates an existing entry:
|
The following example updates an existing entry:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
this.jdbcTemplate.update(
|
this.jdbcTemplate.update(
|
||||||
"update t_actor set last_name = ? where id = ?",
|
"update t_actor set last_name = ? where id = ?",
|
||||||
"Banjo", 5276L);
|
"Banjo", 5276L);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
jdbcTemplate.update(
|
jdbcTemplate.update(
|
||||||
"update t_actor set last_name = ? where id = ?",
|
"update t_actor set last_name = ? where id = ?",
|
||||||
"Banjo", 5276L)
|
"Banjo", 5276L)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example deletes an entry:
|
The following example deletes an entry:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
this.jdbcTemplate.update(
|
this.jdbcTemplate.update(
|
||||||
"delete from t_actor where id = ?",
|
"delete from t_actor where id = ?",
|
||||||
Long.valueOf(actorId));
|
Long.valueOf(actorId));
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
jdbcTemplate.update("delete from t_actor where id = ?", actorId.toLong())
|
jdbcTemplate.update("delete from t_actor where id = ?", actorId.toLong())
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[jdbc-JdbcTemplate-examples-other]]
|
[[jdbc-JdbcTemplate-examples-other]]
|
||||||
=== Other `JdbcTemplate` Operations
|
=== Other `JdbcTemplate` Operations
|
||||||
|
|
@ -241,33 +295,45 @@ method is often used for DDL statements. It is heavily overloaded with variants
|
||||||
callback interfaces, binding variable arrays, and so on. The following example creates a
|
callback interfaces, binding variable arrays, and so on. The following example creates a
|
||||||
table:
|
table:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
|
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
jdbcTemplate.execute("create table mytable (id integer, name varchar(100))")
|
jdbcTemplate.execute("create table mytable (id integer, name varchar(100))")
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example invokes a stored procedure:
|
The following example invokes a stored procedure:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
this.jdbcTemplate.update(
|
this.jdbcTemplate.update(
|
||||||
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
|
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
|
||||||
Long.valueOf(unionId));
|
Long.valueOf(unionId));
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
jdbcTemplate.update(
|
jdbcTemplate.update(
|
||||||
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
|
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
|
||||||
unionId.toLong())
|
unionId.toLong())
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
More sophisticated stored procedure support is xref:data-access/jdbc/object.adoc#jdbc-StoredProcedure[covered later].
|
More sophisticated stored procedure support is xref:data-access/jdbc/object.adoc#jdbc-StoredProcedure[covered later].
|
||||||
|
|
@ -288,8 +354,11 @@ that shared `DataSource` bean into your DAO classes. The `JdbcTemplate` is creat
|
||||||
the setter for the `DataSource`. This leads to DAOs that resemble the following:
|
the setter for the `DataSource`. This leads to DAOs that resemble the following:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcCorporateEventDao implements CorporateEventDao {
|
public class JdbcCorporateEventDao implements CorporateEventDao {
|
||||||
|
|
||||||
|
|
@ -302,8 +371,10 @@ the setter for the `DataSource`. This leads to DAOs that resemble the following:
|
||||||
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao {
|
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao {
|
||||||
|
|
||||||
|
|
@ -312,6 +383,7 @@ the setter for the `DataSource`. This leads to DAOs that resemble the following:
|
||||||
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
The following example shows the corresponding XML configuration:
|
The following example shows the corresponding XML configuration:
|
||||||
|
|
@ -350,8 +422,11 @@ support for dependency injection. In this case, you can annotate the class with
|
||||||
method with `@Autowired`. The following example shows how to do so:
|
method with `@Autowired`. The following example shows how to do so:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository // <1>
|
@Repository // <1>
|
||||||
public class JdbcCorporateEventDao implements CorporateEventDao {
|
public class JdbcCorporateEventDao implements CorporateEventDao {
|
||||||
|
|
@ -366,6 +441,7 @@ method with `@Autowired`. The following example shows how to do so:
|
||||||
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> Annotate the class with `@Repository`.
|
<1> Annotate the class with `@Repository`.
|
||||||
<2> Annotate the `DataSource` setter method with `@Autowired`.
|
<2> Annotate the `DataSource` setter method with `@Autowired`.
|
||||||
<3> Create a new `JdbcTemplate` with the `DataSource`.
|
<3> Create a new `JdbcTemplate` with the `DataSource`.
|
||||||
|
|
@ -440,8 +516,11 @@ section describes only those areas of the `NamedParameterJdbcTemplate` class tha
|
||||||
from the `JdbcTemplate` itself -- namely, programming JDBC statements by using named
|
from the `JdbcTemplate` itself -- namely, programming JDBC statements by using named
|
||||||
parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
|
parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// some JDBC-backed DAO class...
|
// some JDBC-backed DAO class...
|
||||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||||
|
|
@ -460,8 +539,9 @@ parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
||||||
|
|
||||||
|
|
@ -471,6 +551,7 @@ parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
|
||||||
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Notice the use of the named parameter notation in the value assigned to the `sql`
|
Notice the use of the named parameter notation in the value assigned to the `sql`
|
||||||
variable and the corresponding value that is plugged into the `namedParameters`
|
variable and the corresponding value that is plugged into the `namedParameters`
|
||||||
|
|
@ -483,8 +564,11 @@ methods exposed by the `NamedParameterJdbcOperations` and implemented by the
|
||||||
|
|
||||||
The following example shows the use of the `Map`-based style:
|
The following example shows the use of the `Map`-based style:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// some JDBC-backed DAO class...
|
// some JDBC-backed DAO class...
|
||||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||||
|
|
@ -502,8 +586,10 @@ The following example shows the use of the `Map`-based style:
|
||||||
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
|
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// some JDBC-backed DAO class...
|
// some JDBC-backed DAO class...
|
||||||
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
||||||
|
|
@ -514,6 +600,7 @@ The following example shows the use of the `Map`-based style:
|
||||||
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
One nice feature related to the `NamedParameterJdbcTemplate` (and existing in the same
|
One nice feature related to the `NamedParameterJdbcTemplate` (and existing in the same
|
||||||
Java package) is the `SqlParameterSource` interface. You have already seen an example of
|
Java package) is the `SqlParameterSource` interface. You have already seen an example of
|
||||||
|
|
@ -531,8 +618,11 @@ of named parameter values.
|
||||||
|
|
||||||
The following example shows a typical JavaBean:
|
The following example shows a typical JavaBean:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Actor {
|
public class Actor {
|
||||||
|
|
||||||
|
|
@ -556,17 +646,23 @@ The following example shows a typical JavaBean:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
data class Actor(val id: Long, val firstName: String, val lastName: String)
|
data class Actor(val id: Long, val firstName: String, val lastName: String)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example uses a `NamedParameterJdbcTemplate` to return the count of the
|
The following example uses a `NamedParameterJdbcTemplate` to return the count of the
|
||||||
members of the class shown in the preceding example:
|
members of the class shown in the preceding example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// some JDBC-backed DAO class...
|
// some JDBC-backed DAO class...
|
||||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||||
|
|
@ -585,8 +681,10 @@ members of the class shown in the preceding example:
|
||||||
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
|
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// some JDBC-backed DAO class...
|
// some JDBC-backed DAO class...
|
||||||
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
|
||||||
|
|
@ -600,6 +698,7 @@ members of the class shown in the preceding example:
|
||||||
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Remember that the `NamedParameterJdbcTemplate` class wraps a classic `JdbcTemplate`
|
Remember that the `NamedParameterJdbcTemplate` class wraps a classic `JdbcTemplate`
|
||||||
template. If you need access to the wrapped `JdbcTemplate` instance to access
|
template. If you need access to the wrapped `JdbcTemplate` instance to access
|
||||||
|
|
@ -651,8 +750,11 @@ name from the database metadata of the database in use.
|
||||||
|
|
||||||
You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example shows:
|
You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
|
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
|
||||||
|
|
||||||
|
|
@ -664,8 +766,10 @@ You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example sh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class CustomSQLErrorCodesTranslator : SQLErrorCodeSQLExceptionTranslator() {
|
class CustomSQLErrorCodesTranslator : SQLErrorCodeSQLExceptionTranslator() {
|
||||||
|
|
||||||
|
|
@ -677,6 +781,7 @@ You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example sh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example, the specific error code (`-12345`) is translated, while other errors are
|
In the preceding example, the specific error code (`-12345`) is translated, while other errors are
|
||||||
left to be translated by the default translator implementation. To use this custom
|
left to be translated by the default translator implementation. To use this custom
|
||||||
|
|
@ -685,8 +790,11 @@ translator, you must pass it to the `JdbcTemplate` through the method
|
||||||
processing where this translator is needed. The following example shows how you can use this custom
|
processing where this translator is needed. The following example shows how you can use this custom
|
||||||
translator:
|
translator:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
|
@ -710,8 +818,10 @@ translator:
|
||||||
" where id = ?", pct, orderId);
|
" where id = ?", pct, orderId);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// create a JdbcTemplate and set data source
|
// create a JdbcTemplate and set data source
|
||||||
private val jdbcTemplate = JdbcTemplate(dataSource).apply {
|
private val jdbcTemplate = JdbcTemplate(dataSource).apply {
|
||||||
|
|
@ -728,6 +838,7 @@ translator:
|
||||||
" where id = ?", pct, orderId)
|
" where id = ?", pct, orderId)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The custom translator is passed a data source in order to look up the error codes in
|
The custom translator is passed a data source in order to look up the error codes in
|
||||||
`sql-error-codes.xml`.
|
`sql-error-codes.xml`.
|
||||||
|
|
@ -741,8 +852,11 @@ Running an SQL statement requires very little code. You need a `DataSource` and
|
||||||
`JdbcTemplate`. The following example shows what you need to include for a minimal but
|
`JdbcTemplate`. The following example shows what you need to include for a minimal but
|
||||||
fully functional class that creates a new table:
|
fully functional class that creates a new table:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
@ -760,8 +874,10 @@ fully functional class that creates a new table:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
import org.springframework.jdbc.core.JdbcTemplate
|
import org.springframework.jdbc.core.JdbcTemplate
|
||||||
|
|
@ -775,6 +891,7 @@ fully functional class that creates a new table:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-statements-querying]]
|
[[jdbc-statements-querying]]
|
||||||
|
|
@ -786,8 +903,11 @@ Java class that is passed in as an argument. If the type conversion is invalid,
|
||||||
`InvalidDataAccessApiUsageException` is thrown. The following example contains two
|
`InvalidDataAccessApiUsageException` is thrown. The following example contains two
|
||||||
query methods, one for an `int` and one that queries for a `String`:
|
query methods, one for an `int` and one that queries for a `String`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
@ -809,8 +929,10 @@ query methods, one for an `int` and one that queries for a `String`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
import org.springframework.jdbc.core.JdbcTemplate
|
import org.springframework.jdbc.core.JdbcTemplate
|
||||||
|
|
@ -826,6 +948,7 @@ class RunAQuery(dataSource: DataSource) {
|
||||||
get() = jdbcTemplate.queryForObject("select name from mytable")
|
get() = jdbcTemplate.queryForObject("select name from mytable")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In addition to the single result query methods, several methods return a list with an
|
In addition to the single result query methods, several methods return a list with an
|
||||||
entry for each row that the query returned. The most generic method is `queryForList(..)`,
|
entry for each row that the query returned. The most generic method is `queryForList(..)`,
|
||||||
|
|
@ -833,8 +956,11 @@ which returns a `List` where each element is a `Map` containing one entry for ea
|
||||||
using the column name as the key. If you add a method to the preceding example to retrieve a
|
using the column name as the key. If you add a method to the preceding example to retrieve a
|
||||||
list of all the rows, it might be as follows:
|
list of all the rows, it might be as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
|
@ -846,8 +972,10 @@ list of all the rows, it might be as follows:
|
||||||
return this.jdbcTemplate.queryForList("select * from mytable");
|
return this.jdbcTemplate.queryForList("select * from mytable");
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
private val jdbcTemplate = JdbcTemplate(dataSource)
|
private val jdbcTemplate = JdbcTemplate(dataSource)
|
||||||
|
|
||||||
|
|
@ -855,6 +983,7 @@ list of all the rows, it might be as follows:
|
||||||
return jdbcTemplate.queryForList("select * from mytable")
|
return jdbcTemplate.queryForList("select * from mytable")
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The returned list would resemble the following:
|
The returned list would resemble the following:
|
||||||
|
|
||||||
|
|
@ -869,8 +998,11 @@ The returned list would resemble the following:
|
||||||
|
|
||||||
The following example updates a column for a certain primary key:
|
The following example updates a column for a certain primary key:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
@ -888,8 +1020,10 @@ The following example updates a column for a certain primary key:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
import org.springframework.jdbc.core.JdbcTemplate
|
import org.springframework.jdbc.core.JdbcTemplate
|
||||||
|
|
@ -903,6 +1037,7 @@ The following example updates a column for a certain primary key:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example,
|
In the preceding example,
|
||||||
an SQL statement has placeholders for row parameters. You can pass the parameter values
|
an SQL statement has placeholders for row parameters. You can pass the parameter values
|
||||||
|
|
@ -922,8 +1057,11 @@ update. There is no standard single way to create an appropriate `PreparedStatem
|
||||||
(which explains why the method signature is the way it is). The following example works
|
(which explains why the method signature is the way it is). The following example works
|
||||||
on Oracle but may not work on other platforms:
|
on Oracle but may not work on other platforms:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
final String INSERT_SQL = "insert into my_test (name) values(?)";
|
final String INSERT_SQL = "insert into my_test (name) values(?)";
|
||||||
final String name = "Rob";
|
final String name = "Rob";
|
||||||
|
|
@ -937,8 +1075,10 @@ on Oracle but may not work on other platforms:
|
||||||
|
|
||||||
// keyHolder.getKey() now contains the generated key
|
// keyHolder.getKey() now contains the generated key
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val INSERT_SQL = "insert into my_test (name) values(?)"
|
val INSERT_SQL = "insert into my_test (name) values(?)"
|
||||||
val name = "Rob"
|
val name = "Rob"
|
||||||
|
|
@ -950,6 +1090,7 @@ on Oracle but may not work on other platforms:
|
||||||
|
|
||||||
// keyHolder.getKey() now contains the generated key
|
// keyHolder.getKey() now contains the generated key
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,11 @@ The `EmbeddedDatabaseBuilder` class provides a fluent API for constructing an em
|
||||||
database programmatically. You can use this when you need to create an embedded database in a
|
database programmatically. You can use this when you need to create an embedded database in a
|
||||||
stand-alone environment or in a stand-alone integration test, as in the following example:
|
stand-alone environment or in a stand-alone integration test, as in the following example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
|
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
|
||||||
.generateUniqueName(true)
|
.generateUniqueName(true)
|
||||||
|
|
@ -60,8 +63,10 @@ stand-alone environment or in a stand-alone integration test, as in the followin
|
||||||
|
|
||||||
db.shutdown()
|
db.shutdown()
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val db = EmbeddedDatabaseBuilder()
|
val db = EmbeddedDatabaseBuilder()
|
||||||
.generateUniqueName(true)
|
.generateUniqueName(true)
|
||||||
|
|
@ -76,6 +81,7 @@ stand-alone environment or in a stand-alone integration test, as in the followin
|
||||||
|
|
||||||
db.shutdown()
|
db.shutdown()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
See the {api-spring-framework}/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.html[javadoc for `EmbeddedDatabaseBuilder`]
|
See the {api-spring-framework}/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.html[javadoc for `EmbeddedDatabaseBuilder`]
|
||||||
for further details on all supported options.
|
for further details on all supported options.
|
||||||
|
|
@ -83,8 +89,11 @@ for further details on all supported options.
|
||||||
You can also use the `EmbeddedDatabaseBuilder` to create an embedded database by using Java
|
You can also use the `EmbeddedDatabaseBuilder` to create an embedded database by using Java
|
||||||
configuration, as the following example shows:
|
configuration, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
public class DataSourceConfig {
|
public class DataSourceConfig {
|
||||||
|
|
@ -102,8 +111,10 @@ configuration, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
class DataSourceConfig {
|
class DataSourceConfig {
|
||||||
|
|
@ -121,6 +132,7 @@ configuration, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-types]]
|
[[jdbc-embedded-database-types]]
|
||||||
|
|
@ -168,8 +180,11 @@ configuring the embedded database as a bean in the Spring `ApplicationContext` a
|
||||||
in xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-xml[Creating an Embedded Database by Using Spring XML] and xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-java[Creating an Embedded Database Programmatically]. The following listing
|
in xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-xml[Creating an Embedded Database by Using Spring XML] and xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-java[Creating an Embedded Database Programmatically]. The following listing
|
||||||
shows the test template:
|
shows the test template:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class DataAccessIntegrationTestTemplate {
|
public class DataAccessIntegrationTestTemplate {
|
||||||
|
|
||||||
|
|
@ -198,8 +213,10 @@ shows the test template:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class DataAccessIntegrationTestTemplate {
|
class DataAccessIntegrationTestTemplate {
|
||||||
|
|
||||||
|
|
@ -227,6 +244,7 @@ shows the test template:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-unique-names]]
|
[[jdbc-embedded-database-unique-names]]
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,11 @@ abstract `mapRow(..)` method to convert each row of the supplied `ResultSet` int
|
||||||
object of the type specified. The following example shows a custom query that maps the
|
object of the type specified. The following example shows a custom query that maps the
|
||||||
data from the `t_actor` relation to an instance of the `Actor` class:
|
data from the `t_actor` relation to an instance of the `Actor` class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ActorMappingQuery extends MappingSqlQuery<Actor> {
|
public class ActorMappingQuery extends MappingSqlQuery<Actor> {
|
||||||
|
|
||||||
|
|
@ -61,8 +64,10 @@ data from the `t_actor` relation to an instance of the `Actor` class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ActorMappingQuery(ds: DataSource) : MappingSqlQuery<Actor>(ds, "select id, first_name, last_name from t_actor where id = ?") {
|
class ActorMappingQuery(ds: DataSource) : MappingSqlQuery<Actor>(ds, "select id, first_name, last_name from t_actor where id = ?") {
|
||||||
|
|
||||||
|
|
@ -79,6 +84,7 @@ data from the `t_actor` relation to an instance of the `Actor` class:
|
||||||
}
|
}
|
||||||
|
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The class extends `MappingSqlQuery` parameterized with the `Actor` type. The constructor
|
The class extends `MappingSqlQuery` parameterized with the `Actor` type. The constructor
|
||||||
for this customer query takes a `DataSource` as the only parameter. In this
|
for this customer query takes a `DataSource` as the only parameter. In this
|
||||||
|
|
@ -93,8 +99,11 @@ thread-safe after it is compiled, so, as long as these instances are created whe
|
||||||
is initialized, they can be kept as instance variables and be reused. The following
|
is initialized, they can be kept as instance variables and be reused. The following
|
||||||
example shows how to define such a class:
|
example shows how to define such a class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
private ActorMappingQuery actorMappingQuery;
|
private ActorMappingQuery actorMappingQuery;
|
||||||
|
|
||||||
|
|
@ -107,13 +116,16 @@ example shows how to define such a class:
|
||||||
return actorMappingQuery.findObject(id);
|
return actorMappingQuery.findObject(id);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
private val actorMappingQuery = ActorMappingQuery(dataSource)
|
private val actorMappingQuery = ActorMappingQuery(dataSource)
|
||||||
|
|
||||||
fun getCustomer(id: Long) = actorMappingQuery.findObject(id)
|
fun getCustomer(id: Long) = actorMappingQuery.findObject(id)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The method in the preceding example retrieves the customer with the `id` that is passed in as the
|
The method in the preceding example retrieves the customer with the `id` that is passed in as the
|
||||||
only parameter. Since we want only one object to be returned, we call the `findObject` convenience
|
only parameter. Since we want only one object to be returned, we call the `findObject` convenience
|
||||||
|
|
@ -122,19 +134,25 @@ list of objects and took additional parameters, we would use one of the `execute
|
||||||
methods that takes an array of parameter values passed in as varargs. The following
|
methods that takes an array of parameter values passed in as varargs. The following
|
||||||
example shows such a method:
|
example shows such a method:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public List<Actor> searchForActors(int age, String namePattern) {
|
public List<Actor> searchForActors(int age, String namePattern) {
|
||||||
return actorSearchMappingQuery.execute(age, namePattern);
|
return actorSearchMappingQuery.execute(age, namePattern);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun searchForActors(age: Int, namePattern: String) =
|
fun searchForActors(age: Int, namePattern: String) =
|
||||||
actorSearchMappingQuery.execute(age, namePattern)
|
actorSearchMappingQuery.execute(age, namePattern)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-SqlUpdate]]
|
[[jdbc-SqlUpdate]]
|
||||||
|
|
@ -149,8 +167,11 @@ However, you do not have to subclass the `SqlUpdate`
|
||||||
class, since it can easily be parameterized by setting SQL and declaring parameters.
|
class, since it can easily be parameterized by setting SQL and declaring parameters.
|
||||||
The following example creates a custom update method named `execute`:
|
The following example creates a custom update method named `execute`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
@ -177,8 +198,10 @@ The following example creates a custom update method named `execute`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.sql.Types
|
import java.sql.Types
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
|
|
@ -205,6 +228,7 @@ The following example creates a custom update method named `execute`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-StoredProcedure]]
|
[[jdbc-StoredProcedure]]
|
||||||
|
|
@ -219,18 +243,24 @@ To define a parameter for the `StoredProcedure` class, you can use an `SqlParame
|
||||||
of its subclasses. You must specify the parameter name and SQL type in the constructor,
|
of its subclasses. You must specify the parameter name and SQL type in the constructor,
|
||||||
as the following code snippet shows:
|
as the following code snippet shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
new SqlParameter("in_id", Types.NUMERIC),
|
new SqlParameter("in_id", Types.NUMERIC),
|
||||||
new SqlOutParameter("out_first_name", Types.VARCHAR),
|
new SqlOutParameter("out_first_name", Types.VARCHAR),
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
SqlParameter("in_id", Types.NUMERIC),
|
SqlParameter("in_id", Types.NUMERIC),
|
||||||
SqlOutParameter("out_first_name", Types.VARCHAR),
|
SqlOutParameter("out_first_name", Types.VARCHAR),
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The SQL type is specified using the `java.sql.Types` constants.
|
The SQL type is specified using the `java.sql.Types` constants.
|
||||||
|
|
||||||
|
|
@ -259,8 +289,11 @@ returned date from the results `Map`. The results `Map` has an entry for each de
|
||||||
output parameter (in this case, only one) by using the parameter name as the key.
|
output parameter (in this case, only one) by using the parameter name as the key.
|
||||||
The following listing shows our custom StoredProcedure class:
|
The following listing shows our custom StoredProcedure class:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -306,8 +339,10 @@ The following listing shows our custom StoredProcedure class:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.sql.Types
|
import java.sql.Types
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
@ -343,12 +378,16 @@ The following listing shows our custom StoredProcedure class:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example of a `StoredProcedure` has two output parameters (in this case,
|
The following example of a `StoredProcedure` has two output parameters (in this case,
|
||||||
Oracle REF cursors):
|
Oracle REF cursors):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -374,8 +413,10 @@ Oracle REF cursors):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
|
|
@ -401,6 +442,7 @@ Oracle REF cursors):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Notice how the overloaded variants of the `declareParameter(..)` method that have been
|
Notice how the overloaded variants of the `declareParameter(..)` method that have been
|
||||||
used in the `TitlesAndGenresStoredProcedure` constructor are passed `RowMapper`
|
used in the `TitlesAndGenresStoredProcedure` constructor are passed `RowMapper`
|
||||||
|
|
@ -410,8 +452,11 @@ functionality. The next two examples provide code for the two `RowMapper` implem
|
||||||
The `TitleMapper` class maps a `ResultSet` to a `Title` domain object for each row in
|
The `TitleMapper` class maps a `ResultSet` to a `Title` domain object for each row in
|
||||||
the supplied `ResultSet`, as follows:
|
the supplied `ResultSet`, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
@ -428,8 +473,10 @@ the supplied `ResultSet`, as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.sql.ResultSet
|
import java.sql.ResultSet
|
||||||
import com.foo.domain.Title
|
import com.foo.domain.Title
|
||||||
|
|
@ -441,12 +488,16 @@ the supplied `ResultSet`, as follows:
|
||||||
Title(rs.getLong("id"), rs.getString("name"))
|
Title(rs.getLong("id"), rs.getString("name"))
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `GenreMapper` class maps a `ResultSet` to a `Genre` domain object for each row in
|
The `GenreMapper` class maps a `ResultSet` to a `Genre` domain object for each row in
|
||||||
the supplied `ResultSet`, as follows:
|
the supplied `ResultSet`, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
@ -460,8 +511,10 @@ the supplied `ResultSet`, as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.sql.ResultSet
|
import java.sql.ResultSet
|
||||||
import com.foo.domain.Genre
|
import com.foo.domain.Genre
|
||||||
|
|
@ -474,13 +527,17 @@ the supplied `ResultSet`, as follows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
To pass parameters to a stored procedure that has one or more input parameters in its
|
To pass parameters to a stored procedure that has one or more input parameters in its
|
||||||
definition in the RDBMS, you can code a strongly typed `execute(..)` method that would
|
definition in the RDBMS, you can code a strongly typed `execute(..)` method that would
|
||||||
delegate to the untyped `execute(Map)` method in the superclass, as the following example shows:
|
delegate to the untyped `execute(Map)` method in the superclass, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -511,8 +568,10 @@ delegate to the untyped `execute(Map)` method in the superclass, as the followin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import java.sql.Types
|
import java.sql.Types
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
@ -539,6 +598,7 @@ delegate to the untyped `execute(Map)` method in the superclass, as the followin
|
||||||
mapOf<String, Any>(CUTOFF_DATE_PARAM to cutoffDate))
|
mapOf<String, Any>(CUTOFF_DATE_PARAM to cutoffDate))
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,11 @@ dependency injection.
|
||||||
|
|
||||||
The following example shows how to create and insert a BLOB:
|
The following example shows how to create and insert a BLOB:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
final File blobIn = new File("spring2004.jpg");
|
final File blobIn = new File("spring2004.jpg");
|
||||||
final InputStream blobIs = new FileInputStream(blobIn);
|
final InputStream blobIs = new FileInputStream(blobIn);
|
||||||
|
|
@ -86,6 +89,7 @@ The following example shows how to create and insert a BLOB:
|
||||||
blobIs.close();
|
blobIs.close();
|
||||||
clobReader.close();
|
clobReader.close();
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`.
|
<1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`.
|
||||||
<2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB.
|
<2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB.
|
||||||
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
|
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
|
||||||
|
|
@ -134,8 +138,11 @@ Now it is time to read the LOB data from the database. Again, you use a `JdbcTem
|
||||||
with the same instance variable `lobHandler` and a reference to a `DefaultLobHandler`.
|
with the same instance variable `lobHandler` and a reference to a `DefaultLobHandler`.
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",
|
List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",
|
||||||
new RowMapper<Map<String, Object>>() {
|
new RowMapper<Map<String, Object>>() {
|
||||||
|
|
@ -149,6 +156,7 @@ The following example shows how to do so:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
|
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
|
||||||
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
|
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
|
||||||
|
|
||||||
|
|
@ -203,8 +211,11 @@ implemented. This interface is used as part of the declaration of an `SqlOutPara
|
||||||
The following example shows returning the value of an Oracle `STRUCT` object of the user
|
The following example shows returning the value of an Oracle `STRUCT` object of the user
|
||||||
declared type `ITEM_TYPE`:
|
declared type `ITEM_TYPE`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class TestItemStoredProcedure extends StoredProcedure {
|
public class TestItemStoredProcedure extends StoredProcedure {
|
||||||
|
|
||||||
|
|
@ -223,8 +234,10 @@ declared type `ITEM_TYPE`:
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
|
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
|
||||||
|
|
||||||
|
|
@ -239,6 +252,7 @@ declared type `ITEM_TYPE`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can use `SqlTypeValue` to pass the value of a Java object (such as `TestItem`) to a
|
You can use `SqlTypeValue` to pass the value of a Java object (such as `TestItem`) to a
|
||||||
stored procedure. The `SqlTypeValue` interface has a single method (named
|
stored procedure. The `SqlTypeValue` interface has a single method (named
|
||||||
|
|
@ -246,8 +260,11 @@ stored procedure. The `SqlTypeValue` interface has a single method (named
|
||||||
can use it to create database-specific objects, such as `StructDescriptor` instances
|
can use it to create database-specific objects, such as `StructDescriptor` instances
|
||||||
or `ArrayDescriptor` instances. The following example creates a `StructDescriptor` instance:
|
or `ArrayDescriptor` instances. The following example creates a `StructDescriptor` instance:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
final TestItem testItem = new TestItem(123L, "A test item",
|
final TestItem testItem = new TestItem(123L, "A test item",
|
||||||
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
|
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
|
||||||
|
|
@ -265,8 +282,10 @@ or `ArrayDescriptor` instances. The following example creates a `StructDescripto
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val (id, description, expirationDate) = TestItem(123L, "A test item",
|
val (id, description, expirationDate) = TestItem(123L, "A test item",
|
||||||
SimpleDateFormat("yyyy-M-d").parse("2010-12-31"))
|
SimpleDateFormat("yyyy-M-d").parse("2010-12-31"))
|
||||||
|
|
@ -279,6 +298,7 @@ or `ArrayDescriptor` instances. The following example creates a `StructDescripto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You can now add this `SqlTypeValue` to the `Map` that contains the input parameters for the
|
You can now add this `SqlTypeValue` to the `Map` that contains the input parameters for the
|
||||||
`execute` call of the stored procedure.
|
`execute` call of the stored procedure.
|
||||||
|
|
@ -288,8 +308,11 @@ procedure. Oracle has its own internal `ARRAY` class that must be used in this c
|
||||||
you can use the `SqlTypeValue` to create an instance of the Oracle `ARRAY` and populate
|
you can use the `SqlTypeValue` to create an instance of the Oracle `ARRAY` and populate
|
||||||
it with values from the Java `ARRAY`, as the following example shows:
|
it with values from the Java `ARRAY`, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
final Long[] ids = new Long[] {1L, 2L};
|
final Long[] ids = new Long[] {1L, 2L};
|
||||||
|
|
||||||
|
|
@ -301,8 +324,10 @@ it with values from the Java `ARRAY`, as the following example shows:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
|
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
|
||||||
|
|
||||||
|
|
@ -317,6 +342,7 @@ it with values from the Java `ARRAY`, as the following example shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,11 @@ Configuration methods for this class follow the `fluid` style that returns the i
|
||||||
of the `SimpleJdbcInsert`, which lets you chain all configuration methods. The following
|
of the `SimpleJdbcInsert`, which lets you chain all configuration methods. The following
|
||||||
example uses only one configuration method (we show examples of multiple methods later):
|
example uses only one configuration method (we show examples of multiple methods later):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -41,8 +44,10 @@ example uses only one configuration method (we show examples of multiple methods
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -59,6 +64,7 @@ example uses only one configuration method (we show examples of multiple methods
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `execute` method used here takes a plain `java.util.Map` as its only parameter. The
|
The `execute` method used here takes a plain `java.util.Map` as its only parameter. The
|
||||||
important thing to note here is that the keys used for the `Map` must match the column
|
important thing to note here is that the keys used for the `Map` must match the column
|
||||||
|
|
@ -75,8 +81,11 @@ the `SimpleJdbcInsert`, in addition to specifying the table name, it specifies t
|
||||||
of the generated key column with the `usingGeneratedKeyColumns` method. The following
|
of the generated key column with the `usingGeneratedKeyColumns` method. The following
|
||||||
listing shows how it works:
|
listing shows how it works:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -99,8 +108,10 @@ listing shows how it works:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -118,6 +129,7 @@ listing shows how it works:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The main difference when you run the insert by using this second approach is that you do not
|
The main difference when you run the insert by using this second approach is that you do not
|
||||||
add the `id` to the `Map`, and you call the `executeAndReturnKey` method. This returns a
|
add the `id` to the `Map`, and you call the `executeAndReturnKey` method. This returns a
|
||||||
|
|
@ -134,8 +146,11 @@ use a `KeyHolder` that is returned from the `executeAndReturnKeyHolder` method.
|
||||||
You can limit the columns for an insert by specifying a list of column names with the
|
You can limit the columns for an insert by specifying a list of column names with the
|
||||||
`usingColumns` method, as the following example shows:
|
`usingColumns` method, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -159,8 +174,10 @@ You can limit the columns for an insert by specifying a list of column names wit
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -180,6 +197,7 @@ You can limit the columns for an insert by specifying a list of column names wit
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The execution of the insert is the same as if you had relied on the metadata to determine
|
The execution of the insert is the same as if you had relied on the metadata to determine
|
||||||
which columns to use.
|
which columns to use.
|
||||||
|
|
@ -195,8 +213,11 @@ which is a very convenient class if you have a JavaBean-compliant class that con
|
||||||
your values. It uses the corresponding getter method to extract the parameter
|
your values. It uses the corresponding getter method to extract the parameter
|
||||||
values. The following example shows how to use `BeanPropertySqlParameterSource`:
|
values. The following example shows how to use `BeanPropertySqlParameterSource`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -217,8 +238,10 @@ values. The following example shows how to use `BeanPropertySqlParameterSource`:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -235,12 +258,16 @@ values. The following example shows how to use `BeanPropertySqlParameterSource`:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Another option is the `MapSqlParameterSource` that resembles a `Map` but provides a more
|
Another option is the `MapSqlParameterSource` that resembles a `Map` but provides a more
|
||||||
convenient `addValue` method that can be chained. The following example shows how to use it:
|
convenient `addValue` method that can be chained. The following example shows how to use it:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -263,8 +290,10 @@ convenient `addValue` method that can be chained. The following example shows ho
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -283,6 +312,7 @@ convenient `addValue` method that can be chained. The following example shows ho
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
As you can see, the configuration is the same. Only the executing code has to change to
|
As you can see, the configuration is the same. Only the executing code has to change to
|
||||||
use these alternative input classes.
|
use these alternative input classes.
|
||||||
|
|
@ -325,8 +355,11 @@ The following example of a `SimpleJdbcCall` configuration uses the preceding sto
|
||||||
procedure (the only configuration option, in addition to the `DataSource`, is the name
|
procedure (the only configuration option, in addition to the `DataSource`, is the name
|
||||||
of the stored procedure):
|
of the stored procedure):
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -352,8 +385,10 @@ of the stored procedure):
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -374,6 +409,7 @@ of the stored procedure):
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The code you write for the execution of the call involves creating an `SqlParameterSource`
|
The code you write for the execution of the call involves creating an `SqlParameterSource`
|
||||||
containing the IN parameter. You must match the name provided for the input value
|
containing the IN parameter. You must match the name provided for the input value
|
||||||
|
|
@ -397,8 +433,11 @@ To do the latter, you can create your own `JdbcTemplate` and set the `setResults
|
||||||
property to `true`. Then you can pass this customized `JdbcTemplate` instance into
|
property to `true`. Then you can pass this customized `JdbcTemplate` instance into
|
||||||
the constructor of your `SimpleJdbcCall`. The following example shows this configuration:
|
the constructor of your `SimpleJdbcCall`. The following example shows this configuration:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -414,8 +453,10 @@ the constructor of your `SimpleJdbcCall`. The following example shows this confi
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -426,6 +467,7 @@ the constructor of your `SimpleJdbcCall`. The following example shows this confi
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
By taking this action, you avoid conflicts in the case used for the names of your
|
By taking this action, you avoid conflicts in the case used for the names of your
|
||||||
returned `out` parameters.
|
returned `out` parameters.
|
||||||
|
|
@ -456,8 +498,11 @@ of IN parameter names to include for a given signature.
|
||||||
The following example shows a fully declared procedure call and uses the information from
|
The following example shows a fully declared procedure call and uses the information from
|
||||||
the preceding example:
|
the preceding example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -481,8 +526,10 @@ the preceding example:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -501,6 +548,7 @@ the preceding example:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The execution and end results of the two examples are the same. The second example specifies all
|
The execution and end results of the two examples are the same. The second example specifies all
|
||||||
details explicitly rather than relying on metadata.
|
details explicitly rather than relying on metadata.
|
||||||
|
|
@ -515,18 +563,24 @@ To do so, you typically specify the parameter name and SQL type in the construct
|
||||||
is specified by using the `java.sql.Types` constants. Earlier in this chapter, we saw declarations
|
is specified by using the `java.sql.Types` constants. Earlier in this chapter, we saw declarations
|
||||||
similar to the following:
|
similar to the following:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
new SqlParameter("in_id", Types.NUMERIC),
|
new SqlParameter("in_id", Types.NUMERIC),
|
||||||
new SqlOutParameter("out_first_name", Types.VARCHAR),
|
new SqlOutParameter("out_first_name", Types.VARCHAR),
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
SqlParameter("in_id", Types.NUMERIC),
|
SqlParameter("in_id", Types.NUMERIC),
|
||||||
SqlOutParameter("out_first_name", Types.VARCHAR),
|
SqlOutParameter("out_first_name", Types.VARCHAR),
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The first line with the `SqlParameter` declares an IN parameter. You can use IN parameters
|
The first line with the `SqlParameter` declares an IN parameter. You can use IN parameters
|
||||||
for both stored procedure calls and for queries by using the `SqlQuery` and its
|
for both stored procedure calls and for queries by using the `SqlQuery` and its
|
||||||
|
|
@ -578,8 +632,11 @@ that returns an actor's full name:
|
||||||
To call this function, we again create a `SimpleJdbcCall` in the initialization method,
|
To call this function, we again create a `SimpleJdbcCall` in the initialization method,
|
||||||
as the following example shows:
|
as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -602,8 +659,10 @@ as the following example shows:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -621,6 +680,7 @@ as the following example shows:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `executeFunction` method used returns a `String` that contains the return value from the
|
The `executeFunction` method used returns a `String` that contains the return value from the
|
||||||
function call.
|
function call.
|
||||||
|
|
@ -656,8 +716,11 @@ to map follows the JavaBean rules, you can use a `BeanPropertyRowMapper` that is
|
||||||
passing in the required class to map to in the `newInstance` method.
|
passing in the required class to map to in the `newInstance` method.
|
||||||
The following example shows how to do so:
|
The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class JdbcActorDao implements ActorDao {
|
public class JdbcActorDao implements ActorDao {
|
||||||
|
|
||||||
|
|
@ -680,8 +743,10 @@ The following example shows how to do so:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
class JdbcActorDao(dataSource: DataSource) : ActorDao {
|
||||||
|
|
||||||
|
|
@ -699,6 +764,7 @@ The following example shows how to do so:
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `execute` call passes in an empty `Map`, because this call does not take any parameters.
|
The `execute` call passes in an empty `Map`, because this call does not take any parameters.
|
||||||
The list of actors is then retrieved from the results map and returned to the caller.
|
The list of actors is then retrieved from the results map and returned to the caller.
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,11 @@ do not need any special exception treatment (or both). However, Spring lets exce
|
||||||
translation be applied transparently through the `@Repository` annotation. The following
|
translation be applied transparently through the `@Repository` annotation. The following
|
||||||
examples (one for Java configuration and one for XML configuration) show how to do so:
|
examples (one for Java configuration and one for XML configuration) show how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
public class ProductDaoImpl implements ProductDao {
|
public class ProductDaoImpl implements ProductDao {
|
||||||
|
|
@ -71,8 +74,10 @@ examples (one for Java configuration and one for XML configuration) show how to
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Repository
|
@Repository
|
||||||
class ProductDaoImpl : ProductDao {
|
class ProductDaoImpl : ProductDao {
|
||||||
|
|
@ -81,6 +86,7 @@ examples (one for Java configuration and one for XML configuration) show how to
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,11 @@ one current `Session` per transaction. This is roughly equivalent to Spring's
|
||||||
synchronization of one Hibernate `Session` per transaction. A corresponding DAO
|
synchronization of one Hibernate `Session` per transaction. A corresponding DAO
|
||||||
implementation resembles the following example, based on the plain Hibernate API:
|
implementation resembles the following example, based on the plain Hibernate API:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ProductDaoImpl implements ProductDao {
|
public class ProductDaoImpl implements ProductDao {
|
||||||
|
|
||||||
|
|
@ -114,8 +117,10 @@ implementation resembles the following example, based on the plain Hibernate API
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao {
|
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao {
|
||||||
|
|
||||||
|
|
@ -127,6 +132,7 @@ implementation resembles the following example, based on the plain Hibernate API
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
This style is similar to that of the Hibernate reference documentation and examples,
|
This style is similar to that of the Hibernate reference documentation and examples,
|
||||||
except for holding the `SessionFactory` in an instance variable. We strongly recommend
|
except for holding the `SessionFactory` in an instance variable. We strongly recommend
|
||||||
|
|
@ -192,8 +198,11 @@ You can annotate the service layer with `@Transactional` annotations and instruc
|
||||||
Spring container to find these annotations and provide transactional semantics for
|
Spring container to find these annotations and provide transactional semantics for
|
||||||
these annotated methods. The following example shows how to do so:
|
these annotated methods. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ProductServiceImpl implements ProductService {
|
public class ProductServiceImpl implements ProductService {
|
||||||
|
|
||||||
|
|
@ -215,8 +224,10 @@ these annotated methods. The following example shows how to do so:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ProductServiceImpl(private val productDao: ProductDao) : ProductService {
|
class ProductServiceImpl(private val productDao: ProductDao) : ProductService {
|
||||||
|
|
||||||
|
|
@ -230,6 +241,7 @@ these annotated methods. The following example shows how to do so:
|
||||||
fun findAllProducts() = productDao.findAllProducts()
|
fun findAllProducts() = productDao.findAllProducts()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the container, you need to set up the `PlatformTransactionManager` implementation
|
In the container, you need to set up the `PlatformTransactionManager` implementation
|
||||||
(as a bean) and a `<tx:annotation-driven/>` entry, opting into `@Transactional`
|
(as a bean) and a `<tx:annotation-driven/>` entry, opting into `@Transactional`
|
||||||
|
|
@ -295,8 +307,11 @@ and an example for a business method implementation:
|
||||||
</beans>
|
</beans>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ProductServiceImpl implements ProductService {
|
public class ProductServiceImpl implements ProductService {
|
||||||
|
|
||||||
|
|
@ -321,8 +336,10 @@ and an example for a business method implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ProductServiceImpl(transactionManager: PlatformTransactionManager,
|
class ProductServiceImpl(transactionManager: PlatformTransactionManager,
|
||||||
private val productDao: ProductDao) : ProductService {
|
private val productDao: ProductDao) : ProductService {
|
||||||
|
|
@ -337,6 +354,7 @@ and an example for a business method implementation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Spring's `TransactionInterceptor` lets any checked application exception be thrown
|
Spring's `TransactionInterceptor` lets any checked application exception be thrown
|
||||||
with the callback code, while `TransactionTemplate` is restricted to unchecked
|
with the callback code, while `TransactionTemplate` is restricted to unchecked
|
||||||
|
|
|
||||||
|
|
@ -293,8 +293,11 @@ using an injected `EntityManagerFactory` or `EntityManager`. Spring can understa
|
||||||
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain JPA DAO implementation
|
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain JPA DAO implementation
|
||||||
that uses the `@PersistenceUnit` annotation:
|
that uses the `@PersistenceUnit` annotation:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ProductDaoImpl implements ProductDao {
|
public class ProductDaoImpl implements ProductDao {
|
||||||
|
|
||||||
|
|
@ -320,8 +323,10 @@ that uses the `@PersistenceUnit` annotation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ProductDaoImpl : ProductDao {
|
class ProductDaoImpl : ProductDao {
|
||||||
|
|
||||||
|
|
@ -340,6 +345,7 @@ that uses the `@PersistenceUnit` annotation:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding DAO has no dependency on Spring and still fits nicely into a Spring
|
The preceding DAO has no dependency on Spring and still fits nicely into a Spring
|
||||||
application context. Moreover, the DAO takes advantage of annotations to require the
|
application context. Moreover, the DAO takes advantage of annotations to require the
|
||||||
|
|
@ -382,8 +388,11 @@ the factory. You can avoid this by requesting a transactional `EntityManager` (a
|
||||||
called a "`shared EntityManager`" because it is a shared, thread-safe proxy for the actual
|
called a "`shared EntityManager`" because it is a shared, thread-safe proxy for the actual
|
||||||
transactional EntityManager) to be injected instead of the factory. The following example shows how to do so:
|
transactional EntityManager) to be injected instead of the factory. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class ProductDaoImpl implements ProductDao {
|
public class ProductDaoImpl implements ProductDao {
|
||||||
|
|
||||||
|
|
@ -397,8 +406,10 @@ transactional EntityManager) to be injected instead of the factory. The followin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class ProductDaoImpl : ProductDao {
|
class ProductDaoImpl : ProductDao {
|
||||||
|
|
||||||
|
|
@ -412,6 +423,7 @@ transactional EntityManager) to be injected instead of the factory. The followin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `@PersistenceContext` annotation has an optional attribute called `type`, which defaults to
|
The `@PersistenceContext` annotation has an optional attribute called `type`, which defaults to
|
||||||
`PersistenceContextType.TRANSACTION`. You can use this default to receive a shared
|
`PersistenceContextType.TRANSACTION`. You can use this default to receive a shared
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,11 @@ You can use Spring's OXM for a wide variety of situations. In the following exam
|
||||||
use it to marshal the settings of a Spring-managed application as an XML file. In the following example, we
|
use it to marshal the settings of a Spring-managed application as an XML file. In the following example, we
|
||||||
use a simple JavaBean to represent the settings:
|
use a simple JavaBean to represent the settings:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class Settings {
|
public class Settings {
|
||||||
|
|
||||||
|
|
@ -187,21 +190,27 @@ use a simple JavaBean to represent the settings:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Settings {
|
class Settings {
|
||||||
var isFooEnabled: Boolean = false
|
var isFooEnabled: Boolean = false
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The application class uses this bean to store its settings. Besides a main method, the
|
The application class uses this bean to store its settings. Besides a main method, the
|
||||||
class has two methods: `saveSettings()` saves the settings bean to a file named
|
class has two methods: `saveSettings()` saves the settings bean to a file named
|
||||||
`settings.xml`, and `loadSettings()` loads these settings again. The following `main()` method
|
`settings.xml`, and `loadSettings()` loads these settings again. The following `main()` method
|
||||||
constructs a Spring application context and calls these two methods:
|
constructs a Spring application context and calls these two methods:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
@ -249,8 +258,10 @@ constructs a Spring application context and calls these two methods:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class Application {
|
class Application {
|
||||||
|
|
||||||
|
|
@ -276,6 +287,7 @@ constructs a Spring application context and calls these two methods:
|
||||||
application.loadSettings()
|
application.loadSettings()
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `Application` requires both a `marshaller` and an `unmarshaller` property to be set. We
|
The `Application` requires both a `marshaller` and an `unmarshaller` property to be set. We
|
||||||
can do so by using the following `applicationContext.xml`:
|
can do so by using the following `applicationContext.xml`:
|
||||||
|
|
|
||||||
|
|
@ -60,16 +60,22 @@ and give it to DAOs as a bean reference.
|
||||||
|
|
||||||
The simplest way to create a `DatabaseClient` object is through a static factory method, as follows:
|
The simplest way to create a `DatabaseClient` object is through a static factory method, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DatabaseClient client = DatabaseClient.create(connectionFactory);
|
DatabaseClient client = DatabaseClient.create(connectionFactory);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val client = DatabaseClient.create(connectionFactory)
|
val client = DatabaseClient.create(connectionFactory)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: The `ConnectionFactory` should always be configured as a bean in the Spring IoC
|
NOTE: The `ConnectionFactory` should always be configured as a bean in the Spring IoC
|
||||||
container.
|
container.
|
||||||
|
|
@ -119,18 +125,24 @@ See the attendant {api-spring-framework}/r2dbc/core/DatabaseClient.html[javadoc]
|
||||||
The following example shows what you need to include for minimal but fully functional
|
The following example shows what you need to include for minimal but fully functional
|
||||||
code that creates a new table:
|
code that creates a new table:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Mono<Void> completion = client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
Mono<Void> completion = client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
||||||
.then();
|
.then();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
||||||
.await()
|
.await()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`DatabaseClient` is designed for convenient, fluent usage.
|
`DatabaseClient` is designed for convenient, fluent usage.
|
||||||
It exposes intermediate, continuation, and terminal methods at each stage of the
|
It exposes intermediate, continuation, and terminal methods at each stage of the
|
||||||
|
|
@ -150,35 +162,47 @@ depending on the issued query.
|
||||||
|
|
||||||
The following query gets the `id` and `name` columns from a table:
|
The following query gets the `id` and `name` columns from a table:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person")
|
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person")
|
||||||
.fetch().first();
|
.fetch().first();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val first = client.sql("SELECT id, name FROM person")
|
val first = client.sql("SELECT id, name FROM person")
|
||||||
.fetch().awaitSingle()
|
.fetch().awaitSingle()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following query uses a bind variable:
|
The following query uses a bind variable:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
|
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
|
||||||
.bind("fn", "Joe")
|
.bind("fn", "Joe")
|
||||||
.fetch().first();
|
.fetch().first();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
|
val first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
|
||||||
.bind("fn", "Joe")
|
.bind("fn", "Joe")
|
||||||
.fetch().awaitSingle()
|
.fetch().awaitSingle()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You might have noticed the use of `fetch()` in the example above. `fetch()` is a
|
You might have noticed the use of `fetch()` in the example above. `fetch()` is a
|
||||||
continuation operator that lets you specify how much data you want to consume.
|
continuation operator that lets you specify how much data you want to consume.
|
||||||
|
|
@ -205,20 +229,26 @@ collections and maps, and objects).
|
||||||
|
|
||||||
The following example extracts the `name` column and emits its value:
|
The following example extracts the `name` column and emits its value:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Flux<String> names = client.sql("SELECT name FROM person")
|
Flux<String> names = client.sql("SELECT name FROM person")
|
||||||
.map(row -> row.get("name", String.class))
|
.map(row -> row.get("name", String.class))
|
||||||
.all();
|
.all();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val names = client.sql("SELECT name FROM person")
|
val names = client.sql("SELECT name FROM person")
|
||||||
.map{ row: Row -> row.get("name", String.class) }
|
.map{ row: Row -> row.get("name", String.class) }
|
||||||
.flow()
|
.flow()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[r2dbc-DatabaseClient-mapping-null]]
|
[[r2dbc-DatabaseClient-mapping-null]]
|
||||||
|
|
@ -242,20 +272,26 @@ do not return tabular data so you use `rowsUpdated()` to consume results.
|
||||||
The following example shows an `UPDATE` statement that returns the number
|
The following example shows an `UPDATE` statement that returns the number
|
||||||
of updated rows:
|
of updated rows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Mono<Integer> affectedRows = client.sql("UPDATE person SET first_name = :fn")
|
Mono<Integer> affectedRows = client.sql("UPDATE person SET first_name = :fn")
|
||||||
.bind("fn", "Joe")
|
.bind("fn", "Joe")
|
||||||
.fetch().rowsUpdated();
|
.fetch().rowsUpdated();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val affectedRows = client.sql("UPDATE person SET first_name = :fn")
|
val affectedRows = client.sql("UPDATE person SET first_name = :fn")
|
||||||
.bind("fn", "Joe")
|
.bind("fn", "Joe")
|
||||||
.fetch().awaitRowsUpdated()
|
.fetch().awaitRowsUpdated()
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[r2dbc-DatabaseClient-named-parameters]]
|
[[r2dbc-DatabaseClient-named-parameters]]
|
||||||
==== Binding Values to Queries
|
==== Binding Values to Queries
|
||||||
|
|
@ -277,7 +313,6 @@ Parameter binding supports two binding strategies:
|
||||||
|
|
||||||
The following example shows parameter binding for a query:
|
The following example shows parameter binding for a query:
|
||||||
|
|
||||||
====
|
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||||
|
|
@ -285,7 +320,6 @@ db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||||
.bind("name", "Joe")
|
.bind("name", "Joe")
|
||||||
.bind("age", 34);
|
.bind("age", 34);
|
||||||
----
|
----
|
||||||
====
|
|
||||||
|
|
||||||
.R2DBC Native Bind Markers
|
.R2DBC Native Bind Markers
|
||||||
****
|
****
|
||||||
|
|
@ -318,8 +352,11 @@ SELECT id, name, state FROM table WHERE (name, age) IN (('John', 35), ('Ann', 50
|
||||||
|
|
||||||
The preceding query can be parameterized and run as follows:
|
The preceding query can be parameterized and run as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
List<Object[]> tuples = new ArrayList<>();
|
List<Object[]> tuples = new ArrayList<>();
|
||||||
tuples.add(new Object[] {"John", 35});
|
tuples.add(new Object[] {"John", 35});
|
||||||
|
|
@ -328,8 +365,10 @@ The preceding query can be parameterized and run as follows:
|
||||||
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
||||||
.bind("tuples", tuples);
|
.bind("tuples", tuples);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val tuples: MutableList<Array<Any>> = ArrayList()
|
val tuples: MutableList<Array<Any>> = ArrayList()
|
||||||
tuples.add(arrayOf("John", 35))
|
tuples.add(arrayOf("John", 35))
|
||||||
|
|
@ -338,19 +377,25 @@ The preceding query can be parameterized and run as follows:
|
||||||
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
||||||
.bind("tuples", tuples)
|
.bind("tuples", tuples)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: Usage of select lists is vendor-dependent.
|
NOTE: Usage of select lists is vendor-dependent.
|
||||||
|
|
||||||
The following example shows a simpler variant using `IN` predicates:
|
The following example shows a simpler variant using `IN` predicates:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
||||||
.bind("ages", Arrays.asList(35, 50));
|
.bind("ages", Arrays.asList(35, 50));
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val tuples: MutableList<Array<Any>> = ArrayList()
|
val tuples: MutableList<Array<Any>> = ArrayList()
|
||||||
tuples.add(arrayOf("John", 35))
|
tuples.add(arrayOf("John", 35))
|
||||||
|
|
@ -359,6 +404,7 @@ The following example shows a simpler variant using `IN` predicates:
|
||||||
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
||||||
.bind("tuples", arrayOf(35, 50))
|
.bind("tuples", arrayOf(35, 50))
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: R2DBC itself does not support Collection-like values. Nevertheless,
|
NOTE: R2DBC itself does not support Collection-like values. Nevertheless,
|
||||||
expanding a given `List` in the example above works for named parameters
|
expanding a given `List` in the example above works for named parameters
|
||||||
|
|
@ -376,27 +422,36 @@ before it gets run. Register a `Statement` filter
|
||||||
(`StatementFilterFunction`) through `DatabaseClient` to intercept and
|
(`StatementFilterFunction`) through `DatabaseClient` to intercept and
|
||||||
modify statements in their execution, as the following example shows:
|
modify statements in their execution, as the following example shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter((s, next) -> next.execute(s.returnGeneratedValues("id")))
|
.filter((s, next) -> next.execute(s.returnGeneratedValues("id")))
|
||||||
.bind("name", …)
|
.bind("name", …)
|
||||||
.bind("state", …);
|
.bind("state", …);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter { s: Statement, next: ExecuteFunction -> next.execute(s.returnGeneratedValues("id")) }
|
.filter { s: Statement, next: ExecuteFunction -> next.execute(s.returnGeneratedValues("id")) }
|
||||||
.bind("name", …)
|
.bind("name", …)
|
||||||
.bind("state", …)
|
.bind("state", …)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`DatabaseClient` exposes also simplified `filter(…)` overload accepting `Function<Statement, Statement>`:
|
`DatabaseClient` exposes also simplified `filter(…)` overload accepting `Function<Statement, Statement>`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter(statement -> s.returnGeneratedValues("id"));
|
.filter(statement -> s.returnGeneratedValues("id"));
|
||||||
|
|
@ -404,8 +459,10 @@ modify statements in their execution, as the following example shows:
|
||||||
client.sql("SELECT id, name, state FROM table")
|
client.sql("SELECT id, name, state FROM table")
|
||||||
.filter(statement -> s.fetchSize(25));
|
.filter(statement -> s.fetchSize(25));
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter { statement -> s.returnGeneratedValues("id") }
|
.filter { statement -> s.returnGeneratedValues("id") }
|
||||||
|
|
@ -413,6 +470,7 @@ modify statements in their execution, as the following example shows:
|
||||||
client.sql("SELECT id, name, state FROM table")
|
client.sql("SELECT id, name, state FROM table")
|
||||||
.filter { statement -> s.fetchSize(25) }
|
.filter { statement -> s.fetchSize(25) }
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`StatementFilterFunction` implementations allow filtering of the
|
`StatementFilterFunction` implementations allow filtering of the
|
||||||
`Statement` and filtering of `Result` objects.
|
`Statement` and filtering of `Result` objects.
|
||||||
|
|
@ -432,8 +490,11 @@ that shared `ConnectionFactory` bean into your DAO classes. The `DatabaseClient`
|
||||||
the setter for the `ConnectionFactory`. This leads to DAOs that resemble the following:
|
the setter for the `ConnectionFactory`. This leads to DAOs that resemble the following:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class R2dbcCorporateEventDao implements CorporateEventDao {
|
public class R2dbcCorporateEventDao implements CorporateEventDao {
|
||||||
|
|
||||||
|
|
@ -446,8 +507,10 @@ the setter for the `ConnectionFactory`. This leads to DAOs that resemble the fol
|
||||||
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class R2dbcCorporateEventDao(connectionFactory: ConnectionFactory) : CorporateEventDao {
|
class R2dbcCorporateEventDao(connectionFactory: ConnectionFactory) : CorporateEventDao {
|
||||||
|
|
||||||
|
|
@ -456,6 +519,7 @@ the setter for the `ConnectionFactory`. This leads to DAOs that resemble the fol
|
||||||
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
--
|
--
|
||||||
|
|
||||||
An alternative to explicit configuration is to use component-scanning and annotation
|
An alternative to explicit configuration is to use component-scanning and annotation
|
||||||
|
|
@ -464,8 +528,11 @@ support for dependency injection. In this case, you can annotate the class with
|
||||||
method with `@Autowired`. The following example shows how to do so:
|
method with `@Autowired`. The following example shows how to do so:
|
||||||
|
|
||||||
--
|
--
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component // <1>
|
@Component // <1>
|
||||||
public class R2dbcCorporateEventDao implements CorporateEventDao {
|
public class R2dbcCorporateEventDao implements CorporateEventDao {
|
||||||
|
|
@ -480,6 +547,7 @@ method with `@Autowired`. The following example shows how to do so:
|
||||||
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
// R2DBC-backed implementations of the methods on the CorporateEventDao follow...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
<1> Annotate the class with `@Component`.
|
<1> Annotate the class with `@Component`.
|
||||||
<2> Annotate the `ConnectionFactory` setter method with `@Autowired`.
|
<2> Annotate the `ConnectionFactory` setter method with `@Autowired`.
|
||||||
<3> Create a new `DatabaseClient` with the `ConnectionFactory`.
|
<3> Create a new `DatabaseClient` with the `ConnectionFactory`.
|
||||||
|
|
@ -516,8 +584,11 @@ that defines an auto-increment or identity column. To get full control over
|
||||||
the column name to generate, simply register a `StatementFilterFunction` that
|
the column name to generate, simply register a `StatementFilterFunction` that
|
||||||
requests the generated key for the desired column.
|
requests the generated key for the desired column.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
Mono<Integer> generatedId = client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
Mono<Integer> generatedId = client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter(statement -> s.returnGeneratedValues("id"))
|
.filter(statement -> s.returnGeneratedValues("id"))
|
||||||
|
|
@ -526,8 +597,10 @@ requests the generated key for the desired column.
|
||||||
|
|
||||||
// generatedId emits the generated key once the INSERT statement has finished
|
// generatedId emits the generated key once the INSERT statement has finished
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val generatedId = client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
val generatedId = client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
|
||||||
.filter { statement -> s.returnGeneratedValues("id") }
|
.filter { statement -> s.returnGeneratedValues("id") }
|
||||||
|
|
@ -536,6 +609,7 @@ requests the generated key for the desired column.
|
||||||
|
|
||||||
// generatedId emits the generated key once the INSERT statement has finished
|
// generatedId emits the generated key once the INSERT statement has finished
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[r2dbc-connections]]
|
[[r2dbc-connections]]
|
||||||
|
|
@ -575,16 +649,22 @@ To configure a `ConnectionFactory`:
|
||||||
|
|
||||||
The following example shows how to configure a `ConnectionFactory`:
|
The following example shows how to configure a `ConnectionFactory`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
ConnectionFactory factory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
ConnectionFactory factory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val factory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
val factory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[r2dbc-ConnectionFactoryUtils]]
|
[[r2dbc-ConnectionFactoryUtils]]
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@ The ease-of-use afforded by the use of the `@Transactional` annotation is best
|
||||||
illustrated with an example, which is explained in the text that follows.
|
illustrated with an example, which is explained in the text that follows.
|
||||||
Consider the following class definition:
|
Consider the following class definition:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// the service class that we want to make transactional
|
// the service class that we want to make transactional
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -43,8 +46,10 @@ Consider the following class definition:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// the service class that we want to make transactional
|
// the service class that we want to make transactional
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -67,6 +72,7 @@ Consider the following class definition:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Used at the class level as above, the annotation indicates a default for all methods of
|
Used at the class level as above, the annotation indicates a default for all methods of
|
||||||
the declaring class (as well as its subclasses). Alternatively, each method can be
|
the declaring class (as well as its subclasses). Alternatively, each method can be
|
||||||
|
|
@ -128,8 +134,11 @@ preceding example.
|
||||||
Reactive transactional methods use reactive return types in contrast to imperative
|
Reactive transactional methods use reactive return types in contrast to imperative
|
||||||
programming arrangements as the following listing shows:
|
programming arrangements as the following listing shows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// the reactive service class that we want to make transactional
|
// the reactive service class that we want to make transactional
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -156,8 +165,10 @@ programming arrangements as the following listing shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// the reactive service class that we want to make transactional
|
// the reactive service class that we want to make transactional
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -180,6 +191,7 @@ programming arrangements as the following listing shows:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Note that there are special considerations for the returned `Publisher` with regards to
|
Note that there are special considerations for the returned `Publisher` with regards to
|
||||||
Reactive Streams cancellation signals. See the xref:data-access/transaction/programmatic.adoc#tx-prog-operator-cancel[Cancel Signals] section under
|
Reactive Streams cancellation signals. See the xref:data-access/transaction/programmatic.adoc#tx-prog-operator-cancel[Cancel Signals] section under
|
||||||
|
|
@ -322,8 +334,11 @@ annotated at the class level with the settings for a read-only transaction, but
|
||||||
`@Transactional` annotation on the `updateFoo(Foo)` method in the same class takes
|
`@Transactional` annotation on the `updateFoo(Foo)` method in the same class takes
|
||||||
precedence over the transactional settings defined at the class level.
|
precedence over the transactional settings defined at the class level.
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public class DefaultFooService implements FooService {
|
public class DefaultFooService implements FooService {
|
||||||
|
|
@ -339,8 +354,10 @@ precedence over the transactional settings defined at the class level.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
class DefaultFooService : FooService {
|
class DefaultFooService : FooService {
|
||||||
|
|
@ -356,6 +373,7 @@ precedence over the transactional settings defined at the class level.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[transaction-declarative-attransactional-settings]]
|
[[transaction-declarative-attransactional-settings]]
|
||||||
|
|
@ -455,8 +473,11 @@ of the transaction manager bean. For example, using the qualifier notation, you
|
||||||
combine the following Java code with the following transaction manager bean declarations
|
combine the following Java code with the following transaction manager bean declarations
|
||||||
in the application context:
|
in the application context:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class TransactionalService {
|
public class TransactionalService {
|
||||||
|
|
||||||
|
|
@ -470,8 +491,10 @@ in the application context:
|
||||||
public Mono<Void> doSomethingReactive() { ... }
|
public Mono<Void> doSomethingReactive() { ... }
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TransactionalService {
|
class TransactionalService {
|
||||||
|
|
||||||
|
|
@ -491,6 +514,7 @@ in the application context:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following listing shows the bean declarations:
|
The following listing shows the bean declarations:
|
||||||
|
|
||||||
|
|
@ -527,8 +551,11 @@ methods, xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[Spring's
|
||||||
define custom composed annotations for your specific use cases. For example, consider the
|
define custom composed annotations for your specific use cases. For example, consider the
|
||||||
following annotation definitions:
|
following annotation definitions:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -542,8 +569,10 @@ following annotation definitions:
|
||||||
public @interface AccountTx {
|
public @interface AccountTx {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
|
@ -555,11 +584,15 @@ following annotation definitions:
|
||||||
@Transactional(transactionManager = "account", label = ["retryable"])
|
@Transactional(transactionManager = "account", label = ["retryable"])
|
||||||
annotation class AccountTx
|
annotation class AccountTx
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The preceding annotations let us write the example from the previous section as follows:
|
The preceding annotations let us write the example from the previous section as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class TransactionalService {
|
public class TransactionalService {
|
||||||
|
|
||||||
|
|
@ -574,8 +607,10 @@ The preceding annotations let us write the example from the previous section as
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class TransactionalService {
|
class TransactionalService {
|
||||||
|
|
||||||
|
|
@ -590,6 +625,7 @@ The preceding annotations let us write the example from the previous section as
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
In the preceding example, we used the syntax to define the transaction manager qualifier
|
In the preceding example, we used the syntax to define the transaction manager qualifier
|
||||||
and transactional labels, but we could also have included propagation behavior,
|
and transactional labels, but we could also have included propagation behavior,
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,11 @@ configuration and AOP in general.
|
||||||
|
|
||||||
The following code shows the simple profiling aspect discussed earlier:
|
The following code shows the simple profiling aspect discussed earlier:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package x.y;
|
package x.y;
|
||||||
|
|
||||||
|
|
@ -55,8 +58,10 @@ The following code shows the simple profiling aspect discussed earlier:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package x.y
|
package x.y
|
||||||
|
|
||||||
|
|
@ -92,6 +97,7 @@ The following code shows the simple profiling aspect discussed earlier:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The ordering of advice
|
The ordering of advice
|
||||||
is controlled through the `Ordered` interface. For full details on advice ordering, see
|
is controlled through the `Ordered` interface. For full details on advice ordering, see
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,11 @@ xref:core/aop.adoc[AOP] respectively.
|
||||||
The following example shows how to create a transaction manager and configure the
|
The following example shows how to create a transaction manager and configure the
|
||||||
`AnnotationTransactionAspect` to use it:
|
`AnnotationTransactionAspect` to use it:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// construct an appropriate transaction manager
|
// construct an appropriate transaction manager
|
||||||
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
|
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
|
||||||
|
|
@ -29,8 +32,10 @@ The following example shows how to create a transaction manager and configure th
|
||||||
// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
|
// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
|
||||||
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
|
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// construct an appropriate transaction manager
|
// construct an appropriate transaction manager
|
||||||
val txManager = DataSourceTransactionManager(getDataSource())
|
val txManager = DataSourceTransactionManager(getDataSource())
|
||||||
|
|
@ -38,6 +43,7 @@ The following example shows how to create a transaction manager and configure th
|
||||||
// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
|
// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
|
||||||
AnnotationTransactionAspect.aspectOf().transactionManager = txManager
|
AnnotationTransactionAspect.aspectOf().transactionManager = txManager
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
NOTE: When you use this aspect, you must annotate the implementation class (or the methods
|
NOTE: When you use this aspect, you must annotate the implementation class (or the methods
|
||||||
within that class or both), not the interface (if any) that the class implements. AspectJ
|
within that class or both), not the interface (if any) that the class implements. AspectJ
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,11 @@ transactions being created and then rolled back in response to the
|
||||||
`UnsupportedOperationException` instance. The following listing shows the `FooService`
|
`UnsupportedOperationException` instance. The following listing shows the `FooService`
|
||||||
interface:
|
interface:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// the service interface that we want to make transactional
|
// the service interface that we want to make transactional
|
||||||
|
|
||||||
|
|
@ -29,8 +32,10 @@ interface:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// the service interface that we want to make transactional
|
// the service interface that we want to make transactional
|
||||||
|
|
||||||
|
|
@ -47,11 +52,15 @@ interface:
|
||||||
fun updateFoo(foo: Foo)
|
fun updateFoo(foo: Foo)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows an implementation of the preceding interface:
|
The following example shows an implementation of the preceding interface:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package x.y.service;
|
package x.y.service;
|
||||||
|
|
||||||
|
|
@ -78,8 +87,10 @@ The following example shows an implementation of the preceding interface:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package x.y.service
|
package x.y.service
|
||||||
|
|
||||||
|
|
@ -102,6 +113,7 @@ The following example shows an implementation of the preceding interface:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Assume that the first two methods of the `FooService` interface, `getFoo(String)` and
|
Assume that the first two methods of the `FooService` interface, `getFoo(String)` and
|
||||||
`getFoo(String, String)`, must run in the context of a transaction with read-only
|
`getFoo(String, String)`, must run in the context of a transaction with read-only
|
||||||
|
|
@ -215,8 +227,11 @@ a transaction is started, suspended, marked as read-only, and so on, depending o
|
||||||
transaction configuration associated with that method. Consider the following program
|
transaction configuration associated with that method. Consider the following program
|
||||||
that test drives the configuration shown earlier:
|
that test drives the configuration shown earlier:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public final class Boot {
|
public final class Boot {
|
||||||
|
|
||||||
|
|
@ -227,8 +242,10 @@ that test drives the configuration shown earlier:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
import org.springframework.beans.factory.getBean
|
import org.springframework.beans.factory.getBean
|
||||||
|
|
||||||
|
|
@ -238,6 +255,7 @@ that test drives the configuration shown earlier:
|
||||||
fooService.insertFoo(Foo())
|
fooService.insertFoo(Foo())
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The output from running the preceding program should resemble the following (the Log4J
|
The output from running the preceding program should resemble the following (the Log4J
|
||||||
output and the stack trace from the `UnsupportedOperationException` thrown by the
|
output and the stack trace from the `UnsupportedOperationException` thrown by the
|
||||||
|
|
@ -281,8 +299,11 @@ return type is reactive.
|
||||||
The following listing shows a modified version of the previously used `FooService`, but
|
The following listing shows a modified version of the previously used `FooService`, but
|
||||||
this time the code uses reactive types:
|
this time the code uses reactive types:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
// the reactive service interface that we want to make transactional
|
// the reactive service interface that we want to make transactional
|
||||||
|
|
||||||
|
|
@ -300,8 +321,10 @@ this time the code uses reactive types:
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// the reactive service interface that we want to make transactional
|
// the reactive service interface that we want to make transactional
|
||||||
|
|
||||||
|
|
@ -318,11 +341,15 @@ this time the code uses reactive types:
|
||||||
fun updateFoo(foo: Foo) : Mono<Void>
|
fun updateFoo(foo: Foo) : Mono<Void>
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example shows an implementation of the preceding interface:
|
The following example shows an implementation of the preceding interface:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
package x.y.service;
|
package x.y.service;
|
||||||
|
|
||||||
|
|
@ -349,8 +376,10 @@ The following example shows an implementation of the preceding interface:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
package x.y.service
|
package x.y.service
|
||||||
|
|
||||||
|
|
@ -373,6 +402,7 @@ The following example shows an implementation of the preceding interface:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Imperative and reactive transaction management share the same semantics for transaction
|
Imperative and reactive transaction management share the same semantics for transaction
|
||||||
boundary and transaction attribute definitions. The main difference between imperative
|
boundary and transaction attribute definitions. The main difference between imperative
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,11 @@ automatically rolled back in case of a failure. For more information on Vavr's T
|
||||||
refer to the [official Vavr documentation](https://www.vavr.io/vavr-docs/#_try).
|
refer to the [official Vavr documentation](https://www.vavr.io/vavr-docs/#_try).
|
||||||
|
|
||||||
Here's an example of how to use Vavr's Try with a transactional method:
|
Here's an example of how to use Vavr's Try with a transactional method:
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Transactional
|
@Transactional
|
||||||
public Try<String> myTransactionalMethod() {
|
public Try<String> myTransactionalMethod() {
|
||||||
|
|
@ -37,6 +40,7 @@ Here's an example of how to use Vavr's Try with a transactional method:
|
||||||
return Try.of(delegate::myDataAccessOperation);
|
return Try.of(delegate::myDataAccessOperation);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
Checked exceptions that are thrown from a transactional method do not result in a rollback
|
Checked exceptions that are thrown from a transactional method do not result in a rollback
|
||||||
in the default configuration. You can configure exactly which `Exception` types mark a
|
in the default configuration. You can configure exactly which `Exception` types mark a
|
||||||
|
|
@ -138,8 +142,11 @@ is quite invasive and tightly couples your code to the Spring Framework's transa
|
||||||
infrastructure. The following example shows how to programmatically indicate a required
|
infrastructure. The following example shows how to programmatically indicate a required
|
||||||
rollback:
|
rollback:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public void resolvePosition() {
|
public void resolvePosition() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -150,8 +157,10 @@ rollback:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
fun resolvePosition() {
|
fun resolvePosition() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -162,6 +171,7 @@ rollback:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
You are strongly encouraged to use the declarative approach to rollback, if at all
|
You are strongly encouraged to use the declarative approach to rollback, if at all
|
||||||
possible. Programmatic rollback is available should you absolutely need it, but its
|
possible. Programmatic rollback is available should you absolutely need it, but its
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@ event and that we want to define a listener that should only handle that event o
|
||||||
transaction in which it has been published has committed successfully. The following
|
transaction in which it has been published has committed successfully. The following
|
||||||
example sets up such an event listener:
|
example sets up such an event listener:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
public class MyComponent {
|
public class MyComponent {
|
||||||
|
|
@ -27,8 +30,10 @@ example sets up such an event listener:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
@Component
|
@Component
|
||||||
class MyComponent {
|
class MyComponent {
|
||||||
|
|
@ -39,6 +44,7 @@ example sets up such an event listener:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The `@TransactionalEventListener` annotation exposes a `phase` attribute that lets you
|
The `@TransactionalEventListener` annotation exposes a `phase` attribute that lets you
|
||||||
customize the phase of the transaction to which the listener should be bound.
|
customize the phase of the transaction to which the listener should be bound.
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,11 @@ anonymous inner class) that contains the code that you need to run in the contex
|
||||||
a transaction. You can then pass an instance of your custom `TransactionCallback` to the
|
a transaction. You can then pass an instance of your custom `TransactionCallback` to the
|
||||||
`execute(..)` method exposed on the `TransactionTemplate`. The following example shows how to do so:
|
`execute(..)` method exposed on the `TransactionTemplate`. The following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleService implements Service {
|
public class SimpleService implements Service {
|
||||||
|
|
||||||
|
|
@ -57,8 +60,10 @@ a transaction. You can then pass an instance of your custom `TransactionCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// use constructor-injection to supply the PlatformTransactionManager
|
// use constructor-injection to supply the PlatformTransactionManager
|
||||||
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
|
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
|
||||||
|
|
@ -72,13 +77,17 @@ a transaction. You can then pass an instance of your custom `TransactionCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
If there is no return value, you can use the convenient `TransactionCallbackWithoutResult` class
|
If there is no return value, you can use the convenient `TransactionCallbackWithoutResult` class
|
||||||
with an anonymous class, as follows:
|
with an anonymous class, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
|
@ -87,8 +96,10 @@ with an anonymous class, as follows:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
|
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
|
||||||
override fun doInTransactionWithoutResult(status: TransactionStatus) {
|
override fun doInTransactionWithoutResult(status: TransactionStatus) {
|
||||||
|
|
@ -97,13 +108,17 @@ with an anonymous class, as follows:
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
Code within the callback can roll the transaction back by calling the
|
Code within the callback can roll the transaction back by calling the
|
||||||
`setRollbackOnly()` method on the supplied `TransactionStatus` object, as follows:
|
`setRollbackOnly()` method on the supplied `TransactionStatus` object, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
|
||||||
|
|
@ -117,8 +132,10 @@ Code within the callback can roll the transaction back by calling the
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
|
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
|
||||||
|
|
||||||
|
|
@ -132,6 +149,7 @@ Code within the callback can roll the transaction back by calling the
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[tx-prog-template-settings]]
|
[[tx-prog-template-settings]]
|
||||||
=== Specifying Transaction Settings
|
=== Specifying Transaction Settings
|
||||||
|
|
@ -143,8 +161,11 @@ xref:data-access/transaction/declarative/txadvice-settings.adoc[default transact
|
||||||
following example shows the programmatic customization of the transactional settings for
|
following example shows the programmatic customization of the transactional settings for
|
||||||
a specific `TransactionTemplate:`
|
a specific `TransactionTemplate:`
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleService implements Service {
|
public class SimpleService implements Service {
|
||||||
|
|
||||||
|
|
@ -160,8 +181,10 @@ a specific `TransactionTemplate:`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
|
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
|
||||||
|
|
||||||
|
|
@ -173,6 +196,7 @@ a specific `TransactionTemplate:`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The following example defines a `TransactionTemplate` with some custom transactional
|
The following example defines a `TransactionTemplate` with some custom transactional
|
||||||
settings by using Spring XML configuration:
|
settings by using Spring XML configuration:
|
||||||
|
|
@ -212,8 +236,11 @@ to make yourself.
|
||||||
Application code that must run in a transactional context and that explicitly uses
|
Application code that must run in a transactional context and that explicitly uses
|
||||||
the `TransactionalOperator` resembles the next example:
|
the `TransactionalOperator` resembles the next example:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleService implements Service {
|
public class SimpleService implements Service {
|
||||||
|
|
||||||
|
|
@ -235,8 +262,10 @@ the `TransactionalOperator` resembles the next example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
// use constructor-injection to supply the ReactiveTransactionManager
|
// use constructor-injection to supply the ReactiveTransactionManager
|
||||||
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
|
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
|
||||||
|
|
@ -250,6 +279,7 @@ the `TransactionalOperator` resembles the next example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
`TransactionalOperator` can be used in two ways:
|
`TransactionalOperator` can be used in two ways:
|
||||||
|
|
||||||
|
|
@ -259,8 +289,11 @@ the `TransactionalOperator` resembles the next example:
|
||||||
Code within the callback can roll the transaction back by calling the `setRollbackOnly()`
|
Code within the callback can roll the transaction back by calling the `setRollbackOnly()`
|
||||||
method on the supplied `ReactiveTransaction` object, as follows:
|
method on the supplied `ReactiveTransaction` object, as follows:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
transactionalOperator.execute(new TransactionCallback<>() {
|
transactionalOperator.execute(new TransactionCallback<>() {
|
||||||
|
|
||||||
|
|
@ -271,8 +304,10 @@ method on the supplied `ReactiveTransaction` object, as follows:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
transactionalOperator.execute(object : TransactionCallback() {
|
transactionalOperator.execute(object : TransactionCallback() {
|
||||||
|
|
||||||
|
|
@ -282,6 +317,7 @@ method on the supplied `ReactiveTransaction` object, as follows:
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[tx-prog-operator-cancel]]
|
[[tx-prog-operator-cancel]]
|
||||||
=== Cancel Signals
|
=== Cancel Signals
|
||||||
|
|
@ -306,8 +342,11 @@ xref:data-access/transaction/declarative/txadvice-settings.adoc[default transact
|
||||||
following example shows customization of the transactional settings for a specific
|
following example shows customization of the transactional settings for a specific
|
||||||
`TransactionalOperator:`
|
`TransactionalOperator:`
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
public class SimpleService implements Service {
|
public class SimpleService implements Service {
|
||||||
|
|
||||||
|
|
@ -325,8 +364,10 @@ following example shows customization of the transactional settings for a specif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
|
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
|
||||||
|
|
||||||
|
|
@ -339,6 +380,7 @@ following example shows customization of the transactional settings for a specif
|
||||||
private val transactionalOperator = TransactionalOperator(transactionManager, definition)
|
private val transactionalOperator = TransactionalOperator(transactionManager, definition)
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[transaction-programmatic-tm]]
|
[[transaction-programmatic-tm]]
|
||||||
== Using the `TransactionManager`
|
== Using the `TransactionManager`
|
||||||
|
|
@ -356,8 +398,11 @@ use to your bean through a bean reference. Then, by using the `TransactionDefini
|
||||||
`TransactionStatus` objects, you can initiate transactions, roll back, and commit. The
|
`TransactionStatus` objects, you can initiate transactions, roll back, and commit. The
|
||||||
following example shows how to do so:
|
following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||||
// explicitly setting the transaction name is something that can be done only programmatically
|
// explicitly setting the transaction name is something that can be done only programmatically
|
||||||
|
|
@ -373,8 +418,10 @@ following example shows how to do so:
|
||||||
}
|
}
|
||||||
txManager.commit(status);
|
txManager.commit(status);
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val def = DefaultTransactionDefinition()
|
val def = DefaultTransactionDefinition()
|
||||||
// explicitly setting the transaction name is something that can be done only programmatically
|
// explicitly setting the transaction name is something that can be done only programmatically
|
||||||
|
|
@ -391,6 +438,7 @@ following example shows how to do so:
|
||||||
|
|
||||||
txManager.commit(status)
|
txManager.commit(status)
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
[[transaction-programmatic-rtm]]
|
[[transaction-programmatic-rtm]]
|
||||||
|
|
@ -403,8 +451,11 @@ use to your bean through a bean reference. Then, by using the `TransactionDefini
|
||||||
`ReactiveTransaction` objects, you can initiate transactions, roll back, and commit. The
|
`ReactiveTransaction` objects, you can initiate transactions, roll back, and commit. The
|
||||||
following example shows how to do so:
|
following example shows how to do so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
|
||||||
----
|
----
|
||||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||||
// explicitly setting the transaction name is something that can be done only programmatically
|
// explicitly setting the transaction name is something that can be done only programmatically
|
||||||
|
|
@ -421,8 +472,10 @@ following example shows how to do so:
|
||||||
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
|
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
|
||||||
});
|
});
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
.Kotlin
|
|
||||||
----
|
----
|
||||||
val def = DefaultTransactionDefinition()
|
val def = DefaultTransactionDefinition()
|
||||||
// explicitly setting the transaction name is something that can be done only programmatically
|
// explicitly setting the transaction name is something that can be done only programmatically
|
||||||
|
|
@ -438,5 +491,6 @@ following example shows how to do so:
|
||||||
.onErrorResume { ex -> txManager.rollback(status).then(Mono.error(ex)) }
|
.onErrorResume { ex -> txManager.rollback(status).then(Mono.error(ex)) }
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,10 @@ you can instead write the following:
|
||||||
registerBean { Bar(it.getBean()) }
|
registerBean { Bar(it.getBean()) }
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
====
|
|
||||||
|
|
||||||
When the class `Bar` has a single constructor, you can even just specify the bean class,
|
When the class `Bar` has a single constructor, you can even just specify the bean class,
|
||||||
the constructor parameters will be autowired by type:
|
the constructor parameters will be autowired by type:
|
||||||
|
|
||||||
====
|
|
||||||
[source,kotlin,indent=0]
|
[source,kotlin,indent=0]
|
||||||
----
|
----
|
||||||
val context = GenericApplicationContext().apply {
|
val context = GenericApplicationContext().apply {
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,6 @@ in order to use `val` instead of `lateinit var`. You can use
|
||||||
{api-spring-framework}/test/context/TestConstructor.html[`@TestConstructor(autowireMode = AutowireMode.ALL)`]
|
{api-spring-framework}/test/context/TestConstructor.html[`@TestConstructor(autowireMode = AutowireMode.ALL)`]
|
||||||
to enable autowiring for all parameters.
|
to enable autowiring for all parameters.
|
||||||
|
|
||||||
====
|
|
||||||
[source,kotlin,indent=0]
|
[source,kotlin,indent=0]
|
||||||
----
|
----
|
||||||
@SpringJUnitConfig(TestConfig::class)
|
@SpringJUnitConfig(TestConfig::class)
|
||||||
|
|
@ -267,7 +266,6 @@ class OrderServiceIntegrationTests(val orderService: OrderService,
|
||||||
// tests that use the injected OrderService and CustomerService
|
// tests that use the injected OrderService and CustomerService
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
====
|
|
||||||
|
|
||||||
|
|
||||||
[[per_class-lifecycle]]
|
[[per_class-lifecycle]]
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue