#1275 - Align with Spring Framework naming convention for Kotlin co-routines.

* Deprecated existing `toCollectionModel` extension function using Kotlin's @Deprecated providing maximum ease for developers to migrate to new API.
* Added functions that create a full complement between ReactiveRepresentationModelAssemblerBuildDsl and SimpleReactiveRepresentationModelAssemblerBuildDsl on both `toModelAndAwait` and `toCollectionModelAndAwait`.

Related issue: #1213.
This commit is contained in:
Greg Turnquist
2020-04-22 13:02:31 -05:00
parent 90377a6e8d
commit 24a005abde
4 changed files with 96 additions and 8 deletions

View File

@@ -20,8 +20,20 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.reactive.awaitFirst
import kotlinx.coroutines.reactor.asFlux
import org.springframework.hateoas.CollectionModel
import org.springframework.hateoas.EntityModel
import org.springframework.hateoas.RepresentationModel
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
/**
* Add support for Kotlin co-routines.
*
* @author Greg Turnquist
* @since 1.1
*/
suspend fun <T : Any, D : RepresentationModel<D>> ReactiveRepresentationModelAssembler<T, D>.toModelAndAwait(
entity: T,
exchange: ServerWebExchange): D = toModel(entity, exchange).awaitFirst()
/**
* Add support for Kotlin co-routines.
@@ -30,6 +42,19 @@ import org.springframework.web.server.ServerWebExchange
* @author Greg Turnquist
* @since 1.1
*/
@Deprecated("use toCollectionModelAndAwait(entites, exchange)",
replaceWith = ReplaceWith("toCollectionModelAndAwait(entities, exchange)"))
suspend fun <T : Any, D : RepresentationModel<D>> ReactiveRepresentationModelAssembler<T, D>.toCollectionModel(
entities: Flow<T>,
exchange: ServerWebExchange): CollectionModel<D> = toCollectionModelAndAwait(entities, exchange)
/**
* Add support for Kotlin co-routines.
*
* @author Juergen Zimmerman
* @author Greg Turnquist
* @since 1.1
*/
suspend fun <T : Any, D : RepresentationModel<D>> ReactiveRepresentationModelAssembler<T, D>.toCollectionModelAndAwait(
entities: Flow<T>,
exchange: ServerWebExchange): CollectionModel<D> = toCollectionModel(entities.asFlux(), exchange).awaitFirst()

View File

@@ -23,6 +23,30 @@ import org.springframework.hateoas.CollectionModel
import org.springframework.hateoas.EntityModel
import org.springframework.web.server.ServerWebExchange
/**
* Add support for Kotlin co-routines.
*
* @author Greg Turnquist
* @since 1.1
*/
suspend fun <T : Any> SimpleReactiveRepresentationModelAssembler<T>.toModelAndAwait(
entity: T,
exchange: ServerWebExchange): EntityModel<T> = toModel(entity, exchange).awaitFirst()
/**
* Add support for Kotlin co-routines.
*
* @author Juergen Zimmerman
* @author Greg Turnquist
* @since 1.1
*
*/
@Deprecated("use toCollectionModelAndAwait(entites, exchange)",
replaceWith = ReplaceWith("toCollectionModelAndAwait(entities, exchange)"))
suspend fun <T : Any> SimpleReactiveRepresentationModelAssembler<T>.toCollectionModel(
entities: Flow<T>,
exchange: ServerWebExchange): CollectionModel<EntityModel<T>> = toCollectionModelAndAwait(entities, exchange)
/**
* Add support for Kotlin co-routines.
*
@@ -30,6 +54,7 @@ import org.springframework.web.server.ServerWebExchange
* @author Greg Turnquist
* @since 1.1
*/
suspend fun <T : Any> SimpleReactiveRepresentationModelAssembler<T>.toCollectionModel(
suspend fun <T : Any> SimpleReactiveRepresentationModelAssembler<T>.toCollectionModelAndAwait(
entities: Flow<T>,
exchange: ServerWebExchange): CollectionModel<EntityModel<T>> = toCollectionModel(entities.asFlux(), exchange).awaitFirst()

View File

@@ -31,23 +31,38 @@ import reactor.core.publisher.Mono
* @author Greg Turnquist
* @since 1.1
*/
class ReactiveRepresentationModelAssemblerBuilderDslUnitTest : TestUtils() {
private val EMPLOYEES_RELATION = LinkRelation.of("employees")
val EMPLOYEES_RELATION = LinkRelation.of("employees")
private val employees = flow {
emit(Employee("Frodo"))
emit(Employee("Bilbo"))
}
@Test // #1213
fun `Kotlin Flows should render as CollectionModels`() {
@Test // #1275
fun `Kotlin co-routine should render as a RepresentationModel`() {
val testResourceAssembler = TestResourceAssembler()
val exchange = mockk<ServerWebExchange>()
runBlocking {
val collectionModel = testResourceAssembler.toCollectionModel(employees, exchange)
val model = testResourceAssembler.toModelAndAwait(Employee("Frodo"), exchange)
assertThat(model.content.name).isEqualTo("Frodo")
assertThat(model.links).containsExactlyInAnyOrder(Link.of("/employees", EMPLOYEES_RELATION))
}
}
@Test // #1213
fun `Kotlin co-routine should render as CollectionModels`() {
val testResourceAssembler = TestResourceAssembler()
val exchange = mockk<ServerWebExchange>()
runBlocking {
val collectionModel = testResourceAssembler.toCollectionModelAndAwait(employees, exchange)
assertThat(collectionModel.content.flatMap { entityModel -> entityModel.links })
.containsExactlyInAnyOrder(Link.of("/employees", EMPLOYEES_RELATION), Link.of("/employees", EMPLOYEES_RELATION))
@@ -55,6 +70,7 @@ class ReactiveRepresentationModelAssemblerBuilderDslUnitTest : TestUtils() {
}
class TestResourceAssembler : ReactiveRepresentationModelAssembler<Employee, EntityModel<Employee>> {
override fun toModel(entity: Employee, exchange: ServerWebExchange): Mono<EntityModel<Employee>> {
return Mono.just(EntityModel.of(entity, Link.of("/employees", LinkRelation.of("employees"))))
}

View File

@@ -34,21 +34,43 @@ class SimpleReactiveRexpresentationModelAssemblerBuilderDslUnitTest : TestUtils(
emit(Employee("Bilbo"))
}
@Test // #1213
fun `Kotlin Flows should render as CollectionModels`() {
@Test // #1275
fun `Kotlin co-routine should render as a RepresentationModel`() {
val testResourceAssembler = SimpleTestResourceAssembler()
val exchange = mockk<ServerWebExchange>()
runBlocking {
val collectionModel = testResourceAssembler.toCollectionModel(employees, exchange)
val model = testResourceAssembler.toModelAndAwait(Employee("Frodo"), exchange)
assertThat(model.content.name).isEqualTo("Frodo")
assertThat(model.links).containsExactlyInAnyOrder(Link.of("/employees", LinkRelation.of("employees")))
}
}
@Test // #1213
fun `Kotlin co-routine should render as CollectionModels`() {
val testResourceAssembler = SimpleTestResourceAssembler()
val exchange = mockk<ServerWebExchange>()
runBlocking {
val collectionModel = testResourceAssembler.toCollectionModelAndAwait(employees, exchange)
assertThat(collectionModel.links).containsExactly(Link.of("/employees"))
}
}
class SimpleTestResourceAssembler : SimpleReactiveRepresentationModelAssembler<Employee> {
override fun addLinks(resource: EntityModel<Employee>, exchange: ServerWebExchange): EntityModel<Employee> {
resource.add(Link.of("/employees", LinkRelation.of("employees")))
return resource
}
override fun addLinks(resources: CollectionModel<EntityModel<Employee>>, exchange: ServerWebExchange): CollectionModel<EntityModel<Employee>> {
resources.add(Link.of("/employees"))
return resources
}