Editing pass for the integration and languages chapters.
I edited for spelling, puncutation, grammar, usage, and corporate voice. I also added a bunch of cross-references and links to the Javadoc. I also corrected the rendering problems that I had accidentally created in previous commits (because I was adjusting headings and adding callouts to listings.
This commit is contained in:
committed by
Juergen Hoeller
parent
45ecfc6df9
commit
6d226326c9
@@ -6805,12 +6805,13 @@ preamble of the XML configuration file. The following example shows how to do so
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:oxm="http://www.springframework.org/schema/oxm"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <1>
|
||||
xmlns:oxm="http://www.springframework.org/schema/oxm" <1>
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <2>
|
||||
----
|
||||
<1> Reference the `oxm` schema.
|
||||
<2> Specify the `oxm` schema location.
|
||||
====
|
||||
|
||||
Currently, the schema makes the following elements available:
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
= Appendix
|
||||
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas]]
|
||||
== XML Schemas
|
||||
|
||||
@@ -11,15 +9,16 @@ This part of the appendix lists XML schemas related to integration technologies.
|
||||
|
||||
|
||||
[[xsd-schemas-jee]]
|
||||
=== The jee schema
|
||||
=== The `jee` Schema
|
||||
|
||||
The `jee` tags deal with Java EE (Java Enterprise Edition)-related configuration issues,
|
||||
The `jee` elements deal with issues related to Java EE (Java Enterprise Edition) configuration,
|
||||
such as looking up a JNDI object and defining EJB references.
|
||||
|
||||
To use the tags in the `jee` 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 `jee` namespace are available to you.
|
||||
To use the elements in the `jee` 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 elements in the `jee` namespace are available to you:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -28,17 +27,22 @@ correct schema so that the tags in the `jee` namespace are available to you.
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
__xmlns:jee="http://www.springframework.org/schema/jee"__ xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
__http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__> <!-- bean definitions here -->
|
||||
__http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__>
|
||||
<!-- bean definitions here -->
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-jee-jndi-lookup]]
|
||||
==== <jee:jndi-lookup/> (simple)
|
||||
|
||||
Before...
|
||||
The following example shows how to use JNDI to look up a data source without the `jee`
|
||||
schema:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -50,9 +54,12 @@ Before...
|
||||
<property name="dataSource" ref="**dataSource**"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to use JNDI to look up a data source with the `jee`
|
||||
schema:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -63,13 +70,17 @@ After...
|
||||
<property name="dataSource" ref="**dataSource**"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-jee-jndi-lookup-environment-single]]
|
||||
==== <jee:jndi-lookup/> (with single JNDI environment setting)
|
||||
==== `<jee:jndi-lookup/>` (with Single JNDI Environment Setting)
|
||||
|
||||
Before...
|
||||
The following example shows how to use JNDI to look up an environment variable without
|
||||
`jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -77,62 +88,71 @@ Before...
|
||||
<property name="jndiName" value="jdbc/MyDataSource"/>
|
||||
<property name="jndiEnvironment">
|
||||
<props>
|
||||
<prop key="foo">bar</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
|
||||
After...
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
|
||||
<jee:environment>foo=bar</jee:environment>
|
||||
</jee:jndi-lookup>
|
||||
----
|
||||
|
||||
|
||||
[[xsd-schemas-jee-jndi-lookup-evironment-multiple]]
|
||||
==== <jee:jndi-lookup/> (with multiple JNDI environment settings)
|
||||
|
||||
Before...
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="simple" class="org.springframework.jndi.JndiObjectFactoryBean">
|
||||
<property name="jndiName" value="jdbc/MyDataSource"/>
|
||||
<property name="jndiEnvironment">
|
||||
<props>
|
||||
<prop key="foo">bar</prop>
|
||||
<prop key="ping">pong</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to use JNDI to look up an environment variable with `jee`:
|
||||
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
|
||||
<jee:environment>ping=pong</jee:environment>
|
||||
</jee:jndi-lookup>
|
||||
----
|
||||
|
||||
|
||||
[[xsd-schemas-jee-jndi-lookup-evironment-multiple]]
|
||||
==== `<jee:jndi-lookup/>` (with Multiple JNDI Environment Settings)
|
||||
|
||||
The following example shows how to use JNDI to look up multiple environment variables
|
||||
without `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="simple" class="org.springframework.jndi.JndiObjectFactoryBean">
|
||||
<property name="jndiName" value="jdbc/MyDataSource"/>
|
||||
<property name="jndiEnvironment">
|
||||
<props>
|
||||
<prop key="sing">song</prop>
|
||||
<prop key="ping">pong</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
The following example shows how to use JNDI to look up multiple environment variables with
|
||||
`jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
|
||||
<!-- newline-separated, key-value pairs for the environment (standard Properties format) -->
|
||||
<jee:environment>
|
||||
foo=bar
|
||||
sing=song
|
||||
ping=pong
|
||||
</jee:environment>
|
||||
</jee:jndi-lookup>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[xsd-schemas-jee-jndi-lookup-complex]]
|
||||
==== <jee:jndi-lookup/> (complex)
|
||||
==== `<jee:jndi-lookup/>` (Complex)
|
||||
|
||||
Before...
|
||||
The following example shows how to use JNDI to look up a data source and a number of
|
||||
different properties without `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -141,13 +161,16 @@ Before...
|
||||
<property name="cache" value="true"/>
|
||||
<property name="resourceRef" value="true"/>
|
||||
<property name="lookupOnStartup" value="false"/>
|
||||
<property name="expectedType" value="com.myapp.DefaultFoo"/>
|
||||
<property name="proxyInterface" value="com.myapp.Foo"/>
|
||||
<property name="expectedType" value="com.myapp.DefaultThing"/>
|
||||
<property name="proxyInterface" value="com.myapp.Thing"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to use JNDI to look up a data source and a number of
|
||||
different properties with `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -156,18 +179,22 @@ After...
|
||||
cache="true"
|
||||
resource-ref="true"
|
||||
lookup-on-startup="false"
|
||||
expected-type="com.myapp.DefaultFoo"
|
||||
proxy-interface="com.myapp.Foo"/>
|
||||
expected-type="com.myapp.DefaultThing"
|
||||
proxy-interface="com.myapp.Thing"/>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-jee-local-slsb]]
|
||||
==== <jee:local-slsb/> (simple)
|
||||
==== `<jee:local-slsb/>` (Simple)
|
||||
|
||||
The `<jee:local-slsb/>` tag configures a reference to an EJB Stateless SessionBean.
|
||||
The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless SessionBean.
|
||||
|
||||
Before...
|
||||
The following example shows how to configures a reference to a local EJB Stateless
|
||||
SessionBean without `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -177,35 +204,49 @@ Before...
|
||||
<property name="businessInterface" value="com.foo.service.RentalService"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to configures a reference to a local EJB Stateless
|
||||
SessionBean with `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<jee:local-slsb id="simpleSlsb" jndi-name="ejb/RentalServiceBean"
|
||||
business-interface="com.foo.service.RentalService"/>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-jee-local-slsb-complex]]
|
||||
==== <jee:local-slsb/> (complex)
|
||||
==== `<jee:local-slsb/>` (Complex)
|
||||
|
||||
The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless SessionBean.
|
||||
|
||||
The following example shows how to configures a reference to a local EJB Stateless
|
||||
SessionBean and a number of properties without `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="complexLocalEjb"
|
||||
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
|
||||
<property name="jndiName" value="ejb/RentalServiceBean"/>
|
||||
<property name="businessInterface" value="com.foo.service.RentalService"/>
|
||||
<property name="businessInterface" value="com.example.service.RentalService"/>
|
||||
<property name="cacheHome" value="true"/>
|
||||
<property name="lookupHomeOnStartup" value="true"/>
|
||||
<property name="resourceRef" value="true"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to configures a reference to a local EJB Stateless
|
||||
SessionBean and a number of properties with `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -216,16 +257,19 @@ After...
|
||||
lookup-home-on-startup="true"
|
||||
resource-ref="true">
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[xsd-schemas-jee-remote-slsb]]
|
||||
==== <jee:remote-slsb/>
|
||||
|
||||
The `<jee:remote-slsb/>` tag configures a reference to a `remote` EJB Stateless
|
||||
The `<jee:remote-slsb/>` element configures a reference to a `remote` EJB Stateless
|
||||
SessionBean.
|
||||
|
||||
Before...
|
||||
The following example shows how to configures a reference to a remote EJB Stateless
|
||||
SessionBean without `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -240,9 +284,12 @@ Before...
|
||||
<property name="refreshHomeOnConnectFailure" value="true"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
|
||||
After...
|
||||
The following example shows how to configures a reference to a remote EJB Stateless
|
||||
SessionBean with `jee`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -255,24 +302,25 @@ After...
|
||||
home-interface="com.foo.service.RentalService"
|
||||
refresh-home-on-connect-failure="true">
|
||||
----
|
||||
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-jms]]
|
||||
=== The jms schema
|
||||
=== The `jms` Schema
|
||||
|
||||
The `jms` tags deal with configuring JMS-related beans such as Spring's
|
||||
<<integration.adoc#jms-mdp,MessageListenerContainers>>. These tags are detailed in the
|
||||
The `jms` elements deal with configuring JMS-related beans, such as Spring's
|
||||
<<integration.adoc#jms-mdp,Message Listener Containers>>. These elements are detailed in the
|
||||
section of the <<integration.adoc#jms,JMS chapter>> entitled <<integration.adoc#jms-namespace,
|
||||
JMS namespace support>>. Please do consult that chapter for full details on this support
|
||||
and the `jms` tags themselves.
|
||||
JMS Namespace Support>>. See that chapter for full details on this support
|
||||
and the `jms` elements themselves.
|
||||
|
||||
In the interest of completeness, to use the tags in the `jms` 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 `jms` namespace
|
||||
are available to you.
|
||||
In the interest of completeness, to use the elements in the `jms` 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 elements in the `jms` namespace
|
||||
are available to you:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -285,28 +333,31 @@ are available to you.
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-context-mbe]]
|
||||
=== <context:mbean-export/>
|
||||
=== Using `<context:mbean-export/>`
|
||||
|
||||
This element is detailed in
|
||||
<<integration.adoc#jmx-context-mbeanexport, Configuring annotation based MBean export>>.
|
||||
<<integration.adoc#jmx-context-mbeanexport, Configuring Annotation-based MBean Export>>.
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-cache]]
|
||||
=== The cache schema
|
||||
=== The `cache` Schema
|
||||
|
||||
The `cache` tags can be used to enable support for Spring's `@CacheEvict`, `@CachePut`
|
||||
You can use the `cache` elements to enable support for Spring's `@CacheEvict`, `@CachePut`,
|
||||
and `@Caching` annotations. It it also supports declarative XML-based caching. See
|
||||
<<integration.adoc#cache-annotation-enable,Enable caching annotations>> and
|
||||
<<integration.adoc#cache-declarative-xml,Declarative XML-based caching>> for details.
|
||||
<<integration.adoc#cache-annotation-enable,Enabling Caching Annotations>> and
|
||||
<<integration.adoc#cache-declarative-xml,Declarative XML-based Caching>> for details.
|
||||
|
||||
To use the tags in the `cache` 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 `cache` namespace are available to you.
|
||||
To use the elements in the `cache` 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 elements in the `cache` namespace are available to you:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -319,3 +370,4 @@ the correct schema so that the tags in the `cache` namespace are available to yo
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,13 @@
|
||||
[[dynamic-language]]
|
||||
= Dynamic Language Support
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-introduction]]
|
||||
== Introduction
|
||||
|
||||
Spring 2.0 introduces comprehensive support for using classes and objects that have been
|
||||
defined using a dynamic language (such as JRuby) with Spring. This support allows you to
|
||||
write any number of classes in a supported dynamic language, and have the Spring
|
||||
container transparently instantiate, configure and dependency inject the resulting
|
||||
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
|
||||
container transparently instantiate, configure, and dependency inject the resulting
|
||||
objects.
|
||||
|
||||
The dynamic languages currently supported are:
|
||||
Spring currently supports the following dynamic languages:
|
||||
|
||||
* JRuby 1.5+
|
||||
* Groovy 1.8+
|
||||
@@ -20,32 +15,34 @@ The dynamic languages currently supported are:
|
||||
|
||||
.Why only these languages?
|
||||
****
|
||||
The supported languages were chosen because __a)__ the languages have a lot of traction in
|
||||
the Java enterprise community, __b)__ no requests were made for other languages at the time
|
||||
that this support was added, and __c)__ the Spring developers were most familiar with
|
||||
them.
|
||||
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.
|
||||
****
|
||||
|
||||
Fully working examples of where this dynamic language support can be immediately useful
|
||||
are described in <<dynamic-language-scenarios>>.
|
||||
You can find fully working examples of where this dynamic language support can be immediately useful
|
||||
in <<dynamic-language-scenarios>>.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-a-first-example]]
|
||||
== A first example
|
||||
== A First Example
|
||||
|
||||
This bulk of this chapter is concerned with describing the dynamic language support in
|
||||
The bulk of this chapter is concerned with describing the dynamic language support in
|
||||
detail. Before diving into all of the ins and outs of the dynamic language support,
|
||||
let's look at a quick example of a bean defined in a dynamic language. The dynamic
|
||||
language for this first bean is Groovy (the basis of this example was taken from the
|
||||
Spring test suite, so if you want to see equivalent examples in any of the other
|
||||
we look at a quick example of a bean defined in a dynamic language. The dynamic
|
||||
language for this first bean is Groovy. (The basis of this example was taken from the
|
||||
Spring test suite. If you want to see equivalent examples in any of the other
|
||||
supported languages, take a look at the source code).
|
||||
|
||||
Find below the `Messenger` interface that the Groovy bean is going to be implementing,
|
||||
and note that this interface is defined in plain Java. Dependent objects that are
|
||||
injected with a reference to the `Messenger` won't know that the underlying
|
||||
implementation is a Groovy script.
|
||||
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]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -57,9 +54,11 @@ implementation is a Groovy script.
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Here is the definition of a class that has a dependency on the `Messenger` interface.
|
||||
The following example defines a class that has a dependency on the `Messenger` interface:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -79,9 +78,11 @@ Here is the definition of a class that has a dependency on the `Messenger` inter
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Here is an implementation of the `Messenger` interface in Groovy.
|
||||
The following example implements the `Messenger` interface in Groovy:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -98,16 +99,13 @@ Here is an implementation of the `Messenger` interface in Groovy.
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
Finally, here are the bean definitions that will effect the injection of the
|
||||
Groovy-defined `Messenger` implementation into an instance of the
|
||||
`DefaultBookingService` class.
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
To use the custom dynamic language tags to define dynamic-language-backed beans, you
|
||||
need to have the XML Schema preamble at the top of your Spring XML configuration file.
|
||||
You also need to be using a Spring `ApplicationContext` implementation as your IoC
|
||||
You also need to use a Spring `ApplicationContext` implementation as your IoC
|
||||
container. Using the dynamic-language-backed beans with a plain `BeanFactory`
|
||||
implementation is supported, but you have to manage the plumbing of the Spring internals
|
||||
to do so.
|
||||
@@ -116,6 +114,11 @@ For more information on schema-based configuration, see <<appendix.adoc#xsd-conf
|
||||
XML Schema-based configuration>>.
|
||||
====
|
||||
|
||||
Finally, the following example shows the bean definitions that effect the injection of the
|
||||
Groovy-defined `Messenger` implementation into an instance of the
|
||||
`DefaultBookingService` class:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -138,60 +141,64 @@ XML Schema-based configuration>>.
|
||||
|
||||
</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
|
||||
`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 above XML snippet is self-explanatory, but don't worry unduly if it isn't.
|
||||
Keep reading for the in-depth detail on the whys and wherefores of the above
|
||||
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.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans]]
|
||||
== Defining beans that are backed by dynamic languages
|
||||
== Defining Beans that Are Backed by Dynamic Languages
|
||||
|
||||
This section describes exactly how you define Spring managed beans in any of the
|
||||
This section describes exactly how you define Spring-managed beans in any of the
|
||||
supported dynamic languages.
|
||||
|
||||
Please note that this chapter does not attempt to explain the syntax and idioms of the
|
||||
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, then the assumption is that you already know Groovy. If
|
||||
you need further details about the dynamic languages themselves, please
|
||||
consult <<dynamic-language-resources>> at the end of this chapter.
|
||||
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.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-concepts]]
|
||||
=== Common concepts
|
||||
=== Common Concepts
|
||||
|
||||
The steps involved in using dynamic-language-backed beans are as follows:
|
||||
|
||||
* Write the test for the dynamic language source code (naturally)
|
||||
* __Then__ write the dynamic language source code itself :)
|
||||
* Define your dynamic-language-backed beans using the appropriate `<lang:language/>`
|
||||
element in the XML configuration (you can of course define such beans programmatically
|
||||
using the Spring API - although you will have to consult the source code for
|
||||
directions on how to do this as this type of advanced configuration is not covered in
|
||||
this chapter). Note this is an iterative step. You will need at least one bean
|
||||
definition per dynamic language source file (although the same dynamic language source
|
||||
file can of course be referenced by multiple bean definitions).
|
||||
. Write the test for the dynamic language source code (naturally).
|
||||
. Then write the dynamic language source code itself.
|
||||
. Define your dynamic-language-backed beans by using the appropriate `<lang:language/>`
|
||||
element in the XML configuration (you can define such beans programmatically by
|
||||
using the Spring API, although you will have to consult the source code for
|
||||
directions on how to do this, as this chapter does not cover this type of advanced configuration).
|
||||
Note that this is an iterative step. You need at least one bean
|
||||
definition for each dynamic language source file (although multiple bean definitions can reference the same dynamic language source
|
||||
file).
|
||||
|
||||
The first two steps (testing and writing your dynamic language source files) are beyond
|
||||
the scope of this chapter. Refer to the language specification and / or reference manual
|
||||
the scope of this chapter. See the language specification and reference manual
|
||||
for your chosen dynamic language and crack on with developing your dynamic language
|
||||
source files. You __will__ first want to read the rest of this chapter though, as
|
||||
source files. You first want to read the rest of this chapter, though, as
|
||||
Spring's dynamic language support does make some (small) assumptions about the contents
|
||||
of your dynamic language source files.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-concepts-xml-language-element]]
|
||||
==== The <lang:language/> element
|
||||
|
||||
The final step involves defining dynamic-language-backed bean definitions, one for each
|
||||
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 use 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:
|
||||
@@ -202,42 +209,42 @@ Each of the supported languages has a corresponding `<lang:language/>` element:
|
||||
|
||||
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
|
||||
below provide the full lowdown on this).
|
||||
later in this chapter detail this).
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-refreshable-beans]]
|
||||
==== Refreshable beans
|
||||
==== Refreshable Beans
|
||||
|
||||
One of the (if not __the__) 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 that with a small amount of
|
||||
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 a developer edits and saves changes to the file on the
|
||||
filesystem).
|
||||
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).
|
||||
|
||||
This allows a developer to deploy any number of dynamic language source files as part of
|
||||
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 then later,
|
||||
as requirements change or some other external factor comes into play, simply edit a
|
||||
dynamic language source file and have any change they make reflected in the bean that is
|
||||
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
|
||||
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 will pick up the new state and logic from the
|
||||
dynamic-language-backed bean so amended picks up the new state and logic from the
|
||||
changed dynamic language source file.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Please note that this feature is __off__ by default.
|
||||
====
|
||||
NOTE: This feature is off by default.
|
||||
|
||||
Let's take a look at an example to see just how easy it is to start using refreshable
|
||||
beans. To __turn on__ the refreshable beans feature, you simply 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, here's what we would change in the Spring XML configuration to effect
|
||||
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:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -256,21 +263,25 @@ refreshable beans:
|
||||
|
||||
</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 will be
|
||||
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
|
||||
`'refresh-check-delay'` attribute. Remember that, by default, the refresh behavior is
|
||||
disabled. If you don't want the refresh behavior, then simply don't define the attribute.
|
||||
`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 I (the author) go off and edit the underlying dynamic language
|
||||
source file so that the refresh will trigger on the dynamic-language-backed bean when
|
||||
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.
|
||||
|
||||
The following listing shows this sample application:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -290,12 +301,14 @@ the program resumes execution.
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Let's assume then, for the purposes of this example, that all calls to the
|
||||
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 quotes. Below are the changes that I (the author) make to the
|
||||
`Messenger.groovy` source file when the execution of the program is paused.
|
||||
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"]
|
||||
----
|
||||
@@ -315,38 +328,42 @@ message is surrounded by quotes. Below are the changes that I (the author) make
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When the program executes, 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
|
||||
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 will be __'I Can Do The Frug'__
|
||||
(notice the inclusion of the additional quotes).
|
||||
dynamic-language-backed `Messenger` implementation is `'I Can Do The Frug'`
|
||||
(notice the inclusion of the additional quotation marks).
|
||||
|
||||
It is important to understand that changes to a script will __not__ trigger a refresh if
|
||||
the changes occur within the window of the `'refresh-check-delay'` value. It is equally
|
||||
important to understand that 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 relating to refreshing the script (such as
|
||||
encountering a compilation error, or finding that the script file has been deleted) will
|
||||
result in a __fatal__ exception being propagated to the calling code.
|
||||
source has changed. Any exceptions that relate to refreshing the script (such as
|
||||
encountering a compilation error or finding that the script file has been deleted)
|
||||
results in a fatal exception being propagated to the calling code.
|
||||
|
||||
The refreshable bean behavior described above does __not__ apply to dynamic language
|
||||
source files defined using the `<lang:inline-script/>` element notation (see
|
||||
<<dynamic-language-beans-inline>>). Additionally, it __only__ applies to beans where
|
||||
changes to the underlying source file can actually be detected; for example, by code
|
||||
The refreshable bean behavior described earlier does not apply to dynamic language
|
||||
source files defined with the `<lang:inline-script/>` element notation (see
|
||||
<<dynamic-language-beans-inline>>). Additionally, it applies only to beans where
|
||||
changes to the underlying source file can actually be detected (for example, by code
|
||||
that checks the last modified date of a dynamic language source file that exists on the
|
||||
filesystem.
|
||||
file system).
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-inline]]
|
||||
==== Inline dynamic language source files
|
||||
==== Inline Dynamic Language Source Files
|
||||
|
||||
The dynamic language support can also cater for dynamic language source files that are
|
||||
The dynamic language support can also cater to dynamic language source files that are
|
||||
embedded directly in Spring bean definitions. More specifically, the
|
||||
`<lang:inline-script/>` element allows you to define dynamic language source immediately
|
||||
inside a Spring configuration file. An example will perhaps make the inline script
|
||||
feature crystal clear:
|
||||
`<lang:inline-script/>` element lets you define dynamic language source immediately
|
||||
inside a Spring configuration file. An example might clarify how the inline script
|
||||
feature works:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -365,6 +382,7 @@ feature crystal clear:
|
||||
<lang:property name="message" value="I Can Do The Frug" />
|
||||
</lang:groovy>
|
||||
----
|
||||
====
|
||||
|
||||
If we put to one side the issues surrounding whether it is good practice to define
|
||||
dynamic language source inside a Spring configuration file, the `<lang:inline-script/>`
|
||||
@@ -373,16 +391,20 @@ Spring `Validator` implementation to a Spring MVC `Controller`. This is but a mo
|
||||
work using inline source. (See <<dynamic-language-scenarios-validators>> for such an
|
||||
example.)
|
||||
|
||||
[[dynamic-language-beans-ctor-injection]]
|
||||
==== Understanding Constructor Injection in the context of dynamic-language-backed beans
|
||||
|
||||
There is one __very__ important thing to be aware of with regard to Spring's dynamic
|
||||
language support. Namely, it is not (currently) possible to supply constructor arguments
|
||||
to dynamic-language-backed beans (and hence constructor-injection is not available for
|
||||
|
||||
[[dynamic-language-beans-ctor-injection]]
|
||||
==== Understanding Constructor Injection in the Context of Dynamic-language-backed Beans
|
||||
|
||||
There is one very important thing to be aware of with regard to Spring's dynamic
|
||||
language support. Namely, you can not (currently) supply constructor arguments
|
||||
to dynamic-language-backed beans (and, hence, constructor-injection is not available for
|
||||
dynamic-language-backed beans). In the interests of making this special handling of
|
||||
constructors and properties 100% clear, the following mixture of code and configuration
|
||||
will __not__ work.
|
||||
does not work:
|
||||
|
||||
.An approach that cannot work
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -421,36 +443,41 @@ will __not__ work.
|
||||
|
||||
</lang>
|
||||
----
|
||||
====
|
||||
|
||||
In practice this limitation is not as significant as it first appears since setter
|
||||
In practice this limitation is not as significant as it first appears, since setter
|
||||
injection is the injection style favored by the overwhelming majority of developers
|
||||
anyway (let's leave the discussion as to whether that is a good thing to another day).
|
||||
(we leave the discussion as to whether that is a good thing to another day).
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-groovy]]
|
||||
=== Groovy beans
|
||||
=== Groovy Beans
|
||||
|
||||
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.
|
||||
classpath of your application:
|
||||
|
||||
* `groovy-1.8.jar`
|
||||
* `asm-3.2.jar`
|
||||
* `antlr-2.7.7.jar`
|
||||
****
|
||||
|
||||
From the Groovy homepage...
|
||||
The Groovy homepage includes the following description:
|
||||
|
||||
"__Groovy is an agile dynamic language for the Java 2 Platform that has many of the
|
||||
"`Groovy is an agile dynamic language for the Java 2 Platform that has many of the
|
||||
features that people like so much in languages like Python, Ruby and Smalltalk, making
|
||||
them available to Java developers using a Java-like syntax. __"
|
||||
them available to Java developers using a Java-like syntax.`"
|
||||
|
||||
If you have read this chapter straight from the top, you will already have
|
||||
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
|
||||
bean. Let's look at another example (again using an example from the Spring test suite).
|
||||
bean. Now consider another example (again using an example from the Spring test suite):
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -462,9 +489,11 @@ bean. Let's look at another example (again using an example from the Spring test
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Here is an implementation of the `Calculator` interface in Groovy.
|
||||
The following example implements the `Calculator` interface in Groovy:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -479,7 +508,11 @@ Here is an implementation of the `Calculator` interface in Groovy.
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The following bean definition uses the calculator defined in Groovy:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -488,9 +521,11 @@ Here is an implementation of the `Calculator` interface in Groovy.
|
||||
<lang:groovy id="calculator" script-source="classpath:calculator.groovy"/>
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
Lastly, here is a small application to exercise the above configuration.
|
||||
Finally, the following small application exercises the preceding configuration:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -508,25 +543,30 @@ Lastly, here is a small application to exercise the above configuration.
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The resulting output from running the above program will be (unsurprisingly) __10__.
|
||||
(Exciting example, huh? Remember that the intent is to illustrate the concept. Please
|
||||
consult the dynamic language showcase project for a more complex example, or indeed
|
||||
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).
|
||||
|
||||
It is important that you __do 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 this author) respect
|
||||
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]]
|
||||
==== Customizing Groovy objects via a callback
|
||||
==== Customizing Groovy Objects by Using a Callback
|
||||
|
||||
The `GroovyObjectCustomizer` interface is a callback that allows you to hook additional
|
||||
The `GroovyObjectCustomizer` interface is a callback that lets you hook additional
|
||||
creation logic into the process of creating a Groovy-backed bean. For example,
|
||||
implementations of this interface could invoke any required initialization method(s), or
|
||||
set some default property values, or specify a custom `MetaClass`.
|
||||
implementations of this interface could invoke any required initialization methods,
|
||||
set some default property values, or specify a custom `MetaClass`. The following listing
|
||||
shows the `GroovyObjectCustomizer` interface definition:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -535,13 +575,15 @@ set some default property values, or specify a custom `MetaClass`.
|
||||
void customize(GroovyObject goo);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The Spring Framework will instantiate an instance of your Groovy-backed bean, and will
|
||||
then pass the created `GroovyObject` to the specified `GroovyObjectCustomizer` if one
|
||||
has been defined. You can do whatever you like with the supplied `GroovyObject`
|
||||
reference: it is expected that the setting of a custom `MetaClass` is what most folks
|
||||
will want to do with this callback, and you can see an example of doing that below.
|
||||
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:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -561,12 +603,15 @@ will want to do with this callback, and you can see an example of doing that bel
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
A full discussion of meta-programming in Groovy is beyond the scope of the Spring
|
||||
reference manual. Consult the relevant section of the Groovy reference manual, or do a
|
||||
search online: there are plenty of articles concerning this topic. Actually making use
|
||||
of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace support.
|
||||
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
|
||||
following example shows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -578,10 +623,12 @@ of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace supp
|
||||
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
|
||||
customizer-ref="tracingCustomizer"/>
|
||||
----
|
||||
====
|
||||
|
||||
If you are not using the Spring namespace support, you can still use the
|
||||
`GroovyObjectCustomizer` functionality.
|
||||
If you do not use the Spring namespace support, you can still use the
|
||||
`GroovyObjectCustomizer` functionality, as the following example shows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -595,47 +642,49 @@ If you are not using the Spring namespace support, you can still use the
|
||||
|
||||
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer`
|
||||
|
||||
NOTE: As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer`
|
||||
(such as an `ImportCustomizer`) or even a full Groovy `CompilerConfiguration` object
|
||||
in the same place as Spring's `GroovyObjectCustomizer`.
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-beans-bsh]]
|
||||
=== BeanShell beans
|
||||
=== BeanShell Beans
|
||||
|
||||
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.
|
||||
classpath of your application:
|
||||
|
||||
* `bsh-2.0b4.jar`
|
||||
****
|
||||
|
||||
From the BeanShell homepage...
|
||||
The BeanShell homepage includes the following description: {JB}
|
||||
|
||||
"__BeanShell is a small, free, embeddable Java source interpreter with dynamic language
|
||||
"`BeanShell is a small, free, embeddable Java source interpreter with dynamic language
|
||||
features, written in Java. BeanShell dynamically executes standard Java syntax and
|
||||
extends it with common scripting conveniences such as loose types, commands, and method
|
||||
closures like those in Perl and JavaScript.__"
|
||||
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 in that what happens is this: Spring creates a JDK dynamic proxy
|
||||
implementing 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 (accordingly) program to interfaces
|
||||
when using BeanShell-backed beans). This means that every method call on a
|
||||
BeanShell-backed object is going 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.
|
||||
|
||||
Let's look at a fully working example of using a BeanShell-based bean that implements
|
||||
the `Messenger` interface that was defined earlier in this chapter (repeated below for
|
||||
your convenience).
|
||||
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
|
||||
definition of the `Messenger` interface:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -647,10 +696,12 @@ your convenience).
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Here is the BeanShell 'implementation' (the term is used 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"]
|
||||
----
|
||||
@@ -664,10 +715,12 @@ Here is the BeanShell 'implementation' (the term is used loosely here) of the
|
||||
message = aMessage;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
And here is the Spring XML that defines an 'instance' of the above 'class' (again, the
|
||||
term is used very loosely here).
|
||||
The following exxample 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"]
|
||||
----
|
||||
@@ -677,6 +730,7 @@ term is used very loosely here).
|
||||
<lang:property name="message" value="Hello World!" />
|
||||
</lang:bsh>
|
||||
----
|
||||
====
|
||||
|
||||
See <<dynamic-language-scenarios>> for some scenarios where you might want to use
|
||||
BeanShell-based beans.
|
||||
@@ -687,40 +741,39 @@ BeanShell-based beans.
|
||||
== Scenarios
|
||||
|
||||
The possible scenarios where defining Spring managed beans in a scripting language would
|
||||
be beneficial are, of course, many and varied. This section describes two possible use
|
||||
be beneficial are many and varied. This section describes two possible use
|
||||
cases for the dynamic language support in Spring.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-scenarios-controllers]]
|
||||
=== Scripted Spring MVC Controllers
|
||||
|
||||
One group of classes that may benefit from using dynamic-language-backed beans is that
|
||||
One group of classes that can benefit from using dynamic-language-backed beans is that
|
||||
of Spring MVC controllers. In pure Spring MVC applications, the navigational flow
|
||||
through a web application is to a large extent determined by code encapsulated within
|
||||
through a web application is, to a large extent, determined by code encapsulated within
|
||||
your Spring MVC controllers. As the navigational flow and other presentation layer logic
|
||||
of a web application needs to be updated to respond to support issues or changing
|
||||
business requirements, it may well be easier to effect any such required changes by
|
||||
editing one or more dynamic language source files and seeing those changes being
|
||||
immediately reflected in the state of a running application.
|
||||
|
||||
Remember that in the lightweight architectural model espoused by projects such as
|
||||
Spring, you are typically aiming to have a really __thin__ presentation layer, with all
|
||||
Remember that, in the lightweight architectural model espoused by projects such as
|
||||
Spring, you typically aim to have a really thin presentation layer, with all
|
||||
the meaty business logic of an application being contained in the domain and service
|
||||
layer classes. Developing Spring MVC controllers as dynamic-language-backed beans allows
|
||||
you to change presentation layer logic by simply editing and saving text files; any
|
||||
changes to such dynamic language source files will (depending on the configuration)
|
||||
automatically be reflected in the beans that are backed by dynamic language source files.
|
||||
layer classes. Developing Spring MVC controllers as dynamic-language-backed beans lets
|
||||
you change presentation layer logic by editing and saving text files. Any
|
||||
changes to such dynamic language source files is (depending on the configuration)
|
||||
automatically reflected in the beans that are backed by dynamic language source files.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
In order to effect this automatic 'pickup' of any changes to dynamic-language-backed
|
||||
beans, you will have had to enable the 'refreshable beans' functionality. See
|
||||
NOTE: To effect this automatic "`pickup`" of any changes to dynamic-language-backed
|
||||
beans, you have to enable the "`refreshable beans`" functionality. See
|
||||
<<dynamic-language-refreshable-beans>> for a full treatment of this feature.
|
||||
|
||||
The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented
|
||||
by using the Groovy dynamic language:
|
||||
|
||||
====
|
||||
|
||||
Find below an example of an `org.springframework.web.servlet.mvc.Controller` implemented
|
||||
using the Groovy dynamic language.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -756,34 +809,34 @@ using the Groovy dynamic language.
|
||||
<lang:property name="fortuneService" ref="fortuneService"/>
|
||||
</lang:groovy>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-scenarios-validators]]
|
||||
=== Scripted Validators
|
||||
|
||||
Another area of application development with Spring that may benefit from the
|
||||
flexibility afforded by dynamic-language-backed beans is that of validation. It __may__
|
||||
be easier to express complex validation logic using a loosely typed dynamic language
|
||||
flexibility afforded by dynamic-language-backed beans is that of validation. It can
|
||||
be easier to express complex validation logic by using a loosely typed dynamic language
|
||||
(that may also have support for inline regular expressions) as opposed to regular Java.
|
||||
|
||||
Again, developing validators as dynamic-language-backed beans allows you to change
|
||||
validation logic by simply editing and saving a simple text file; any such changes will
|
||||
(depending on the configuration) automatically be reflected in the execution of a
|
||||
Again, developing validators as dynamic-language-backed beans lets you change
|
||||
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]
|
||||
====
|
||||
Please note that in order to effect the automatic 'pickup' of any changes to
|
||||
dynamic-language-backed beans, you will have had to enable the 'refreshable beans'
|
||||
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.
|
||||
====
|
||||
|
||||
Find below an example of a Spring `org.springframework.validation.Validator` implemented
|
||||
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.)
|
||||
`Validator` interface):
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -806,43 +859,47 @@ Validation using Spring’s Validator interface>> for a discussion of the
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-final-notes]]
|
||||
== Bits and bobs
|
||||
== Additional Details
|
||||
|
||||
This last section contains some additional details related to the dynamic language support.
|
||||
|
||||
This last section contains some bits and bobs related to the dynamic language support.
|
||||
|
||||
|
||||
[[dynamic-language-final-notes-aop]]
|
||||
=== AOP - advising scripted beans
|
||||
=== AOP -- Advising Scripted Beans
|
||||
|
||||
It is possible to use the Spring AOP framework to advise scripted beans. The Spring AOP
|
||||
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 may be using or aim to use
|
||||
will work with scripted beans. There is just one (small) thing that you need to be aware
|
||||
of when advising scripted beans... you cannot use class-based proxies, you must
|
||||
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>>.
|
||||
|
||||
You are of course not just limited to advising scripted beans... you can also write
|
||||
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.
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-final-notes-scopes]]
|
||||
=== Scoping
|
||||
|
||||
In case it is not immediately obvious, scripted beans can of course be scoped just like
|
||||
any other bean. The `scope` attribute on the various `<lang:language/>` elements allows
|
||||
you to control the scope of the underlying scripted bean, just as it does with a regular
|
||||
bean. (The default scope is <<core.adoc#beans-factory-scopes-singleton,singleton>>, just as it is
|
||||
with 'regular' beans.)
|
||||
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.)
|
||||
|
||||
Find below an example of using the `scope` attribute to define a Groovy bean scoped as
|
||||
a <<core.adoc#beans-factory-scopes-prototype,prototype>>.
|
||||
The following example uses the `scope` attribute to define a Groovy bean scoped as
|
||||
a <<core.adoc#beans-factory-scopes-prototype,prototype>>:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -863,28 +920,30 @@ a <<core.adoc#beans-factory-scopes-prototype,prototype>>.
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
See <<core.adoc#beans-factory-scopes,Bean scopes>> in <<core.adoc#beans,The IoC container>>
|
||||
for a fuller discussion of the scoping support in the Spring Framework.
|
||||
for a full discussion of the scoping support in the Spring Framework.
|
||||
|
||||
|
||||
|
||||
|
||||
[[xsd-schemas-lang]]
|
||||
=== The lang XML schema
|
||||
=== The `lang` XML schema
|
||||
|
||||
The `lang` tags 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 JRuby or Groovy) as beans in the Spring container.
|
||||
|
||||
These tags (and the dynamic language support) are comprehensively covered in the chapter
|
||||
entitled <<integration.adoc#dynamic-language,Dynamic language support>>.
|
||||
Please do consult that chapter for full details on this support and the `lang` tags themselves.
|
||||
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.
|
||||
|
||||
In the interest of completeness, to use the tags in the `lang` schema, you need to have
|
||||
the following preamble at the top of your Spring XML configuration file; the text in the
|
||||
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.
|
||||
are available to you:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -897,15 +956,15 @@ are available to you.
|
||||
|
||||
</beans>
|
||||
----
|
||||
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[dynamic-language-resources]]
|
||||
== Further Resources
|
||||
|
||||
Find below links to further resources about the various dynamic languages described in
|
||||
this chapter.
|
||||
The following links go to further resources about the various dynamic languages described in
|
||||
this chapter:
|
||||
|
||||
* The http://jruby.org/[JRuby] homepage
|
||||
* The http://www.groovy-lang.org/[Groovy] homepage
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[[groovy]]
|
||||
= Apache Groovy
|
||||
|
||||
Groovy is a powerful, optionally typed and dynamic language, with static-typing and static
|
||||
Groovy is a powerful, optionally typed, and dynamic language, with static-typing and static
|
||||
compilation capabilities. It offers a concise syntax and integrates smoothly with any
|
||||
existing Java application.
|
||||
|
||||
@@ -9,5 +9,5 @@ The Spring Framework provides a dedicated `ApplicationContext` that supports a G
|
||||
Bean Definition DSL. For more details, see
|
||||
<<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 next the section <<dynamic-language>>.
|
||||
Further support for Groovy, including beans written in Groovy, refreshable script beans,
|
||||
and more is available in <<dynamic-language>>.
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
[[kotlin]]
|
||||
= Kotlin
|
||||
|
||||
https://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms)
|
||||
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 allows developers to write
|
||||
Kotlin applications almost as if the Spring Framework was a native Kotlin framework.
|
||||
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 + Kotlin is to follow
|
||||
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` tags on
|
||||
question with `spring` and `kotlin` as tags on
|
||||
https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support.
|
||||
|
||||
|
||||
@@ -20,178 +20,163 @@ https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you n
|
||||
[[kotlin-requirements]]
|
||||
== Requirements
|
||||
|
||||
Spring Framework supports Kotlin 1.1+ and requires
|
||||
The Spring Framework supports Kotlin 1.1+ and requires
|
||||
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib[`kotlin-stdlib`]
|
||||
(or one of its variants like https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]
|
||||
(or one of its variants, such as https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]
|
||||
for Kotlin 1.1 or https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`] for Kotlin 1.2+)
|
||||
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 one bootstraps a Kotlin project on
|
||||
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
|
||||
|
||||
Kotlin https://kotlinlang.org/docs/reference/extensions.html[extensions] provide the ability
|
||||
to extend existing classes with additional functionality. The Spring Framework Kotlin APIs make
|
||||
use of these extensions to add new Kotlin specific conveniences to existing Spring APIs.
|
||||
to extend existing classes with additional functionality. The Spring Framework Kotlin APIs
|
||||
use these extensions to add new Kotlin-specific conveniences to existing Spring APIs.
|
||||
|
||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists
|
||||
and documents all the Kotlin extensions and DSLs available.
|
||||
The {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists
|
||||
and documents all available the Kotlin extensions and DSLs.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Keep in mind that Kotlin extensions need to be imported to be used. This means
|
||||
for example that the `GenericApplicationContext.registerBean` Kotlin extension
|
||||
will only be available if `import org.springframework.context.support.registerBean` is imported.
|
||||
NOTE: Keep in mind that Kotlin extensions need to be imported to be used. This means,
|
||||
for example, that the `GenericApplicationContext.registerBean` Kotlin extension
|
||||
is available only if `org.springframework.context.support.registerBean` is imported.
|
||||
That said, similar to static imports, an IDE should automatically suggest the import in most cases.
|
||||
====
|
||||
|
||||
For example, https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters[Kotlin reified type parameters]
|
||||
provide a workaround for JVM https://docs.oracle.com/javase/tutorial/java/generics/erasure.html[generics type erasure],
|
||||
and Spring Framework provides some extensions to take advantage of this feature.
|
||||
This allows for a better Kotlin API `RestTemplate`, the new `WebClient` from Spring
|
||||
WebFlux and for various other APIs.
|
||||
and the Spring Framework provides some extensions to take advantage of this feature.
|
||||
This allows for a better Kotlin API `RestTemplate`, for the new `WebClient` from Spring
|
||||
WebFlux, and for various other APIs.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Other libraries like Reactor and Spring Data also provide Kotlin extensions
|
||||
NOTE: Other libraries, such as Reactor and Spring Data, also provide Kotlin extensions
|
||||
for their APIs, thus giving a better Kotlin development experience overall.
|
||||
|
||||
To retrieve a list of `User` objects in Java, you would normally write the following:
|
||||
|
||||
====
|
||||
|
||||
To retrieve a list of `Foo` objects in Java, one would normally write:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
Flux<User> users = client.get().retrieve().bodyToFlux(User.class)
|
||||
----
|
||||
====
|
||||
|
||||
Whilst with Kotlin and Spring Framework extensions, one is able to write:
|
||||
With Kotlin and the Spring Framework extensions, you can instead write the following:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
val users = client.get().retrieve().bodyToFlux<User>()
|
||||
// or (both are equivalent)
|
||||
val users : Flux<User> = client.get().retrieve().bodyToFlux()
|
||||
----
|
||||
====
|
||||
|
||||
As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows
|
||||
for shorter syntax.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-null-safety]]
|
||||
== Null-safety
|
||||
|
||||
One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety]
|
||||
- which cleanly deals with `null` values at compile time rather than bumping into the famous
|
||||
One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety],
|
||||
which cleanly deals with `null` values at compile time rather than bumping into the famous
|
||||
`NullPointerException` at runtime. This makes applications safer through nullability
|
||||
declarations and expressing "value or no value" semantics without paying the cost of wrappers like `Optional`.
|
||||
(Kotlin allows using functional constructs with nullable values; check out this
|
||||
declarations and expressing "`value or no value`" semantics without paying the cost of wrappers, such as `Optional`.
|
||||
(Kotlin allows using functional constructs with nullable values. See this
|
||||
http://www.baeldung.com/kotlin-null-safety[comprehensive guide to Kotlin null-safety].)
|
||||
|
||||
Although Java does not allow one to express null-safety in its type-system, Spring Framework now
|
||||
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>>
|
||||
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]
|
||||
https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types],
|
||||
for which null-checks are relaxed.
|
||||
https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR 305 annotations]
|
||||
+ Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,
|
||||
with the advantage of dealing with `null` related issues at compile time.
|
||||
https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR-305 annotations]
|
||||
and Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,
|
||||
with the advantage of dealing with `null`-related issues at compile time.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Libraries like Reactor or Spring Data provide null-safe APIs leveraging this feature.
|
||||
====
|
||||
NOTE: Libraries such as Reactor or Spring Data provide null-safe APIs to leverage this feature.
|
||||
|
||||
The JSR 305 checks can be configured by adding the `-Xjsr305` compiler flag with the following
|
||||
You can configure JSR-305 checks by adding the `-Xjsr305` compiler flag with the following
|
||||
options: `-Xjsr305={strict|warn|ignore}`.
|
||||
|
||||
For kotlin versions 1.1+, the default behavior is the same to `-Xjsr305=warn`.
|
||||
The `strict` value is required to have Spring Framework API null-safety taken in account
|
||||
For kotlin versions 1.1+, the default behavior is the same as `-Xjsr305=warn`.
|
||||
The `strict` value is required to have Spring Framework API null-safety taken into account
|
||||
in Kotlin types inferred from Spring API but should be used with the knowledge that Spring
|
||||
API nullability declaration could evolve even between minor releases and more checks may
|
||||
API nullability declaration could evolve even between minor releases and that more checks may
|
||||
be added in the future).
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Generic type arguments, varargs and array elements nullability are not supported yet,
|
||||
but should be in an upcoming release, see https://github.com/Kotlin/KEEP/issues/79[this discussion]
|
||||
NOTE: Generic type arguments, varargs, and array elements nullability are not supported yet,
|
||||
but should be in an upcoming release. See https://github.com/Kotlin/KEEP/issues/79[this discussion]
|
||||
for up-to-date information.
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-classes-interfaces]]
|
||||
== Classes & Interfaces
|
||||
== Classes and Interfaces
|
||||
|
||||
Spring Framework supports various Kotlin constructs like instantiating Kotlin classes
|
||||
via primary constructors, immutable classes data binding and function optional parameters
|
||||
The Spring Framework supports various Kotlin constructs, such as instantiating Kotlin classes
|
||||
through primary constructors, immutable classes data binding, and function optional parameters
|
||||
with default values.
|
||||
|
||||
Kotlin parameter names are recognized via a dedicated `KotlinReflectionParameterNameDiscoverer`
|
||||
Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,
|
||||
which allows finding interface method parameter names without requiring the Java 8 `-parameters`
|
||||
compiler flag enabled during compilation.
|
||||
compiler flag to be enabled during compilation.
|
||||
|
||||
https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module] which is required
|
||||
for serializing / deserializing JSON data is automatically registered when
|
||||
found in the classpath and a warning message will be logged if Jackson and Kotlin are
|
||||
detected without the Jackson Kotlin module present.
|
||||
The https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module], which is required
|
||||
for serializing or deserializing JSON data, is automatically registered when
|
||||
found in the classpath, and a warning message is logged if Jackson and Kotlin are
|
||||
detected without the Jackson Kotlin module being present.
|
||||
|
||||
Configuration classes can be
|
||||
https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner]
|
||||
You can declare configuration classes as
|
||||
https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner],
|
||||
since the later requires a reference to the outer class.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-annotations]]
|
||||
== Annotations
|
||||
|
||||
Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety]
|
||||
The Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety]
|
||||
to determine if a HTTP parameter is required without having to explicitly
|
||||
define the `required` attribute. That means `@RequestParam name: String?` will be treated
|
||||
as not required and conversely `@RequestParam name: String` as being required.
|
||||
define the `required` attribute. That means `@RequestParam name: String?` is treated
|
||||
as not required and, conversely, `@RequestParam name: String` is treated as being required.
|
||||
This feature is also supported on the Spring Messaging `@Header` annotation.
|
||||
|
||||
In a similar fashion, Spring bean injection with `@Autowired`, `@Bean` or `@Inject` uses
|
||||
In a similar fashion, Spring bean injection with `@Autowired`, `@Bean`, or `@Inject` uses
|
||||
this information to determine if a bean is required or not.
|
||||
|
||||
For example, `@Autowired lateinit var foo: Foo` implies that a bean
|
||||
of type `Foo` must be registered in the application context, while `@Autowired lateinit var foo: Foo?`
|
||||
won’t raise an error if such bean does not exist.
|
||||
For example, `@Autowired lateinit var thing: Thing` implies that a bean
|
||||
of type `Thing` must be registered in the application context, while `@Autowired lateinit var thing: Thing?`
|
||||
does not raise an error if such a bean does not exist.
|
||||
|
||||
Following the same principle, `@Bean fun baz(foo: Foo, bar: Bar?) = Baz(foo, bar)` implies
|
||||
that a bean of type `Foo` must be registered in the application context while a bean of
|
||||
type `Bar` may or may not exist. The same behavior applies to autowired constructor parameters.
|
||||
Following the same principle, `@Bean fun play(toy: Toy, car: Car?) = Baz(toy, Car)` implies
|
||||
that a bean of type `Toy` must be registered in the application context, while a bean of
|
||||
type `Car` may or may not exist. The same behavior applies to autowired constructor parameters.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If you are using bean validation on classes with properties or a primary constructor
|
||||
parameters, you may need to leverage
|
||||
https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets]
|
||||
like `@field:NotNull` or `@get:Size(min=5, max=15)` as described in
|
||||
NOTE: If you use bean validation on classes with properties or a primary constructor
|
||||
parameters, you may need to use
|
||||
https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets],
|
||||
such as `@field:NotNull` or `@get:Size(min=5, max=15)`, as described in
|
||||
https://stackoverflow.com/a/35853200/1092077[this Stack Overflow response].
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-bean-definition-dsl]]
|
||||
== Bean definition DSL
|
||||
== Bean Definition DSL
|
||||
|
||||
Spring Framework 5 introduces a new way to register beans in a functional way using lambdas
|
||||
as an alternative to XML or JavaConfig (`@Configuration` and `@Bean`). In a nutshell,
|
||||
it makes it possible to register beans with a lambda that acts as a `FactoryBean`.
|
||||
This mechanism is very efficient as it does not require any reflection or CGLIB proxies.
|
||||
Spring Framework 5 introduces a new way to register beans in a functional way by using lambdas
|
||||
as an alternative to XML or Java configuration (`@Configuration` and `@Bean`). In a nutshell,
|
||||
it lets you register beans with a lambda that acts as a `FactoryBean`.
|
||||
This mechanism is very efficient, as it does not require any reflection or CGLIB proxies.
|
||||
|
||||
In Java, one may for example write:
|
||||
In Java, you can, for example, write the following:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
@@ -199,10 +184,12 @@ In Java, one may for example write:
|
||||
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class))
|
||||
);
|
||||
----
|
||||
====
|
||||
|
||||
Whilst in Kotlin with reified type parameters and `GenericApplicationContext`
|
||||
Kotlin extensions one can instead simply write:
|
||||
In Kotlin, with reified type parameters and `GenericApplicationContext`
|
||||
Kotlin extensions, you can instead write the following:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
val context = GenericApplicationContext().apply {
|
||||
@@ -210,13 +197,15 @@ Kotlin extensions one can instead simply write:
|
||||
registerBean { Bar(it.getBean<Foo>()) }
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In order to allow a more declarative approach and cleaner syntax, Spring Framework provides
|
||||
a {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.context.support/-bean-definition-dsl/[Kotlin bean definition DSL]
|
||||
It declares an `ApplicationContextInitializer` via a clean declarative API
|
||||
which enables one to deal with profiles and `Environment` for customizing
|
||||
how beans are registered.
|
||||
It declares an `ApplicationContextInitializer` through a clean declarative API,
|
||||
which lets you deal with profiles and `Environment` for customizing
|
||||
how beans are registered. The following example creates a `Play` profile:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
fun beans() = beans {
|
||||
@@ -243,17 +232,20 @@ how beans are registered.
|
||||
setSuffix(suffix)
|
||||
}
|
||||
}
|
||||
profile("foo") {
|
||||
bean<Foo>()
|
||||
profile("play") {
|
||||
bean<Play>()
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In this example, `bean<Routes>()` is using autowiring by constructor and `ref<Routes>()`
|
||||
In the preceding example, `bean<Routes>()` uses autowiring by constructor, and `ref<Routes>()`
|
||||
is a shortcut for `applicationContext.getBean(Routes::class.java)`.
|
||||
|
||||
This `beans()` function can then be used to register beans on the application context.
|
||||
You can then use this `beans()` function to register beans on the application context,
|
||||
as the following example shows:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
val context = GenericApplicationContext().apply {
|
||||
@@ -261,25 +253,19 @@ This `beans()` function can then be used to register beans on the application co
|
||||
refresh()
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This DSL is programmatic, thus it allows custom registration logic of beans
|
||||
via an `if` expression, a `for` loop or any other Kotlin constructs.
|
||||
====
|
||||
NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans
|
||||
through an `if` expression, a `for` loop, or any other Kotlin constructs.
|
||||
|
||||
See https://github.com/sdeleuze/spring-kotlin-functional/blob/master/src/main/kotlin/functional/Beans.kt[spring-kotlin-functional beans declaration]
|
||||
for a concrete example.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Spring Boot is based on Java Config and
|
||||
https://github.com/spring-projects/spring-boot/issues/8115[does not provide specific support for functional bean definition yet],
|
||||
but one can experimentally use functional bean definitions via Spring Boot's `ApplicationContextInitializer` support,
|
||||
see https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
|
||||
NOTE: Spring Boot is based on Java configuration and
|
||||
https://github.com/spring-projects/spring-boot/issues/8115[does not yet provide specific support for functional bean definition],
|
||||
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
|
||||
See https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
|
||||
for more details and up-to-date information.
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -292,9 +278,10 @@ for more details and up-to-date information.
|
||||
|
||||
Spring Framework now comes with a
|
||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL]
|
||||
that allows one to leverage the <<web-reactive#webflux-fn,WebFlux functional
|
||||
API>> for writing clean and idiomatic Kotlin code:
|
||||
that lets you use the <<web-reactive#webflux-fn,WebFlux functional
|
||||
API>> to write clean and idiomatic Kotlin code, as the following example shows:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
router {
|
||||
@@ -314,37 +301,36 @@ API>> for writing clean and idiomatic Kotlin code:
|
||||
resources("/**", ClassPathResource("static/"))
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This DSL is programmatic, thus it allows custom registration logic of beans
|
||||
via an `if` expression, a `for` loop or any other Kotlin constructs. That can be useful when routes need to be registered
|
||||
NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans
|
||||
through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful when you need to register routes
|
||||
depending on dynamic data (for example, from a database).
|
||||
====
|
||||
|
||||
See https://github.com/mixitconf/mixit/tree/bad6b92bce6193f9b3f696af9d416c276501dbf1/src/main/kotlin/mixit/web/routes[MiXiT project routes]
|
||||
for a concrete example.
|
||||
|
||||
|
||||
|
||||
=== Kotlin Script templates
|
||||
=== Kotlin Script Templates
|
||||
|
||||
As of version 4.3, Spring Framework provides a
|
||||
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/view/script/ScriptTemplateView.html[ScriptTemplateView]
|
||||
to render templates using script engines that supports
|
||||
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/view/script/ScriptTemplateView.html[`ScriptTemplateView`]
|
||||
to render templates by using script engines. It supports
|
||||
https://www.jcp.org/en/jsr/detail?id=223[JSR-223].
|
||||
Spring Framework 5 goes even further by extending this feature to WebFlux and supporting
|
||||
https://jira.spring.io/browse/SPR-15064[i18n and nested templates].
|
||||
|
||||
Kotlin provides similar support and allows the rendering of Kotlin based templates, see
|
||||
Kotlin provides similar support and allows the rendering of Kotlin-based templates. See
|
||||
https://github.com/spring-projects/spring-framework/commit/badde3a479a53e1dd0777dd1bd5b55cb1021cf9e[this commit] for details.
|
||||
|
||||
This enables some interesting use cases - like writing type-safe templates using
|
||||
https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or simply using Kotlin multiline `String` with interpolation.
|
||||
This enables some interesting use cases - such as writing type-safe templates by using
|
||||
https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or by a using Kotlin multiline `String` with interpolation.
|
||||
|
||||
This can allow one to write Kotlin templates with full autocompletion and
|
||||
refactoring support in a supported IDE:
|
||||
This can let you write Kotlin templates with full autocompletion and
|
||||
refactoring support in a supported IDE, as the following example shows:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
import io.spring.demo.*
|
||||
@@ -358,40 +344,40 @@ refactoring support in a supported IDE:
|
||||
${include("footer")}
|
||||
"""
|
||||
----
|
||||
====
|
||||
|
||||
See https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
|
||||
See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
|
||||
project for more details.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-spring-projects-in-kotlin]]
|
||||
== Spring projects in Kotlin
|
||||
== Spring Projects in Kotlin
|
||||
|
||||
This section provides focus on some specific hints and recommendations worth
|
||||
knowing when developing Spring projects in Kotlin.
|
||||
This section provides some specific hints and recommendations worth
|
||||
for developing Spring projects in Kotlin.
|
||||
|
||||
|
||||
|
||||
=== Final by default
|
||||
=== 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
|
||||
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.
|
||||
|
||||
Whilst 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 in
|
||||
consideration. This is because Spring beans are normally proxied by CGLIB
|
||||
- such as `@Configuration` classes - which need to be inherited at runtime for technical reasons.
|
||||
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
|
||||
functions of Spring beans proxied by CGLIB such as `@Configuration` classes, which can
|
||||
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
|
||||
https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin[`kotlin-spring`]
|
||||
plugin, a preconfigured version of `kotlin-allopen` plugin that automatically opens classes
|
||||
and their member functions for types annotated or meta-annotated with one of the following
|
||||
plugin (a preconfigured version of the `kotlin-allopen` plugin) that automatically opens classes
|
||||
and their member functions for types that are annotated or meta-annotated with one of the following
|
||||
annotations:
|
||||
|
||||
* `@Component`
|
||||
@@ -400,35 +386,38 @@ annotations:
|
||||
* `@Cacheable`
|
||||
|
||||
Meta-annotations support means that types annotated with `@Configuration`, `@Controller`,
|
||||
`@RestController`, `@Service` or `@Repository` are automatically opened since these
|
||||
`@RestController`, `@Service`, or `@Repository` are automatically opened since these
|
||||
annotations are meta-annotated with `@Component`.
|
||||
|
||||
http://start.spring.io/#!language=kotlin[start.spring.io] enables it by default, so in practice
|
||||
you will be able to write your Kotlin beans without any additional `open` keyword, like in Java.
|
||||
http://start.spring.io/#!language=kotlin[start.spring.io] enables it by default, so, in practice,
|
||||
you can write your Kotlin beans without any additional `open` keyword, as in Java.
|
||||
|
||||
|
||||
|
||||
=== Using immutable class instances for persistence
|
||||
=== Using Immutable Class Instances for Persistence
|
||||
|
||||
In Kotlin, it is very convenient and considered best practice to declare read-only properties
|
||||
In Kotlin, it is convenient and considered to be a best practice to declare read-only properties
|
||||
within the primary constructor, as in the following example:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
class Person(val name: String, val age: Int)
|
||||
----
|
||||
====
|
||||
|
||||
You can optionally add https://kotlinlang.org/docs/reference/data-classes.html[the `data` keyword]
|
||||
to make the compiler automatically derive the following members from all properties declared
|
||||
in the primary constructor:
|
||||
|
||||
* equals()/hashCode() pair
|
||||
* toString() of the form "User(name=John, age=42)"
|
||||
* componentN() functions corresponding to the properties in their order of declaration
|
||||
* copy() function
|
||||
* `equals()` and `hashCode()`
|
||||
* `toString()` of the form `"User(name=John, age=42)"`
|
||||
* `componentN()` functions that correspond to the properties in their order of declaration
|
||||
* `copy()` function
|
||||
|
||||
This allows for easy changes to individual properties even if `Person` properties are read-only:
|
||||
As the following example shows, this allows for easy changes to individual properties, even if `Person` properties are read-only:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
data class Person(val name: String, val age: Int)
|
||||
@@ -436,31 +425,30 @@ This allows for easy changes to individual properties even if `Person` propertie
|
||||
val jack = Person(name = "Jack", age = 1)
|
||||
val olderJack = jack.copy(age = 2)
|
||||
----
|
||||
====
|
||||
|
||||
Common persistence technologies such as JPA require a default constructor, preventing this
|
||||
Common persistence technologies (such as JPA) require a default constructor, preventing this
|
||||
kind of design. Fortunately, there is now a workaround for this
|
||||
https://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell["default constructor hell"]
|
||||
since Kotlin provides a https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-jpa-compiler-plugin[kotlin-jpa]
|
||||
plugin which generates synthetic no-arg constructor for classes annotated with JPA annotations.
|
||||
https://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell["`default constructor hell`"],
|
||||
since Kotlin provides a https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-jpa-compiler-plugin[`kotlin-jpa`]
|
||||
plugin that generates synthetic no-arg constructor for classes annotated with JPA annotations.
|
||||
|
||||
If you need to leverage this kind of mechanism for other persistence technologies, you can configure
|
||||
the https://kotlinlang.org/docs/reference/compiler-plugins.html#how-to-use-no-arg-plugin[kotlin-noarg]
|
||||
the https://kotlinlang.org/docs/reference/compiler-plugins.html#how-to-use-no-arg-plugin[`kotlin-noarg`]
|
||||
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 leverages Spring Data object
|
||||
mappings (like with MongoDB, Redis, Cassandra, etc).
|
||||
====
|
||||
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).
|
||||
|
||||
|
||||
|
||||
=== Injecting dependencies
|
||||
=== 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].
|
||||
https://kotlinlang.org/docs/reference/properties.html[properties], as the following example shows:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@Component
|
||||
@@ -469,17 +457,16 @@ https://kotlinlang.org/docs/reference/properties.html[properties].
|
||||
private val solrClient: SolrClient
|
||||
)
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
As of Spring Framework 4.3, classes with a single constructor have their
|
||||
|
||||
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:
|
||||
|
||||
====
|
||||
|
||||
If one really needs to use field injection, use the `lateinit var` construct,
|
||||
i.e.,
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@Component
|
||||
@@ -492,20 +479,22 @@ i.e.,
|
||||
lateinit var solrClient: SolrClient
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
=== Injecting configuration properties
|
||||
=== Injecting Configuration Properties
|
||||
|
||||
In Java, one can inject configuration properties using annotations like `@Value("${property}")`,
|
||||
however in Kotlin `$` is a reserved character that is used for https://kotlinlang.org/docs/reference/idioms.html#string-interpolation[string interpolation].
|
||||
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].
|
||||
|
||||
Therefore, if one wishes to use the `@Value` annotation in Kotlin, the `$`
|
||||
character will need to be escaped by writing `@Value("\${property}")`.
|
||||
Therefore, if you wish to use the `@Value` annotation in Kotlin, you need to escape the `$`
|
||||
character by writing `@Value("\${property}")`.
|
||||
|
||||
As an alternative, it is possible to customize the properties placeholder prefix by declaring
|
||||
As an alternative, you can customize the properties placeholder prefix by declaring
|
||||
the following configuration beans:
|
||||
|
||||
====
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@Bean
|
||||
@@ -513,10 +502,12 @@ the following configuration beans:
|
||||
setPlaceholderPrefix("%{")
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Existing code (like Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax,
|
||||
can be customised with configuration beans, like as follows:
|
||||
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]
|
||||
----
|
||||
@Bean
|
||||
@@ -528,32 +519,31 @@ can be customised with configuration beans, like as follows:
|
||||
@Bean
|
||||
fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer()
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If Spring Boot is being used, then
|
||||
|
||||
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 can be used, but currently this only works with `lateinit` or nullable `var`
|
||||
properties (the former is recommended) since immutable classes initialized by
|
||||
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.
|
||||
====
|
||||
|
||||
|
||||
|
||||
=== Annotation array attributes
|
||||
=== Annotation Array Attributes
|
||||
|
||||
Kotlin annotations are mostly similar to Java ones, but array attributes - which are
|
||||
extensively used in Spring - behave differently. As explained in
|
||||
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]
|
||||
unlike other attributes, the `value` attribute name can be omitted and
|
||||
specified as a `vararg` parameter.
|
||||
you can omit the `value` attribute name, unlike other attributes, and
|
||||
specify it as a `vararg` parameter.
|
||||
|
||||
To understand what that means, let's take `@RequestMapping`, which is one
|
||||
of the most widely used Spring annotations as an example. This Java annotation is declared as:
|
||||
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]
|
||||
----
|
||||
public @interface RequestMapping {
|
||||
@@ -569,43 +559,48 @@ of the most widely used Spring annotations as an example. This Java annotation i
|
||||
// ...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The typical use case for `@RequestMapping` is to map a handler method to a specific path
|
||||
and method. In Java, it is possible to specify a single value for the
|
||||
annotation array attribute and it will be 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's why one can write
|
||||
`@RequestMapping(value = "/foo", method = RequestMethod.GET)` or
|
||||
`@RequestMapping(path = "/foo", method = RequestMethod.GET)`.
|
||||
That is why one can write
|
||||
`@RequestMapping(value = "/toys", method = RequestMethod.GET)` or
|
||||
`@RequestMapping(path = "/toys", method = RequestMethod.GET)`.
|
||||
|
||||
However, in Kotlin 1.2+, one will have to write `@RequestMapping("/foo", method = [RequestMethod.GET])`
|
||||
or `@RequestMapping(path = ["/foo"], method = [RequestMethod.GET])` (square brackets need
|
||||
However, in Kotlin 1.2+, 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).
|
||||
|
||||
An alternative for this specific `method` attribute (the most common one) is to
|
||||
use a shortcut annotation such as `@GetMapping` or `@PostMapping`, etc.
|
||||
use a shortcut annotation, such as `@GetMapping`, `@PostMapping`, and others.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Reminder: If the `@RequestMapping` `method` attribute is not specified,
|
||||
NOTE: Reminder: If the `@RequestMapping` `method` attribute is not specified,
|
||||
all HTTP methods will be matched, not only the `GET` one.
|
||||
====
|
||||
|
||||
|
||||
|
||||
=== Testing
|
||||
|
||||
This section address testing with the combination of Kotlin and the Spring Framework.
|
||||
|
||||
==== Per class lifecycle
|
||||
|
||||
Kotlin allows one to specify meaningful test function names between backticks,
|
||||
and 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`
|
||||
|
||||
==== `PER_CLASS` Lifecycle
|
||||
|
||||
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.
|
||||
|
||||
It is now possible to change the default behavior to `PER_CLASS` thanks to a
|
||||
You can now 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 `@BeforeAll` and `@AfterAll` annotations on non-static methods:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
class IntegrationTests {
|
||||
@@ -635,12 +630,16 @@ class IntegrationTests {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
==== Specification-like tests
|
||||
|
||||
It is possible to create specification-like tests with JUnit 5 and Kotlin.
|
||||
==== Specification-like Tests
|
||||
|
||||
You can create specification-like tests with JUnit 5 and Kotlin.
|
||||
The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
class SpecificationLikeTests {
|
||||
@@ -664,13 +663,15 @@ class SpecificationLikeTests {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[kotlin-webtestclient-issue]]
|
||||
==== `WebTestClient` type inference issue in Kotlin
|
||||
==== `WebTestClient` Type Inference Issue in Kotlin
|
||||
|
||||
Due to a https://youtrack.jetbrains.com/issue/KT-5464[type inference issue], make sure to
|
||||
use Kotlin `expectBody` extension (like `.expectBody<String>().isEqualTo("foo")`) since it
|
||||
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.
|
||||
|
||||
See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
|
||||
@@ -678,41 +679,46 @@ See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
|
||||
|
||||
|
||||
[[kotlin-getting-started]]
|
||||
== Getting started
|
||||
== Getting Started
|
||||
|
||||
This section describes the fastest way to get started with a project that combines
|
||||
Kotlin and the Spring Framework.
|
||||
|
||||
|
||||
|
||||
=== start.spring.io
|
||||
=== Using `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].
|
||||
|
||||
It is also possible to create a standalone WebFlux project as described in
|
||||
You can also create a standalone WebFlux project, as described in
|
||||
https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way[this blog post].
|
||||
|
||||
|
||||
|
||||
=== Choosing the web flavor
|
||||
=== Choosing the Web Flavor
|
||||
|
||||
Spring Framework now comes with 2 different web stacks: <<web#mvc,Spring MVC>> and
|
||||
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 one wants to create applications that will deal with latency,
|
||||
long-lived connections, streaming scenarios or simply if one wants to use the web functional
|
||||
Spring WebFlux is recommended if you want to create applications that will deal with latency,
|
||||
long-lived connections, o streaming scenarios or if you want to use the web functional
|
||||
Kotlin DSL.
|
||||
|
||||
For other use cases, especially if you are using blocking technologies like JPA, Spring
|
||||
For other use cases, especially if you are using blocking technologies such as JPA, Spring
|
||||
MVC and its annotation-based programming model is a perfectly valid and fully supported choice.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-resources]]
|
||||
== Resources
|
||||
|
||||
We recommend the following resources for people learning how to build applications with
|
||||
Kotlin and the Spring Framework:
|
||||
|
||||
* http://kotlinlang.org/docs/reference/[Kotlin language reference]
|
||||
* http://slack.kotlinlang.org/[Kotlin Slack] (with a dedicated #spring channel)
|
||||
* https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow with `spring` and `kotlin` tags]
|
||||
* https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow, with `spring` and `kotlin` tags]
|
||||
* https://try.kotlinlang.org/[Try Kotlin in your browser]
|
||||
* https://blog.jetbrains.com/kotlin/[Kotlin blog]
|
||||
* https://kotlin.link/[Awesome Kotlin]
|
||||
@@ -721,6 +727,8 @@ MVC and its annotation-based programming model is a perfectly valid and fully su
|
||||
|
||||
=== Tutorials
|
||||
|
||||
We recommend the following tutorials:
|
||||
|
||||
* https://spring.io/guides/tutorials/spring-boot-kotlin/[Building web applications with Spring Boot and Kotlin]
|
||||
* https://kotlinlang.org/docs/tutorials/spring-boot-restful.html[Creating a RESTful Web Service with Spring Boot]
|
||||
|
||||
@@ -728,6 +736,8 @@ MVC and its annotation-based programming model is a perfectly valid and fully su
|
||||
|
||||
=== Blog posts
|
||||
|
||||
The following blog posts provide further details:
|
||||
|
||||
* https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin[Developing Spring Boot applications with Kotlin]
|
||||
* https://spring.io/blog/2016/03/20/a-geospatial-messenger-with-kotlin-spring-boot-and-postgresql[A Geospatial Messenger with Kotlin, Spring Boot and PostgreSQL]
|
||||
* https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0[Introducing Kotlin support in Spring Framework 5.0]
|
||||
@@ -737,44 +747,38 @@ MVC and its annotation-based programming model is a perfectly valid and fully su
|
||||
|
||||
=== Examples
|
||||
|
||||
* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: regular Spring Boot + Spring Data JPA project
|
||||
* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2 + WebFlux + Reactive Spring Data MongoDB
|
||||
* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: standalone WebFlux + functional bean definition DSL
|
||||
The following Github projects offer examples that you can learn from and possibly even extend:
|
||||
|
||||
* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: Regular Spring Boot and Spring Data JPA project
|
||||
* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2, WebFlux, and Reactive Spring Data MongoDB
|
||||
* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: Standalone WebFlux and functional bean definition DSL
|
||||
* https://github.com/sdeleuze/spring-kotlin-fullstack[spring-kotlin-fullstack]: WebFlux Kotlin fullstack example with Kotlin2js for frontend instead of JavaScript or TypeScript
|
||||
* https://github.com/spring-petclinic/spring-petclinic-kotlin[spring-petclinic-kotlin]: Kotlin version of the Spring PetClinic Sample Application
|
||||
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: a step by step migration for Boot 1.0 + Java to Boot 2.0 + Kotlin
|
||||
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin
|
||||
|
||||
|
||||
|
||||
=== Issues
|
||||
|
||||
Here is a list of pending issues related to Spring + Kotlin support.
|
||||
The following list categorizes the pending issues related to Spring and Kotlin support:
|
||||
|
||||
|
||||
==== Spring Framework
|
||||
|
||||
* https://jira.spring.io/browse/SPR-16057[Unable to use WebTestClient with mock server in Kotlin]
|
||||
* https://jira.spring.io/browse/SPR-15942[Support null-safety at generics, varargs and array elements level]
|
||||
* https://jira.spring.io/browse/SPR-15413[Add support for Kotlin coroutines]
|
||||
|
||||
|
||||
==== Spring Boot
|
||||
|
||||
* https://github.com/spring-projects/spring-boot/issues/8762[Allow `@ConfigurationProperties` binding for immutable POJOs]
|
||||
* https://github.com/spring-projects/spring-boot/issues/1254[Allow `@ConfigurationProperties` binding on interfaces]
|
||||
* https://github.com/spring-projects/spring-boot/issues/8115[Expose the functional bean registration API via `SpringApplication`]
|
||||
* https://github.com/spring-projects/spring-boot/issues/10712[Add null-safety annotations on Spring Boot APIs]
|
||||
* https://github.com/spring-projects/spring-boot/issues/9486[Use Kotlin's bom to provide dependency management for Kotlin]
|
||||
|
||||
|
||||
==== Kotlin
|
||||
|
||||
* https://youtrack.jetbrains.com/issue/KT-6380[Parent issue for Spring Framework support]
|
||||
* https://youtrack.jetbrains.com/issue/KT-5464[Kotlin requires type inference where Java doesn't]
|
||||
* https://github.com/Kotlin/KEEP/issues/79[Better generics null-safety support]
|
||||
* https://youtrack.jetbrains.com/issue/KT-20283[Smart cast regression with open classes]
|
||||
* https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function]
|
||||
* https://youtrack.jetbrains.com/issue/KT-19592[Apply JSR 305 meta-annotations to generic type parameters]
|
||||
* https://youtrack.jetbrains.com/issue/KT-18398[Provide a way for libraries to avoid mixing Kotlin 1.0 and 1.1 dependencies]
|
||||
* https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables]
|
||||
* https://youtrack.jetbrains.com/issue/KT-15467[Support all-open and no-arg compiler plugins in Kotlin Eclipse plugin]
|
||||
* Spring Framework
|
||||
** https://jira.spring.io/browse/SPR-16057[Unable to use WebTestClient with mock server in Kotlin]
|
||||
** https://jira.spring.io/browse/SPR-15942[Support null-safety at generics, varargs and array elements level]
|
||||
** https://jira.spring.io/browse/SPR-15413[Add support for Kotlin coroutines]
|
||||
* Spring Boot
|
||||
** https://github.com/spring-projects/spring-boot/issues/8762[Allow `@ConfigurationProperties` binding for immutable POJOs]
|
||||
** https://github.com/spring-projects/spring-boot/issues/1254[Allow `@ConfigurationProperties` binding on interfaces]
|
||||
** https://github.com/spring-projects/spring-boot/issues/8115[Expose the functional bean registration API via `SpringApplication`]
|
||||
** https://github.com/spring-projects/spring-boot/issues/10712[Add null-safety annotations on Spring Boot APIs]
|
||||
** https://github.com/spring-projects/spring-boot/issues/9486[Use Kotlin's bom to provide dependency management for Kotlin]
|
||||
* Kotlin
|
||||
** https://youtrack.jetbrains.com/issue/KT-6380[Parent issue for Spring Framework support]
|
||||
** https://youtrack.jetbrains.com/issue/KT-5464[Kotlin requires type inference where Java doesn't]
|
||||
** https://github.com/Kotlin/KEEP/issues/79[Better generics null-safety support]
|
||||
** https://youtrack.jetbrains.com/issue/KT-20283[Smart cast regression with open classes]
|
||||
** https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function]
|
||||
** https://youtrack.jetbrains.com/issue/KT-19592[Apply JSR 305 meta-annotations to generic type parameters]
|
||||
** https://youtrack.jetbrains.com/issue/KT-18398[Provide a way for libraries to avoid mixing Kotlin 1.0 and 1.1 dependencies]
|
||||
** https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables]
|
||||
** https://youtrack.jetbrains.com/issue/KT-15467[Support all-open and no-arg compiler plugins in Kotlin Eclipse plugin]
|
||||
|
||||
@@ -230,15 +230,14 @@ shows:
|
||||
};
|
||||
|
||||
ClientHttpConnector connector =
|
||||
new JettyClientHttpConnector(resourceFactory(), customizer); <2>
|
||||
new JettyClientHttpConnector(resourceFactory(), customizer); // <1>
|
||||
|
||||
return WebClient.builder().clientConnector(connector).build(); <3>
|
||||
return WebClient.builder().clientConnector(connector).build(); // <2>
|
||||
}
|
||||
----
|
||||
|
||||
<1> Create resource factory for shared resources.
|
||||
<2> Use the `JettyClientHttpConnector` constructor with resource factory.
|
||||
<3> Plug the connector into the `WebClient.Builder`.
|
||||
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
|
||||
<2> Plug the connector into the `WebClient.Builder`.
|
||||
====
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ If a publisher cannot slow down, it has to decide whether to buffer, drop, or fa
|
||||
|
||||
|
||||
[[webflux-reactive-api]]
|
||||
=== Reactive API
|
||||
== Reactive API
|
||||
|
||||
Reactive Streams plays an important role for interoperability. It is of interest to libraries
|
||||
and infrastructure components but less useful as an application API, because it is too
|
||||
@@ -103,7 +103,7 @@ of RxJava or another reactive library. See <<webflux-reactive-libraries>> for mo
|
||||
|
||||
|
||||
[[webflux-programming-models]]
|
||||
=== Programming Models
|
||||
== Programming Models
|
||||
|
||||
The `spring-web` module contains the reactive foundation that underlies Spring WebFlux,
|
||||
including HTTP abstractions, Reactive Streams <<webflux-httphandler,adapters>> for supported
|
||||
@@ -125,7 +125,7 @@ annotations and being called back.
|
||||
|
||||
|
||||
[[webflux-framework-choice]]
|
||||
=== Applicability
|
||||
== Applicability
|
||||
|
||||
Spring MVC or WebFlux?
|
||||
|
||||
@@ -181,7 +181,7 @@ unsure what benefits to look for, start by learning about how non-blocking I/O w
|
||||
|
||||
|
||||
[[webflux-server-choice]]
|
||||
=== Servers
|
||||
== Servers
|
||||
|
||||
Spring WebFlux is supported on Tomcat, Jetty, Servlet 3.1+ containers, as well as on
|
||||
non-Servlet runtimes such as Netty and Undertow. All servers are adapted to a low-level,
|
||||
@@ -209,7 +209,7 @@ For Undertow, Spring WebFlux uses Undertow APIs directly without the Servlet API
|
||||
|
||||
|
||||
[[webflux-performance]]
|
||||
=== Performance versus Scale
|
||||
== Performance versus Scale
|
||||
|
||||
Performance has many characteristics and meanings. Reactive and non-blocking generally
|
||||
do not make applications run faster. They can, in some cases, (for example, if using the
|
||||
@@ -226,7 +226,7 @@ dramatic.
|
||||
|
||||
|
||||
[[webflux-concurrency-model]]
|
||||
=== Concurrency Model
|
||||
== Concurrency Model
|
||||
|
||||
Both Spring MVC and Spring WebFlux support annotated controllers, but there is a key
|
||||
difference in the concurrency model and the default assumptions for blocking and threads.
|
||||
|
||||
Reference in New Issue
Block a user