Skip to content

Commit

Permalink
Make Policy.whenever return Iterable<Message> again
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-yevsyukov committed Nov 3, 2023
1 parent 9c21972 commit 790e87b
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 7 deletions.
2 changes: 1 addition & 1 deletion server/src/main/java/io/spine/server/tuple/Either.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public abstract class Either implements Iterable<Message>, Serializable {
protected Either(Message value, int index) {
/* We need instances of GeneratedMessageV3 as they are Serializable.
The only known case of message class which does not descend from
GeneratedMessageV3 is DynamicMessage, and Spine does not support it. */
GeneratedMessageV3 is DynamicMessage, and Spine SDK does not support it. */
this.value = (GeneratedMessageV3) checkNotNull(value);
checkArgument(index >= 0, "Index must be greater or equal zero");
this.index = index;
Expand Down
20 changes: 19 additions & 1 deletion server/src/main/kotlin/io/spine/server/event/Policy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
package io.spine.server.event

import com.google.common.collect.ImmutableSet
import com.google.protobuf.Message
import io.spine.base.EventMessage
import io.spine.core.ContractFor
import io.spine.logging.WithLogging
Expand Down Expand Up @@ -107,9 +108,26 @@ public abstract class Policy<E : EventMessage> : AbstractEventReactor(), WithLog

/**
* Handles an event and produces some number of events in response.
*
* ### API NOTE
*
* This method returns `Iterable<Message>` instead of `Iterable<EventMessage>`,
* to allow implementing classes declare the return types using classes descending from
* [Either][io.spine.server.tuple.Either]. For example, `EitherOf2<Event1, Event2>`.
*
* `Either` implements `Iterable<Message>`. Classes extending `Either` have two or
* more generic parameters bounded by `Message`, not `EventMessage`.
* Therefore, these classes will not be accepted as return types of
* the overridden methods because `Iterable<EventMessage>` will not be
* a super type for them.
*
* Policy authors should declare return types of the overridden methods as described
* in the [class documentation][Policy].
*
* @see Policy
*/
@ContractFor(handler = React::class)
protected abstract fun whenever(event: E): Iterable<EventMessage>
protected abstract fun whenever(event: E): Iterable<Message>

final override fun registerWith(context: BoundedContext) {
super.registerWith(context)
Expand Down
27 changes: 22 additions & 5 deletions server/src/test/kotlin/io/spine/server/event/PolicySpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ package io.spine.server.event
import io.kotest.matchers.shouldBe
import io.spine.core.External
import io.spine.server.model.Nothing
import io.spine.server.tuple.EitherOf2
import io.spine.test.shared.event.SomethingHappened
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
Expand All @@ -37,6 +38,13 @@ import org.junit.jupiter.api.assertThrows
@DisplayName("`Policy` should")
internal class PolicySpec {

@Test
fun `do not allow adding more react methods`() {
assertThrows<IllegalStateException> {
GreedyPolicy()
}
}

@Test
fun `allow using 'Just' in return value`() {
val policy = object : Policy<SomethingHappened>() {
Expand All @@ -45,16 +53,25 @@ internal class PolicySpec {
return Just.nothing
}
}

policy.whenever(SomethingHappened.getDefaultInstance()) shouldBe Just.nothing
policy.whenever(somethingHappened) shouldBe Just.nothing
}

@Test
fun `do not allow adding more react methods`() {
assertThrows<IllegalStateException> {
GreedyPolicy()
fun `allow using 'Either' in return value`() {
object : Policy<SomethingHappened>() {
@React
public override fun whenever(event: SomethingHappened): EitherOf2<Nothing, Nothing> {
return EitherOf2.withA(nothing)
}
}.let {
it.whenever(somethingHappened) shouldBe EitherOf2.withA(nothing)
}
}

companion object {
val somethingHappened = SomethingHappened.getDefaultInstance()
val nothing = Nothing.getDefaultInstance()
}
}

/**
Expand Down

0 comments on commit 790e87b

Please sign in to comment.