Skip to content

Commit 7954ab5

Browse files
Add documentation and metadata fields to EndpointManifest (#397)
Propagate Javadocs using sdk-api-gen
1 parent fe7f106 commit 7954ab5

File tree

10 files changed

+191
-40
lines changed

10 files changed

+191
-40
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,36 @@
1919
import org.apache.logging.log4j.LogManager;
2020
import org.apache.logging.log4j.Logger;
2121

22+
/** Counter virtual object */
2223
@VirtualObject(name = "Counter")
2324
public class Counter {
2425

2526
private static final Logger LOG = LogManager.getLogger(Counter.class);
2627

2728
private static final StateKey<Long> TOTAL = StateKey.of("total", JsonSerdes.LONG);
2829

30+
/** Reset the counter. */
2931
@Handler
3032
public void reset(ObjectContext ctx) {
3133
ctx.clearAll();
3234
}
3335

36+
/** Add the given value to the count. */
3437
@Handler
3538
public void add(ObjectContext ctx, long request) {
3639
long currentValue = ctx.get(TOTAL).orElse(0L);
3740
long newValue = currentValue + request;
3841
ctx.set(TOTAL, newValue);
3942
}
4043

44+
/** Get the current counter value. */
4145
@Shared
4246
@Handler
4347
public long get(SharedObjectContext ctx) {
4448
return ctx.get(TOTAL).orElse(0L);
4549
}
4650

51+
/** Add a value, and get both the previous value and the new value. */
4752
@Handler
4853
public CounterUpdateResult getAndAdd(ObjectContext ctx, long request) {
4954
LOG.info("Invoked get and add with {}", request);

sdk-api-gen-common/src/main/java/dev/restate/sdk/gen/model/Handler.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@ public class Handler {
1818
private final @Nullable String inputAccept;
1919
private final PayloadType inputType;
2020
private final PayloadType outputType;
21+
private final @Nullable String documentation;
2122

2223
public Handler(
2324
CharSequence name,
2425
HandlerType handlerType,
2526
@Nullable String inputAccept,
2627
PayloadType inputType,
27-
PayloadType outputType) {
28+
PayloadType outputType,
29+
@Nullable String documentation) {
2830
this.name = name;
2931
this.handlerType = handlerType;
3032
this.inputAccept = inputAccept;
3133
this.inputType = inputType;
3234
this.outputType = outputType;
35+
this.documentation = documentation;
3336
}
3437

3538
public CharSequence getName() {
@@ -40,6 +43,7 @@ public HandlerType getHandlerType() {
4043
return handlerType;
4144
}
4245

46+
@Nullable
4347
public String getInputAccept() {
4448
return inputAccept;
4549
}
@@ -52,6 +56,10 @@ public PayloadType getOutputType() {
5256
return outputType;
5357
}
5458

59+
public @Nullable String getDocumentation() {
60+
return documentation;
61+
}
62+
5563
public static Builder builder() {
5664
return new Builder();
5765
}
@@ -62,6 +70,7 @@ public static class Builder {
6270
private String inputAccept;
6371
private PayloadType inputType;
6472
private PayloadType outputType;
73+
private String documentation;
6574

6675
public Builder withName(CharSequence name) {
6776
this.name = name;
@@ -88,6 +97,11 @@ public Builder withOutputType(PayloadType outputType) {
8897
return this;
8998
}
9099

100+
public Builder withDocumentation(String documentation) {
101+
this.documentation = documentation;
102+
return this;
103+
}
104+
91105
public CharSequence getName() {
92106
return name;
93107
}
@@ -117,7 +131,8 @@ public Handler validateAndBuild() {
117131
Objects.requireNonNull(handlerType),
118132
inputAccept,
119133
inputType,
120-
outputType);
134+
outputType,
135+
documentation);
121136
}
122137
}
123138
}

sdk-api-gen-common/src/main/java/dev/restate/sdk/gen/model/Service.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.List;
1515
import java.util.Objects;
1616
import java.util.stream.Collectors;
17+
import org.jspecify.annotations.Nullable;
1718

1819
public class Service {
1920

@@ -22,19 +23,22 @@ public class Service {
2223
private final String serviceName;
2324
private final ServiceType serviceType;
2425
private final List<Handler> handlers;
26+
private final @Nullable String documentation;
2527

2628
public Service(
2729
CharSequence targetPkg,
2830
CharSequence targetFqcn,
2931
String serviceName,
3032
ServiceType serviceType,
31-
List<Handler> handlers) {
33+
List<Handler> handlers,
34+
@Nullable String documentation) {
3235
this.targetPkg = targetPkg;
3336
this.targetFqcn = targetFqcn;
3437
this.serviceName = serviceName;
3538

3639
this.serviceType = serviceType;
3740
this.handlers = handlers;
41+
this.documentation = documentation;
3842
}
3943

4044
public CharSequence getTargetPkg() {
@@ -68,6 +72,10 @@ public List<Handler> getMethods() {
6872
return handlers;
6973
}
7074

75+
public @Nullable String getDocumentation() {
76+
return documentation;
77+
}
78+
7179
public static Builder builder() {
7280
return new Builder();
7381
}
@@ -78,6 +86,7 @@ public static class Builder {
7886
private String serviceName;
7987
private ServiceType serviceType;
8088
private final List<Handler> handlers = new ArrayList<>();
89+
private String documentation;
8190

8291
public Builder withTargetPkg(CharSequence targetPkg) {
8392
this.targetPkg = targetPkg;
@@ -109,6 +118,11 @@ public Builder withHandler(Handler handler) {
109118
return this;
110119
}
111120

121+
public Builder withDocumentation(String documentation) {
122+
this.documentation = documentation;
123+
return this;
124+
}
125+
112126
public CharSequence getTargetPkg() {
113127
return targetPkg;
114128
}
@@ -155,7 +169,8 @@ public Service validateAndBuild() {
155169
Objects.requireNonNull(targetFqcn),
156170
Objects.requireNonNull(serviceName),
157171
Objects.requireNonNull(serviceType),
158-
handlers);
172+
handlers,
173+
documentation);
159174
}
160175
}
161176
}

sdk-api-gen-common/src/main/java/dev/restate/sdk/gen/template/HandlebarsTemplateEngine.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.github.jknack.handlebars.Template;
1414
import com.github.jknack.handlebars.context.FieldValueResolver;
1515
import com.github.jknack.handlebars.helper.StringHelpers;
16+
import com.github.jknack.handlebars.internal.text.StringEscapeUtils;
1617
import com.github.jknack.handlebars.io.TemplateLoader;
1718
import dev.restate.sdk.common.ServiceType;
1819
import dev.restate.sdk.common.function.ThrowingFunction;
@@ -60,6 +61,7 @@ public HandlebarsTemplateEngine(
6061
}
6162
throw new IllegalStateException();
6263
});
64+
handlebars.registerHelpers(StringEscapeUtils.class);
6365

6466
this.templates =
6567
templates.entrySet().stream()
@@ -104,6 +106,8 @@ static class ServiceTemplateModel {
104106
public final String generatedClassSimpleNamePrefix;
105107
public final String generatedClassSimpleName;
106108
public final String serviceName;
109+
public final String documentation;
110+
107111
public final String serviceType;
108112
public final boolean isWorkflow;
109113
public final boolean isObject;
@@ -119,6 +123,8 @@ private ServiceTemplateModel(
119123
this.generatedClassSimpleName = this.generatedClassSimpleNamePrefix + baseTemplateName;
120124
this.serviceName = inner.getFullyQualifiedServiceName();
121125

126+
this.documentation = inner.getDocumentation();
127+
122128
this.serviceType = inner.getServiceType().toString();
123129
this.isWorkflow = inner.getServiceType() == ServiceType.WORKFLOW;
124130
this.isObject = inner.getServiceType() == ServiceType.VIRTUAL_OBJECT;
@@ -149,6 +155,7 @@ static class HandlerTemplateModel {
149155

150156
private final ServiceType serviceType;
151157
private final String definitionsClass;
158+
public final String documentation;
152159

153160
public final boolean inputEmpty;
154161
public final String inputFqcn;
@@ -180,6 +187,7 @@ private HandlerTemplateModel(
180187

181188
this.serviceType = serviceType;
182189
this.definitionsClass = definitionsClass;
190+
this.documentation = inner.getDocumentation();
183191

184192
this.inputEmpty = inner.getInputType().isEmpty();
185193
this.inputFqcn = inner.getInputType().getName();

sdk-api-gen/src/main/java/dev/restate/sdk/gen/ElementConverter.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Service fromTypeElement(MetaRestateAnnotation metaAnnotation, TypeElement elemen
100100
.withTargetPkg(targetPkg)
101101
.withTargetFqcn(targetFqcn)
102102
.withServiceName(serviceName)
103+
.withDocumentation(sanitizeJavadoc(elements.getDocComment(element)))
103104
.withServiceType(metaAnnotation.getServiceType())
104105
.withHandlers(handlers)
105106
.validateAndBuild();
@@ -181,6 +182,7 @@ private Handler fromExecutableElement(ServiceType serviceType, ExecutableElement
181182
return new Handler.Builder()
182183
.withName(element.getSimpleName())
183184
.withHandlerType(handlerType)
185+
.withDocumentation(sanitizeJavadoc(elements.getDocComment(element)))
184186
.withInputAccept(inputAcceptFromParameterList(element.getParameters()))
185187
.withInputType(inputPayloadFromParameterList(element.getParameters()))
186188
.withOutputType(outputPayloadFromExecutableElement(element))
@@ -390,4 +392,10 @@ private static String boxedType(TypeMirror ty) {
390392
return ty.toString();
391393
}
392394
}
395+
396+
private static String sanitizeJavadoc(String documentation) {
397+
// TODO this needs probably a bit more work, but eventually people will use markdown for
398+
// javadocs anyway!
399+
return documentation == null ? null : documentation.trim().replaceAll("[\t\n\r] *", "\n");
400+
}
393401
}

sdk-api-gen/src/main/resources/templates/ServiceDefinitionFactory.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ public class {{generatedClassSimpleName}} implements dev.restate.sdk.common.sysc
1515
{{#if isExclusive}}dev.restate.sdk.common.HandlerType.EXCLUSIVE{{else if isWorkflow}}dev.restate.sdk.common.HandlerType.WORKFLOW{{else}}dev.restate.sdk.common.HandlerType.SHARED{{/if}},
1616
{{inputSerdeRef}},
1717
{{outputSerdeRef}}
18-
){{#if inputAcceptContentType}}.withAcceptContentType("{{inputAcceptContentType}}"){{/if}},
18+
){{#if inputAcceptContentType}}.withAcceptContentType("{{inputAcceptContentType}}"){{/if}}{{#if documentation}}.withDocumentation("{{escapeJava documentation}}"){{/if}},
1919
dev.restate.sdk.HandlerRunner.of(bindableService::{{name}})
2020
){{#unless @last}},{{/unless}}
2121
{{/handlers}}
2222
)
23-
);
23+
){{#if documentation}}.withDocumentation("{{escapeJava documentation}}"){{/if}};
2424
}
2525

2626
@java.lang.Override

sdk-common/src/main/java/dev/restate/sdk/common/syscalls/HandlerSpecification.java

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import dev.restate.sdk.common.HandlerType;
1212
import dev.restate.sdk.common.Serde;
13+
import java.util.Collections;
14+
import java.util.Map;
1315
import java.util.Objects;
1416
import org.jspecify.annotations.Nullable;
1517

@@ -20,23 +22,30 @@ public final class HandlerSpecification<REQ, RES> {
2022
private final @Nullable String acceptContentType;
2123
private final Serde<REQ> requestSerde;
2224
private final Serde<RES> responseSerde;
25+
private final @Nullable String documentation;
26+
private final Map<String, String> metadata;
2327

2428
HandlerSpecification(
2529
String name,
2630
HandlerType handlerType,
2731
@Nullable String acceptContentType,
2832
Serde<REQ> requestSerde,
29-
Serde<RES> responseSerde) {
33+
Serde<RES> responseSerde,
34+
@Nullable String documentation,
35+
Map<String, String> metadata) {
3036
this.name = name;
3137
this.handlerType = handlerType;
3238
this.acceptContentType = acceptContentType;
3339
this.requestSerde = requestSerde;
3440
this.responseSerde = responseSerde;
41+
this.documentation = documentation;
42+
this.metadata = metadata;
3543
}
3644

3745
public static <T, R> HandlerSpecification<T, R> of(
3846
String method, HandlerType handlerType, Serde<T> requestSerde, Serde<R> responseSerde) {
39-
return new HandlerSpecification<>(method, handlerType, null, requestSerde, responseSerde);
47+
return new HandlerSpecification<>(
48+
method, handlerType, null, requestSerde, responseSerde, null, Collections.emptyMap());
4049
}
4150

4251
public String getName() {
@@ -59,32 +68,47 @@ public Serde<RES> getResponseSerde() {
5968
return responseSerde;
6069
}
6170

71+
public @Nullable String getDocumentation() {
72+
return documentation;
73+
}
74+
75+
public Map<String, String> getMetadata() {
76+
return metadata;
77+
}
78+
6279
public HandlerSpecification<REQ, RES> withAcceptContentType(String acceptContentType) {
6380
return new HandlerSpecification<>(
64-
name, handlerType, acceptContentType, requestSerde, responseSerde);
81+
name, handlerType, acceptContentType, requestSerde, responseSerde, documentation, metadata);
82+
}
83+
84+
public HandlerSpecification<REQ, RES> withDocumentation(@Nullable String documentation) {
85+
return new HandlerSpecification<>(
86+
name, handlerType, acceptContentType, requestSerde, responseSerde, documentation, metadata);
87+
}
88+
89+
public HandlerSpecification<REQ, RES> withMetadata(Map<String, String> metadata) {
90+
return new HandlerSpecification<>(
91+
name, handlerType, acceptContentType, requestSerde, responseSerde, documentation, metadata);
6592
}
6693

6794
@Override
6895
public boolean equals(Object o) {
6996
if (this == o) return true;
70-
if (o == null || getClass() != o.getClass()) return false;
71-
97+
if (!(o instanceof HandlerSpecification)) return false;
7298
HandlerSpecification<?, ?> that = (HandlerSpecification<?, ?>) o;
7399
return Objects.equals(name, that.name)
74100
&& handlerType == that.handlerType
75101
&& Objects.equals(acceptContentType, that.acceptContentType)
76102
&& Objects.equals(requestSerde, that.requestSerde)
77-
&& Objects.equals(responseSerde, that.responseSerde);
103+
&& Objects.equals(responseSerde, that.responseSerde)
104+
&& Objects.equals(documentation, that.documentation)
105+
&& Objects.equals(metadata, that.metadata);
78106
}
79107

80108
@Override
81109
public int hashCode() {
82-
int result = Objects.hashCode(name);
83-
result = 31 * result + Objects.hashCode(handlerType);
84-
result = 31 * result + Objects.hashCode(acceptContentType);
85-
result = 31 * result + Objects.hashCode(requestSerde);
86-
result = 31 * result + Objects.hashCode(responseSerde);
87-
return result;
110+
return Objects.hash(
111+
name, handlerType, acceptContentType, requestSerde, responseSerde, documentation, metadata);
88112
}
89113

90114
@Override
@@ -102,6 +126,10 @@ public String toString() {
102126
+ requestSerde.contentType()
103127
+ ", responseContentType="
104128
+ responseSerde.contentType()
129+
+ ", documentation="
130+
+ documentation
131+
+ ", metadata="
132+
+ metadata
105133
+ '}';
106134
}
107135
}

0 commit comments

Comments
 (0)