Slide 1

Slide 1 text

Spring Boot ♡ Kotlin Stanislav Slavin INFOBIP/KUG SPB 1

Slide 2

Slide 2 text

Infobit? Infobig? Infobip! 2

Slide 3

Slide 3 text

Simplest Spring Boot App https://start.spring.io/ 3

Slide 4

Slide 4 text

Simplest Spring Boot App dependencies { compile "org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE" } 4

Slide 5

Slide 5 text

Simplest Spring Boot App dependencies { compile "org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE" } @SpringBootApplication public class MyFabulousApplication { public static void main(String[] args) { new SpringApplicationBuilder(MyFabulousApplication.class).run(args); } } 5

Slide 6

Slide 6 text

Simplest Spring Boot App dependencies { compile "org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE" } @SpringBootApplication @RestController public class MyFabulousApplication { public static void main(String[] args) { new SpringApplicationBuilder(MyFabulousApplication.class).run(args); } @RequestMapping("/anything") private Response anything() { return new Response("anything is here"); } class Response { private final String message; Response(String message) { this.message = message; } public String getMessage() { return message; } } } 6

Slide 7

Slide 7 text

? 7

Slide 8

Slide 8 text

? CTRL+ALT+SHIFT+K ( CMD+ALT+SHIFT+K) -> DONE! 8

Slide 9

Slide 9 text

-> Kotlin? dependencies { // ... Idea will do the thing } 9

Slide 10

Slide 10 text

-> Kotlin? dependencies { // ... Idea will do the thing } @SpringBootApplication @RestController class MyFabulousApplication { @RequestMapping("/anything") private fun anything(): Response { return Response("anything is here") } internal inner class Response(val message: String) companion object { @JvmStatic fun main(args: Array) { SpringApplicationBuilder(MyFabulousApplication::class.java).run(*args) } } } 10

Slide 11

Slide 11 text

-> Kotlin? dependencies { // ... Idea will do the thing } @SpringBootApplication @RestController class MyFabulousApplication { @RequestMapping("/anything") private fun anything(): Response { return Response("anything is here") } } data class Response(val message: String) fun main(args: Array) { SpringApplicationBuilder(MyFabulousApplication::class.java).run(*args) } 11

Slide 12

Slide 12 text

-> Kotlin? dependencies { // ... Idea will do the thing } @SpringBootApplication @RestController class MyFabulousApplication { @RequestMapping("/anything") private fun anything(): Response { return Response("anything is here") } } data class Response(val message: String) fun main(args: Array) { SpringApplicationBuilder(MyFabulousApplication::class.java).run(*args) } 12 Will it start?

Slide 13

Slide 13 text

-> Kotlin? org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'MyFabulousApplication' may not be final. Remove the final modifier to continue. Offending resource: org.stanislavin.fabulous.MyFabulousApplication at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClass.validate(ConfigurationClass.java:214) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.validate(ConfigurationClassParser.java:207) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:309) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.stanislavin.fabulous.MyFabulousApplicationKt.main(MyFabulousApplication.kt:25) [classes/:na] 13

Slide 14

Slide 14 text

-> Kotlin? org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'MyFabulousApplication' may not be final. Remove the final modifier to continue. Offending resource: org.stanislavin.fabulous.MyFabulousApplication at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClass.validate(ConfigurationClass.java:214) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.validate(ConfigurationClassParser.java:207) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:309) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.stanislavin.fabulous.MyFabulousApplicationKt.main(MyFabulousApplication.kt:25) [classes/:na] @SpringBootApplication @RestController open class MyFabulousApplication 14

Slide 15

Slide 15 text

-> Kotlin? org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'MyFabulousApplication' may not be final. Remove the final modifier to continue. Offending resource: org.stanislavin.fabulous.MyFabulousApplication at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClass.validate(ConfigurationClass.java:214) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.validate(ConfigurationClassParser.java:207) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:309) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE] at org.stanislavin.fabulous.MyFabulousApplicationKt.main(MyFabulousApplication.kt:25) [classes/:na] plugins { id "org.jetbrains.kotlin.plugin.spring" version "1.2.0" } 15

Slide 16

Slide 16 text

Kotlin Service @Service class StasService 16

Slide 17

Slide 17 text

Kotlin Service @Service class StasService { fun eat() { } } 17

Slide 18

Slide 18 text

Kotlin Service @Service class StasService(private val foodService: FoodService) { fun eat() { val food = foodService.getFood() } } interface FoodService { fun getFood(): Food } 18

Slide 19

Slide 19 text

Kotlin Service @Service class StasService(private val foodService: FoodService, private val bellyRepository: BellyRepository) { fun eat() { val food = foodService.getFood() bellyRepository.save(food) } } interface FoodService { fun getFood(): Food } interface BellyRepository { fun save(food: Food) } 19

Slide 20

Slide 20 text

Kotlin Service @SpringBootApplication @RestController class MyFabulousApplication { } 20

Slide 21

Slide 21 text

Kotlin Service @SpringBootApplication @RestController class MyFabulousApplication { @RequestMapping("/eat") private fun eat(): String { } } 21

Slide 22

Slide 22 text

Kotlin Service @SpringBootApplication @RestController class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") private fun eat(): String { stasService.eat() return "THANKS" } } 22

Slide 23

Slide 23 text

Kotlin Service @SpringBootApplication @RestController class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") private fun eat(): String { return try { stasService.eat() "WANT MORE\n" } catch (e : IAmFullException) { "FULL\n" } } } 23

Slide 24

Slide 24 text

Kotlin Service @SpringBootApplication @RestController open class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") private fun eat(): String { return try { stasService.eat() "WANT MORE" } catch (e : IAmFullException) { "FULL" } } } $ curl 127.0.0.1:8080/eat WANT MORE $ curl 127.0.0.1:8080/eat WANT MORE ... $ curl 127.0.0.1:8080/eat FULL 24

Slide 25

Slide 25 text

Properties? 25

Slide 26

Slide 26 text

Properties? @SpringBootApplication @RestController class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") private fun eat(): String { return try { stasService.eat() "WANT MORE\n" } catch (e : IAmFullException) { "FULL\n" } } } 26

Slide 27

Slide 27 text

Properties? @Configuration @ConfigurationProperties("messages") data class MessageProperties(val good: String, val bad: String) 27

Slide 28

Slide 28 text

Properties? @Configuration @ConfigurationProperties("messages") data class MessageProperties(val good: String, val bad: String) 28 Will it work?

Slide 29

Slide 29 text

Properties? @Configuration @ConfigurationProperties("messages") data class MessageProperties(val good: String, val bad: String) *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in org.stanislavin.fabulous.MessageProperties required a bean of type 'java.lang.String' that could not be found. 29 Spring Boot 2.1 maybe :(

Slide 30

Slide 30 text

Properties? @Configuration @ConfigurationProperties("messages") data class MessageProperties(var good: String? = null, var bad: String? = null) 30

Slide 31

Slide 31 text

Properties? @Configuration class MessageProperties(@Value("\${messages.good}") val good: String, @Value("\${messages.bad}") val bad: String) 31

Slide 32

Slide 32 text

Properties? @Configuration class MessageProperties(@Value("\${messages.good:THANKS}") val good: String, @Value("\${messages.bad:FULL}") val bad: String) 32

Slide 33

Slide 33 text

Properties? @Configuration class MessageProperties(@Value("\${messages.good:THANKS}") val good: String, @Value("\${messages.bad:FULL}") val bad: String) @SpringBootApplication @RestController class MyFabulousApplication(private val stasService: StasService, private val properties: MessageProperties) { @RequestMapping("/eat") private fun eat(): String { return try { stasService.eat() "${properties.good}\n" } catch (e : IAmFullException) { "${properties.bad}\n" } } } 33

Slide 34

Slide 34 text

Coroutines? 34

Slide 35

Slide 35 text

Coroutines? @SpringBootApplication @RestController class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") fun eat(): String { stasService.eat() return "THANKS" } } 35

Slide 36

Slide 36 text

Coroutines? @SpringBootApplication @RestController open class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") suspend fun eat(): String { stasService.eat() return "THANKS" } } 36

Slide 37

Slide 37 text

Coroutines? @SpringBootApplication @RestController open class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") suspend fun eat(): String { stasService.eat() return "THANKS" } } 37 Will it work?

Slide 38

Slide 38 text

org.springframework.beans.BeanInstantiationException: Failed to instantiate [kotlin.coroutines.experimental.Continuation]: Specified class is an interface org.springframework.beans.BeanInstantiationException: Failed to instantiate [kotlin.coroutines.experimental.Continuation]: Specified class is an interface at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:99) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:139) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:82) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:106) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.23.jar:8.5.23] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23] Coroutines? 38

Slide 39

Slide 39 text

org.springframework.beans.BeanInstantiationException: Failed to instantiate [kotlin.coroutines.experimental.Continuation]: Specified class is an interface ... suspend fun eat(): String final Object eat(@NotNull Continuation var1) Coroutines? 39

Slide 40

Slide 40 text

Coroutines? dependencies { compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20' compile 'org.springframework.kotlin:spring-kotlin-coroutine:0.2.2' } 40

Slide 41

Slide 41 text

Coroutines? dependencies { compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20' compile 'org.springframework.kotlin:spring-kotlin-coroutine:0.2.2' } @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS" } } 41

Slide 42

Slide 42 text

Coroutines? dependencies { compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20' compile 'org.springframework.kotlin:spring-kotlin-coroutine:0.2.2' } @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS" } } 42

Slide 43

Slide 43 text

CoroutineContext? 43

Slide 44

Slide 44 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } } 44

Slide 45

Slide 45 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } } 45

Slide 46

Slide 46 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } } $ curl 127.0.0.1:8080/eat THANKS FROM http-nio-8080-exec-1 46

Slide 47

Slide 47 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } @Bean fun stasCoroutineContext() = newSingleThreadContext("stas-context-thread") } 47

Slide 48

Slide 48 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine("stasCoroutineContext") suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } @Bean fun stasCoroutineContext() = newSingleThreadContext("stas-context-thread") } 48

Slide 49

Slide 49 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine("stasCoroutineContext") suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } @Bean fun stasCoroutineContext() = newSingleThreadContext("stas-context-thread") } 49

Slide 50

Slide 50 text

CoroutineContext? @SpringBootApplication @RestController @EnableCoroutine class MyFabulousApplication(private val stasService: StasService) { @RequestMapping("/eat") @Coroutine("stasCoroutineContext") suspend fun eat(): String { stasService.eat() return "THANKS FROM ${Thread.currentThread().name}\n" } @Bean fun stasCoroutineContext() = newSingleThreadContext("stas-context-thread") } $ curl 127.0.0.1:8080/eat THANKS FROM stas-context-thread 50

Slide 51

Slide 51 text

Kotlin in Spring 5 51

Slide 52

Slide 52 text

Kotlin in Spring 5 Null-safety 52

Slide 53

Slide 53 text

Kotlin in Spring 5 Null-safety No need for required=false, use nullability HTTP: @RequestParam, @Header Beans: @Autowired, @Inject 53

Slide 54

Slide 54 text

Kotlin in Spring 5 Null-safety No need for required=false, use nullability HTTP: @RequestParam, @Header Beans: @Autowired, @Inject Kotlin DSL for WebFlux 54

Slide 55

Slide 55 text

Kotlin in Spring 5 Null-safety No need for required=false, use nullability HTTP: @RequestParam, @Header Beans: @Autowired, @Inject Kotlin DSL for WebFlux Built-in support for Reactor 55

Slide 56

Slide 56 text

Kotlin in Spring 5 Null-safety No need for required=false, use nullability HTTP: @RequestParam, @Header Beans: @Autowired, @Inject Kotlin DSL for WebFlux Built-in support for Reactor Kotlin for Gradle 56

Slide 57

Slide 57 text

Kotlin in Spring 5 Null-safety No need for required=false, use nullability HTTP: @RequestParam, @Header Beans: @Autowired, @Inject Kotlin DSL for WebFlux Built-in support for Reactor Kotlin for Gradle https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0 57

Slide 58

Slide 58 text

Thanks 58 @stanislavin

Slide 59

Slide 59 text

Links Spring 5 https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0 https://kotlinlang.org/docs/tutorials/spring-boot-restful.html https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin Spring-Coroutines https://github.com/konrad-kaminski/spring-kotlin-coroutine https://www.youtube.com/watch?v=byXSyDtYYJU Repo https://github.com/stanislavin/fabulous-service Telegram @kug_spb @stanislavin 59