Skip to content

Commit 930527b

Browse files
committed
feat(trpc): add Maven/Gradle plugins and filter framework parameters
This commit introduces the build tool plugins required to execute the tRPC TypeScript generator automatically during the build lifecycle, and fixes a bug regarding how framework-specific parameters are handled in the tRPC network payload. Key changes: * MvcRoute (APT) & TrpcGenerator: Explicitly filter out `io.jooby.Context` and `kotlin.coroutines.Continuation` when evaluating tRPC parameters. This prevents the backend from incorrectly expecting a JSON array (tuple) when a method mixes a single payload argument with framework injections, and ensures the TypeScript signatures remain clean. * Maven Plugin: Added `TrpcMojo` bound to the `process-classes` phase. Exposes full configuration for the generator, including `jsonLibrary` (Jackson2, JSON-B, Gson), `customTypeMappings`, and `outputDir` (defaulting to `target/classes`). * Gradle Plugin: Added `TrpcTask` and registered the `io.jooby.trpc` plugin in the `jooby-gradle-plugin` build script, ensuring feature parity with the Maven implementation.
1 parent 4b748a5 commit 930527b

File tree

8 files changed

+381
-70
lines changed

8 files changed

+381
-70
lines changed

modules/jooby-apt/src/main/java/io/jooby/internal/apt/MvcRoute.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,18 @@ public List<String> generateHandlerCall(boolean kt) {
317317
")",
318318
semicolon(kt)));
319319

320+
// Calculate actual tRPC payload parameters (ignore Context and Coroutines)
321+
long trpcPayloadCount =
322+
parameters.stream()
323+
.filter(
324+
p -> {
325+
String type = p.getType().getRawType().toString();
326+
return !type.equals("io.jooby.Context")
327+
&& !p.getType().is("kotlin.coroutines.Continuation");
328+
})
329+
.count();
330+
boolean isTuple = trpcPayloadCount > 1;
331+
320332
if (resolvedTrpcMethod == HttpMethod.GET) {
321333
buffer.add(
322334
statement(
@@ -327,8 +339,7 @@ public List<String> generateHandlerCall(boolean kt) {
327339
").value()",
328340
semicolon(kt)));
329341

330-
// Only enforce JSON array tuples if there are multiple arguments
331-
if (parameters.size() > 1) {
342+
if (isTuple) { // <-- Use calculated isTuple
332343
if (kt) {
333344
buffer.add(
334345
statement(
@@ -351,8 +362,7 @@ public List<String> generateHandlerCall(boolean kt) {
351362
} else {
352363
buffer.add(statement(indent(2), var(kt), "input = ctx.body().bytes()", semicolon(kt)));
353364

354-
// Only enforce JSON array tuples if there are multiple arguments
355-
if (parameters.size() > 1) {
365+
if (isTuple) { // <-- Use calculated isTuple
356366
if (kt) {
357367
buffer.add(
358368
statement(
@@ -373,7 +383,6 @@ public List<String> generateHandlerCall(boolean kt) {
373383
}
374384
}
375385

376-
boolean isTuple = parameters.size() > 1;
377386
if (kt) {
378387
buffer.add(
379388
statement(

modules/jooby-gradle-plugin/build.gradle

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@ group = "io.jooby"
2626
dependencies {
2727
implementation "io.jooby:jooby-run:$version"
2828
implementation "io.jooby:jooby-openapi:$version"
29+
implementation "io.jooby:jooby-trpc:$version"
2930
implementation "com.github.spotbugs:spotbugs-annotations:4.7.2"
3031
}
3132

3233
// Use java-gradle-plugin to generate plugin descriptors and specify plugin ids
3334
gradlePlugin {
3435
website = 'https://jooby.io'
3536
vcsUrl = 'https://github.com/jooby-project/jooby'
36-
description = 'Jooby is a modern, performant and easy to use web framework for Java and Kotlin ' +
37-
'built on top of your favorite web server. The joobyRun task allows to restart your ' +
38-
'application on code changes without exiting the JVM'
37+
description = 'Jooby is a modular, high-performance web framework for Java and Kotlin. Designed ' +
38+
'for simplicity and speed, it gives you the freedom to build on your favorite server with a ' +
39+
'clean, modern API.'
3940
plugins {
4041
joobyRun {
4142
id = 'io.jooby.run'
@@ -51,5 +52,12 @@ gradlePlugin {
5152
tags = ['jooby', 'openAPI']
5253
description = 'Generates an Open-API compatible output from your application'
5354
}
55+
trpc {
56+
id = 'io.jooby.trpc'
57+
implementationClass = 'io.jooby.gradle.JoobyPlugin'
58+
displayName = 'Jooby tRPC plugin'
59+
tags = ['jooby', 'trpc', 'typescript']
60+
description = 'Generates a tRPC-compatible TypeScript API definition from your application'
61+
}
5462
}
5563
}

modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/JoobyPlugin.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public JoobyPlugin() {
2828

2929
@Override public void apply(Project project) {
3030
openAPI(project);
31+
trpc(project);
3132

3233
joobyRun(project);
3334
joobyTestRun(project);
@@ -64,4 +65,16 @@ private void openAPI(Project project) {
6465

6566
project.getTasks().create(openAPIOptions);
6667
}
68+
69+
private void trpc(Project project) {
70+
Map<String, Object> options = new HashMap<>();
71+
options.put(Task.TASK_TYPE, OpenAPITask.class);
72+
options.put(Task.TASK_DEPENDS_ON, "classes");
73+
options.put(Task.TASK_NAME, "tRPC");
74+
options
75+
.put(Task.TASK_DESCRIPTION, "tRPC Generator");
76+
options.put(Task.TASK_GROUP, "jooby");
77+
78+
project.getTasks().create(options);
79+
}
6780
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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.gradle;
7+
8+
import cz.habarta.typescript.generator.DateMapping;
9+
import cz.habarta.typescript.generator.EnumMapping;
10+
import cz.habarta.typescript.generator.JsonLibrary;
11+
import io.jooby.trpc.TrpcGenerator;
12+
import org.gradle.api.tasks.Input;
13+
import org.gradle.api.tasks.Optional;
14+
import org.gradle.api.tasks.TaskAction;
15+
16+
import java.io.File;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
/**
21+
* Generate a tRpc script file from a jooby application.
22+
*
23+
* Usage: https://jooby.io/modules/trpc
24+
*
25+
* @author edgar
26+
* @since 4.0.17
27+
*/
28+
public class TrpcTask extends BaseTask {
29+
30+
private Map<String, String> customTypeMappings;
31+
32+
private Map<String, String> customTypeNaming;
33+
34+
private JsonLibrary jsonLibrary = JsonLibrary.jackson2;
35+
36+
private DateMapping mapDate = DateMapping.asString;
37+
38+
private EnumMapping mapEnum = EnumMapping.asInlineUnion;
39+
40+
private File outputDir;
41+
42+
private String outputFile = "trpc.d.ts";
43+
44+
private List<String> importDeclarations;
45+
46+
/**
47+
* Creates a tRPC task.
48+
*/
49+
public TrpcTask() {}
50+
51+
/**
52+
* Generate tRPC files from Jooby application.
53+
*
54+
* @throws Throwable If something goes wrong.
55+
*/
56+
@TaskAction
57+
public void generate() throws Throwable {
58+
var projects = getProjects();
59+
var classLoader = createClassLoader(projects);
60+
61+
// Default to the compiled classes directory if the user hasn't overridden outputDir
62+
var outDir = outputDir != null ? outputDir.toPath() : classes(getProject(), false);
63+
64+
var generator = new TrpcGenerator();
65+
generator.setClassLoader(classLoader);
66+
generator.setOutputDir(outDir);
67+
generator.setOutputFile(outputFile);
68+
69+
if (customTypeMappings != null) {
70+
generator.setCustomTypeMappings(customTypeMappings);
71+
}
72+
generator.setJsonLibrary(jsonLibrary);
73+
generator.setMapDate(mapDate);
74+
generator.setMapEnum(mapEnum);
75+
if (importDeclarations != null) {
76+
generator.setImportDeclarations(importDeclarations);
77+
}
78+
if (customTypeNaming != null) {
79+
generator.setCustomTypeNaming(customTypeNaming);
80+
}
81+
82+
getLogger().info("Generating: " + outDir.resolve(outputFile));
83+
84+
generator.generate();
85+
}
86+
87+
@Input
88+
@Optional
89+
public Map<String, String> getCustomTypeMappings() {
90+
return customTypeMappings;
91+
}
92+
93+
public void setCustomTypeMappings(Map<String, String> customTypeMappings) {
94+
this.customTypeMappings = customTypeMappings;
95+
}
96+
97+
@Input
98+
@Optional
99+
public Map<String, String> getCustomTypeNaming() {
100+
return customTypeNaming;
101+
}
102+
103+
public void setCustomTypeNaming(Map<String, String> customTypeNaming) {
104+
this.customTypeNaming = customTypeNaming;
105+
}
106+
107+
@Input
108+
@Optional
109+
public JsonLibrary getJsonLibrary() {
110+
return jsonLibrary;
111+
}
112+
113+
public void setJsonLibrary(JsonLibrary jsonLibrary) {
114+
this.jsonLibrary = jsonLibrary;
115+
}
116+
117+
@Input
118+
@Optional
119+
public DateMapping getMapDate() {
120+
return mapDate;
121+
}
122+
123+
public void setMapDate(DateMapping mapDate) {
124+
this.mapDate = mapDate;
125+
}
126+
127+
@Input
128+
@Optional
129+
public EnumMapping getMapEnum() {
130+
return mapEnum;
131+
}
132+
133+
public void setMapEnum(EnumMapping mapEnum) {
134+
this.mapEnum = mapEnum;
135+
}
136+
137+
@Input
138+
@Optional
139+
public File getOutputDir() {
140+
return outputDir;
141+
}
142+
143+
public void setOutputDir(File outputDir) {
144+
this.outputDir = outputDir;
145+
}
146+
147+
@Input
148+
@Optional
149+
public String getOutputFile() {
150+
return outputFile;
151+
}
152+
153+
public void setOutputFile(String outputFile) {
154+
this.outputFile = outputFile;
155+
}
156+
157+
@Input
158+
@Optional
159+
public List<String> getImportDeclarations() {
160+
return importDeclarations;
161+
}
162+
163+
public void setImportDeclarations(List<String> importDeclarations) {
164+
this.importDeclarations = importDeclarations;
165+
}
166+
}

modules/jooby-maven-plugin/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
<version>${jooby.version}</version>
3030
</dependency>
3131

32+
<dependency>
33+
<groupId>io.jooby</groupId>
34+
<artifactId>jooby-trpc</artifactId>
35+
<version>${jooby.version}</version>
36+
</dependency>
37+
3238
<dependency>
3339
<groupId>org.apache.maven</groupId>
3440
<artifactId>maven-plugin-api</artifactId>

0 commit comments

Comments
 (0)