Skip to content

Commit 9cf371f

Browse files
lion7gklijs
authored andcommitted
Add kotlin.serialization implementation of Serializer
1 parent 826f591 commit 9cf371f

File tree

7 files changed

+854
-23
lines changed

7 files changed

+854
-23
lines changed

kotlin/src/main/kotlin/org/axonframework/extensions/kotlin/QueryGatewayExtensions.kt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import java.util.stream.Stream
4141
* @see ResponseTypes
4242
* @since 0.1.0
4343
*/
44-
inline fun <reified R, reified Q> QueryGateway.queryMany(query: Q): CompletableFuture<List<R>> {
44+
inline fun <reified R, reified Q: Any> QueryGateway.queryMany(query: Q): CompletableFuture<List<R>> {
4545
return this.query(query, ResponseTypes.multipleInstancesOf(R::class.java))
4646
}
4747

@@ -57,7 +57,7 @@ inline fun <reified R, reified Q> QueryGateway.queryMany(query: Q): CompletableF
5757
* @see ResponseTypes
5858
* @since 0.1.0
5959
*/
60-
inline fun <reified R, reified Q> QueryGateway.queryMany(queryName: String, query: Q): CompletableFuture<List<R>> {
60+
inline fun <reified R, reified Q: Any> QueryGateway.queryMany(queryName: String, query: Q): CompletableFuture<List<R>> {
6161
return this.query(queryName, query, ResponseTypes.multipleInstancesOf(R::class.java))
6262
}
6363

@@ -72,7 +72,7 @@ inline fun <reified R, reified Q> QueryGateway.queryMany(queryName: String, quer
7272
* @see ResponseTypes
7373
* @since 0.1.0
7474
*/
75-
inline fun <reified R, reified Q> QueryGateway.query(query: Q): CompletableFuture<R> {
75+
inline fun <reified R, reified Q: Any> QueryGateway.query(query: Q): CompletableFuture<R> {
7676
return this.query(query, ResponseTypes.instanceOf(R::class.java))
7777
}
7878

@@ -88,7 +88,7 @@ inline fun <reified R, reified Q> QueryGateway.query(query: Q): CompletableFutur
8888
* @see ResponseTypes
8989
* @since 0.1.0
9090
*/
91-
inline fun <reified R, reified Q> QueryGateway.query(queryName: String, query: Q): CompletableFuture<R> {
91+
inline fun <reified R, reified Q: Any> QueryGateway.query(queryName: String, query: Q): CompletableFuture<R> {
9292
return this.query(queryName, query, ResponseTypes.instanceOf(R::class.java))
9393
}
9494

@@ -103,7 +103,7 @@ inline fun <reified R, reified Q> QueryGateway.query(queryName: String, query: Q
103103
* @see ResponseTypes
104104
* @since 0.1.0
105105
*/
106-
inline fun <reified R, reified Q> QueryGateway.queryOptional(query: Q): CompletableFuture<Optional<R>> {
106+
inline fun <reified R, reified Q: Any> QueryGateway.queryOptional(query: Q): CompletableFuture<Optional<R>> {
107107
return this.query(query, ResponseTypes.optionalInstanceOf(R::class.java))
108108
}
109109

@@ -119,7 +119,7 @@ inline fun <reified R, reified Q> QueryGateway.queryOptional(query: Q): Completa
119119
* @see ResponseTypes
120120
* @since 0.1.0
121121
*/
122-
inline fun <reified R, reified Q> QueryGateway.queryOptional(queryName: String, query: Q): CompletableFuture<Optional<R>> {
122+
inline fun <reified R, reified Q: Any> QueryGateway.queryOptional(queryName: String, query: Q): CompletableFuture<Optional<R>> {
123123
return this.query(queryName, query, ResponseTypes.optionalInstanceOf(R::class.java))
124124
}
125125

@@ -136,7 +136,7 @@ inline fun <reified R, reified Q> QueryGateway.queryOptional(queryName: String,
136136
* @see ResponseTypes
137137
* @since 0.2.0
138138
*/
139-
inline fun <reified R, reified Q> QueryGateway.scatterGather(query: Q, timeout: Long,
139+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGather(query: Q, timeout: Long,
140140
timeUnit: TimeUnit): Stream<R> {
141141
return this.scatterGather(query, ResponseTypes.instanceOf(R::class.java), timeout, timeUnit)
142142
}
@@ -155,7 +155,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGather(query: Q, timeout:
155155
* @see ResponseTypes
156156
* @since 0.2.0
157157
*/
158-
inline fun <reified R, reified Q> QueryGateway.scatterGather(queryName: String, query: Q, timeout: Long,
158+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGather(queryName: String, query: Q, timeout: Long,
159159
timeUnit: TimeUnit): Stream<R> {
160160
return this.scatterGather(queryName, query, ResponseTypes.instanceOf(R::class.java), timeout, timeUnit)
161161
}
@@ -173,7 +173,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGather(queryName: String,
173173
* @see ResponseTypes
174174
* @since 0.2.0
175175
*/
176-
inline fun <reified R, reified Q> QueryGateway.scatterGatherMany(query: Q, timeout: Long,
176+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGatherMany(query: Q, timeout: Long,
177177
timeUnit: TimeUnit): Stream<List<R>> {
178178
return this.scatterGather(query, ResponseTypes.multipleInstancesOf(R::class.java), timeout, timeUnit)
179179
}
@@ -192,7 +192,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGatherMany(query: Q, timeo
192192
* @see ResponseTypes
193193
* @since 0.2.0
194194
*/
195-
inline fun <reified R, reified Q> QueryGateway.scatterGatherMany(queryName: String, query: Q, timeout: Long,
195+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGatherMany(queryName: String, query: Q, timeout: Long,
196196
timeUnit: TimeUnit): Stream<List<R>> {
197197
return this.scatterGather(queryName, query, ResponseTypes.multipleInstancesOf(R::class.java), timeout, timeUnit)
198198
}
@@ -210,7 +210,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGatherMany(queryName: Stri
210210
* @see ResponseTypes
211211
* @since 0.2.0
212212
*/
213-
inline fun <reified R, reified Q> QueryGateway.scatterGatherOptional(query: Q, timeout: Long,
213+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGatherOptional(query: Q, timeout: Long,
214214
timeUnit: TimeUnit): Stream<Optional<R>> {
215215
return this.scatterGather(query, ResponseTypes.optionalInstanceOf(R::class.java), timeout, timeUnit)
216216
}
@@ -229,7 +229,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGatherOptional(query: Q, t
229229
* @see ResponseTypes
230230
* @since 0.2.0
231231
*/
232-
inline fun <reified R, reified Q> QueryGateway.scatterGatherOptional(queryName: String, query: Q, timeout: Long,
232+
inline fun <reified R, reified Q: Any> QueryGateway.scatterGatherOptional(queryName: String, query: Q, timeout: Long,
233233
timeUnit: TimeUnit): Stream<Optional<R>> {
234234
return this.scatterGather(queryName, query, ResponseTypes.optionalInstanceOf(R::class.java), timeout, timeUnit)
235235
}
@@ -246,7 +246,7 @@ inline fun <reified R, reified Q> QueryGateway.scatterGatherOptional(queryName:
246246
* @see ResponseTypes
247247
* @since 0.3.0
248248
*/
249-
inline fun <reified Q, reified I, reified U> QueryGateway.subscriptionQuery(query: Q): SubscriptionQueryResult<I, U> =
249+
inline fun <reified Q: Any, reified I, reified U> QueryGateway.subscriptionQuery(query: Q): SubscriptionQueryResult<I, U> =
250250
this.subscriptionQuery(query, ResponseTypes.instanceOf(I::class.java), ResponseTypes.instanceOf(U::class.java))
251251

252252
/**
@@ -262,5 +262,5 @@ inline fun <reified Q, reified I, reified U> QueryGateway.subscriptionQuery(quer
262262
* @see ResponseTypes
263263
* @since 0.3.0
264264
*/
265-
inline fun <reified Q, reified I, reified U> QueryGateway.subscriptionQuery(queryName: String, query: Q): SubscriptionQueryResult<I, U> =
265+
inline fun <reified Q: Any, reified I, reified U> QueryGateway.subscriptionQuery(queryName: String, query: Q): SubscriptionQueryResult<I, U> =
266266
this.subscriptionQuery(queryName, query, ResponseTypes.instanceOf(I::class.java), ResponseTypes.instanceOf(U::class.java))
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.axonframework.extensions.kotlin.serialization
2+
3+
import org.axonframework.common.ReflectionUtils
4+
import org.axonframework.common.TypeReflectionUtils
5+
import org.axonframework.messaging.responsetypes.AbstractResponseType
6+
import org.axonframework.messaging.responsetypes.InstanceResponseType
7+
import org.axonframework.messaging.responsetypes.ResponseType
8+
import java.lang.reflect.Type
9+
import java.util.concurrent.Future
10+
11+
/**
12+
* A [ResponseType] implementation that will match with query handlers which return a multiple instances of the
13+
* expected response type. If matching succeeds, the [ResponseType.convert] function will be called, which
14+
* will cast the query handler it's response to an [Array] with element type [E].
15+
*
16+
* @param E The element type which will be matched against and converted to
17+
* @author Gerard de Leeuw
18+
* @see org.axonframework.messaging.responsetypes.MultipleInstancesResponseType
19+
*/
20+
class ArrayResponseType<E>(elementType: Class<E>) : AbstractResponseType<Array<E>>(elementType) {
21+
22+
companion object {
23+
/**
24+
* Indicates that the response matches with the [Type] while returning an iterable result.
25+
*
26+
* @see ResponseType.MATCH
27+
*
28+
* @see ResponseType.NO_MATCH
29+
*/
30+
const val ITERABLE_MATCH = 1024
31+
}
32+
33+
private val instanceResponseType: InstanceResponseType<E> = InstanceResponseType(elementType)
34+
35+
/**
36+
* Match the query handler's response [Type] with this implementation's [E].
37+
* Will return true in the following scenarios:
38+
*
39+
* * If the response type is an [Array]
40+
* * If the response type is a [E]
41+
*
42+
* If there is no match at all, it will return false to indicate a non-match.
43+
*
44+
* @param responseType the response [Type] of the query handler which is matched against
45+
* @return true for [Array] or [E] and [ResponseType.NO_MATCH] for non-matches
46+
*/
47+
override fun matches(responseType: Type): Boolean =
48+
matchRank(responseType) > NO_MATCH
49+
50+
/**
51+
* Match the query handler's response [Type] with this implementation's [E].
52+
* Will return a value greater than 0 in the following scenarios:
53+
*
54+
* * [ITERABLE_MATCH]: If the response type is an [Array]
55+
* * [ResponseType.MATCH]: If the response type is a [E]
56+
*
57+
* If there is no match at all, it will return [ResponseType.NO_MATCH] to indicate a non-match.
58+
*
59+
* @param responseType the response [Type] of the query handler which is matched against
60+
* @return [ITERABLE_MATCH] for [Array], [ResponseType.MATCH] for [E] and [ResponseType.NO_MATCH] for non-matches
61+
*/
62+
override fun matchRank(responseType: Type): Int = when {
63+
isMatchingArray(responseType) -> ITERABLE_MATCH
64+
else -> instanceResponseType.matchRank(responseType)
65+
}
66+
67+
/**
68+
* Converts the given [response] of type [Object] into an [Array] with element type [E] from
69+
* this [ResponseType] instance. Should only be called if [ResponseType.matches] returns true.
70+
* Will throw an [IllegalArgumentException] if the given response
71+
* is not convertible to an [Array] of the expected response type.
72+
*
73+
* @param response the [Object] to convert into an [Array] with element type [E]
74+
* @return an [Array] with element type [E], based on the given [response]
75+
*/
76+
override fun convert(response: Any): Array<E> {
77+
val responseType: Class<*> = response.javaClass
78+
if (responseType.isArray) {
79+
@Suppress("UNCHECKED_CAST")
80+
return response as Array<E>
81+
}
82+
throw IllegalArgumentException(
83+
"Retrieved response [$responseType] is not convertible to an array with the expected element type [$expectedResponseType]"
84+
)
85+
}
86+
87+
@Suppress("UNCHECKED_CAST")
88+
override fun responseMessagePayloadType(): Class<Array<E>> =
89+
Array::class.java as Class<Array<E>>
90+
91+
override fun toString(): String = "ArrayResponseType[$expectedResponseType]"
92+
93+
private fun isMatchingArray(responseType: Type): Boolean {
94+
val unwrapped = ReflectionUtils.unwrapIfType(responseType, Future::class.java)
95+
val iterableType = TypeReflectionUtils.getExactSuperType(unwrapped, Array::class.java)
96+
return iterableType != null && isParameterizedTypeOfExpectedType(iterableType)
97+
}
98+
}

0 commit comments

Comments
 (0)