Skip to content

Commit b46082b

Browse files
committed
#1213 - Add support for Kotlin co-routines.
The ReactiveRepresentationModelAssembler and SimpleRepresentationModelAssembler both accept Flux inputs for entities. This change adds support for Kotlin co-routines to the same inputs. Related pull request: #1258.
1 parent 1f8c0a4 commit b46082b

File tree

5 files changed

+221
-2
lines changed

5 files changed

+221
-2
lines changed

pom.xml

+27-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@
8585
<spring.version>5.2.5.RELEASE</spring.version>
8686
<spring-plugin.version>2.0.0.RELEASE</spring-plugin.version>
8787
<kotlin.version>1.3.71</kotlin.version>
88+
<kotlinx-coroutines.version>1.3.5</kotlinx-coroutines.version>
89+
<mockk.version>1.9.3</mockk.version>
8890
</properties>
8991

9092
<profiles>
@@ -704,6 +706,20 @@
704706
<type>pom</type>
705707
<scope>import</scope>
706708
</dependency>
709+
<dependency>
710+
<groupId>org.jetbrains.kotlin</groupId>
711+
<artifactId>kotlin-bom</artifactId>
712+
<version>${kotlin.version}</version>
713+
<type>pom</type>
714+
<scope>import</scope>
715+
</dependency>
716+
<dependency>
717+
<groupId>org.jetbrains.kotlinx</groupId>
718+
<artifactId>kotlinx-coroutines-bom</artifactId>
719+
<version>${kotlinx-coroutines.version}</version>
720+
<type>pom</type>
721+
<scope>import</scope>
722+
</dependency>
707723
</dependencies>
708724
</dependencyManagement>
709725

@@ -713,13 +729,16 @@
713729
<dependency>
714730
<groupId>org.jetbrains.kotlin</groupId>
715731
<artifactId>kotlin-stdlib</artifactId>
716-
<version>${kotlin.version}</version>
717732
<optional>true</optional>
718733
</dependency>
719734
<dependency>
720735
<groupId>org.jetbrains.kotlin</groupId>
721736
<artifactId>kotlin-reflect</artifactId>
722-
<version>${kotlin.version}</version>
737+
<optional>true</optional>
738+
</dependency>
739+
<dependency>
740+
<groupId>org.jetbrains.kotlinx</groupId>
741+
<artifactId>kotlinx-coroutines-reactor</artifactId>
723742
<optional>true</optional>
724743
</dependency>
725744
<dependency>
@@ -728,6 +747,12 @@
728747
<version>${kotlin.version}</version>
729748
<scope>test</scope>
730749
</dependency>
750+
<dependency>
751+
<groupId>io.mockk</groupId>
752+
<artifactId>mockk</artifactId>
753+
<version>${mockk.version}</version>
754+
<scope>test</scope>
755+
</dependency>
731756

732757
<dependency>
733758
<groupId>org.springframework</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.hateoas.server.reactive
18+
19+
import kotlinx.coroutines.flow.Flow
20+
import kotlinx.coroutines.reactive.awaitFirst
21+
import kotlinx.coroutines.reactor.asFlux
22+
import org.springframework.hateoas.CollectionModel
23+
import org.springframework.hateoas.RepresentationModel
24+
import org.springframework.web.server.ServerWebExchange
25+
26+
/**
27+
* Add support for Kotlin co-routines.
28+
*
29+
* @author Juergen Zimmerman
30+
* @author Greg Turnquist
31+
* @since 1.1
32+
*/
33+
suspend fun <T : Any, D : RepresentationModel<D>> ReactiveRepresentationModelAssembler<T, D>.toCollectionModel(
34+
entities: Flow<T>,
35+
exchange: ServerWebExchange): CollectionModel<D> = toCollectionModel(entities.asFlux(), exchange).awaitFirst()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.hateoas.server.reactive
18+
19+
import kotlinx.coroutines.flow.Flow
20+
import kotlinx.coroutines.reactive.awaitFirst
21+
import kotlinx.coroutines.reactor.asFlux
22+
import org.springframework.hateoas.CollectionModel
23+
import org.springframework.hateoas.EntityModel
24+
import org.springframework.web.server.ServerWebExchange
25+
26+
/**
27+
* Add support for Kotlin co-routines.
28+
*
29+
* @author Juergen Zimmerman
30+
* @author Greg Turnquist
31+
* @since 1.1
32+
*/
33+
suspend fun <T : Any> SimpleReactiveRepresentationModelAssembler<T>.toCollectionModel(
34+
entities: Flow<T>,
35+
exchange: ServerWebExchange): CollectionModel<EntityModel<T>> = toCollectionModel(entities.asFlux(), exchange).awaitFirst()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2019-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.hateoas.server.reactive
17+
18+
import io.mockk.mockk
19+
import kotlinx.coroutines.flow.flow
20+
import kotlinx.coroutines.runBlocking
21+
import org.assertj.core.api.Assertions.assertThat
22+
import org.junit.jupiter.api.Test
23+
import org.springframework.hateoas.EntityModel
24+
import org.springframework.hateoas.Link
25+
import org.springframework.hateoas.LinkRelation
26+
import org.springframework.hateoas.TestUtils
27+
import org.springframework.web.server.ServerWebExchange
28+
import reactor.core.publisher.Mono
29+
30+
/**
31+
* @author Greg Turnquist
32+
* @since 1.1
33+
*/
34+
class ReactiveRepresentationModelAssemblerBuilderDslUnitTest : TestUtils() {
35+
36+
private val EMPLOYEES_RELATION = LinkRelation.of("employees")
37+
38+
private val employees = flow {
39+
emit(Employee("Frodo"))
40+
emit(Employee("Bilbo"))
41+
}
42+
43+
@Test // #1213
44+
fun `Kotlin Flows should render as CollectionModels`() {
45+
46+
val testResourceAssembler = TestResourceAssembler()
47+
val exchange = mockk<ServerWebExchange>()
48+
49+
runBlocking {
50+
val collectionModel = testResourceAssembler.toCollectionModel(employees, exchange)
51+
52+
assertThat(collectionModel.content.flatMap { entityModel -> entityModel.links })
53+
.containsExactlyInAnyOrder(Link.of("/employees", EMPLOYEES_RELATION), Link.of("/employees", EMPLOYEES_RELATION))
54+
}
55+
}
56+
57+
class TestResourceAssembler : ReactiveRepresentationModelAssembler<Employee, EntityModel<Employee>> {
58+
override fun toModel(entity: Employee, exchange: ServerWebExchange): Mono<EntityModel<Employee>> {
59+
return Mono.just(EntityModel.of(entity, Link.of("/employees", LinkRelation.of("employees"))))
60+
}
61+
}
62+
63+
data class Employee(val name: String)
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2019-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.hateoas.server.reactive
17+
18+
import io.mockk.mockk
19+
import kotlinx.coroutines.flow.flow
20+
import kotlinx.coroutines.runBlocking
21+
import org.assertj.core.api.Assertions.assertThat
22+
import org.junit.jupiter.api.Test
23+
import org.springframework.hateoas.*
24+
import org.springframework.web.server.ServerWebExchange
25+
26+
/**
27+
* @author Greg Turnquist
28+
* @since 1.1
29+
*/
30+
class SimpleReactiveRexpresentationModelAssemblerBuilderDslUnitTest : TestUtils() {
31+
32+
private val employees = flow {
33+
emit(Employee("Frodo"))
34+
emit(Employee("Bilbo"))
35+
}
36+
37+
@Test // #1213
38+
fun `Kotlin Flows should render as CollectionModels`() {
39+
40+
val testResourceAssembler = SimpleTestResourceAssembler()
41+
val exchange = mockk<ServerWebExchange>()
42+
43+
runBlocking {
44+
val collectionModel = testResourceAssembler.toCollectionModel(employees, exchange)
45+
46+
assertThat(collectionModel.links).containsExactly(Link.of("/employees"))
47+
}
48+
}
49+
50+
class SimpleTestResourceAssembler : SimpleReactiveRepresentationModelAssembler<Employee> {
51+
override fun addLinks(resources: CollectionModel<EntityModel<Employee>>, exchange: ServerWebExchange): CollectionModel<EntityModel<Employee>> {
52+
resources.add(Link.of("/employees"))
53+
return resources
54+
}
55+
}
56+
57+
data class Employee(val name: String)
58+
59+
}

0 commit comments

Comments
 (0)