Skip to content

Commit 9b39c05

Browse files
Kotlin Misk Add Extra Parameters (#21271)
* first pass * squash * fixing FILES
1 parent cfe0b6f commit 9b39c05

File tree

27 files changed

+286
-146
lines changed

27 files changed

+286
-146
lines changed

bin/configs/kotlin-misk-config.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@ outputDir: samples/server/petstore/kotlin-misk-config
33
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
44
templateDir: modules/openapi-generator/src/main/resources/kotlin-misk
55
validateSpec: false
6+
useBeanValidation: true
67
additionalProperties:
78
hideGenerationTimestamp: "true"
89
moduleClassName: "PetStoreModule"
910
generateStubImplClasses: true
1011
addModelMoshiJsonAnnotation: true
11-
actionPathPrefix : "samplePrefix"
12+
actionPathPrefix: "samplePrefix"
13+
actionAnnotations: "@LogRequestResponse(bodySampling = 1.0, errorBodySampling = 2.0);@Suppress(\"unused\")"
14+
actionImports: "misk.web.actions.WebAction;misk.web.interceptors.LogRequestResponse"
15+
actionParentClass: "WebAction"
16+
actionRequestContentType: "@RequestContentType"
17+
actionRequestContentTypePrefix: "MediaTypes"
18+
testingModule: "misk.web.MiskWebModule"

docs/generators/kotlin-misk.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ These options may be applied as additional-properties (cli) or configOptions (pl
1818

1919
| Option | Description | Values | Default |
2020
| ------ | ----------- | ------ | ------- |
21+
|actionAnnotations|String Annotations for Actions separated by a semicolon(;)| |@LogRequestResponse(bodySampling = 1.0, errorBodySampling = 1.0)|
22+
|actionImports|String Imports for Actions separated by a semicolon(;)| |misk.web.actions.WebAction;misk.web.interceptors.LogRequestResponse|
23+
|actionParentClass|Parent Class for Action| |WebAction|
2124
|actionPathPrefix|Prefix for action path| ||
25+
|actionRequestContentType|Request ContentType for Action| |@RequestContentType|
26+
|actionRequestContentTypePrefix|Request ContentType Prefix for Action| |MediaTypes|
2227
|addModelMoshiJsonAnnotation|Add a Moshi JSON adapter annotation to all model classes| |true|
2328
|additionalModelTypeAnnotations|Additional annotations for model type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)| |null|
2429
|apiSuffix|suffix for api classes| |Api|
@@ -35,6 +40,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
3540
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |null|
3641
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |null|
3742
|sourceFolder|source folder for generated code| |src/main/kotlin|
43+
|testingModule|Testing module class| |misk.testing.MiskTestModule|
3844
|useBeanValidation|Use BeanValidation API annotations to validate data types| |true|
3945

4046
## IMPORT MAPPING

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinMiskServerCodegen.java

Lines changed: 88 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.slf4j.LoggerFactory;
3838

3939
import java.io.File;
40+
import java.util.Arrays;
4041
import java.util.EnumSet;
4142
import java.util.HashMap;
4243
import java.util.List;
@@ -55,6 +56,13 @@ public class KotlinMiskServerCodegen extends AbstractKotlinCodegen implements Be
5556
private static final String ROOT_PACKAGE = "rootPackage";
5657
public static final String GENERATE_STUB_IMPL_CLASSES = "generateStubImplClasses";
5758
public static final String ADD_MODEL_MOSHI_JSON_ANNOTATION = "addModelMoshiJsonAnnotation";
59+
public static final String ACTION_ANNOTATIONS = "actionAnnotations";
60+
public static final String ACTION_IMPORTS = "actionImports";
61+
public static final String ACTION_PARENT_CLASS = "actionParentClass";
62+
public static final String ACTION_REQUEST_CONTENT_TYPE = "actionRequestContentType";
63+
public static final String ACTION_REQUEST_CONTENT_TYPE_PREFIX = "actionRequestContentTypePrefix";
64+
public static final String TESTING_MODULE = "testingModule";
65+
private static final String TESTING_MODULE_NAME = "testingModuleName";
5866

5967
private boolean useBeanValidation = true;
6068

@@ -69,6 +77,15 @@ public class KotlinMiskServerCodegen extends AbstractKotlinCodegen implements Be
6977

7078
@Setter protected String moduleClassName = "OpenApiModule";
7179
@Setter protected String actionPathPrefix = "";
80+
@Setter protected List<String> actionAnnotations =
81+
List.of("@LogRequestResponse(bodySampling = 1.0, errorBodySampling = 1.0)");
82+
@Setter protected List<String> actionImports =
83+
List.of("misk.web.actions.WebAction","misk.web.interceptors.LogRequestResponse");
84+
@Setter protected String actionParentClass = "WebAction";
85+
@Setter protected String actionRequestContentType = "@RequestContentType";
86+
@Setter protected String actionRequestContentTypePrefix = "MediaTypes";
87+
@Setter protected String testingModule = "misk.testing.MiskTestModule";
88+
@Setter protected String testingModuleName;
7289

7390
@Override
7491
public CodegenType getTag() {
@@ -122,6 +139,12 @@ public KotlinMiskServerCodegen() {
122139

123140
addOption(MODULE_CLASS_NAME, "Name of the generated module class", moduleClassName);
124141
addOption(ACTION_PATH_PREFIX, "Prefix for action path", actionPathPrefix);
142+
addOption(ACTION_IMPORTS, "String Imports for Actions separated by a semicolon(;)", String.join(";", actionImports));
143+
addOption(ACTION_ANNOTATIONS, "String Annotations for Actions separated by a semicolon(;)", String.join(";", actionAnnotations));
144+
addOption(ACTION_PARENT_CLASS, "Parent Class for Action", actionParentClass);
145+
addOption(ACTION_REQUEST_CONTENT_TYPE, "Request ContentType for Action", actionRequestContentType);
146+
addOption(ACTION_REQUEST_CONTENT_TYPE_PREFIX, "Request ContentType Prefix for Action", actionRequestContentTypePrefix);
147+
addOption(TESTING_MODULE, "Testing module class", testingModule);
125148

126149
apiTestTemplateFiles.clear();
127150
apiTestTemplateFiles.put("api_test.mustache", ".kt");
@@ -163,6 +186,23 @@ public KotlinMiskServerCodegen() {
163186
public void processOpts() {
164187
super.processOpts();
165188

189+
if (additionalProperties.containsKey(ACTION_ANNOTATIONS)) {
190+
convertPropertyToTypeAndWriteBack(ACTION_ANNOTATIONS,
191+
it -> Arrays.asList(it.split(";")), this::setActionAnnotations);
192+
}
193+
writePropertyBack(ACTION_ANNOTATIONS, actionAnnotations);
194+
195+
if (additionalProperties.containsKey(ACTION_IMPORTS)) {
196+
convertPropertyToTypeAndWriteBack(ACTION_IMPORTS,
197+
it -> Arrays.asList(it.split(";")), this::setActionImports);
198+
}
199+
writePropertyBack(ACTION_IMPORTS, actionImports);
200+
201+
if (additionalProperties.containsKey(ACTION_PARENT_CLASS)) {
202+
setActionParentClass((String) additionalProperties.get(ACTION_PARENT_CLASS));
203+
}
204+
writePropertyBack(ACTION_PARENT_CLASS, actionParentClass);
205+
166206
if (additionalProperties.containsKey(MODULE_CLASS_NAME)) {
167207
setModuleClassName((String) additionalProperties.get(MODULE_CLASS_NAME));
168208
}
@@ -173,6 +213,23 @@ public void processOpts() {
173213
}
174214
writePropertyBack(ACTION_PATH_PREFIX, actionPathPrefix);
175215

216+
if (additionalProperties.containsKey(ACTION_REQUEST_CONTENT_TYPE)) {
217+
setActionRequestContentType((String) additionalProperties.get(ACTION_REQUEST_CONTENT_TYPE));
218+
}
219+
writePropertyBack(ACTION_REQUEST_CONTENT_TYPE, actionRequestContentType);
220+
221+
if (additionalProperties.containsKey(ACTION_REQUEST_CONTENT_TYPE_PREFIX)) {
222+
setActionRequestContentTypePrefix((String) additionalProperties.get(ACTION_REQUEST_CONTENT_TYPE_PREFIX));
223+
}
224+
writePropertyBack(ACTION_REQUEST_CONTENT_TYPE_PREFIX, actionRequestContentTypePrefix);
225+
226+
if (additionalProperties.containsKey(TESTING_MODULE)) {
227+
setTestingModule((String) additionalProperties.get(TESTING_MODULE));
228+
}
229+
writePropertyBack(TESTING_MODULE, testingModule);
230+
231+
writePropertyBack(TESTING_MODULE_NAME, getTestingModuleName());
232+
176233
if (additionalProperties.containsKey(USE_BEANVALIDATION)) {
177234
this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
178235
}
@@ -187,6 +244,7 @@ public void processOpts() {
187244
setAddModelMoshiJsonAnnotation(convertPropertyToBoolean(ADD_MODEL_MOSHI_JSON_ANNOTATION));
188245
}
189246
writePropertyBack(ADD_MODEL_MOSHI_JSON_ANNOTATION, addModelMoshiJsonAnnotation);
247+
190248
applyJakartaPackage();
191249

192250
String apiModuleFolder = (sourceFolder + File.separator + apiPackage).replace(".", File.separator);
@@ -230,39 +288,43 @@ public boolean getUseBeanValidation() {
230288
}
231289

232290
private String mapMediaType(String mediaType) {
233-
return MEDIA_MAPPING.getOrDefault(mediaType, "MediaTypes.APPLICATION_OCTETSTREAM /* @todo(unknown) -> " + mediaType + " */ ");
291+
return MEDIA_MAPPING.getOrDefault(mediaType, "APPLICATION_OCTETSTREAM /* @todo(unknown) -> " + mediaType + " */ ");
292+
}
293+
294+
public String getTestingModuleName() {
295+
return testingModule.substring(testingModule.lastIndexOf(".")+1);
234296
}
235297

236298
private final static Map<String, String> MEDIA_MAPPING = getMappings();
237299

238300
private static Map<String, String> getMappings() {
239301
// add new values in order
240302
Map<String, String> result = new HashMap<>();
241-
result.put("*/*", "MediaTypes.ALL");
242-
243-
result.put("application/grpc", "MediaTypes.APPLICATION_GRPC");
244-
result.put("application/javascript", "MediaTypes.APPLICATION_JAVASCRIPT");
245-
result.put("application/json", "MediaTypes.APPLICATION_JSON");
246-
result.put("application/jwt", "MediaTypes.APPLICATION_JWT");
247-
result.put("application/octetstream", "MediaTypes.APPLICATION_OCTETSTREAM");
248-
result.put("application/pdf", "MediaTypes.APPLICATION_OCTETSTREAM");
249-
result.put("application/x-protobuf", "MediaTypes.APPLICATION_PROTOBUF");
250-
result.put("application/x-www-form-urlencoded", "MediaTypes.APPLICATION_FORM_URLENCODED");
251-
result.put("application/xml", "MediaTypes.APPLICATION_XML");
252-
result.put("application/zip", "MediaTypes.APPLICATION_ZIP");
253-
254-
result.put("image/gif", "MediaTypes.IMAGE_GIF");
255-
result.put("image/x-icon", "MediaTypes.IMAGE_ICO");
256-
result.put("image/jpeg", "MediaTypes.IMAGE_JPEG");
257-
result.put("image/png", "MediaTypes.IMAGE_PNG");
258-
result.put("image/svg+xml", "MediaTypes.IMAGE_SVG");
259-
result.put("image/tiff", "MediaTypes.IMAGE_TIFF");
260-
261-
result.put("multipart/form-data", "MediaTypes.FORM_DATA");
262-
263-
result.put("text/css", "MediaTypes.TEXT_CSS");
264-
result.put("text/html", "MediaTypes.TEXT_HTML");
265-
result.put("text/plain", "MediaTypes.TEXT_PLAIN_UTF8");
303+
result.put("*/*", "ALL");
304+
305+
result.put("application/grpc", "APPLICATION_GRPC");
306+
result.put("application/javascript", "APPLICATION_JAVASCRIPT");
307+
result.put("application/json", "APPLICATION_JSON");
308+
result.put("application/jwt", "APPLICATION_JWT");
309+
result.put("application/octetstream", "APPLICATION_OCTETSTREAM");
310+
result.put("application/pdf", "APPLICATION_OCTETSTREAM");
311+
result.put("application/x-protobuf", "APPLICATION_PROTOBUF");
312+
result.put("application/x-www-form-urlencoded", "APPLICATION_FORM_URLENCODED");
313+
result.put("application/xml", "APPLICATION_XML");
314+
result.put("application/zip", "APPLICATION_ZIP");
315+
316+
result.put("image/gif", "IMAGE_GIF");
317+
result.put("image/x-icon", "IMAGE_ICO");
318+
result.put("image/jpeg", "IMAGE_JPEG");
319+
result.put("image/png", "IMAGE_PNG");
320+
result.put("image/svg+xml", "IMAGE_SVG");
321+
result.put("image/tiff", "IMAGE_TIFF");
322+
323+
result.put("multipart/form-data", "FORM_DATA");
324+
325+
result.put("text/css", "TEXT_CSS");
326+
result.put("text/html", "TEXT_HTML");
327+
result.put("text/plain", "TEXT_PLAIN_UTF8");
266328

267329
return result;
268330
}

modules/openapi-generator/src/main/resources/kotlin-misk/apiAction.mustache

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import {{javaxPackage}}.validation.constraints.NotNull
1313
import {{javaxPackage}}.validation.constraints.Pattern
1414
import {{javaxPackage}}.validation.constraints.Size
1515
{{/useBeanValidation}}
16+
{{#actionImports}}
17+
import {{{.}}}
18+
{{/actionImports}}
1619
import misk.web.Delete
1720
import misk.web.Description
1821
import misk.web.Get
@@ -26,10 +29,9 @@ import misk.web.RequestBody
2629
import misk.web.RequestContentType
2730
import misk.web.RequestHeader
2831
import misk.web.ResponseContentType
29-
import misk.web.actions.WebAction
30-
import misk.web.interceptors.LogRequestResponse
3132
import misk.web.mediatype.MediaTypes
32-
{{#imports}}import {{import}}
33+
{{#imports}}
34+
import {{import}}
3335
{{/imports}}
3436

3537
/**
@@ -38,14 +40,16 @@ import misk.web.mediatype.MediaTypes
3840
{{#operations}}
3941
@Singleton
4042
class {{classname}}Action @Inject constructor(
41-
) : WebAction {
43+
) : {{actionParentClass}} {
4244
{{#operation}}
4345

44-
@{{httpMethod}}("{{actionPathPrefix}}{{path}}")
46+
@{{httpMethod}}("{{{actionPathPrefix}}}{{path}}")
4547
@Description("{{{summary}}}"){{#hasConsumes}}
46-
@RequestContentType({{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}){{/hasConsumes}}{{#hasProduces}}
47-
@ResponseContentType({{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}){{/hasProduces}}
48-
@LogRequestResponse(bodySampling = 1.0, errorBodySampling = 1.0)
48+
{{{actionRequestContentType}}}({{#consumes}}{{{actionRequestContentTypePrefix}}}.{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}){{/hasConsumes}}{{#hasProduces}}
49+
@ResponseContentType({{#produces}}MediaTypes.{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}){{/hasProduces}}
50+
{{#actionAnnotations}}
51+
{{{.}}}
52+
{{/actionAnnotations}}
4953
fun {{operationId}}({{#allParams}}
5054
{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}){{#returnType}}: {{{returnType}}}{{/returnType}} {
5155
TODO()

modules/openapi-generator/src/main/resources/kotlin-misk/apiImpl.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import misk.web.PathParam
1818
import misk.web.QueryParam
1919
import misk.web.RequestBody
2020
import misk.web.RequestHeader
21-
{{#imports}}import {{import}}
21+
{{#imports}}
22+
import {{import}}
2223
{{/imports}}
2324

2425
/**

modules/openapi-generator/src/main/resources/kotlin-misk/apiInterface.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import misk.web.PathParam
1616
import misk.web.QueryParam
1717
import misk.web.RequestBody
1818
import misk.web.RequestHeader
19-
{{#imports}}import {{import}}
19+
{{#imports}}
20+
import {{import}}
2021
{{/imports}}
2122

2223
{{#operations}}
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
package {{package}}
22

3+
import {{{testingModule}}}
34
import {{javaxPackage}}.inject.Inject
45
import misk.testing.MiskTest
6+
import misk.testing.MiskTestModule
57
import org.junit.jupiter.api.Test
6-
78
import misk.web.HttpCall
89
import misk.web.PathParam
910
import misk.web.QueryParam
1011
import misk.web.RequestBody
1112
import misk.web.RequestHeader
12-
13-
{{#imports}}import {{import}}
13+
{{#imports}}
14+
import {{import}}
1415
{{/imports}}
1516

1617
@MiskTest(startService = true)
1718
internal class {{classname}}Test {
1819
20+
@Suppress("unused")
21+
@MiskTestModule
22+
private val module = {{{testingModuleName}}}()
23+
1924
@Inject private lateinit var {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}: {{classname}}Action
25+
{{#operations}}
26+
{{#operation}}
2027

21-
{{#operations}}
22-
{{#operation}}
2328
/**
2429
* To test {{classname}}Action.{{operationId}}
2530
*/
2631
@Test
2732
fun `should handle {{operationId}}`() {
28-
{{#allParams}}
33+
{{#allParams}}
2934
val {{{paramName}}} = TODO()
30-
{{/allParams}}
35+
{{/allParams}}
3136
val response{{#returnType}}: {{{returnType}}}{{/returnType}} = {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}.{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
3237
}
33-
34-
{{/operation}}
35-
{{/operations}}
38+
{{/operation}}
39+
{{/operations}}
3640
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/misk/KotlinMiskServerCodegenOptionsTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ protected void verifyOptions() {
3939
verify(codegen).setUseBeanValidation(Boolean.valueOf(KotlinMiskServerCodegenOptionsProvider.USE_BEAN_VALIDATION));
4040
verify(codegen).setModuleClassName(KotlinMiskServerCodegenOptionsProvider.MODULE_CLASS_NAME);
4141
verify(codegen).setActionPathPrefix(KotlinMiskServerCodegenOptionsProvider.ACTION_PATH_PREFIX);
42+
verify(codegen).setActionImports(List.of("a.x","b.y"));
43+
verify(codegen).setActionAnnotations(List.of("@c()","@d()"));
44+
verify(codegen).setActionParentClass(KotlinMiskServerCodegenOptionsProvider.ACTION_PARENT_CLASS);
45+
verify(codegen).setActionRequestContentType(KotlinMiskServerCodegenOptionsProvider.ACTION_REQUEST_CONTENT_TYPE);
46+
verify(codegen).setActionRequestContentTypePrefix(KotlinMiskServerCodegenOptionsProvider.ACTION_REQUEST_CONTENT_TYPE_PREFIX);
4247
verify(codegen).setGenerateStubImplClasses(Boolean.valueOf(KotlinMiskServerCodegenOptionsProvider.GENERATE_STUB_IMPL_CLASSES));
4348
verify(codegen).setAddModelMoshiJsonAnnotation(Boolean.valueOf(KotlinMiskServerCodegenOptionsProvider.ADD_MODEL_MOSHI_JSON_ANNOTATION));
4449
}
45-
}
50+
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/options/KotlinMiskServerCodegenOptionsProvider.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ public class KotlinMiskServerCodegenOptionsProvider implements OptionsProvider {
2626
public static final String GENERATE_STUB_IMPL_CLASSES = "false";
2727
public static final String ADD_MODEL_MOSHI_JSON_ANNOTATION = "true";
2828
public static final String MODULE_CLASS_NAME = "OpenApiModule";
29-
public static final String ACTION_PATH_PREFIX = "samplePrefix";
29+
public static final String ACTION_PATH_PREFIX = "samplePrefix<";
30+
public static final String ACTION_IMPORTS = "a.x;b.y";
31+
public static final String ACTION_ANNOTATIONS = "@c();@d()";
32+
public static final String ACTION_PARENT_CLASS = "class<";
33+
public static final String ACTION_REQUEST_CONTENT_TYPE = "contentType<";
34+
public static final String ACTION_REQUEST_CONTENT_TYPE_PREFIX = "contentTypePrefix<";
35+
public static final String TESTING_MODULE = "testingModule";
3036

3137
@Override
3238
public String getLanguage() {
@@ -55,13 +61,19 @@ public Map<String, String> createOptions() {
5561
.put(KotlinMiskServerCodegen.MODULE_CLASS_NAME, MODULE_CLASS_NAME)
5662
.put(BeanValidationFeatures.USE_BEANVALIDATION, USE_BEAN_VALIDATION)
5763
.put(KotlinMiskServerCodegen.ACTION_PATH_PREFIX, ACTION_PATH_PREFIX)
64+
.put(KotlinMiskServerCodegen.ACTION_IMPORTS, ACTION_IMPORTS)
65+
.put(KotlinMiskServerCodegen.ACTION_ANNOTATIONS, ACTION_ANNOTATIONS)
66+
.put(KotlinMiskServerCodegen.ACTION_PARENT_CLASS, ACTION_PARENT_CLASS)
67+
.put(KotlinMiskServerCodegen.ACTION_REQUEST_CONTENT_TYPE, ACTION_REQUEST_CONTENT_TYPE)
68+
.put(KotlinMiskServerCodegen.ACTION_REQUEST_CONTENT_TYPE_PREFIX, ACTION_REQUEST_CONTENT_TYPE_PREFIX)
5869
.put(KotlinMiskServerCodegen.ADD_MODEL_MOSHI_JSON_ANNOTATION, ADD_MODEL_MOSHI_JSON_ANNOTATION)
5970
.put(KotlinMiskServerCodegen.GENERATE_STUB_IMPL_CLASSES, GENERATE_STUB_IMPL_CLASSES)
71+
.put(KotlinMiskServerCodegen.TESTING_MODULE, TESTING_MODULE)
6072
.build();
6173
}
6274

6375
@Override
6476
public boolean isServer() {
6577
return true;
6678
}
67-
}
79+
}

0 commit comments

Comments
 (0)