diff --git a/src/docs/asciidoc/core/core-aop.adoc b/src/docs/asciidoc/core/core-aop.adoc index a342ab9421..62009be9aa 100644 --- a/src/docs/asciidoc/core/core-aop.adoc +++ b/src/docs/asciidoc/core/core-aop.adoc @@ -481,33 +481,38 @@ pointcut expressions by name. The following example shows three pointcut express [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- - // matches if a method execution join point represents the execution of any public method @Pointcut("execution(public * *(..))") - private void anyPublicOperation() {} + private void anyPublicOperation() {} // <1> - // matches if a method execution is in the trading module @Pointcut("within(com.xyz.someapp.trading..*)") - private void inTrading() {} + private void inTrading() {} // <2> - // matches if a method execution represents any public method in the trading module @Pointcut("anyPublicOperation() && inTrading()") - private void tradingOperation() {} + private void tradingOperation() {} // <3> ---- +<1> `anyPublicOperation` matches if a method execution join point represents the execution +of any public method. +<2> `inTrading` matches if a method execution is in the trading module. +<3> `tradingOperation` matches if a method execution represents any public method in the +trading module. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- - // matches if a method execution join point represents the execution of any public method. @Pointcut("execution(public * *(..))") - private fun anyPublicOperation() {} + private fun anyPublicOperation() {} // <1> - // matches if a method execution is in the trading module @Pointcut("within(com.xyz.someapp.trading..*)") - private fun inTrading() {} + private fun inTrading() {} // <2> - // matches if a method execution represents any public method in the trading module @Pointcut("anyPublicOperation() && inTrading()") - private fun tradingOperation() {} + private fun tradingOperation() {} // <3> ---- +<1> `anyPublicOperation` matches if a method execution join point represents the execution +of any public method. +<2> `inTrading` matches if a method execution is in the trading module. +<3> `tradingOperation` matches if a method execution represents any public method in the +trading module. It is a best practice to build more complex pointcut expressions out of smaller named components, as shown earlier. When referring to pointcuts by name, normal Java visibility diff --git a/src/docs/asciidoc/core/core-appendix.adoc b/src/docs/asciidoc/core/core-appendix.adoc index 3a27c330e6..e047d3d8ea 100644 --- a/src/docs/asciidoc/core/core-appendix.adoc +++ b/src/docs/asciidoc/core/core-appendix.adoc @@ -860,14 +860,10 @@ we can parse our custom XML content, as you can see in the following example: import java.text.SimpleDateFormat; - // We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of - // the basic grunt work of creating a single BeanDefinition. - public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // <1> protected Class getBeanClass(Element element) { - // We supply the AbstractSingleBeanDefinitionParser superclass with the type that our - // single BeanDefinition represents. - return SimpleDateFormat.class; + return SimpleDateFormat.class; // <2> } protected void doParse(Element element, BeanDefinitionBuilder bean) { @@ -884,6 +880,11 @@ we can parse our custom XML content, as you can see in the following example: } ---- +<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of +the basic grunt work of creating a single `BeanDefinition`. +<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our +single `BeanDefinition` represents. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- @@ -896,13 +897,9 @@ we can parse our custom XML content, as you can see in the following example: import java.text.SimpleDateFormat - // We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of - // the basic grunt work of creating a single BeanDefinition. - class SimpleDateFormatBeanDefinitionParser : AbstractSingleBeanDefinitionParser() { + class SimpleDateFormatBeanDefinitionParser : AbstractSingleBeanDefinitionParser() { // <1> - override fun getBeanClass(element: Element): Class<*>? { - // We supply the AbstractSingleBeanDefinitionParser superclass with the type that our - // single BeanDefinition represents. + override fun getBeanClass(element: Element): Class<*>? { // <2> return SimpleDateFormat::class.java } @@ -919,6 +916,11 @@ we can parse our custom XML content, as you can see in the following example: } } ---- +<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of +the basic grunt work of creating a single `BeanDefinition`. +<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our +single `BeanDefinition` represents. + In this simple case, this is all that we need to do. The creation of our single `BeanDefinition` is handled by the `AbstractSingleBeanDefinitionParser` superclass, as diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 69667ded09..06300027ab 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -5599,24 +5599,27 @@ following example: public class MovieRecommender { @Autowired - @Offline + @Offline // <1> private MovieCatalog offlineCatalog; // ... } ---- +<1> This line adds the `@Offline` annotation. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- class MovieRecommender { @Autowired - @Offline + @Offline // <1> private lateinit var offlineCatalog: MovieCatalog // ... } ---- +<1> This line adds the `@Offline` annotation. Now the bean definition only needs a qualifier `type`, as shown in the following example: @@ -5915,21 +5918,24 @@ as demonstrated in the following example: private MovieFinder movieFinder; - @Resource(name="myMovieFinder") // This line injects a @Resource + @Resource(name="myMovieFinder") // <1> public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } } ---- +<1> This line injects a `@Resource`. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- class SimpleMovieLister { - @Resource(name="myMovieFinder") // This line injects a @Resource + @Resource(name="myMovieFinder") // <1> private lateinit var movieFinder:MovieFinder } ---- +<1> This line injects a `@Resource`. If no name is explicitly specified, the default name is derived from the field name or @@ -5986,10 +5992,8 @@ named "customerPreferenceDao" and then falls back to a primary type match for th @Resource private CustomerPreferenceDao customerPreferenceDao; - // The context field is injected based on the known resolvable dependency - // type: ApplicationContext @Resource - private ApplicationContext context; + private ApplicationContext context; // <1> public MovieRecommender() { } @@ -5997,6 +6001,9 @@ named "customerPreferenceDao" and then falls back to a primary type match for th // ... } ---- +<1> The `context` field is injected based on the known resolvable dependency type: +`ApplicationContext`. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- @@ -6005,14 +6012,15 @@ named "customerPreferenceDao" and then falls back to a primary type match for th @Resource private lateinit var customerPreferenceDao: CustomerPreferenceDao - // The context field is injected based on the known resolvable dependency - // type: ApplicationContext + @Resource - private lateinit var context: ApplicationContext + private lateinit var context: ApplicationContext // <1> // ... } ---- +<1> The `context` field is injected based on the known resolvable dependency type: +`ApplicationContext`. [[beans-value-annotations]] === Using `@Value` @@ -6341,24 +6349,27 @@ is meta-annotated with `@Component`, as the following example shows: @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented - @Component // Causes @Service to be treated in the same way as @Component + @Component // <1> public @interface Service { // ... } ---- +<1> The `Component` causes `@Service` to be treated in the same way as `@Component`. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- @Target(AnnotationTarget.TYPE) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented - @Component // Causes @Service to be treated in the same way as @Component + @Component // <1> annotation class Service { // ... } ---- +<1> The `Component` causes `@Service` to be treated in the same way as `@Component`. You can also combine meta-annotations to create "`composed annotations`". For example, the `@RestController` annotation from Spring MVC is composed of `@Controller` and @@ -7779,20 +7790,23 @@ To enable component scanning, you can annotate your `@Configuration` class as fo .Java ---- @Configuration - @ComponentScan(basePackages = "com.acme") // This annotation enables component scanning + @ComponentScan(basePackages = "com.acme") // <1> public class AppConfig { ... } ---- +<1> This annotation enables component scanning. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- @Configuration - @ComponentScan(basePackages = ["com.acme"]) // This annotation enables component scanning + @ComponentScan(basePackages = ["com.acme"]) // <1> class AppConfig { // ... } ---- +<1> This annotation enables component scanning. [TIP] @@ -9655,7 +9669,7 @@ the following example shows: public class AppConfig { @Bean("dataSource") - @Profile("development") // The standaloneDataSource method is available only in the development profile + @Profile("development") // <1> public DataSource standaloneDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) @@ -9665,13 +9679,16 @@ the following example shows: } @Bean("dataSource") - @Profile("production") // The jndiDataSource method is available only in the production profile + @Profile("production") // <2> public DataSource jndiDataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); } } ---- +<1> The `standaloneDataSource` method is available only in the `development` profile. +<2> The `jndiDataSource` method is available only in the `production` profile. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- @@ -9679,7 +9696,7 @@ the following example shows: class AppConfig { @Bean("dataSource") - @Profile("development") // The standaloneDataSource method is available only in the development profile + @Profile("development") // <1> fun standaloneDataSource(): DataSource { return EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) @@ -9689,11 +9706,13 @@ the following example shows: } @Bean("dataSource") - @Profile("production") // The jndiDataSource method is available only in the production profile + @Profile("production") // <2> fun jndiDataSource() = InitialContext().lookup("java:comp/env/jdbc/datasource") as DataSource } ---- +<1> The `standaloneDataSource` method is available only in the `development` profile. +<2> The `jndiDataSource` method is available only in the `production` profile. [NOTE] ==== diff --git a/src/docs/asciidoc/core/core-expressions.adoc b/src/docs/asciidoc/core/core-expressions.adoc index a85607ada7..369b972466 100644 --- a/src/docs/asciidoc/core/core-expressions.adoc +++ b/src/docs/asciidoc/core/core-expressions.adoc @@ -69,16 +69,19 @@ The following code introduces the SpEL API to evaluate the literal string expres .Java ---- ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("'Hello World'"); // The value of the message variable is 'Hello World' + Expression exp = parser.parseExpression("'Hello World'"); // <1> String message = (String) exp.getValue(); ---- +<1> The value of the message variable is `'Hello World'`. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- val parser = SpelExpressionParser() - val exp = parser.parseExpression("'Hello World'") // The value of the message variable is 'Hello World' + val exp = parser.parseExpression("'Hello World'") // <1> val message = exp.value as String ---- +<1> The value of the message variable is `'Hello World'`. The SpEL classes and interfaces you are most likely to use are located in the @@ -100,18 +103,19 @@ In the following example of method invocation, we call the `concat` method on th .Java ---- ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("'Hello World'.concat('!')"); - // The value of message is now 'Hello World!' + Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1> String message = (String) exp.getValue(); ---- +<1> The value of `message` is now 'Hello World!'. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- val parser = SpelExpressionParser() - val exp = parser.parseExpression("'Hello World'.concat('!')") - // The value of message is now 'Hello World!' + val exp = parser.parseExpression("'Hello World'.concat('!')") // <1> val message = exp.value as String ---- +<1> The value of `message` is now 'Hello World!'. The following example of calling a JavaBean property calls the `String` property `Bytes`: @@ -121,18 +125,21 @@ The following example of calling a JavaBean property calls the `String` property ExpressionParser parser = new SpelExpressionParser(); // invokes 'getBytes()' - Expression exp = parser.parseExpression("'Hello World'.bytes"); // This line converts the literal to a byte array + Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1> byte[] bytes = (byte[]) exp.getValue(); ---- +<1> This line converts the literal to a byte array. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- val parser = SpelExpressionParser() // invokes 'getBytes()' - val exp = parser.parseExpression("'Hello World'.bytes") // This line converts the literal to a byte array + val exp = parser.parseExpression("'Hello World'.bytes") // <1> val bytes = exp.value as ByteArray ---- +<1> This line converts the literal to a byte array. SpEL also supports nested properties by using the standard dot notation (such as `prop1.prop2.prop3`) and also the corresponding setting of property values. @@ -146,18 +153,21 @@ The following example shows how to use dot notation to get the length of a liter ExpressionParser parser = new SpelExpressionParser(); // invokes 'getBytes().length' - Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // 'Hello World'.bytes.length gives the length of the literal. + Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1> int length = (Integer) exp.getValue(); ---- +<1> `'Hello World'.bytes.length` gives the length of the literal. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- val parser = SpelExpressionParser() // invokes 'getBytes().length' - val exp = parser.parseExpression("'Hello World'.bytes.length") // 'Hello World'.bytes.length gives the length of the literal. + val exp = parser.parseExpression("'Hello World'.bytes.length") // <1> val length = exp.value as Int ---- +<1> `'Hello World'.bytes.length` gives the length of the literal. The String's constructor can be called instead of using a string literal, as the following example shows: @@ -166,18 +176,19 @@ example shows: .Java ---- ExpressionParser parser = new SpelExpressionParser(); - // Construct a new String from the literal and make it be upper case Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); String message = exp.getValue(String.class); ---- +<1> Construct a new `String` from the literal and make it be upper case. + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] .Kotlin ---- val parser = SpelExpressionParser() - // Construct a new String from the literal and make it be upper case val exp = parser.parseExpression("new String('hello world').toUpperCase()") val message = exp.getValue(String::class.java) ---- +<1> Construct a new `String` from the literal and make it be upper case. Note the use of the generic method: `public T getValue(Class desiredResultType)`.