Skip to content

Commit 1d60d42

Browse files
committed
- redo code generation for @trpc
- it uses a cool parser which allow to provide custom implemantation of it (Jackson/Avajeb) - remove hardcode dependency to Jackson - implement Java/Kotlin code generation - implement success, void/empty and error reponses - add protocol integration test - ref #3863
1 parent eab9d0c commit 1d60d42

33 files changed

Lines changed: 1220 additions & 269 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.trpc;
7+
8+
/** A pre-resolved decoder used at RUNTIME for single-argument methods. */
9+
public interface TrpcDecoder<T> {
10+
T decode(String name, byte[] payload);
11+
12+
T decode(String name, String payload);
13+
}

jooby/src/main/java/io/jooby/trpc/TrpcError.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

jooby/src/main/java/io/jooby/trpc/TrpcErrorCode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import io.jooby.StatusCode;
99

1010
public enum TrpcErrorCode {
11-
PARSE_ERROR(-32700, StatusCode.BAD_REQUEST),
1211
BAD_REQUEST(-32600, StatusCode.BAD_REQUEST),
12+
PARSE_ERROR(-32700, StatusCode.BAD_REQUEST),
1313
INTERNAL_SERVER_ERROR(-32603, StatusCode.SERVER_ERROR),
1414
UNAUTHORIZED(-32001, StatusCode.UNAUTHORIZED),
1515
FORBIDDEN(-32003, StatusCode.FORBIDDEN),

jooby/src/main/java/io/jooby/trpc/TrpcErrorHandler.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,39 @@
66
package io.jooby.trpc;
77

88
import java.util.Map;
9+
import java.util.Optional;
910

1011
import edu.umd.cs.findbugs.annotations.NonNull;
1112
import io.jooby.Context;
1213
import io.jooby.ErrorHandler;
14+
import io.jooby.Reified;
1315
import io.jooby.StatusCode;
1416

1517
public class TrpcErrorHandler implements ErrorHandler {
1618
@Override
1719
public void apply(@NonNull Context ctx, @NonNull Throwable cause, @NonNull StatusCode code) {
1820
if (ctx.getRequestPath().startsWith("/trpc/")) {
21+
TrpcException trpcError;
22+
if (cause instanceof TrpcException) {
23+
trpcError = (TrpcException) cause;
24+
} else {
25+
Map<Class<?>, TrpcErrorCode> customMapping =
26+
ctx.require(Reified.map(Class.class, TrpcErrorCode.class));
27+
var procedure = ctx.getRequestPath().replace("/trpc/", "");
28+
trpcError =
29+
new TrpcException(
30+
procedure, errorCode(customMapping, cause).orElse(TrpcErrorCode.of(code)), cause);
31+
}
32+
ctx.setResponseCode(trpcError.getStatusCode()).render(trpcError.toMap());
33+
}
34+
}
1935

20-
var trpcCode = TrpcErrorCode.of(code);
21-
22-
Map<String, Object> errorData =
23-
Map.of(
24-
"code", trpcCode.name(),
25-
"httpStatus", code.value(),
26-
"path", ctx.getRequestPath().replace("/trpc/", ""));
27-
28-
var errorDetail =
29-
new TrpcError.ErrorDetail(cause.getMessage(), trpcCode.getRpcCode(), errorData);
30-
var trpcResponse = new TrpcError(errorDetail);
31-
32-
ctx.setResponseCode(code).render(trpcResponse);
36+
private Optional<TrpcErrorCode> errorCode(Map<Class<?>, TrpcErrorCode> mappings, Throwable x) {
37+
for (var mapping : mappings.entrySet()) {
38+
if (mapping.getKey().isInstance(x)) {
39+
return Optional.of(mapping.getValue());
40+
}
3341
}
42+
return Optional.empty();
3443
}
3544
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.trpc;
7+
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
import java.util.Objects;
11+
import java.util.Optional;
12+
13+
import io.jooby.StatusCode;
14+
15+
public class TrpcException extends RuntimeException {
16+
private final String procedure;
17+
private final TrpcErrorCode errorCode;
18+
19+
public TrpcException(String procedure, StatusCode code, Throwable cause) {
20+
this(procedure, TrpcErrorCode.of(code), cause);
21+
}
22+
23+
public TrpcException(String procedure, TrpcErrorCode code, Throwable cause) {
24+
super(procedure + ": " + code.name(), cause);
25+
this.procedure = procedure;
26+
this.errorCode = code;
27+
}
28+
29+
public TrpcException(String procedure, TrpcErrorCode code) {
30+
super(procedure + ": " + code.name());
31+
this.procedure = procedure;
32+
this.errorCode = code;
33+
}
34+
35+
public TrpcException(String procedure, StatusCode code) {
36+
this(procedure, TrpcErrorCode.of(code));
37+
}
38+
39+
public StatusCode getStatusCode() {
40+
return errorCode.getStatusCode();
41+
}
42+
43+
public String getProcedure() {
44+
return procedure;
45+
}
46+
47+
public Map<String, Object> toMap() {
48+
Map<String, Object> data = new LinkedHashMap<>();
49+
data.put("code", errorCode.name());
50+
data.put("httpStatus", errorCode.getStatusCode().value());
51+
data.put("path", procedure);
52+
53+
Map<String, Object> error = new LinkedHashMap<>();
54+
error.put(
55+
"message",
56+
Optional.ofNullable(getCause())
57+
.map(Throwable::getMessage)
58+
.filter(Objects::nonNull)
59+
.orElse(errorCode.name()));
60+
error.put("code", errorCode.getRpcCode());
61+
error.put("data", data);
62+
return Map.of("error", error);
63+
}
64+
}

jooby/src/main/java/io/jooby/trpc/TrpcModule.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111

1212
public class TrpcModule implements Extension {
1313
@Override
14-
public void install(@NonNull Jooby application) throws Exception {
15-
application.error(new TrpcErrorHandler());
14+
public void install(@NonNull Jooby app) throws Exception {
15+
var services = app.getServices();
16+
17+
services.require(TrpcParser.class);
18+
// Custom mapping for TrpcErrorCode
19+
services.mapOf(Class.class, TrpcErrorCode.class);
20+
21+
app.error(new TrpcErrorHandler());
1622
}
1723
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.trpc;
7+
8+
import java.lang.reflect.Type;
9+
10+
/**
11+
* Factory provided by the JSON module (Jackson or Avaje). Used by the APT-generated routes AT
12+
* STARTUP to cache deserializers.
13+
*/
14+
public interface TrpcParser {
15+
16+
/** Resolves and caches the deserializer for a specific type during route initialization. */
17+
<T> TrpcDecoder<T> decoder(Type type);
18+
19+
/**
20+
* Creates a sequential reader for parsing tRPC arguments from a JSON array.
21+
*
22+
* @param payload A JSON array containing the method arguments.
23+
* @return A reader for sequential argument extraction.
24+
*/
25+
TrpcReader reader(byte[] payload);
26+
27+
/**
28+
* Creates a sequential reader for parsing tRPC arguments from a JSON array.
29+
*
30+
* @param payload A JSON array containing the method arguments.
31+
* @return A reader for sequential argument extraction.
32+
*/
33+
TrpcReader reader(String payload);
34+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.trpc;
7+
8+
/**
9+
* A sequential reader used at RUNTIME for multi-argument methods. Allows the APT code to extract
10+
* arguments one by one, preserving primitives.
11+
*/
12+
public interface TrpcReader extends AutoCloseable {
13+
14+
// Primitive extractors to avoid autoboxing
15+
int nextInt(String name);
16+
17+
long nextLong(String name);
18+
19+
boolean nextBoolean(String name);
20+
21+
double nextDouble(String name);
22+
23+
String nextString(String name);
24+
25+
// Object extractor using a pre-resolved decoder
26+
<T> T nextObject(String name, TrpcDecoder<T> decoder);
27+
}

jooby/src/main/java/io/jooby/trpc/TrpcResponse.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55
*/
66
package io.jooby.trpc;
77

8-
public record TrpcResponse<T>(TrpcResult<T> result) {
8+
import edu.umd.cs.findbugs.annotations.NonNull;
9+
import edu.umd.cs.findbugs.annotations.Nullable;
910

10-
public static <T> TrpcResponse<T> success(T data) {
11-
return new TrpcResponse<>(new TrpcResult<>(data));
11+
public record TrpcResponse<T>(@Nullable T data) {
12+
13+
public static @NonNull <T> TrpcResponse<T> of(@NonNull T data) {
14+
return new TrpcResponse<>(data);
15+
}
16+
17+
public static @NonNull <T> TrpcResponse<T> empty() {
18+
return new TrpcResponse<>(null);
1219
}
1320
}

jooby/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
exports io.jooby.problem;
1515
exports io.jooby.value;
1616
exports io.jooby.output;
17+
exports io.jooby.trpc;
1718

1819
uses io.jooby.Server;
1920
uses io.jooby.SslProvider;

0 commit comments

Comments
 (0)