Skip to content

Commit ac82682

Browse files
sdk-api-kotlin-gen (#240)
* Factor out common codegen module in sdk-api-gen-common * Implement sdk-api-kotlin-gen and test it * Rewrite the kotlin example with sdk-api-kotlin-gen
1 parent 3952fe5 commit ac82682

File tree

34 files changed

+1748
-746
lines changed

34 files changed

+1748
-746
lines changed

examples/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ For a sample project configuration and more elaborated examples, check out the [
77
Available examples:
88

99
* [`Counter`](src/main/java/my/restate/sdk/examples/Counter.java): Shows a simple virtual object using state primitives.
10-
* [`Counter`](src/main/kotlin/my/restate/sdk/examples/Counter.kt): Same as `Counter` but using Kotlin.
10+
* [`CounterKt`](src/main/kotlin/my/restate/sdk/examples/CounterKt.kt): Same as `Counter` but using Kotlin.
1111
* [`LoanWorkflow`](src/main/java/my/restate/sdk/examples/LoanWorkflow.java): Shows a simple workflow example using the Workflow API.
1212

1313
## Package the examples for Lambda
@@ -35,7 +35,7 @@ You can run the Java Counter example via:
3535
You can modify the class to run setting `-PmainClass=<FQCN>`, for example, in order to run the Kotlin implementation:
3636

3737
```shell
38-
./gradlew :examples:run -PmainClass=my.restate.sdk.examples.CounterKt
38+
./gradlew :examples:run -PmainClass=my.restate.sdk.examples.CounterKtKt
3939
```
4040

4141
## Invoking the counter bindableComponent

examples/build.gradle.kts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2+
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
3+
14
plugins {
25
java
36
kotlin("jvm")
47
kotlin("plugin.serialization")
58
application
6-
id("com.github.johnrengelman.shadow").version("7.1.2")
9+
alias(kotlinLibs.plugins.ksp)
10+
id("com.github.johnrengelman.shadow").version("8.1.1")
711
}
812

913
dependencies {
14+
ksp(project(":sdk-api-kotlin-gen"))
1015
annotationProcessor(project(":sdk-api-gen"))
1116

1217
implementation(project(":sdk-api"))
@@ -19,13 +24,6 @@ dependencies {
1924
implementation(platform(jacksonLibs.jackson.bom))
2025
implementation(jacksonLibs.jackson.jsr310)
2126

22-
implementation(coreLibs.protobuf.java)
23-
implementation(coreLibs.protobuf.kotlin)
24-
25-
implementation(platform(vertxLibs.vertx.bom))
26-
implementation(vertxLibs.vertx.core)
27-
implementation(vertxLibs.vertx.kotlin.coroutines)
28-
2927
implementation(kotlinLibs.kotlinx.coroutines)
3028
implementation(kotlinLibs.kotlinx.serialization.core)
3129
implementation(kotlinLibs.kotlinx.serialization.json)
@@ -38,3 +36,7 @@ application {
3836
project.findProperty("mainClass")?.toString() ?: "my.restate.sdk.examples.Counter"
3937
mainClass.set(mainClassValue)
4038
}
39+
40+
tasks.withType<Jar> { this.enabled = false }
41+
42+
tasks.withType<ShadowJar> { transform(ServiceFileTransformer::class.java) }

examples/src/main/java/my/restate/sdk/examples/LambdaHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void register(RestateLambdaEndpointBuilder builder) {
2424
if (Counter.class.getCanonicalName().equals(serviceClass)) {
2525
builder.with(new Counter());
2626
} else if (CounterKt.class.getCanonicalName().equals(serviceClass)) {
27-
builder.with(CounterKt.getCounter());
27+
builder.with(new CounterKt());
2828
} else {
2929
throw new IllegalArgumentException(
3030
"Bad \"LAMBDA_FACTORY_SERVICE_CLASS\" env: " + serviceClass);

examples/src/main/kotlin/my/restate/sdk/examples/Counter.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
2+
//
3+
// This file is part of the Restate Java SDK,
4+
// which is released under the MIT license.
5+
//
6+
// You can find a copy of the license in file LICENSE in the root
7+
// directory of this repository or package, or at
8+
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
9+
package my.restate.sdk.examples
10+
11+
import dev.restate.sdk.annotation.Handler
12+
import dev.restate.sdk.annotation.VirtualObject
13+
import dev.restate.sdk.common.StateKey
14+
import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder
15+
import dev.restate.sdk.kotlin.KtSerdes
16+
import dev.restate.sdk.kotlin.ObjectContext
17+
import kotlinx.serialization.Serializable
18+
19+
@Serializable data class CounterUpdate(var oldValue: Long, val newValue: Long)
20+
21+
@VirtualObject
22+
class CounterKt {
23+
24+
companion object {
25+
private val TOTAL = StateKey.of<Long>("total", KtSerdes.json())
26+
}
27+
28+
@Handler
29+
suspend fun reset(ctx: ObjectContext) {
30+
ctx.clear(TOTAL)
31+
}
32+
33+
@Handler
34+
suspend fun add(ctx: ObjectContext, value: Long) {
35+
val currentValue = ctx.get(TOTAL) ?: 0L
36+
val newValue = currentValue + value
37+
ctx.set(TOTAL, newValue)
38+
}
39+
40+
@Handler
41+
suspend fun get(ctx: ObjectContext): Long {
42+
return ctx.get(TOTAL) ?: 0L
43+
}
44+
45+
@Handler
46+
suspend fun getAndAdd(ctx: ObjectContext, value: Long): CounterUpdate {
47+
val currentValue = ctx.get(TOTAL) ?: 0L
48+
val newValue = currentValue + value
49+
ctx.set(TOTAL, newValue)
50+
return CounterUpdate(currentValue, newValue)
51+
}
52+
}
53+
54+
fun main() {
55+
RestateHttpEndpointBuilder.builder().with(CounterKt()).buildAndListen()
56+
}

sdk-api-gen-common/build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
plugins {
2+
`java-library`
3+
`library-publishing-conventions`
4+
}
5+
6+
description = "Restate SDK API Gen Common"
7+
8+
dependencies {
9+
compileOnly(coreLibs.jspecify)
10+
11+
api("com.github.jknack:handlebars:4.3.1")
12+
api(project(":sdk-common"))
13+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
2+
//
3+
// This file is part of the Restate Java SDK,
4+
// which is released under the MIT license.
5+
//
6+
// You can find a copy of the license in file LICENSE in the root
7+
// directory of this repository or package, or at
8+
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
9+
package dev.restate.sdk.gen.model;
10+
11+
import dev.restate.sdk.common.ComponentType;
12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.List;
15+
import java.util.Objects;
16+
17+
public class Component {
18+
19+
private final CharSequence targetPkg;
20+
private final CharSequence targetFqcn;
21+
private final String componentName;
22+
private final ComponentType componentType;
23+
private final List<Handler> handlers;
24+
25+
public Component(
26+
CharSequence targetPkg,
27+
CharSequence targetFqcn,
28+
String componentName,
29+
ComponentType componentType,
30+
List<Handler> handlers) {
31+
this.targetPkg = targetPkg;
32+
this.targetFqcn = targetFqcn;
33+
this.componentName = componentName;
34+
35+
this.componentType = componentType;
36+
this.handlers = handlers;
37+
}
38+
39+
public CharSequence getTargetPkg() {
40+
return this.targetPkg;
41+
}
42+
43+
public CharSequence getTargetFqcn() {
44+
return this.targetFqcn;
45+
}
46+
47+
public String getFullyQualifiedComponentName() {
48+
return this.componentName;
49+
}
50+
51+
public String getSimpleComponentName() {
52+
return this.componentName.substring(this.componentName.lastIndexOf('.') + 1);
53+
}
54+
55+
public CharSequence getGeneratedClassFqcnPrefix() {
56+
if (this.targetPkg == null || this.targetPkg.length() == 0) {
57+
return getSimpleComponentName();
58+
}
59+
return this.targetPkg + "." + getSimpleComponentName();
60+
}
61+
62+
public ComponentType getComponentType() {
63+
return componentType;
64+
}
65+
66+
public List<Handler> getMethods() {
67+
return handlers;
68+
}
69+
70+
public static Builder builder() {
71+
return new Builder();
72+
}
73+
74+
public static class Builder {
75+
private CharSequence targetPkg;
76+
private CharSequence targetFqcn;
77+
private String componentName;
78+
private ComponentType componentType;
79+
private final List<Handler> handlers = new ArrayList<>();
80+
81+
public Builder withTargetPkg(CharSequence targetPkg) {
82+
this.targetPkg = targetPkg;
83+
return this;
84+
}
85+
86+
public Builder withTargetFqcn(CharSequence targetFqcn) {
87+
this.targetFqcn = targetFqcn;
88+
return this;
89+
}
90+
91+
public Builder withComponentName(String componentName) {
92+
this.componentName = componentName;
93+
return this;
94+
}
95+
96+
public Builder withComponentType(ComponentType componentType) {
97+
this.componentType = componentType;
98+
return this;
99+
}
100+
101+
public Builder withHandlers(Collection<Handler> handlers) {
102+
this.handlers.addAll(handlers);
103+
return this;
104+
}
105+
106+
public Builder withHandler(Handler handler) {
107+
this.handlers.add(handler);
108+
return this;
109+
}
110+
111+
public CharSequence getTargetPkg() {
112+
return targetPkg;
113+
}
114+
115+
public CharSequence getTargetFqcn() {
116+
return targetFqcn;
117+
}
118+
119+
public String getComponentName() {
120+
return componentName;
121+
}
122+
123+
public ComponentType getComponentType() {
124+
return componentType;
125+
}
126+
127+
public List<Handler> getHandlers() {
128+
return handlers;
129+
}
130+
131+
public Component build() {
132+
return new Component(
133+
Objects.requireNonNull(targetPkg),
134+
Objects.requireNonNull(targetFqcn),
135+
Objects.requireNonNull(componentName),
136+
Objects.requireNonNull(componentType),
137+
handlers);
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)