The state of Kotlin support in Spring Sbastien Deleuze @sdeleuze - - PowerPoint PPT Presentation

the state of kotlin support in spring s bastien deleuze
SMART_READER_LITE
LIVE PREVIEW

The state of Kotlin support in Spring Sbastien Deleuze @sdeleuze - - PowerPoint PPT Presentation

The state of Kotlin support in Spring Sbastien Deleuze @sdeleuze Copenhagen Denmark Safe Harbor Statement The following is intended to outline the general direction of Pivotal's offerings. It is intended for information purposes only and


slide-1
SLIDE 1

Copenhagen Denmark

The state of Kotlin support in Spring Sébastien Deleuze

@sdeleuze

slide-2
SLIDE 2

Safe Harbor Statement

The following is intended to outline the general direction of Pivotal's offerings. It is intended for information purposes only and may not be incorporated into any contract. Any information regarding pre-release of Pivotal offerings, future updates or other planned modifications is subject to ongoing evaluation by Pivotal and is subject to change. This information is provided without warranty or any kind, express or implied, and is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions regarding Pivotal's offerings. These purchasing decisions should only be based on features currently available. The development, release, and timing of any features or functionality described for Pivotal's offerings in this presentation remain at the sole discretion of Pivotal. Pivotal has no obligation to update forward looking information in this presentation.

slide-3
SLIDE 3

3 

Less flights

slide-4
SLIDE 4

4 

Slower but more surprises ;-)

slide-5
SLIDE 5

Why Kotlin?

slide-6
SLIDE 6

6 

Improve signal to noise ratio

slide-7
SLIDE 7

7 

Improve the signal to noise ratio

  • f the code

Safety

slide-8
SLIDE 8

8 

Improve the signal to noise ratio

  • f the code

Discoverability

slide-9
SLIDE 9

9 

Pleasure

slide-10
SLIDE 10

1 

Android

slide-11
SLIDE 11

Spring Kotlin

slide-12
SLIDE 12

How much?

slide-13
SLIDE 13

Framework documentation in Kotlin!

13 

slide-14
SLIDE 14

14 

Status

Reference documentation in Kotlin Spring Boot 2.2 Next year estimate Spring Framework Spring Boot Spring Data Spring Security

slide-15
SLIDE 15

Gradle Kotlin DSL on start.spring.io

15 

slide-16
SLIDE 16

More DSLs

slide-17
SLIDE 17

17

mockMvc.request(HttpMethod.GET, "/person/{name}", "Lee") { secure = true accept = APPLICATION_JSON headers { contentLanguage = Locale.FRANCE } principal = Principal { "foo" } }.andExpect { status { isOk } content { contentType(APPLICATION_JSON) } jsonPath("$.name") { value("Lee") } content { json("""{"someBoolean": false}""", false) } }.andDo { print() }

MockMvc DSL by Clint Checketts and JB Nizet

slide-18
SLIDE 18

18 

contract { request { url = url("/foo") method = PUT headers { header("foo", "bar") } body = body("foo" to "bar") } response { status = OK } }

Spring Cloud Contract DSL by Tim Ysewyn

slide-19
SLIDE 19

19 

http { formLogin { loginPage = "/log-in" } authorizeRequests { authorize("/css/**", permitAll) authorize("/user/**", hasAuthority("ROLE_USER")) } }

Spring Security DSL by Eleftheria Stein

https://github.com/spring-projects-experimental/spring-security-kotlin-dsl

slide-20
SLIDE 20

Spring MVC DSL and functional API

slide-21
SLIDE 21

21 

fun hello(request: ServerRequest): ServerResponse

Handler API

slide-22
SLIDE 22

22 

fun hello(request: ServerRequest) = ServerResponse.ok().body("Hello world!")

Handler implementation

slide-23
SLIDE 23

23 

router { GET("/hello", ::hello) } fun hello(request: ServerRequest) = ServerResponse.ok().body("Hello world!")

Router

slide-24
SLIDE 24

24 

@Configuration class RoutesConfiguration { @Bean fun routes(): RouterFunction<ServerResponse> = router { GET("/hello", ::hello) } fun hello(request: ServerRequest) = ServerResponse.ok().body("Hello world!") }

Expose the router to Spring Boot

slide-25
SLIDE 25

25 

@Component class PersonHandler(private val repository: PersonRepository) { fun listPeople(request: ServerRequest): ServerResponse { // ... } fun createPerson(request: ServerRequest): ServerResponse { // ... } fun getPerson(request: ServerRequest): ServerResponse { // ... } }

A more realistic handler

slide-26
SLIDE 26

26 

@Configuration class RouteConfiguration { @Bean fun routes(handler: PersonHandler) = router { accept(APPLICATION_JSON).nest { GET("/person/{id}", handler::getPerson) GET("/person", handler::listPeople) } POST("/person", handler::createPerson) } }

A more realistic router

slide-27
SLIDE 27

27 

@Configuration class RouteConfiguration { @Bean fun routes(routeRepository: RouteRepository) = router { for (route in routeRepository.listRoutes()) { GET("/$route") { request -> hello(request, route) } } } fun hello(request: ServerRequest, message: String) = ServerResponse.ok().body("Hello $message!") }

You can even create routes dynamically

slide-28
SLIDE 28

28 

Status

Kotlin DSLs Spring Boot 2.1 Spring Boot 2.2 Next year estimate Beans DSL WebFlux router DSL WebFlux Coroutines router DSL WebMvc router DSL MockMvc DSL Spring Security DSL

slide-29
SLIDE 29

Coroutines

slide-30
SLIDE 30

Coroutines are lightweight threads (you can create 100.000s of them)

30

slide-31
SLIDE 31

The foundations are in Kotlin language

31

slide-32
SLIDE 32

But most of the implementation lives on library side in kotlinx.coroutines

32

slide-33
SLIDE 33

Coroutines allows to consume Spring Reactive stack with a nice balance between imperative and declarative style

33

slide-34
SLIDE 34

Operations are sequential by default

34

slide-35
SLIDE 35

Concurrency is explicit

35

slide-36
SLIDE 36

3 main building blocks you need to know

36

slide-37
SLIDE 37

Suspending function

37

slide-38
SLIDE 38

38 

suspend fun hello() { delay(1000) println("Hello world!") }

Suspending functions

slide-39
SLIDE 39

Note: suspending functions color your API*

39

* As explained by Bob Nystrom in its great blog post What Color is Your Function?

slide-40
SLIDE 40

Structured concurrency

40

slide-41
SLIDE 41

41 

suspend fun loadAndCombine(name1: String, name2: String) = coroutineScope { val deferred1: Deferred<Image> = async { loadImage(name1) } val deferred2: Deferred<Image> = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) }

Structured concurrency

slide-42
SLIDE 42

Flow<T>*

42

* kotlinx.coroutines.flow.Flow not java.util.concurrent.Flow

slide-43
SLIDE 43

Coroutines 1.3 introduces a new Reactive type: Flow<T>

43

slide-44
SLIDE 44

Flow is the equivalent of Flux in Coroutines world

44

slide-45
SLIDE 45

Flow is interoperable with Reactive Streams and supports backpressure

45

slide-46
SLIDE 46

46 

interface Flow<T> { suspend fun collect(collector: FlowCollector<T>) } interface FlowCollector<T> { suspend fun emit(value: T) }

Flow API

slide-47
SLIDE 47

47 

fun <T> Flow<T>.filter(predicate: suspend (T) -> Boolean): Flow<T> = transform { value -> if (predicate(value)) return@transform emit(value) }

Operators as extensions easy to implement

slide-48
SLIDE 48

48 

val flow = flow { for (i in 1..3) { delay(100) emit(i) } }

Create a Flow

slide-49
SLIDE 49

49 

flow.filter { it < 2 }.map(::asyncOperation).collect()

Consume a Flow

slide-50
SLIDE 50

What about Spring support for Coroutines?

slide-51
SLIDE 51

Spring provides official Coroutines support for Spring WebFlux, Data*, Vault, RSocket

51

* Redis, MongoDB, Cassandra, R2DBC

slide-52
SLIDE 52

No new types introduced

52

slide-53
SLIDE 53

Seamless support with the annotation programming model

53

slide-54
SLIDE 54

54 

@GetMapping("/api/banner") suspend fun suspendingEndpoint(): Banner { delay(10) return Banner("title", "Lorem ipsum") }

WebFlux suspending handler method

slide-55
SLIDE 55

55 

@GetMapping("/banner") suspend fun render(model: Model): String { delay(10) model["banner"] = Banner("title", "Lorem ipsum") return "index" }

WebFlux suspending view rendering

slide-56
SLIDE 56

Reactive types extensions for Coroutines APIs

56

slide-57
SLIDE 57

57 

@GetMapping("/banners") suspend fun flow(): Flow<Banner> = client.get() .uri("/messages") .accept(MediaType.TEXT_EVENT_STREAM) .retrieve() .bodyToFlow<String>() .map { Banner("title", it) }

WebClient

slide-58
SLIDE 58

58 

coRouter { GET("/hello", ::hello) } suspend fun hello(request: ServerRequest) = ServerResponse.ok().bodyValueAndAwait("Hello world!")

WebFlux Router

slide-59
SLIDE 59

59 

private val requester: RSocketRequester = ... @MessageMapping("locate.radars.within") fun findRadars(request: MapRequest): Flow<Radar> = requester .route("locate.radars.within") .data(request.viewBox) .retrieveFlow<AirportLocation>() .take(request.maxRadars)

RSocket

slide-60
SLIDE 60

60 

class PersonRepository(private val client: DatabaseClient, private val operator: TransactionalOperator) { suspend fun initDatabase() = operator.executeAndAwait { save(User("smaldini", "Stéphane", "Maldini")) save(User("sdeleuze", "Sébastien", "Deleuze")) save(User("bclozel", "Brian", "Clozel")) } suspend fun save(user: User) { client.insert().into<User>().table("users").using(user).await() } }

Spring Data R2DBC with transactions

slide-61
SLIDE 61

61 

class UserRepository(private val mongo: ReactiveFluentMongoOperations) { fun findAll(): Flow<User> = mongo.query<User>().flow() suspend fun findOne(id: String): User = mongo.query<User>() .matching(query(where("id").isEqualTo(id))).awaitOne() suspend fun insert(user: User): User = mongo.insert<User>().oneAndAwait(user) suspend fun update(user: User): User = mongo.update<User>().replaceWith(user) .asType<User>().findReplaceAndAwait() }

Spring Data MongoDB

slide-62
SLIDE 62

62 

Coroutines are now the default way to go Reactive in Kotlin

Coroutines dependency added by default on start.spring.io WebFlux & RSocket Kotlin code samples provided with Coroutines API

slide-63
SLIDE 63

63 

Status

Coroutines support Spring Boot 2.2 Next year estimate Spring WebFlux functional APIs Spring WebFlux WebClient Spring WebFlux @RequestMapping RSocket @MessageMapping Spring Data Reactive APIs Functional transactions Spring MVC @RequestMapping Spring Data repositories (DATACMNS-1508) @Transactional

slide-64
SLIDE 64

https://github.com/sdeleuze/spring-boot-coroutines-demo

64

slide-65
SLIDE 65

Spring Boot

slide-66
SLIDE 66

66 

@ConfigurationProperties("blog") class BlogProperties { lateinit var title: String val banner = Banner() class Banner { var title: String? = null lateinit var content: String } }

@ConfigurationProperties

slide-67
SLIDE 67

67 

@ConstructorBinding @ConfigurationProperties("blog") data class BlogProperties(val title: String, val banner: Banner) { data class Banner(val title: String?, val content: String) }

@ConfigurationProperties + @ConstructorBinding

slide-68
SLIDE 68

68 

start.spring.io helps to share Kotlin projects

slide-69
SLIDE 69

Kofu: the mother of all DSLs

slide-70
SLIDE 70

application { }

70

slide-71
SLIDE 71

Explicit configuration for Spring Boot using Kotlin DSLs

71

slide-72
SLIDE 72

Experimental

72

slide-73
SLIDE 73

Leverage existing DSLs : beans, router, security

7 3

slide-74
SLIDE 74

74 

val app = application(WebApplicationType.SERVLET) { beans { bean<SampleService>() bean<SampleHandler>() } webMvc { port = if (profiles.contains("test")) 8181 else 8080 router { val handler = ref<SampleHandler>() GET("/", handler::hello) GET("/api", handler::json) } converters { string() jackson() } } }

Spring Boot configured with Kofu DSL

slide-75
SLIDE 75

Composable configurations

75

slide-76
SLIDE 76

Discoverability via auto-complete instead of conventions

76

slide-77
SLIDE 77

Faster startup, less memory consumption

77

slide-78
SLIDE 78

7 8 

Faster startup

slide-79
SLIDE 79

Demo

slide-80
SLIDE 80

https://github.com/spring-projects-experimental/spring-fu

80

slide-81
SLIDE 81

My goal is to make Kofu the Spring Boot Kotlin DSL

81

slide-82
SLIDE 82

GraalVM Native

slide-83
SLIDE 83

8 3 

OpenJDK versus GraalVM native

JIT GraalVM native CE GraalVM native EE

slide-84
SLIDE 84

https://github.com/spring-projects-experimental/spring-graal-native Kotlin with Spring MVC or Spring WebFlux works on GraalVM native Coroutines support is broken due to graal#366

84

Spring Framework 5.3 should be able to configure reflection, proxies, resources, etc. dynamically with GraalVM native.

slide-85
SLIDE 85

8 5 

More resources

https://spring.io/guides/tutorials/spring-boot-kotlin/

slide-86
SLIDE 86

8 6 

More resources

https://youtu.be/BoidEr_ZCGc https://youtu.be/3eoAxphAUIg

slide-87
SLIDE 87

#KotlinConf

THANK YOU AND REMEMBER TO VOTE

Sébastien Deleuze @sdeleuze