Skip to content

Commit ac4951f

Browse files
Fixed problem with handling of parameter annotations
1 parent 0fb331c commit ac4951f

2 files changed

Lines changed: 34 additions & 45 deletions

File tree

common/src/main/java/dev/restate/common/reflections/ReflectionUtils.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ public record HandlerInfo(String name, boolean shared) {}
3535
return getUniqueDeclaredMethods(
3636
restateAnnotatedClazz,
3737
method ->
38-
method.getDeclaredAnnotation(Handler.class) != null
39-
|| method.getDeclaredAnnotation(Shared.class) != null
40-
|| method.getDeclaredAnnotation(Workflow.class) != null
41-
|| method.getDeclaredAnnotation(Exclusive.class) != null);
38+
!Modifier.isStatic(method.getModifiers())
39+
&& (method.getDeclaredAnnotation(Handler.class) != null
40+
|| method.getDeclaredAnnotation(Shared.class) != null
41+
|| method.getDeclaredAnnotation(Workflow.class) != null
42+
|| method.getDeclaredAnnotation(Exclusive.class) != null));
4243
}
4344

4445
/** Find the class where the Restate annotations are declared. */

sdk-api-kotlin/src/main/kotlin/dev/restate/sdk/kotlin/internal/ReflectionServiceDefinitionFactory.kt

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,23 @@
99
package dev.restate.sdk.kotlin.internal
1010

1111
import dev.restate.common.reflections.ReflectionUtils
12-
import dev.restate.sdk.annotation.Accept
13-
import dev.restate.sdk.annotation.CustomSerdeFactory
14-
import dev.restate.sdk.annotation.Exclusive
15-
import dev.restate.sdk.annotation.Handler
16-
import dev.restate.sdk.annotation.Json
17-
import dev.restate.sdk.annotation.Raw
18-
import dev.restate.sdk.annotation.Shared
19-
import dev.restate.sdk.annotation.Workflow
20-
import dev.restate.sdk.endpoint.definition.HandlerDefinition
12+
import dev.restate.sdk.annotation.*
13+
import dev.restate.sdk.endpoint.definition.*
2114
import dev.restate.sdk.endpoint.definition.HandlerRunner
22-
import dev.restate.sdk.endpoint.definition.HandlerType
23-
import dev.restate.sdk.endpoint.definition.ServiceDefinition
24-
import dev.restate.sdk.endpoint.definition.ServiceDefinitionFactory
25-
import dev.restate.sdk.endpoint.definition.ServiceType
26-
import dev.restate.sdk.kotlin.Context
27-
import dev.restate.sdk.kotlin.ObjectContext
28-
import dev.restate.sdk.kotlin.SharedObjectContext
29-
import dev.restate.sdk.kotlin.SharedWorkflowContext
30-
import dev.restate.sdk.kotlin.WorkflowContext
15+
import dev.restate.sdk.kotlin.*
3116
import dev.restate.serde.Serde
3217
import dev.restate.serde.SerdeFactory
3318
import dev.restate.serde.kotlinx.KotlinSerializationSerdeFactory
3419
import dev.restate.serde.kotlinx.KotlinSerializationSerdeFactory.KtTypeTag
3520
import dev.restate.serde.provider.DefaultSerdeFactoryProvider
3621
import java.lang.reflect.Modifier
3722
import java.util.*
23+
import kotlin.reflect.KClass
3824
import kotlin.reflect.KFunction
3925
import kotlin.reflect.KVisibility
4026
import kotlin.reflect.full.callSuspend
4127
import kotlin.reflect.full.findAnnotation
28+
import kotlin.reflect.full.hasAnnotation
4229
import kotlin.reflect.full.memberFunctions
4330
import kotlin.reflect.full.valueParameters
4431
import kotlin.reflect.jvm.javaMethod
@@ -66,15 +53,23 @@ internal class ReflectionServiceDefinitionFactory : ServiceDefinitionFactory<Any
6653

6754
val serviceClazz: Class<*> = serviceInstance.javaClass
6855

69-
val hasServiceAnnotation = ReflectionUtils.hasServiceAnnotation(serviceClazz)
70-
val hasVirtualObjectAnnotation = ReflectionUtils.hasVirtualObjectAnnotation(serviceClazz)
71-
val hasWorkflowAnnotation = ReflectionUtils.hasWorkflowAnnotation(serviceClazz)
56+
// The behavior of the reflections work as follows:
57+
// * There is one class that has all the restate annotations. That being either the serviceClazz
58+
// itself (concrete class) or some interface in the hierarchy.
59+
// * Then there is the serviceInstance, which is where we call the methods themselves.
60+
val restateAnnotatedClazz = ReflectionUtils.findRestateAnnotatedClass(serviceClazz)
61+
val restateAnnotatedKotlinClazz = restateAnnotatedClazz.kotlin
62+
63+
val hasServiceAnnotation = ReflectionUtils.hasServiceAnnotation(restateAnnotatedClazz)
64+
val hasVirtualObjectAnnotation =
65+
ReflectionUtils.hasVirtualObjectAnnotation(restateAnnotatedClazz)
66+
val hasWorkflowAnnotation = ReflectionUtils.hasWorkflowAnnotation(restateAnnotatedClazz)
7267

7368
val hasAnyAnnotation =
7469
hasServiceAnnotation || hasVirtualObjectAnnotation || hasWorkflowAnnotation
7570
if (!hasAnyAnnotation) {
7671
throw MalformedRestateServiceException(
77-
serviceClazz.simpleName,
72+
restateAnnotatedClazz.simpleName,
7873
"A restate component MUST be annotated with " +
7974
"exactly one annotation between @Service/@VirtualObject/@Workflow, no annotation was found",
8075
)
@@ -84,27 +79,24 @@ internal class ReflectionServiceDefinitionFactory : ServiceDefinitionFactory<Any
8479

8580
if (!hasExactlyOneAnnotation) {
8681
throw MalformedRestateServiceException(
87-
serviceClazz.simpleName,
82+
restateAnnotatedClazz.simpleName,
8883
"A restate component MUST be annotated with " +
8984
"exactly one annotation between @Service/@VirtualObject/@Workflow, more than one annotation found",
9085
)
9186
}
9287

93-
val serviceName = ReflectionUtils.extractServiceName(serviceClazz)
88+
val serviceName = ReflectionUtils.extractServiceName(restateAnnotatedClazz)
9489
val serviceType =
9590
if (hasServiceAnnotation) ServiceType.SERVICE
9691
else if (hasVirtualObjectAnnotation) ServiceType.VIRTUAL_OBJECT else ServiceType.WORKFLOW
97-
val serdeFactory: SerdeFactory = resolveSerdeFactory(serviceClazz)
92+
val serdeFactory: SerdeFactory = resolveSerdeFactory(restateAnnotatedKotlinClazz)
9893

9994
val kFunctions =
100-
serviceClazz.kotlin.memberFunctions.filter {
101-
it.javaMethod?.let { method ->
102-
// Can't use findAnnotations because that won't walk the stack!
103-
ReflectionUtils.findAnnotation(method, Handler::class.java) != null ||
104-
ReflectionUtils.findAnnotation(method, Shared::class.java) != null ||
105-
ReflectionUtils.findAnnotation(method, Workflow::class.java) != null ||
106-
ReflectionUtils.findAnnotation(method, Exclusive::class.java) != null
107-
} ?: false
95+
restateAnnotatedKotlinClazz.memberFunctions.filter {
96+
it.hasAnnotation<Handler>() ||
97+
it.hasAnnotation<Shared>() ||
98+
it.hasAnnotation<Workflow>() ||
99+
it.hasAnnotation<Exclusive>()
108100
}
109101

110102
if (kFunctions.isEmpty()) {
@@ -351,20 +343,16 @@ internal class ReflectionServiceDefinitionFactory : ServiceDefinitionFactory<Any
351343
return serde
352344
}
353345

354-
private fun resolveSerdeFactory(serviceClazz: Class<*>): SerdeFactory {
346+
private fun resolveSerdeFactory(serviceClazz: KClass<*>): SerdeFactory {
355347
// Check for CustomSerdeFactory annotation
356-
val customSerdeFactoryAnnotation: CustomSerdeFactory? =
357-
ReflectionUtils.findAnnotation(
358-
serviceClazz,
359-
CustomSerdeFactory::class.java,
360-
)
348+
val customSerdeFactoryAnnotation = serviceClazz.findAnnotation<CustomSerdeFactory>()
361349

362350
if (customSerdeFactoryAnnotation != null) {
363351
try {
364352
return customSerdeFactoryAnnotation.value.java.getDeclaredConstructor().newInstance()
365353
} catch (e: Exception) {
366354
throw MalformedRestateServiceException(
367-
serviceClazz.simpleName,
355+
serviceClazz.simpleName!!,
368356
"Failed to instantiate custom SerdeFactory: ${customSerdeFactoryAnnotation.value.java.name}",
369357
e,
370358
)
@@ -392,7 +380,7 @@ internal class ReflectionServiceDefinitionFactory : ServiceDefinitionFactory<Any
392380
return this.cachedDefaultSerdeFactory!!
393381
} catch (e: Exception) {
394382
throw MalformedRestateServiceException(
395-
serviceClazz.simpleName,
383+
serviceClazz.simpleName!!,
396384
"Failed to load KotlinSerializationSerdeFactory for Kotlin service. " +
397385
"Make sure sdk-serde-kotlinx is on the classpath.",
398386
e,

0 commit comments

Comments
 (0)