Merge branch '5.1.x'
This commit is contained in:
@@ -1,29 +1,20 @@
|
||||
[[dynamic-language]]
|
||||
= Dynamic Language Support
|
||||
|
||||
Spring 2.0 introduced comprehensive support for using classes and objects that have been
|
||||
defined by using a dynamic language (such as JRuby) with Spring. This support lets you
|
||||
write any number of classes in a supported dynamic language and have the Spring
|
||||
Spring provides comprehensive support for using classes and objects that have been
|
||||
defined by using a dynamic language (such as Groovy) with Spring. This support lets
|
||||
you write any number of classes in a supported dynamic language and have the Spring
|
||||
container transparently instantiate, configure, and dependency inject the resulting
|
||||
objects.
|
||||
|
||||
Spring currently supports the following dynamic languages:
|
||||
Spring's scripting support primarily targets Groovy and BeanShell. Beyond those
|
||||
specifically supported languages, the JSR-223 scripting mechanism is supported
|
||||
for integration with any JSR-223 capable language provider (as of Spring 4.2),
|
||||
e.g. JRuby.
|
||||
|
||||
* JRuby 1.5+
|
||||
* Groovy 1.8+
|
||||
* BeanShell 2.0
|
||||
You can find fully working examples of where this dynamic language support can be
|
||||
immediately useful in <<dynamic-language-scenarios>>.
|
||||
|
||||
.Why only these languages?
|
||||
****
|
||||
We chose to support these languages because:
|
||||
|
||||
* The languages have a lot of traction in the Java enterprise community.
|
||||
* No requests were made for other languages at the time that this support was added
|
||||
* The Spring developers were most familiar with them.
|
||||
****
|
||||
|
||||
You can find fully working examples of where this dynamic language support can be immediately useful
|
||||
in <<dynamic-language-scenarios>>.
|
||||
|
||||
|
||||
|
||||
@@ -37,9 +28,9 @@ language for this first bean is Groovy. (The basis of this example was taken fro
|
||||
Spring test suite. If you want to see equivalent examples in any of the other
|
||||
supported languages, take a look at the source code).
|
||||
|
||||
The next example shows the `Messenger` interface, which the Groovy bean is going to implement.
|
||||
Note that this interface is defined in plain Java. Dependent objects that are
|
||||
injected with a reference to the `Messenger` do not know that the underlying
|
||||
The next example shows the `Messenger` interface, which the Groovy bean is going to
|
||||
implement. Note that this interface is defined in plain Java. Dependent objects that
|
||||
are injected with a reference to the `Messenger` do not know that the underlying
|
||||
implementation is a Groovy script. The following listing shows the `Messenger` interface:
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -50,7 +41,6 @@ implementation is a Groovy script. The following listing shows the `Messenger` i
|
||||
public interface Messenger {
|
||||
|
||||
String getMessage();
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -72,7 +62,6 @@ The following example defines a class that has a dependency on the `Messenger` i
|
||||
public void processBooking() {
|
||||
// use the injected Messenger object...
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -91,7 +80,6 @@ The following example implements the `Messenger` interface in Groovy:
|
||||
class GroovyMessenger implements Messenger {
|
||||
|
||||
String message
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -105,7 +93,7 @@ implementation is supported, but you have to manage the plumbing of the Spring i
|
||||
to do so.
|
||||
|
||||
For more information on schema-based configuration, see <<appendix.adoc#xsd-configuration,
|
||||
XML Schema-based configuration>>.
|
||||
XML Schema-based Configuration>>.
|
||||
====
|
||||
|
||||
Finally, the following example shows the bean definitions that effect the injection of the
|
||||
@@ -135,14 +123,14 @@ Groovy-defined `Messenger` implementation into an instance of the
|
||||
</beans>
|
||||
----
|
||||
|
||||
The `bookingService` bean (a `DefaultBookingService`) can now use its private
|
||||
`messenger` member variable as normal, because the `Messenger` instance that was injected
|
||||
into it is a `Messenger` instance. There is nothing special going on here -- just
|
||||
plain Java and plain Groovy.
|
||||
The `bookingService` bean (a `DefaultBookingService`) can now use its private `messenger`
|
||||
member variable as normal, because the `Messenger` instance that was injected into it is
|
||||
a `Messenger` instance. There is nothing special going on here -- just plain Java and
|
||||
plain Groovy.
|
||||
|
||||
Hopefully, the preceding XML snippet is self-explanatory, but do not worry unduly if it is not.
|
||||
Keep reading for the in-depth detail on the whys and wherefores of the preceding
|
||||
configuration.
|
||||
Keep reading for the in-depth detail on the whys and wherefores of the preceding configuration.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -152,11 +140,11 @@ configuration.
|
||||
This section describes exactly how you define Spring-managed beans in any of the
|
||||
supported dynamic languages.
|
||||
|
||||
Note that this chapter does not attempt to explain the syntax and idioms of the
|
||||
supported dynamic languages. For example, if you want to use Groovy to write certain of
|
||||
the classes in your application, we assume that you already know Groovy. If
|
||||
you need further details about the dynamic languages themselves, see
|
||||
<<dynamic-language-resources>> at the end of this chapter.
|
||||
Note that this chapter does not attempt to explain the syntax and idioms of the supported
|
||||
dynamic languages. For example, if you want to use Groovy to write certain of the classes
|
||||
in your application, we assume that you already know Groovy. If you need further details
|
||||
about the dynamic languages themselves, see <<dynamic-language-resources>> at the end of
|
||||
this chapter.
|
||||
|
||||
|
||||
|
||||
@@ -183,45 +171,43 @@ Spring's dynamic language support does make some (small) assumptions about the c
|
||||
of your dynamic language source files.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-concepts-xml-language-element]]
|
||||
==== The <lang:language/> element
|
||||
|
||||
The final step in the list in the <<dynamic-language-beans-concepts,preceding section>> involves defining dynamic-language-backed bean definitions, one for each
|
||||
bean that you want to configure (this is no different from normal JavaBean
|
||||
configuration). However, instead of specifying the fully qualified classname of the
|
||||
class that is to be instantiated and configured by the container, you can use the
|
||||
`<lang:language/>` element to define the dynamic language-backed bean.
|
||||
The final step in the list in the <<dynamic-language-beans-concepts, preceding section>>
|
||||
involves defining dynamic-language-backed bean definitions, one for each bean that you
|
||||
want to configure (this is no different from normal JavaBean configuration). However,
|
||||
instead of specifying the fully qualified classname of the class that is to be
|
||||
instantiated and configured by the container, you can use the `<lang:language/>`
|
||||
element to define the dynamic language-backed bean.
|
||||
|
||||
Each of the supported languages has a corresponding `<lang:language/>` element:
|
||||
|
||||
* `<lang:groovy/>` (Groovy)
|
||||
* `<lang:bsh/>` (BeanShell)
|
||||
* `<lang:std/>` (JSR-223)
|
||||
* `<lang:std/>` (JSR-223, e.g. with JRuby)
|
||||
|
||||
The exact attributes and child elements that are available for configuration depends on
|
||||
exactly which language the bean has been defined in (the language-specific sections
|
||||
later in this chapter detail this).
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-refreshable-beans]]
|
||||
==== Refreshable Beans
|
||||
|
||||
One of the (and perhaps the single) most compelling value adds of the dynamic language support
|
||||
in Spring is the "`refreshable bean`" feature.
|
||||
One of the (and perhaps the single) most compelling value adds of the dynamic language
|
||||
support in Spring is the "`refreshable bean`" feature.
|
||||
|
||||
A refreshable bean is a dynamic-language-backed bean. With a small amount of
|
||||
configuration, a dynamic-language-backed bean can monitor changes in its underlying
|
||||
source file resource and then reload itself when the dynamic language source file is
|
||||
changed (for example, when you edit and save changes to the file on the
|
||||
file system).
|
||||
changed (for example, when you edit and save changes to the file on the file system).
|
||||
|
||||
This lets you deploy any number of dynamic language source files as part of
|
||||
an application, configure the Spring container to create beans backed by dynamic
|
||||
This lets you deploy any number of dynamic language source files as part of an
|
||||
application, configure the Spring container to create beans backed by dynamic
|
||||
language source files (using the mechanisms described in this chapter), and (later,
|
||||
as requirements change or some other external factor comes into play) edit a
|
||||
dynamic language source file and have any change they make be reflected in the bean that is
|
||||
as requirements change or some other external factor comes into play) edit a dynamic
|
||||
language source file and have any change they make be reflected in the bean that is
|
||||
backed by the changed dynamic language source file. There is no need to shut down a
|
||||
running application (or redeploy in the case of a web application). The
|
||||
dynamic-language-backed bean so amended picks up the new state and logic from the
|
||||
@@ -230,11 +216,11 @@ changed dynamic language source file.
|
||||
NOTE: This feature is off by default.
|
||||
|
||||
Now we can take a look at an example to see how easy it is to start using refreshable
|
||||
beans. To turn on the refreshable beans feature, you have to specify exactly
|
||||
one additional attribute on the `<lang:language/>` element of your bean definition.
|
||||
So, if we stick with <<dynamic-language-a-first-example,the example>> from earlier in this
|
||||
chapter, the following example shows what we would change in the Spring XML configuration to effect
|
||||
refreshable beans:
|
||||
beans. To turn on the refreshable beans feature, you have to specify exactly one
|
||||
additional attribute on the `<lang:language/>` element of your bean definition. So,
|
||||
if we stick with <<dynamic-language-a-first-example, the example>> from earlier in
|
||||
this chapter, the following example shows what we would change in the Spring XML
|
||||
configuration to effect refreshable beans:
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -257,17 +243,17 @@ refreshable beans:
|
||||
|
||||
That really is all you have to do. The `refresh-check-delay` attribute defined on the
|
||||
`messenger` bean definition is the number of milliseconds after which the bean is
|
||||
refreshed with any changes made to the underlying dynamic language source file. You can
|
||||
turn off the refresh behavior by assigning a negative value to the
|
||||
refreshed with any changes made to the underlying dynamic language source file.
|
||||
You can turn off the refresh behavior by assigning a negative value to the
|
||||
`refresh-check-delay` attribute. Remember that, by default, the refresh behavior is
|
||||
disabled. If you do not want the refresh behavior, do not define the attribute.
|
||||
|
||||
If we then run the following application, we can exercise the refreshable feature (Please
|
||||
do excuse the "`jumping-through-hoops-to-pause-the-execution`" shenanigans in this
|
||||
next slice of code.) The `System.in.read()` call is only there so that the execution of
|
||||
the program pauses while you (the developer in this scenario) go off and edit the underlying dynamic language
|
||||
source file so that the refresh triggers on the dynamic-language-backed bean when
|
||||
the program resumes execution.
|
||||
If we then run the following application, we can exercise the refreshable feature.
|
||||
(Please excuse the "`jumping-through-hoops-to-pause-the-execution`" shenanigans
|
||||
in this next slice of code.) The `System.in.read()` call is only there so that the
|
||||
execution of the program pauses while you (the developer in this scenario) go off
|
||||
and edit the underlying dynamic language source file so that the refresh triggers
|
||||
on the dynamic-language-backed bean when the program resumes execution.
|
||||
|
||||
The following listing shows this sample application:
|
||||
|
||||
@@ -291,10 +277,11 @@ The following listing shows this sample application:
|
||||
}
|
||||
----
|
||||
|
||||
Assume then, for the purposes of this example, that all calls to the
|
||||
`getMessage()` method of `Messenger` implementations have to be changed such that the
|
||||
message is surrounded by quotation marks. The following listing shows the changes that you (the developer) should make to the
|
||||
`Messenger.groovy` source file when the execution of the program is paused:
|
||||
Assume then, for the purposes of this example, that all calls to the `getMessage()`
|
||||
method of `Messenger` implementations have to be changed such that the message is
|
||||
surrounded by quotation marks. The following listing shows the changes that you
|
||||
(the developer) should make to the `Messenger.groovy` source file when the
|
||||
execution of the program is paused:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -316,15 +303,14 @@ message is surrounded by quotation marks. The following listing shows the change
|
||||
}
|
||||
----
|
||||
|
||||
When the program runs, the output before the input pause will be `I Can Do The
|
||||
Frug`. After the change to the source file is made and saved and the program resumes
|
||||
execution, the result of calling the `getMessage()` method on the
|
||||
dynamic-language-backed `Messenger` implementation is `'I Can Do The Frug'`
|
||||
(notice the inclusion of the additional quotation marks).
|
||||
When the program runs, the output before the input pause will be `I Can Do The Frug`.
|
||||
After the change to the source file is made and saved and the program resumes execution,
|
||||
the result of calling the `getMessage()` method on the dynamic-language-backed
|
||||
`Messenger` implementation is `'I Can Do The Frug'` (notice the inclusion of the
|
||||
additional quotation marks).
|
||||
|
||||
Changes to a script do not trigger a refresh if
|
||||
the changes occur within the window of the `refresh-check-delay` value.
|
||||
Changes to the script are not actually picked up until
|
||||
Changes to a script do not trigger a refresh if the changes occur within the window of
|
||||
the `refresh-check-delay` value. Changes to the script are not actually picked up until
|
||||
a method is called on the dynamic-language-backed bean. It is only when a method is
|
||||
called on a dynamic-language-backed bean that it checks to see if its underlying script
|
||||
source has changed. Any exceptions that relate to refreshing the script (such as
|
||||
@@ -339,7 +325,6 @@ that checks the last modified date of a dynamic language source file that exists
|
||||
file system).
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-inline]]
|
||||
==== Inline Dynamic Language Source Files
|
||||
|
||||
@@ -376,7 +361,6 @@ work using inline source. (See <<dynamic-language-scenarios-validators>> for suc
|
||||
example.)
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-ctor-injection]]
|
||||
==== Understanding Constructor Injection in the Context of Dynamic-language-backed Beans
|
||||
|
||||
@@ -408,7 +392,6 @@ does not work:
|
||||
String message
|
||||
|
||||
String anotherMessage
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -438,17 +421,6 @@ injection is the injection style favored by the overwhelming majority of develop
|
||||
|
||||
This section describes how to use beans defined in Groovy in Spring.
|
||||
|
||||
.The Groovy library dependencies
|
||||
****
|
||||
|
||||
The Groovy scripting support in Spring requires the following libraries to be on the
|
||||
classpath of your application:
|
||||
|
||||
* `groovy-1.8.jar`
|
||||
* `asm-3.2.jar`
|
||||
* `antlr-2.7.7.jar`
|
||||
****
|
||||
|
||||
The Groovy homepage includes the following description:
|
||||
|
||||
"`Groovy is an agile dynamic language for the Java 2 Platform that has many of the
|
||||
@@ -456,7 +428,7 @@ features that people like so much in languages like Python, Ruby and Smalltalk,
|
||||
them available to Java developers using a Java-like syntax.`"
|
||||
|
||||
If you have read this chapter straight from the top, you have already
|
||||
<<dynamic-language-a-first-example,seen an example>> of a Groovy-dynamic-language-backed
|
||||
<<dynamic-language-a-first-example, seen an example>> of a Groovy-dynamic-language-backed
|
||||
bean. Now consider another example (again using an example from the Spring test suite):
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -467,7 +439,6 @@ bean. Now consider another example (again using an example from the Spring test
|
||||
public interface Calculator {
|
||||
|
||||
int add(int x, int y);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -484,7 +455,6 @@ The following example implements the `Calculator` interface in Groovy:
|
||||
int add(int x, int y) {
|
||||
x + y
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -520,15 +490,13 @@ Finally, the following small application exercises the preceding configuration:
|
||||
----
|
||||
|
||||
The resulting output from running the above program is (unsurprisingly) `10`.
|
||||
(For more interesting examples,
|
||||
see the dynamic language showcase project for a more complex example or see the examples
|
||||
<<dynamic-language-scenarios>> later in this chapter).
|
||||
|
||||
You must not define more than one class per Groovy source file.
|
||||
While this is perfectly legal in Groovy, it is (arguably) a bad practice. In the
|
||||
interests of a consistent approach, you should (in the opinion of the Spring team) respect
|
||||
the standard Java conventions of one (public) class per source file.
|
||||
(For more interesting examples, see the dynamic language showcase project for a more
|
||||
complex example or see the examples <<dynamic-language-scenarios>> later in this chapter).
|
||||
|
||||
You must not define more than one class per Groovy source file. While this is perfectly
|
||||
legal in Groovy, it is (arguably) a bad practice. In the interests of a consistent
|
||||
approach, you should (in the opinion of the Spring team) respect the standard Java
|
||||
conventions of one (public) class per source file.
|
||||
|
||||
|
||||
[[dynamic-language-beans-groovy-customizer]]
|
||||
@@ -549,11 +517,11 @@ shows the `GroovyObjectCustomizer` interface definition:
|
||||
}
|
||||
----
|
||||
|
||||
The Spring Framework instantiates an instance of your Groovy-backed bean and
|
||||
then passes the created `GroovyObject` to the specified `GroovyObjectCustomizer` (if one
|
||||
The Spring Framework instantiates an instance of your Groovy-backed bean and then
|
||||
passes the created `GroovyObject` to the specified `GroovyObjectCustomizer` (if one
|
||||
has been defined). You can do whatever you like with the supplied `GroovyObject`
|
||||
reference. We expect that most people want to set a custom `MetaClass` with this callback,
|
||||
and the following example shows how to do so:
|
||||
reference. We expect that most people want to set a custom `MetaClass` with this
|
||||
callback, and the following example shows how to do so:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -577,8 +545,8 @@ and the following example shows how to do so:
|
||||
|
||||
A full discussion of meta-programming in Groovy is beyond the scope of the Spring
|
||||
reference manual. See the relevant section of the Groovy reference manual or do a
|
||||
search online. Plenty of articles address this topic. Actually, making use
|
||||
of a `GroovyObjectCustomizer` is easy if you use the Spring namespace support, as the
|
||||
search online. Plenty of articles address this topic. Actually, making use of a
|
||||
`GroovyObjectCustomizer` is easy if you use the Spring namespace support, as the
|
||||
following example shows:
|
||||
|
||||
[source,xml,indent=0]
|
||||
@@ -621,15 +589,6 @@ in the same place as Spring's `GroovyObjectCustomizer`.
|
||||
|
||||
This section describes how to use BeanShell beans in Spring.
|
||||
|
||||
.The BeanShell library dependencies
|
||||
****
|
||||
|
||||
The BeanShell scripting support in Spring requires the following libraries to be on the
|
||||
classpath of your application:
|
||||
|
||||
* `bsh-2.0b4.jar`
|
||||
****
|
||||
|
||||
The BeanShell homepage includes the following description: {JB}
|
||||
|
||||
"`BeanShell is a small, free, embeddable Java source interpreter with dynamic language
|
||||
@@ -639,12 +598,12 @@ closures like those in Perl and JavaScript.`"
|
||||
|
||||
In contrast to Groovy, BeanShell-backed bean definitions require some (small) additional
|
||||
configuration. The implementation of the BeanShell dynamic language support in Spring is
|
||||
interesting, because Spring creates a JDK dynamic proxy
|
||||
that implements all of the interfaces that are specified in the `script-interfaces`
|
||||
attribute value of the `<lang:bsh>` element (this is why you must supply at least
|
||||
one interface in the value of the attribute, and, consequently, program to interfaces
|
||||
when you use BeanShell-backed beans). This means that every method call on a
|
||||
BeanShell-backed object goes through the JDK dynamic proxy invocation mechanism.
|
||||
interesting, because Spring creates a JDK dynamic proxy that implements all of the
|
||||
interfaces that are specified in the `script-interfaces` attribute value of the
|
||||
`<lang:bsh>` element (this is why you must supply at least one interface in the value
|
||||
of the attribute, and, consequently, program to interfaces when you use BeanShell-backed
|
||||
beans). This means that every method call on a BeanShell-backed object goes through the
|
||||
JDK dynamic proxy invocation mechanism.
|
||||
|
||||
Now we can show a fully working example of using a BeanShell-based bean that implements
|
||||
the `Messenger` interface that was defined earlier in this chapter. We again show the
|
||||
@@ -658,12 +617,11 @@ definition of the `Messenger` interface:
|
||||
public interface Messenger {
|
||||
|
||||
String getMessage();
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The following example shows the BeanShell "`implementation`" (we use the term loosely here) of the
|
||||
`Messenger` interface:
|
||||
The following example shows the BeanShell "`implementation`" (we use the term loosely here)
|
||||
of the `Messenger` interface:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -679,8 +637,8 @@ The following example shows the BeanShell "`implementation`" (we use the term lo
|
||||
}
|
||||
----
|
||||
|
||||
The following example shows the Spring XML that defines an "`instance`" of the above "`class`" (again,
|
||||
we use these terms very loosely here):
|
||||
The following example shows the Spring XML that defines an "`instance`" of the above
|
||||
"`class`" (again, we use these terms very loosely here):
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -697,12 +655,13 @@ BeanShell-based beans.
|
||||
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-scenarios]]
|
||||
== Scenarios
|
||||
|
||||
The possible scenarios where defining Spring managed beans in a scripting language would
|
||||
be beneficial are many and varied. This section describes two possible use
|
||||
cases for the dynamic language support in Spring.
|
||||
be beneficial are many and varied. This section describes two possible use cases for the
|
||||
dynamic language support in Spring.
|
||||
|
||||
|
||||
|
||||
@@ -755,7 +714,6 @@ by using the Groovy dynamic language:
|
||||
HttpServletResponse httpServletResponse) {
|
||||
return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune())
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -784,13 +742,12 @@ validation logic by editing and saving a simple text file. Any such changes is
|
||||
(depending on the configuration) automatically reflected in the execution of a
|
||||
running application and would not require the restart of an application.
|
||||
|
||||
NOTE: To effect the automatic "`pickup`" of any changes to
|
||||
dynamic-language-backed beans, you have to enable the 'refreshable beans'
|
||||
feature. See <<dynamic-language-refreshable-beans>> for a full and detailed treatment of
|
||||
this feature.
|
||||
NOTE: To effect the automatic "`pickup`" of any changes to dynamic-language-backed
|
||||
beans, you have to enable the 'refreshable beans' feature. See
|
||||
<<dynamic-language-refreshable-beans>> for a full and detailed treatment of this feature.
|
||||
|
||||
The following example shows a Spring `org.springframework.validation.Validator` implemented
|
||||
by using the Groovy dynamic language (see <<core.adoc#validator,
|
||||
The following example shows a Spring `org.springframework.validation.Validator`
|
||||
implemented by using the Groovy dynamic language (see <<core.adoc#validator,
|
||||
Validation using Spring’s Validator interface>> for a discussion of the
|
||||
`Validator` interface):
|
||||
|
||||
@@ -813,12 +770,12 @@ Validation using Spring’s Validator interface>> for a discussion of the
|
||||
}
|
||||
errors.reject("whitespace", "Cannot be composed wholly of whitespace.")
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-final-notes]]
|
||||
== Additional Details
|
||||
|
||||
@@ -832,14 +789,12 @@ This last section contains some additional details related to the dynamic langua
|
||||
You can use the Spring AOP framework to advise scripted beans. The Spring AOP
|
||||
framework actually is unaware that a bean that is being advised might be a scripted
|
||||
bean, so all of the AOP use cases and functionality that you use (or aim to use)
|
||||
work with scripted beans.
|
||||
When you advise scripted beans, you cannot use class-based proxies. You must
|
||||
use <<core.adoc#aop-proxying,interface-based proxies>>.
|
||||
work with scripted beans. When you advise scripted beans, you cannot use class-based
|
||||
proxies. You must use <<core.adoc#aop-proxying, interface-based proxies>>.
|
||||
|
||||
You are not limited to advising scripted beans. You can also write
|
||||
aspects themselves in a supported dynamic language and use such beans to advise other
|
||||
Spring beans. This really would be an advanced use of the dynamic language support
|
||||
though.
|
||||
You are not limited to advising scripted beans. You can also write aspects themselves
|
||||
in a supported dynamic language and use such beans to advise other Spring beans.
|
||||
This really would be an advanced use of the dynamic language support though.
|
||||
|
||||
|
||||
|
||||
@@ -849,11 +804,11 @@ though.
|
||||
In case it is not immediately obvious, scripted beans can be scoped in the same way as
|
||||
any other bean. The `scope` attribute on the various `<lang:language/>` elements lets
|
||||
you control the scope of the underlying scripted bean, as it does with a regular
|
||||
bean. (The default scope is <<core.adoc#beans-factory-scopes-singleton,singleton>>, as it is
|
||||
with "`regular`" beans.)
|
||||
bean. (The default scope is <<core.adoc#beans-factory-scopes-singleton, singleton>>,
|
||||
as it is with "`regular`" beans.)
|
||||
|
||||
The following example uses the `scope` attribute to define a Groovy bean scoped as
|
||||
a <<core.adoc#beans-factory-scopes-prototype,prototype>>:
|
||||
a <<core.adoc#beans-factory-scopes-prototype, prototype>>:
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -876,26 +831,24 @@ a <<core.adoc#beans-factory-scopes-prototype,prototype>>:
|
||||
</beans>
|
||||
----
|
||||
|
||||
See <<core.adoc#beans-factory-scopes,Bean scopes>> in <<core.adoc#beans,The IoC container>>
|
||||
See <<core.adoc#beans-factory-scopes, Bean Scopes>> in <<core.adoc#beans, The IoC Container>>
|
||||
for a full discussion of the scoping support in the Spring Framework.
|
||||
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-lang]]
|
||||
=== The `lang` XML schema
|
||||
|
||||
The `lang` elements in Spring XML configuration deal with exposing objects that have been written
|
||||
in a dynamic language (such as JRuby or Groovy) as beans in the Spring container.
|
||||
The `lang` elements in Spring XML configuration deal with exposing objects that have been
|
||||
written in a dynamic language (such as Groovy or BeanShell) as beans in the Spring container.
|
||||
|
||||
These elements (and the dynamic language support) are comprehensively covered in
|
||||
<<integration.adoc#dynamic-language,Dynamic language support>>.
|
||||
See that chapter for full details on this support and the `lang` elements.
|
||||
<<integration.adoc#dynamic-language, Dynamic Language Support>>. See that chapter
|
||||
for full details on this support and the `lang` elements.
|
||||
|
||||
To use the elements in the `lang` schema, you need to have
|
||||
the following preamble at the top of your Spring XML configuration file. The text in the
|
||||
following snippet references the correct schema so that the tags in the `lang` namespace
|
||||
are available to you:
|
||||
To use the elements in the `lang` schema, you need to have the following preamble at the
|
||||
top of your Spring XML configuration file. The text in the following snippet references
|
||||
the correct schema so that the tags in the `lang` namespace are available to you:
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -914,12 +867,13 @@ are available to you:
|
||||
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-resources]]
|
||||
== Further Resources
|
||||
|
||||
The following links go to further resources about the various dynamic languages described in
|
||||
this chapter:
|
||||
The following links go to further resources about the various dynamic languages referenced
|
||||
in this chapter:
|
||||
|
||||
* The http://jruby.org/[JRuby] homepage
|
||||
* The http://www.groovy-lang.org/[Groovy] homepage
|
||||
* The http://www.beanshell.org/[BeanShell] homepage
|
||||
* The http://jruby.org/[JRuby] homepage
|
||||
|
||||
@@ -7,7 +7,7 @@ existing Java application.
|
||||
|
||||
The Spring Framework provides a dedicated `ApplicationContext` that supports a Groovy-based
|
||||
Bean Definition DSL. For more details, see
|
||||
<<core.adoc#groovy-bean-definition-dsl,The Groovy Bean Definition DSL>>.
|
||||
<<core.adoc#groovy-bean-definition-dsl, The Groovy Bean Definition DSL>>.
|
||||
|
||||
Further support for Groovy, including beans written in Groovy, refreshable script beans,
|
||||
and more is available in <<dynamic-language>>.
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
[[kotlin]]
|
||||
= Kotlin
|
||||
|
||||
https://kotlinlang.org[Kotlin] is a statically typed language that targets the JVM (and other platforms),
|
||||
which allows writing concise and elegant code while providing very good
|
||||
https://kotlinlang.org/docs/reference/java-interop.html[interoperability] with
|
||||
existing libraries written in Java.
|
||||
https://kotlinlang.org[Kotlin] is a statically typed language that targets the JVM
|
||||
(and other platforms), which allows writing concise and elegant code while providing
|
||||
very good https://kotlinlang.org/docs/reference/java-interop.html[interoperability]
|
||||
with existing libraries written in Java.
|
||||
|
||||
The Spring Framework provides first-class support for Kotlin that lets developers write
|
||||
Kotlin applications almost as if the Spring Framework were a native Kotlin framework.
|
||||
|
||||
The easiest way to learn about Spring and Kotlin is to follow
|
||||
https://spring.io/guides/tutorials/spring-boot-kotlin/[this comprehensive tutorial]. Feel
|
||||
free to join the #spring channel of http://slack.kotlinlang.org/[Kotlin Slack] or ask a
|
||||
question with `spring` and `kotlin` as tags on
|
||||
https://spring.io/guides/tutorials/spring-boot-kotlin/[this comprehensive tutorial].
|
||||
Feel free to join the #spring channel of http://slack.kotlinlang.org/[Kotlin Slack]
|
||||
or ask a question with `spring` and `kotlin` as tags on
|
||||
https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-requirements]]
|
||||
== Requirements
|
||||
|
||||
The Spring Framework supports Kotlin 1.3+ and requires
|
||||
Spring Framework 5.2 supports Kotlin 1.3+ and requires
|
||||
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib[`kotlin-stdlib`]
|
||||
(or one of its variants, such as
|
||||
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`])
|
||||
(or one of its variants, such as https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]
|
||||
or https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`])
|
||||
and https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-reflect[`kotlin-reflect`]
|
||||
to be present on the classpath. They are provided by default if you bootstrap a Kotlin project on
|
||||
https://start.spring.io/#!language=kotlin[start.spring.io].
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-extensions]]
|
||||
== Extensions
|
||||
|
||||
@@ -75,6 +77,7 @@ for shorter syntax.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-null-safety]]
|
||||
== Null-safety
|
||||
|
||||
@@ -86,7 +89,7 @@ declarations and expressing "`value or no value`" semantics without paying the c
|
||||
http://www.baeldung.com/kotlin-null-safety[comprehensive guide to Kotlin null-safety].)
|
||||
|
||||
Although Java does not let you express null-safety in its type-system, the Spring Framework
|
||||
provides <<core#null-safety,null-safety of the whole Spring Framework API>>
|
||||
provides <<core#null-safety, null-safety of the whole Spring Framework API>>
|
||||
via tooling-friendly annotations declared in the `org.springframework.lang` package.
|
||||
By default, types from Java APIs used in Kotlin are recognized as
|
||||
https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types],
|
||||
@@ -112,6 +115,7 @@ for up-to-date information.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-classes-interfaces]]
|
||||
== Classes and Interfaces
|
||||
|
||||
@@ -134,6 +138,7 @@ since the later requires a reference to the outer class.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-annotations]]
|
||||
== Annotations
|
||||
|
||||
@@ -162,6 +167,7 @@ https://stackoverflow.com/a/35853200/1092077[this Stack Overflow response].
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-bean-definition-dsl]]
|
||||
== Bean Definition DSL
|
||||
|
||||
@@ -251,11 +257,12 @@ for more details and up-to-date information.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-web]]
|
||||
== Web
|
||||
|
||||
|
||||
=== WebFlux router DSL
|
||||
=== WebFlux Router DSL
|
||||
|
||||
Spring Framework comes with a Kotlin router DSL available in 2 flavors:
|
||||
|
||||
@@ -292,6 +299,8 @@ depending on dynamic data (for example, from a database).
|
||||
See https://github.com/mixitconf/mixit/tree/dafd5ccc92dfab6d9c306fcb60b28921a1ccbf79/src/main/kotlin/mixit/web/routes[MiXiT project routes]
|
||||
for a concrete example.
|
||||
|
||||
|
||||
|
||||
=== Coroutines
|
||||
|
||||
As of Spring Framework 5.2, https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] support
|
||||
@@ -326,6 +335,8 @@ class UserHandler(builder: WebClient.Builder) {
|
||||
Read this blog post about https://medium.com/@elizarov/structured-concurrency-722d765aa952[structured concurrency]
|
||||
to understand how to run code concurrently with Coroutines.
|
||||
|
||||
|
||||
|
||||
=== MockMvc DSL
|
||||
|
||||
A Kotlin DSL is provided via `MockMvc` Kotlin extensions in order to provide a more idiomatic Kotlin API and to allow
|
||||
@@ -351,6 +362,8 @@ mockMvc.get("/person/{name}", "Lee") {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Kotlin Script Templates
|
||||
|
||||
As of version 4.3, Spring Framework provides a
|
||||
@@ -391,27 +404,27 @@ See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templ
|
||||
project for more details.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-spring-projects-in-kotlin]]
|
||||
== Spring Projects in Kotlin
|
||||
|
||||
This section provides some specific hints and recommendations worth
|
||||
for developing Spring projects in Kotlin.
|
||||
This section provides some specific hints and recommendations worth for developing Spring projects
|
||||
in Kotlin.
|
||||
|
||||
|
||||
|
||||
=== Final by Default
|
||||
|
||||
By default, https://discuss.kotlinlang.org/t/classes-final-by-default/166[all classes in Kotlin are `final`].
|
||||
The `open` modifier on a class is the opposite of Java's `final`: It allows others to
|
||||
inherit from this class. This also applies to member functions, in that they need to be marked as `open` to
|
||||
be overridden.
|
||||
The `open` modifier on a class is the opposite of Java's `final`: It allows others to inherit from this
|
||||
class. This also applies to member functions, in that they need to be marked as `open` to be overridden.
|
||||
|
||||
While Kotlin's JVM-friendly design is generally frictionless with Spring,
|
||||
this specific Kotlin feature can prevent the application from starting, if this fact is not taken into
|
||||
consideration. This is because Spring beans
|
||||
(such as `@Configuration` classes which need to be inherited at runtime for technical reasons) are normally proxied by CGLIB.
|
||||
The workaround was to add an `open` keyword on each class and member
|
||||
function of Spring beans that are proxied by CGLIB (such as `@Configuration` classes), which can
|
||||
While Kotlin's JVM-friendly design is generally frictionless with Spring, this specific Kotlin feature
|
||||
can prevent the application from starting, if this fact is not taken into consideration. This is because
|
||||
Spring beans (such as `@Configuration` classes which need to be inherited at runtime for technical
|
||||
reasons) are normally proxied by CGLIB. The workaround was to add an `open` keyword on each class and
|
||||
member function of Spring beans that are proxied by CGLIB (such as `@Configuration` classes), which can
|
||||
quickly become painful and is against the Kotlin principle of keeping code concise and predictable.
|
||||
|
||||
Fortunately, Kotlin now provides a
|
||||
@@ -474,15 +487,16 @@ the https://kotlinlang.org/docs/reference/compiler-plugins.html#how-to-use-no-ar
|
||||
plugin.
|
||||
|
||||
NOTE: As of the Kay release train, Spring Data supports Kotlin immutable class instances and
|
||||
does not require the `kotlin-noarg` plugin if the module uses Spring Data object
|
||||
mappings (such as MongoDB, Redis, Cassandra, and others).
|
||||
does not require the `kotlin-noarg` plugin if the module uses Spring Data object mappings
|
||||
(such as MongoDB, Redis, Cassandra, and others).
|
||||
|
||||
|
||||
|
||||
=== Injecting Dependencies
|
||||
|
||||
Our recommendation is to try and favor constructor injection with `val` read-only (and non-nullable when possible)
|
||||
https://kotlinlang.org/docs/reference/properties.html[properties], as the following example shows:
|
||||
Our recommendation is to try and favor constructor injection with `val` read-only (and
|
||||
non-nullable when possible) https://kotlinlang.org/docs/reference/properties.html[properties],
|
||||
as the following example shows:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@@ -493,9 +507,9 @@ https://kotlinlang.org/docs/reference/properties.html[properties], as the follow
|
||||
)
|
||||
----
|
||||
|
||||
NOTE: As of Spring Framework 4.3, classes with a single constructor have their
|
||||
parameters automatically autowired, that's why there is no need for an
|
||||
explicit `@Autowired constructor` in the example shown above.
|
||||
NOTE: As of Spring Framework 4.3, classes with a single constructor have their parameters
|
||||
automatically autowired, that's why there is no need for an explicit `@Autowired constructor`
|
||||
in the example shown above.
|
||||
|
||||
If you really need to use field injection, you can use the `lateinit var` construct,
|
||||
as the following example shows:
|
||||
@@ -518,13 +532,14 @@ as the following example shows:
|
||||
=== Injecting Configuration Properties
|
||||
|
||||
In Java, you can inject configuration properties by using annotations (such as `@Value("${property}")`).
|
||||
However, in Kotlin, `$` is a reserved character that is used for https://kotlinlang.org/docs/reference/idioms.html#string-interpolation[string interpolation].
|
||||
However, in Kotlin, `$` is a reserved character that is used for
|
||||
https://kotlinlang.org/docs/reference/idioms.html#string-interpolation[string interpolation].
|
||||
|
||||
Therefore, if you wish to use the `@Value` annotation in Kotlin, you need to escape the `$`
|
||||
character by writing `@Value("\${property}")`.
|
||||
|
||||
As an alternative, you can customize the properties placeholder prefix by declaring
|
||||
the following configuration beans:
|
||||
As an alternative, you can customize the properties placeholder prefix by declaring the
|
||||
following configuration beans:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@@ -534,8 +549,8 @@ the following configuration beans:
|
||||
}
|
||||
----
|
||||
|
||||
You can customize existing code (such as Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax,
|
||||
with configuration beans, as the following example shows:
|
||||
You can customize existing code (such as Spring Boot actuators or `@LocalServerPort`)
|
||||
that uses the `${...}` syntax, with configuration beans, as the following example shows:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@@ -551,35 +566,38 @@ with configuration beans, as the following example shows:
|
||||
|
||||
NOTE: If you use Spring Boot, you can use
|
||||
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties[`@ConfigurationProperties`]
|
||||
instead of `@Value` annotations. However, currently, this only works with `lateinit` or nullable `var`
|
||||
properties (we recommended the former), since immutable classes initialized by
|
||||
constructors are not yet supported.
|
||||
See these issues about https://github.com/spring-projects/spring-boot/issues/8762[`@ConfigurationProperties` binding for immutable POJOs]
|
||||
instead of `@Value` annotations. However, currently, this only works with `lateinit` or
|
||||
nullable `var` properties (we recommended the former), since immutable classes initialized
|
||||
by constructors are not yet supported. See these issues about
|
||||
https://github.com/spring-projects/spring-boot/issues/8762[`@ConfigurationProperties` binding for immutable POJOs]
|
||||
and https://github.com/spring-projects/spring-boot/issues/1254[`@ConfigurationProperties` binding on interfaces]
|
||||
for more details.
|
||||
|
||||
|
||||
|
||||
=== Checked Exceptions
|
||||
|
||||
Java and https://kotlinlang.org/docs/reference/exceptions.html[Kotlin exception handling] are pretty close, with the main
|
||||
difference being that Kotlin treats all exceptions as unchecked exceptions. However, when using proxied objects
|
||||
(for example classes or methods annotated with `@Transactional`), checked exceptions thrown will be wrapped by default in
|
||||
Java and https://kotlinlang.org/docs/reference/exceptions.html[Kotlin exception handling]
|
||||
are pretty close, with the main difference being that Kotlin treats all exceptions as
|
||||
unchecked exceptions. However, when using proxied objects (for example classes or methods
|
||||
annotated with `@Transactional`), checked exceptions thrown will be wrapped by default in
|
||||
an `UndeclaredThrowableException`.
|
||||
|
||||
To get the original exception thrown like in Java, methods should be annotated with https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html[`@Throws`]
|
||||
To get the original exception thrown like in Java, methods should be annotated with
|
||||
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html[`@Throws`]
|
||||
to specify explicitly the checked exceptions thrown (for example `@Throws(IOException::class)`).
|
||||
|
||||
|
||||
|
||||
=== Annotation Array Attributes
|
||||
|
||||
Kotlin annotations are mostly similar to Java annotations, but array attributes (which are
|
||||
extensively used in Spring) behave differently. As explained in
|
||||
https://kotlinlang.org/docs/reference/annotations.html[Kotlin documentation]
|
||||
you can omit the `value` attribute name, unlike other attributes, and
|
||||
specify it as a `vararg` parameter.
|
||||
https://kotlinlang.org/docs/reference/annotations.html[Kotlin documentation] you can omit
|
||||
the `value` attribute name, unlike other attributes, and specify it as a `vararg` parameter.
|
||||
|
||||
To understand what that means, consider `@RequestMapping` (which is one
|
||||
of the most widely used Spring annotations) as an example. This Java annotation is declared as follows:
|
||||
To understand what that means, consider `@RequestMapping` (which is one of the most widely
|
||||
used Spring annotations) as an example. This Java annotation is declared as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@@ -598,14 +616,14 @@ of the most widely used Spring annotations) as an example. This Java annotation
|
||||
----
|
||||
|
||||
The typical use case for `@RequestMapping` is to map a handler method to a specific path
|
||||
and method. In Java, you can specify a single value for the
|
||||
annotation array attribute, and it is automatically converted to an array.
|
||||
and method. In Java, you can specify a single value for the annotation array attribute,
|
||||
and it is automatically converted to an array.
|
||||
|
||||
That is why one can write
|
||||
`@RequestMapping(value = "/toys", method = RequestMethod.GET)` or
|
||||
`@RequestMapping(path = "/toys", method = RequestMethod.GET)`.
|
||||
|
||||
However, in Kotlin 1.2+, you must write `@RequestMapping("/toys", method = [RequestMethod.GET])`
|
||||
However, in Kotlin, you must write `@RequestMapping("/toys", method = [RequestMethod.GET])`
|
||||
or `@RequestMapping(path = ["/toys"], method = [RequestMethod.GET])` (square brackets need
|
||||
to be specified with named array attributes).
|
||||
|
||||
@@ -619,14 +637,16 @@ all HTTP methods will be matched, not only the `GET` one.
|
||||
|
||||
=== Testing
|
||||
|
||||
This section addresses testing with the combination of Kotlin and Spring Framework. The recommended testing framework
|
||||
is https://junit.org/junit5/[JUnit 5], as well as https://mockk.io/[Mockk] for mocking.
|
||||
This section addresses testing with the combination of Kotlin and Spring Framework.
|
||||
The recommended testing framework is https://junit.org/junit5/[JUnit 5], as well as
|
||||
https://mockk.io/[Mockk] for mocking.
|
||||
|
||||
|
||||
==== Constructor injection
|
||||
|
||||
As described in the <<testing#testcontext-junit-jupiter-di#spring-web-reactive,dedicated section>>, JUnit 5 allows
|
||||
constructor injection of beans which is pretty useful with Kotlin in order to use `val` instead of `lateinit var`.
|
||||
As described in the <<testing#testcontext-junit-jupiter-di#spring-web-reactive, dedicated section>>,
|
||||
JUnit 5 allows constructor injection of beans which is pretty useful with Kotlin
|
||||
in order to use `val` instead of `lateinit var`.
|
||||
|
||||
|
||||
====
|
||||
@@ -661,12 +681,11 @@ class OrderServiceIntegrationTests @Autowired constructor(
|
||||
|
||||
Kotlin lets you specify meaningful test function names between backticks (```).
|
||||
As of JUnit 5, Kotlin test classes can use the `@TestInstance(TestInstance.Lifecycle.PER_CLASS)`
|
||||
annotation to enable a single instantiation of test classes, which allows the use of `@BeforeAll` and `@AfterAll`
|
||||
annotations on non-static methods, which is a good fit for Kotlin.
|
||||
annotation to enable a single instantiation of test classes, which allows the use of `@BeforeAll`
|
||||
and `@AfterAll` annotations on non-static methods, which is a good fit for Kotlin.
|
||||
|
||||
You can also change the default behavior to `PER_CLASS` thanks to a
|
||||
`junit-platform.properties` file with a
|
||||
`junit.jupiter.testinstance.lifecycle.default = per_class` property.
|
||||
You can also change the default behavior to `PER_CLASS` thanks to a `junit-platform.properties`
|
||||
file with a `junit.jupiter.testinstance.lifecycle.default = per_class` property.
|
||||
|
||||
The following example demonstrates `@BeforeAll` and `@AfterAll` annotations on non-static methods:
|
||||
|
||||
@@ -701,7 +720,6 @@ class IntegrationTests {
|
||||
----
|
||||
|
||||
|
||||
|
||||
==== Specification-like Tests
|
||||
|
||||
You can create specification-like tests with JUnit 5 and Kotlin.
|
||||
@@ -732,18 +750,18 @@ class SpecificationLikeTests {
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[kotlin-webtestclient-issue]]
|
||||
==== `WebTestClient` Type Inference Issue in Kotlin
|
||||
|
||||
Due to a https://youtrack.jetbrains.com/issue/KT-5464[type inference issue], you must
|
||||
use the Kotlin `expectBody` extension (such as `.expectBody<String>().isEqualTo("toys")`), since it
|
||||
provides a workaround for the Kotlin issue with the Java API.
|
||||
use the Kotlin `expectBody` extension (such as `.expectBody<String>().isEqualTo("toys")`),
|
||||
since it provides a workaround for the Kotlin issue with the Java API.
|
||||
|
||||
See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-getting-started]]
|
||||
== Getting Started
|
||||
|
||||
@@ -751,16 +769,18 @@ The easiest way to learn how to build a Spring application with Kotlin is to fol
|
||||
https://spring.io/guides/tutorials/spring-boot-kotlin/[the dedicated tutorial].
|
||||
|
||||
|
||||
|
||||
=== `start.spring.io`
|
||||
|
||||
The easiest way to start a new Spring Framework 5 project in Kotlin is to create a new Spring
|
||||
Boot 2 project on https://start.spring.io/#!language=kotlin[start.spring.io].
|
||||
|
||||
|
||||
|
||||
=== Choosing the Web Flavor
|
||||
|
||||
Spring Framework now comes with two different web stacks: <<web#mvc,Spring MVC>> and
|
||||
<<web-reactive#spring-web-reactive,Spring WebFlux>>.
|
||||
Spring Framework now comes with two different web stacks: <<web#mvc, Spring MVC>> and
|
||||
<<web-reactive#spring-web-reactive, Spring WebFlux>>.
|
||||
|
||||
Spring WebFlux is recommended if you want to create applications that will deal with latency,
|
||||
long-lived connections, streaming scenarios or if you want to use the web functional
|
||||
@@ -771,6 +791,7 @@ MVC and its annotation-based programming model is the recommended choice.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-resources]]
|
||||
== Resources
|
||||
|
||||
@@ -785,6 +806,7 @@ Kotlin and the Spring Framework:
|
||||
* https://kotlin.link/[Awesome Kotlin]
|
||||
|
||||
|
||||
|
||||
=== Examples
|
||||
|
||||
The following Github projects offer examples that you can learn from and possibly even extend:
|
||||
@@ -819,4 +841,3 @@ The following list categorizes the pending issues related to Spring and Kotlin s
|
||||
** https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function]
|
||||
** https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables]
|
||||
** https://youtrack.jetbrains.com/issue/KT-6653[Kotlin properties do not override Java-style getters and setters]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user