Skip to content

Commit d01321a

Browse files
uberbingedependabot[bot]blockvotejwigankow
authored
Update kotlin to 2.0 (#385)
* Bump jvm from 1.9.23 to 2.0.0 Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.9.23 to 2.0.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](JetBrains/kotlin@v1.9.23...v2.0.0) --- updated-dependencies: - dependency-name: jvm dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * Breaking Change: support kotlin 2.0 * Change: make changes only slightly breaking --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yannick Block <[email protected]> Co-authored-by: Julius Wigankow <[email protected]>
1 parent 5b539f7 commit d01321a

File tree

5 files changed

+58
-46
lines changed

5 files changed

+58
-46
lines changed

Diff for: build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ buildscript {
1010

1111
plugins {
1212
java
13-
kotlin("jvm") version "1.9.23"
13+
kotlin("jvm") version "2.0.0"
1414
`maven-publish`
1515
jacoco
1616
id("com.github.kt3k.coveralls") version "2.12.2"

Diff for: router/src/main/kotlin/io/moia/router/RequestHandler.kt

+8-18
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ import com.google.common.net.MediaType
2929
import org.slf4j.Logger
3030
import org.slf4j.LoggerFactory
3131
import kotlin.reflect.KClass
32-
import kotlin.reflect.jvm.ExperimentalReflectionOnLambdas
33-
import kotlin.reflect.jvm.reflect
3432

35-
@Suppress("UnstableApiUsage")
3633
abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
3734
open val objectMapper = jacksonObjectMapper()
3835

@@ -49,7 +46,6 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
4946
.apply { headers = headers.mapKeys { it.key.lowercase() } }
5047
.let { router.filter.then(this::handleRequest)(it) }
5148

52-
@ExperimentalReflectionOnLambdas
5349
@Suppress("UNCHECKED_CAST")
5450
private fun handleRequest(input: APIGatewayProxyRequestEvent): APIGatewayProxyResponseEvent {
5551
log.debug(
@@ -66,16 +62,16 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
6662
routerFunction.requestPredicate.matchedAcceptType(input.acceptedMediaTypes())
6763
?: MediaType.parse(router.defaultContentType)
6864

69-
val handler: HandlerFunction<Any, Any> = routerFunction.handler
65+
val handler: HandlerFunctionWrapper<Any, Any> = routerFunction.handler
7066

7167
val response =
7268
try {
7369
if (missingPermissions(input, routerFunction)) {
7470
throw ApiException("missing permissions", "MISSING_PERMISSIONS", 403)
7571
} else {
7672
val requestBody = deserializeRequest(handler, input)
77-
val request = Request(input, requestBody, routerFunction.requestPredicate.pathPattern)
78-
(handler as HandlerFunction<*, *>)(request)
73+
val request = Request(input, requestBody, routerFunction.requestPredicate.pathPattern) as Request<Any>
74+
handler.handlerFunction(request)
7975
}
8076
} catch (e: Exception) {
8177
exceptionToResponseEntity(e, input)
@@ -144,22 +140,16 @@ abstract class RequestHandler : RequestHandler<APIGatewayProxyRequestEvent, APIG
144140

145141
open fun predicatePermissionHandlerSupplier(): ((r: APIGatewayProxyRequestEvent) -> PredicatePermissionHandler)? = null
146142

147-
@ExperimentalReflectionOnLambdas
148143
private fun deserializeRequest(
149-
handler: HandlerFunction<Any, Any>,
144+
handler: HandlerFunctionWrapper<Any, Any>,
150145
input: APIGatewayProxyRequestEvent,
151146
): Any? {
152-
val requestType =
153-
handler.reflect()?.parameters?.first()?.type?.arguments?.first()?.type
154-
?: throw IllegalArgumentException(
155-
"reflection failed, try using a real lambda instead of function references (Kotlin 1.6 bug?)",
156-
)
157147
return when {
158-
requestType.classifier as KClass<*> == Unit::class -> Unit
159-
input.body == null && requestType.isMarkedNullable -> null
148+
handler.requestType.classifier as KClass<*> == Unit::class -> Unit
149+
input.body == null && handler.requestType.isMarkedNullable -> null
160150
input.body == null -> throw ApiException("no request body present", "REQUEST_BODY_MISSING", 400)
161-
input.body is String && requestType.classifier as KClass<*> == String::class -> input.body
162-
else -> deserializationHandlerChain.deserialize(input, requestType)
151+
input.body is String && handler.requestType.classifier as KClass<*> == String::class -> input.body
152+
else -> deserializationHandlerChain.deserialize(input, handler.requestType)
163153
}
164154
}
165155

Diff for: router/src/main/kotlin/io/moia/router/Router.kt

+39-18
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package io.moia.router
1919
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
2020
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent.ProxyRequestContext
2121
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
22+
import kotlin.reflect.KType
23+
import kotlin.reflect.typeOf
2224

2325
typealias PredicateFactory = (String, String, Set<String>, Set<String>) -> RequestPredicate
2426

@@ -33,35 +35,35 @@ class Router(private val predicateFactory: PredicateFactory) {
3335

3436
var filter: Filter = Filter.NoOp
3537

36-
fun <I, T> GET(
38+
inline fun <reified I, reified T> GET(
3739
pattern: String,
38-
handlerFunction: HandlerFunction<I, T>,
39-
) = defaultRequestPredicate(pattern, "GET", handlerFunction, emptySet())
40+
crossinline handlerFunction: HandlerFunction<I, T>,
41+
) = defaultRequestPredicate(pattern, "GET", HandlerFunctionWrapper.invoke(handlerFunction), emptySet())
4042

41-
fun <I, T> POST(
43+
inline fun <reified I, reified T> POST(
4244
pattern: String,
43-
handlerFunction: HandlerFunction<I, T>,
44-
) = defaultRequestPredicate(pattern, "POST", handlerFunction)
45+
crossinline handlerFunction: HandlerFunction<I, T>,
46+
) = defaultRequestPredicate(pattern, "POST", HandlerFunctionWrapper.invoke(handlerFunction))
4547

46-
fun <I, T> PUT(
48+
inline fun <reified I, reified T> PUT(
4749
pattern: String,
48-
handlerFunction: HandlerFunction<I, T>,
49-
) = defaultRequestPredicate(pattern, "PUT", handlerFunction)
50+
crossinline handlerFunction: HandlerFunction<I, T>,
51+
) = defaultRequestPredicate(pattern, "PUT", HandlerFunctionWrapper.invoke(handlerFunction))
5052

51-
fun <I, T> DELETE(
53+
inline fun <reified I, reified T> DELETE(
5254
pattern: String,
53-
handlerFunction: HandlerFunction<I, T>,
54-
) = defaultRequestPredicate(pattern, "DELETE", handlerFunction, emptySet())
55+
crossinline handlerFunction: HandlerFunction<I, T>,
56+
) = defaultRequestPredicate(pattern, "DELETE", HandlerFunctionWrapper.invoke(handlerFunction), emptySet())
5557

56-
fun <I, T> PATCH(
58+
inline fun <reified I, reified T> PATCH(
5759
pattern: String,
58-
handlerFunction: HandlerFunction<I, T>,
59-
) = defaultRequestPredicate(pattern, "PATCH", handlerFunction)
60+
crossinline handlerFunction: HandlerFunction<I, T>,
61+
) = defaultRequestPredicate(pattern, "PATCH", HandlerFunctionWrapper.invoke(handlerFunction))
6062

61-
private fun <I, T> defaultRequestPredicate(
63+
fun <I, T> defaultRequestPredicate(
6264
pattern: String,
6365
method: String,
64-
handlerFunction: HandlerFunction<I, T>,
66+
handlerFunction: HandlerFunctionWrapper<I, T>,
6567
consuming: Set<String> = defaultConsuming,
6668
) = predicateFactory(method, pattern, consuming, defaultProducing)
6769
.also { routes += RouterFunction(it, handlerFunction) }
@@ -108,9 +110,28 @@ fun Filter.then(next: APIGatewayRequestHandlerFunction): APIGatewayRequestHandle
108110
typealias APIGatewayRequestHandlerFunction = (APIGatewayProxyRequestEvent) -> APIGatewayProxyResponseEvent
109111
typealias HandlerFunction<I, T> = (request: Request<I>) -> ResponseEntity<T>
110112

113+
abstract class HandlerFunctionWrapper<I, T> {
114+
abstract val requestType: KType
115+
abstract val responseType: KType
116+
117+
abstract val handlerFunction: HandlerFunction<I, T>
118+
119+
companion object {
120+
inline operator fun <reified I, reified T> invoke(crossinline handler: HandlerFunction<I, T>): HandlerFunctionWrapper<I, T> {
121+
val requestType = typeOf<I>()
122+
val responseType = typeOf<T>()
123+
return object : HandlerFunctionWrapper<I, T>() {
124+
override val requestType: KType = requestType
125+
override val responseType: KType = responseType
126+
override val handlerFunction: HandlerFunction<I, T> = { request -> handler.invoke(request) }
127+
}
128+
}
129+
}
130+
}
131+
111132
class RouterFunction<I, T>(
112133
val requestPredicate: RequestPredicate,
113-
val handler: HandlerFunction<I, T>,
134+
val handler: HandlerFunctionWrapper<I, T>,
114135
) {
115136
override fun toString(): String {
116137
return "RouterFunction(requestPredicate=$requestPredicate)"

Diff for: router/src/test/kotlin/io/moia/router/RequestHandlerTest.kt

+9-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import io.mockk.mockk
2828
import io.moia.router.Router.Companion.router
2929
import org.junit.jupiter.api.Assertions.assertEquals
3030
import org.junit.jupiter.api.Test
31-
import org.junit.jupiter.api.assertThrows
3231
import java.time.LocalDate
3332

3433
@Suppress("ktlint:standard:max-line-length")
@@ -710,7 +709,7 @@ class RequestHandlerTest {
710709
}
711710

712711
@Test
713-
fun `should fail for function references when using Kotlin 1_6_10`() {
712+
fun `should be able to use function references as handler`() {
714713
class DummyHandler : RequestHandler() {
715714
val dummy =
716715
object {
@@ -725,15 +724,17 @@ class RequestHandlerTest {
725724
GET("/some", dummy::handler).producing("application/json")
726725
}
727726
}
728-
assertThrows<IllegalArgumentException> {
727+
728+
val response =
729729
DummyHandler().handleRequest(
730730
APIGatewayProxyRequestEvent()
731731
.withHttpMethod("GET")
732732
.withPath("/some")
733733
.withAcceptHeader("application/json"),
734734
mockk(),
735735
)
736-
}
736+
737+
assertThat(response.statusCode).isEqualTo(200)
737738
}
738739

739740
class TestRequestHandlerAuthorization : RequestHandler() {
@@ -864,16 +865,16 @@ class RequestHandlerTest {
864865
POST("/no-content") { _: Request<TestRequest> ->
865866
ResponseEntity.noContent()
866867
}
867-
POST("/create-without-location") { _: Request<TestRequest> ->
868+
POST<TestRequest, Unit>("/create-without-location") { _: Request<TestRequest> ->
868869
ResponseEntity.created(null, null, emptyMap())
869870
}
870-
POST("/create-with-location") { r: Request<TestRequest> ->
871+
POST<TestRequest, Unit>("/create-with-location") { r: Request<TestRequest> ->
871872
ResponseEntity.created(null, r.apiRequest.location("test"), emptyMap())
872873
}
873874
DELETE("/delete-me") { _: Request<Unit> ->
874875
ResponseEntity.noContent()
875876
}
876-
GET("/non-existing-path-parameter") { request: Request<Unit> ->
877+
GET<Unit, Unit>("/non-existing-path-parameter") { request: Request<Unit> ->
877878
request.getPathParameter("foo")
878879
ResponseEntity.ok(null)
879880
}
@@ -883,7 +884,7 @@ class RequestHandlerTest {
883884
class TestQueryParamParsingHandler : RequestHandler() {
884885
override val router =
885886
router {
886-
GET("/search") { r: Request<TestRequestHandler.TestRequest> ->
887+
GET<TestRequestHandler.TestRequest, Unit>("/search") { r: Request<TestRequestHandler.TestRequest> ->
887888
assertThat(r.getQueryParameter("testQueryParam")).isNotNull()
888889
assertThat(r.getQueryParameter("testQueryParam")).isEqualTo("foo")
889890
assertThat(r.queryParameters!!["testQueryParam"]).isNotNull()

Diff for: router/src/test/kotlin/io/moia/router/RouterTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class RouterTest {
117117
fun `should not consume for a deletion route`() {
118118
val router =
119119
router {
120-
DELETE("/delete-me") { _: Request<Unit> ->
120+
DELETE<Unit, Unit>("/delete-me") { _: Request<Unit> ->
121121
ResponseEntity.ok(null)
122122
}
123123
}

0 commit comments

Comments
 (0)