diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 07410c41464..18314a12513 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -3868,7 +3868,7 @@ Notice how the `InstantiationTracingBeanPostProcessor` is simply defined. It doe even have a name, and because it is a bean it can be dependency-injected just like any other bean. (The preceding configuration also defines a bean that is backed by a Groovy script. The Spring dynamic language support is detailed in the chapter entitled -<>.) +<>.) The following simple Java application executes the preceding code and configuration: diff --git a/src/docs/asciidoc/core/core-null-safety.adoc b/src/docs/asciidoc/core/core-null-safety.adoc index a32cc584a8a..5ea8ccd2f9f 100644 --- a/src/docs/asciidoc/core/core-null-safety.adoc +++ b/src/docs/asciidoc/core/core-null-safety.adoc @@ -40,7 +40,7 @@ at runtime. They are also used to make Spring API null-safe in Kotlin projects since Kotlin natively supports https://kotlinlang.org/docs/reference/null-safety.html[null-safety]. More details -are available in <>. +are available in <>. == JSR 305 meta-annotations diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index a903ce675c1..a0bab71aed4 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -22,5 +22,5 @@ ORM, Marshalling XML. <> :: Spring WebFlux, WebClient, WebSocket. <> :: Remoting, JMS, JCA, JMX, Email, -Tasks, Scheduling, Cache, Dynamic languages. -<> :: Extensions, Bean Definition DSL, WebFlux DSL. +Tasks, Scheduling, Cache. +<> :: Kotlin, Groovy, Dynamic languages. diff --git a/src/docs/asciidoc/integration-appendix.adoc b/src/docs/asciidoc/integration-appendix.adoc index 69518628825..0f5628e1839 100644 --- a/src/docs/asciidoc/integration-appendix.adoc +++ b/src/docs/asciidoc/integration-appendix.adoc @@ -258,35 +258,6 @@ After... -[[xsd-schemas-lang]] -=== The lang schema - -The `lang` tags 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 <>. -Please do consult that chapter for full details on this support and the `lang` tags themselves. - -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 -following snippet references the correct schema so that the tags in the `lang` namespace -are available to you. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - - [[xsd-schemas-jms]] === The jms schema diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index 05908c20bff..9bf4b1e61a2 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -6841,890 +6841,6 @@ javadocs] for more information. -[[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 -objects. - -The dynamic languages currently supported are: - -* JRuby 1.5+ -* Groovy 1.8+ -* BeanShell 2.0 - -.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. -**** - -Fully working examples of where this dynamic language support can be immediately useful -are described in <>. - - - -[[dynamic-language-a-first-example]] -=== A first example - -This 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 -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. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting; - - public interface Messenger { - - String getMessage(); - - } ----- - -Here is the definition of a class that has a dependency on the `Messenger` interface. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting; - - public class DefaultBookingService implements BookingService { - - private Messenger messenger; - - public void setMessenger(Messenger messenger) { - this.messenger = messenger; - } - - public void processBooking() { - // use the injected Messenger object... - } - - } ----- - -Here is an implementation of the `Messenger` interface in Groovy. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // from the file 'Messenger.groovy' - package org.springframework.scripting.groovy; - - // import the Messenger interface (written in Java) that is to be implemented - import org.springframework.scripting.Messenger - - // define the implementation in Groovy - class GroovyMessenger implements Messenger { - - String message - - } ----- - -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 -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. - -For more information on schema-based configuration, see <>. -==== - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - ----- - -The `bookingService` bean (a `DefaultBookingService`) can now use its private -`messenger` member variable as normal because the `Messenger` instance that was injected -into it __is__ a `Messenger` instance. There is nothing special going on here, just -plain Java and plain Groovy. - -Hopefully the 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 -configuration. - - - -[[dynamic-language-beans]] -=== Defining beans that are backed by dynamic languages - -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 -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 <> at the end of this chapter. - - -[[dynamic-language-beans-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 `` - 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). - -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 -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 -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 element - -The final step 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 -`` element to define the dynamic language-backed bean. - -Each of the supported languages has a corresponding `` element: - -* `` (Groovy) -* `` (BeanShell) -* `` (JSR-223) - -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). - -[[dynamic-language-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. - -A refreshable bean is a dynamic-language-backed bean that 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). - -This allows a developer to 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 -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 -changed dynamic language source file. - -[NOTE] -==== -Please note that 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 `` element of your bean definition. -So if we stick with <> from earlier in this -chapter, here's what we would change in the Spring XML configuration to effect -refreshable beans: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - script-source="classpath:Messenger.groovy"> - - - - - - - - ----- - -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 -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. - -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 -the program resumes execution. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.context.ApplicationContext; - import org.springframework.context.support.ClassPathXmlApplicationContext; - import org.springframework.scripting.Messenger; - - public final class Boot { - - public static void main(final String[] args) throws Exception { - ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); - Messenger messenger = (Messenger) ctx.getBean("messenger"); - System.out.println(messenger.getMessage()); - // pause execution while I go off and make changes to the source file... - System.in.read(); - System.out.println(messenger.getMessage()); - } - } ----- - -Let's 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. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting - - class GroovyMessenger implements Messenger { - - private String message = "Bingo" - - public String getMessage() { - // change the implementation to surround the message in quotes - return "'" + this.message + "'" - } - - public void setMessage(String message) { - this.message = message - } - } ----- - -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 -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). - -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 -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. - -The refreshable bean behavior described above does __not__ apply to dynamic language -source files defined using the `` element notation (see -<>). Additionally, it __only__ applies 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. - -[[dynamic-language-beans-inline]] -===== Inline dynamic language source files - -The dynamic language support can also cater for dynamic language source files that are -embedded directly in Spring bean definitions. More specifically, the -`` 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: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - package org.springframework.scripting.groovy; - - import org.springframework.scripting.Messenger - - class GroovyMessenger implements Messenger { - String message - } - - - - ----- - -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 `` -element can be useful in some scenarios. For instance, we might want to quickly add a -Spring `Validator` implementation to a Spring MVC `Controller`. This is but a moment's -work using inline source. (See <> 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-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. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // from the file 'Messenger.groovy' - package org.springframework.scripting.groovy; - - import org.springframework.scripting.Messenger - - class GroovyMessenger implements Messenger { - - GroovyMessenger() {} - - // this constructor is not available for Constructor Injection - GroovyMessenger(String message) { - this.message = message; - } - - String message - - String anotherMessage - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -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). - - -[[dynamic-language-beans-groovy]] -==== Groovy beans - -.The Groovy library dependencies -**** - -The Groovy scripting support in Spring requires the following libraries to be on the -classpath of your application. - -* `groovy-1.8.jar` -* `asm-3.2.jar` -* `antlr-2.7.7.jar` -**** - -From the Groovy homepage... - -"__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. __" - -If you have read this chapter straight from the top, you will already have -<> of a Groovy-dynamic-language-backed -bean. Let's look at another example (again using an example from the Spring test suite). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting; - - public interface Calculator { - - int add(int x, int y); - - } ----- - -Here is an implementation of the `Calculator` interface in Groovy. - -[source,groovy,indent=0] -[subs="verbatim,quotes"] ----- - // from the file 'calculator.groovy' - package org.springframework.scripting.groovy - - class GroovyCalculator implements Calculator { - - int add(int x, int y) { - x + y - } - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - <-- from the file 'beans.xml' --> - - - ----- - -Lastly, here is a small application to exercise the above configuration. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting; - - import org.springframework.context.ApplicationContext; - import org.springframework.context.support.ClassPathXmlApplicationContext; - - public class Main { - - public static void Main(String[] args) { - ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); - Calculator calc = (Calculator) ctx.getBean("calculator"); - System.out.println(calc.add(2, 8)); - } - } ----- - -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 -<> 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 -the standard Java conventions of one (public) class per source file. - -[[dynamic-language-beans-groovy-customizer]] -===== Customizing Groovy objects via a callback - -The `GroovyObjectCustomizer` interface is a callback that allows you to 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`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface GroovyObjectCustomizer { - - 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. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public final class SimpleMethodTracingCustomizer implements GroovyObjectCustomizer { - - public void customize(GroovyObject goo) { - DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) { - - public Object invokeMethod(Object object, String methodName, Object[] arguments) { - System.out.println("Invoking '" + methodName + "'."); - return super.invokeMethod(object, methodName, arguments); - } - }; - metaClass.initialize(); - goo.setMetaClass(metaClass); - } - - } ----- - -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. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -If you are not using the Spring namespace support, you can still use the -`GroovyObjectCustomizer` functionality. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -[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 - -.The BeanShell library dependencies -**** - -The BeanShell scripting support in Spring requires the following libraries to be on the -classpath of your application. - -* `bsh-2.0b4.jar` -**** - -From the BeanShell homepage... - -"__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.__" - -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 `` 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. - -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). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.scripting; - - public interface Messenger { - - String getMessage(); - - } ----- - -Here is the BeanShell 'implementation' (the term is used loosely here) of the -`Messenger` interface. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - String message; - - String getMessage() { - return message; - } - - void setMessage(String aMessage) { - message = aMessage; - } ----- - -And here is the Spring XML that defines an 'instance' of the above 'class' (again, the -term is used very loosely here). - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -See <> for some scenarios where you might want to use -BeanShell-based beans. - - - -[[dynamic-language-scenarios]] -=== 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 -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 -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 -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 -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. - -[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 -<> for a full treatment of this feature. -==== - -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"] ----- - // from the file '/WEB-INF/groovy/FortuneController.groovy' - package org.springframework.showcase.fortune.web - - import org.springframework.showcase.fortune.service.FortuneService - import org.springframework.showcase.fortune.domain.Fortune - import org.springframework.web.servlet.ModelAndView - import org.springframework.web.servlet.mvc.Controller - - import javax.servlet.http.HttpServletRequest - import javax.servlet.http.HttpServletResponse - - class FortuneController implements Controller { - - @Property FortuneService fortuneService - - ModelAndView handleRequest(HttpServletRequest request, - HttpServletResponse httpServletResponse) { - return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune()) - } - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - - -[[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 -(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 -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' -feature. See <> 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 <> for a discussion of the -`Validator` interface.) - -[source,groovy,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.validation.Validator - import org.springframework.validation.Errors - import org.springframework.beans.TestBean - - class TestBeanValidator implements Validator { - - boolean supports(Class clazz) { - return TestBean.class.isAssignableFrom(clazz) - } - - void validate(Object bean, Errors errors) { - if(bean.name?.trim()?.size() > 0) { - return - } - errors.reject("whitespace", "Cannot be composed wholly of whitespace.") - } - - } ----- - - - -[[dynamic-language-final-notes]] -=== Bits and bobs - -This last section contains some bits and bobs related to the dynamic language support. - - -[[dynamic-language-final-notes-aop]] -==== AOP - advising scripted beans - -It is possible to 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 -use <>. - -You are of course not just 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 `` elements allows -you to control the scope of the underlying scripted bean, just as it does with a regular -bean. (The default scope is <>, just as it is -with 'regular' beans.) - -Find below an example of using the `scope` attribute to define a Groovy bean scoped as -a <>. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -See <> in <> -for a fuller discussion of the scoping support in the Spring Framework. - - - -[[dynamic-language-resources]] -=== Further Resources - -Find below links 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 -* The http://www.beanshell.org/[BeanShell] homepage - - - - [[cache]] == Cache Abstraction diff --git a/src/docs/asciidoc/languages.adoc b/src/docs/asciidoc/languages.adoc new file mode 100644 index 00000000000..3937f1a6d4d --- /dev/null +++ b/src/docs/asciidoc/languages.adoc @@ -0,0 +1,16 @@ +[[lanugages]] += Language Support +:doc-root: https://docs.spring.io +:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework +:toc: left +:toclevels: 4 +:docinfo1: + + +include::languages/kotlin.adoc[leveloffset=+1] + +include::languages/groovy.adoc[leveloffset=+1] + +include::languages/dynamic-languages.adoc[leveloffset=+1] + + diff --git a/src/docs/asciidoc/languages/dynamic-languages.adoc b/src/docs/asciidoc/languages/dynamic-languages.adoc new file mode 100644 index 00000000000..842834713a7 --- /dev/null +++ b/src/docs/asciidoc/languages/dynamic-languages.adoc @@ -0,0 +1,912 @@ +[[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 +objects. + +The dynamic languages currently supported are: + +* JRuby 1.5+ +* Groovy 1.8+ +* BeanShell 2.0 + +.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. +**** + +Fully working examples of where this dynamic language support can be immediately useful +are described in <>. + + + +[[dynamic-language-a-first-example]] +== A first example + +This 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 +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. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting; + + public interface Messenger { + + String getMessage(); + + } +---- + +Here is the definition of a class that has a dependency on the `Messenger` interface. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting; + + public class DefaultBookingService implements BookingService { + + private Messenger messenger; + + public void setMessenger(Messenger messenger) { + this.messenger = messenger; + } + + public void processBooking() { + // use the injected Messenger object... + } + + } +---- + +Here is an implementation of the `Messenger` interface in Groovy. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // from the file 'Messenger.groovy' + package org.springframework.scripting.groovy; + + // import the Messenger interface (written in Java) that is to be implemented + import org.springframework.scripting.Messenger + + // define the implementation in Groovy + class GroovyMessenger implements Messenger { + + String message + + } +---- + +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 +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. + +For more information on schema-based configuration, see <>. +==== + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + +---- + +The `bookingService` bean (a `DefaultBookingService`) can now use its private +`messenger` member variable as normal because the `Messenger` instance that was injected +into it __is__ a `Messenger` instance. There is nothing special going on here, just +plain Java and plain Groovy. + +Hopefully the 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 +configuration. + + + +[[dynamic-language-beans]] +== Defining beans that are backed by dynamic languages + +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 +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 <> at the end of this chapter. + + +[[dynamic-language-beans-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 `` + 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). + +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 +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 +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 element + +The final step 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 +`` element to define the dynamic language-backed bean. + +Each of the supported languages has a corresponding `` element: + +* `` (Groovy) +* `` (BeanShell) +* `` (JSR-223) + +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). + +[[dynamic-language-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. + +A refreshable bean is a dynamic-language-backed bean that 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). + +This allows a developer to 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 +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 +changed dynamic language source file. + +[NOTE] +==== +Please note that 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 `` element of your bean definition. +So if we stick with <> from earlier in this +chapter, here's what we would change in the Spring XML configuration to effect +refreshable beans: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + script-source="classpath:Messenger.groovy"> + + + + + + + + +---- + +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 +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. + +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 +the program resumes execution. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.context.ApplicationContext; + import org.springframework.context.support.ClassPathXmlApplicationContext; + import org.springframework.scripting.Messenger; + + public final class Boot { + + public static void main(final String[] args) throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + System.out.println(messenger.getMessage()); + // pause execution while I go off and make changes to the source file... + System.in.read(); + System.out.println(messenger.getMessage()); + } + } +---- + +Let's 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. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting + + class GroovyMessenger implements Messenger { + + private String message = "Bingo" + + public String getMessage() { + // change the implementation to surround the message in quotes + return "'" + this.message + "'" + } + + public void setMessage(String message) { + this.message = message + } + } +---- + +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 +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). + +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 +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. + +The refreshable bean behavior described above does __not__ apply to dynamic language +source files defined using the `` element notation (see +<>). Additionally, it __only__ applies 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. + +[[dynamic-language-beans-inline]] +==== Inline dynamic language source files + +The dynamic language support can also cater for dynamic language source files that are +embedded directly in Spring bean definitions. More specifically, the +`` 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: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + package org.springframework.scripting.groovy; + + import org.springframework.scripting.Messenger + + class GroovyMessenger implements Messenger { + String message + } + + + + +---- + +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 `` +element can be useful in some scenarios. For instance, we might want to quickly add a +Spring `Validator` implementation to a Spring MVC `Controller`. This is but a moment's +work using inline source. (See <> 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-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. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // from the file 'Messenger.groovy' + package org.springframework.scripting.groovy; + + import org.springframework.scripting.Messenger + + class GroovyMessenger implements Messenger { + + GroovyMessenger() {} + + // this constructor is not available for Constructor Injection + GroovyMessenger(String message) { + this.message = message; + } + + String message + + String anotherMessage + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +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). + + +[[dynamic-language-beans-groovy]] +=== Groovy beans + +.The Groovy library dependencies +**** + +The Groovy scripting support in Spring requires the following libraries to be on the +classpath of your application. + +* `groovy-1.8.jar` +* `asm-3.2.jar` +* `antlr-2.7.7.jar` +**** + +From the Groovy homepage... + +"__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. __" + +If you have read this chapter straight from the top, you will already have +<> of a Groovy-dynamic-language-backed +bean. Let's look at another example (again using an example from the Spring test suite). + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting; + + public interface Calculator { + + int add(int x, int y); + + } +---- + +Here is an implementation of the `Calculator` interface in Groovy. + +[source,groovy,indent=0] +[subs="verbatim,quotes"] +---- + // from the file 'calculator.groovy' + package org.springframework.scripting.groovy + + class GroovyCalculator implements Calculator { + + int add(int x, int y) { + x + y + } + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + <-- from the file 'beans.xml' --> + + + +---- + +Lastly, here is a small application to exercise the above configuration. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting; + + import org.springframework.context.ApplicationContext; + import org.springframework.context.support.ClassPathXmlApplicationContext; + + public class Main { + + public static void Main(String[] args) { + ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); + Calculator calc = (Calculator) ctx.getBean("calculator"); + System.out.println(calc.add(2, 8)); + } + } +---- + +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 +<> 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 +the standard Java conventions of one (public) class per source file. + +[[dynamic-language-beans-groovy-customizer]] +==== Customizing Groovy objects via a callback + +The `GroovyObjectCustomizer` interface is a callback that allows you to 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`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface GroovyObjectCustomizer { + + 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. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public final class SimpleMethodTracingCustomizer implements GroovyObjectCustomizer { + + public void customize(GroovyObject goo) { + DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) { + + public Object invokeMethod(Object object, String methodName, Object[] arguments) { + System.out.println("Invoking '" + methodName + "'."); + return super.invokeMethod(object, methodName, arguments); + } + }; + metaClass.initialize(); + goo.setMetaClass(metaClass); + } + + } +---- + +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. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +If you are not using the Spring namespace support, you can still use the +`GroovyObjectCustomizer` functionality. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +[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 + +.The BeanShell library dependencies +**** + +The BeanShell scripting support in Spring requires the following libraries to be on the +classpath of your application. + +* `bsh-2.0b4.jar` +**** + +From the BeanShell homepage... + +"__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.__" + +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 `` 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. + +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). + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.scripting; + + public interface Messenger { + + String getMessage(); + + } +---- + +Here is the BeanShell 'implementation' (the term is used loosely here) of the +`Messenger` interface. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + String message; + + String getMessage() { + return message; + } + + void setMessage(String aMessage) { + message = aMessage; + } +---- + +And here is the Spring XML that defines an 'instance' of the above 'class' (again, the +term is used very loosely here). + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +See <> for some scenarios where you might want to use +BeanShell-based beans. + + + +[[dynamic-language-scenarios]] +== 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 +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 +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 +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 +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. + +[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 +<> for a full treatment of this feature. +==== + +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"] +---- + // from the file '/WEB-INF/groovy/FortuneController.groovy' + package org.springframework.showcase.fortune.web + + import org.springframework.showcase.fortune.service.FortuneService + import org.springframework.showcase.fortune.domain.Fortune + import org.springframework.web.servlet.ModelAndView + import org.springframework.web.servlet.mvc.Controller + + import javax.servlet.http.HttpServletRequest + import javax.servlet.http.HttpServletResponse + + class FortuneController implements Controller { + + @Property FortuneService fortuneService + + ModelAndView handleRequest(HttpServletRequest request, + HttpServletResponse httpServletResponse) { + return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune()) + } + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + + +[[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 +(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 +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' +feature. See <> 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 <> for a discussion of the +`Validator` interface.) + +[source,groovy,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.validation.Validator + import org.springframework.validation.Errors + import org.springframework.beans.TestBean + + class TestBeanValidator implements Validator { + + boolean supports(Class clazz) { + return TestBean.class.isAssignableFrom(clazz) + } + + void validate(Object bean, Errors errors) { + if(bean.name?.trim()?.size() > 0) { + return + } + errors.reject("whitespace", "Cannot be composed wholly of whitespace.") + } + + } +---- + + + +[[dynamic-language-final-notes]] +== Bits and bobs + +This last section contains some bits and bobs related to the dynamic language support. + + +[[dynamic-language-final-notes-aop]] +=== AOP - advising scripted beans + +It is possible to 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 +use <>. + +You are of course not just 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 `` elements allows +you to control the scope of the underlying scripted bean, just as it does with a regular +bean. (The default scope is <>, just as it is +with 'regular' beans.) + +Find below an example of using the `scope` attribute to define a Groovy bean scoped as +a <>. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + +---- + +See <> in <> +for a fuller discussion of the scoping support in the Spring Framework. + + + + +[[xsd-schemas-lang]] +=== 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. + +These tags (and the dynamic language support) are comprehensively covered in the chapter +entitled <>. +Please do consult that chapter for full details on this support and the `lang` tags themselves. + +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 +following snippet references the correct schema so that the tags in the `lang` namespace +are available to you. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + + + + +[[dynamic-language-resources]] +== Further Resources + +Find below links 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 +* The http://www.beanshell.org/[BeanShell] homepage diff --git a/src/docs/asciidoc/languages/groovy.adoc b/src/docs/asciidoc/languages/groovy.adoc new file mode 100644 index 00000000000..992f60019c7 --- /dev/null +++ b/src/docs/asciidoc/languages/groovy.adoc @@ -0,0 +1,13 @@ +[[groovy]] += Apache Groovy + +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. + +The Spring Framework provides a dedicated `ApplicationContext` that supports a Groovy-based +Bean Definition DSL. For more details, see +<>. + +Further support for Groovy including beans written in Groovy, refreshable script beans, +and more is available in next the section <>. diff --git a/src/docs/asciidoc/kotlin.adoc b/src/docs/asciidoc/languages/kotlin.adoc similarity index 97% rename from src/docs/asciidoc/kotlin.adoc rename to src/docs/asciidoc/languages/kotlin.adoc index 34761c40d0e..2fc2df615fa 100644 --- a/src/docs/asciidoc/kotlin.adoc +++ b/src/docs/asciidoc/languages/kotlin.adoc @@ -1,29 +1,18 @@ [[kotlin]] -= Kotlin support -:doc-root: https://docs.spring.io -:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework -:toc: left -:toclevels: 4 -:docinfo1: - - - - -[[introduction]] -== Introduction += Kotlin https://kotlinlang.org[Kotlin] is a statically-typed language targeting 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. -Spring Framework 5 introduces first-class support for Kotlin and allows developers to write -Spring + Kotlin applications almost as if the Spring Framework was a native Kotlin framework. +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. -[[requirements]] +[[kotlin-requirements]] == Requirements Spring Framework supports Kotlin 1.1+ and requires @@ -37,7 +26,7 @@ https://start.spring.io/#!language=kotlin[start.spring.io]. -[[extensions]] +[[kotlin-extensions]] == Extensions Kotlin https://kotlinlang.org/docs/reference/extensions.html[extensions] provide the ability @@ -89,7 +78,7 @@ for shorter syntax. -[[null-safety]] +[[kotlin-null-safety]] == Null-safety One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety] @@ -132,7 +121,7 @@ for up-to-date information. -[[classes-interfaces]] +[[kotlin-classes-interfaces]] == Classes & Interfaces Spring Framework supports various Kotlin constructs like instantiating Kotlin classes @@ -156,7 +145,7 @@ As of Spring Boot 2.0, Jackson Kotlin module is automatically provided via the J -[[annotations]] +[[kotlin-annotations]] == Annotations Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety] @@ -173,7 +162,7 @@ won’t raise an error if such bean does not exist. -[[bean-definition-dsl]] +[[kotlin-bean-definition-dsl]] == Bean definition DSL Spring Framework 5 introduces a new way to register beans in a functional way using lambdas @@ -275,7 +264,7 @@ for more details and up-to-date information. -[[web]] +[[kotlin-web]] == Web @@ -357,7 +346,7 @@ project for more details. -[[spring-projects-in-kotlin]] +[[kotlin-spring-projects-in-kotlin]] == Spring projects in Kotlin This section provides focus on some specific hints and recommendations worth @@ -667,7 +656,7 @@ class SpecificationLikeTests { -[[getting-started]] +[[kotlin-getting-started]] == Getting started @@ -697,7 +686,7 @@ MVC and its annotation-based programming model is a perfectly valid and fully su -[[resources-started]] +[[kotlin-resources-started]] == Resources * http://kotlinlang.org/docs/reference/[Kotlin language reference]