Skip to content

Commit 296d071

Browse files
committed
seems to work
1 parent e640397 commit 296d071

8 files changed

Lines changed: 223 additions & 130 deletions

File tree

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

Lines changed: 118 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.swagger.v3.oas.models.media.Schema;
55
import io.swagger.v3.oas.models.security.SecurityScheme;
66
import io.swagger.v3.oas.models.servers.Server;
7+
import lombok.Getter;
78
import org.apache.commons.lang3.StringUtils;
89
import org.openapitools.codegen.*;
910
import org.openapitools.codegen.meta.GeneratorMetadata;
@@ -32,23 +33,20 @@ public class ScalaSttp4JsoniterClientCodegen extends AbstractScalaCodegen implem
3233
"F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
3334
"response's error raising them through enclosing monad (F[ReturnType]).",
3435
true);
35-
private static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion", "The version of " +
36-
"joda-time library", "2.10.13");
3736
private static final StringProperty JSONITER_VERSION = new StringProperty("jsoniterVersion",
3837
"The version of jsoniter-scala " +
3938
"library",
4039
"2.31.1");
4140

42-
private static final JsonLibraryProperty JSON_LIBRARY_PROPERTY = new JsonLibraryProperty();
43-
4441
public static final String DEFAULT_PACKAGE_NAME = "org.openapitools.client";
4542
private static final PackageProperty PACKAGE_PROPERTY = new PackageProperty();
4643

4744
private static final List<Property<?>> properties = Arrays.asList(
48-
STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL, JODA_TIME_VERSION,
49-
JSONITER_VERSION, JSON_LIBRARY_PROPERTY, PACKAGE_PROPERTY);
45+
STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL, JSONITER_VERSION, PACKAGE_PROPERTY);
46+
47+
private static final Set<String> NO_JSON_CODEC_TYPES = new HashSet<>(Arrays.asList("UUID", "URI", "URL", "File", "Path"));
5048

51-
private final Logger LOGGER = LoggerFactory.getLogger(ScalaSttp4ClientCodegen.class);
49+
private final Logger LOGGER = LoggerFactory.getLogger(ScalaSttp4JsoniterClientCodegen.class);
5250

5351
protected String groupId = "org.openapitools";
5452
protected String artifactId = "openapi-client";
@@ -57,6 +55,8 @@ public class ScalaSttp4JsoniterClientCodegen extends AbstractScalaCodegen implem
5755
protected boolean renderJavadoc = true;
5856
protected boolean removeOAuthSecurities = true;
5957

58+
protected Map<String, String> jsonCodecNeedingTypes = new HashMap<>();
59+
6060
Map<String, ModelsMap> enumRefs = new HashMap<>();
6161

6262
public ScalaSttp4JsoniterClientCodegen() {
@@ -90,19 +90,20 @@ public ScalaSttp4JsoniterClientCodegen() {
9090
apiTemplateFiles.put("api.mustache", ".scala");
9191
embeddedTemplateDir = templateDir = "scala-sttp4-jsoniter";
9292

93-
String jsonLibrary = JSON_LIBRARY_PROPERTY.getValue(additionalProperties);
94-
9593
String jsonValueClass = "io.circe.Json";
9694

9795
additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
9896
additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
9997
additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
98+
additionalProperties.put("jsonCodecNeedingTypes", jsonCodecNeedingTypes.entrySet());
10099
if (renderJavadoc) {
101100
additionalProperties.put("javadocRenderer", new JavadocLambda());
102101
}
103102
additionalProperties.put("fnCapitalize", new CapitalizeLambda());
104103
additionalProperties.put("fnCamelize", new CamelizeLambda(false));
105104
additionalProperties.put("fnEnumEntry", new EnumEntryLambda());
105+
additionalProperties.put("fnCodecName", new CodecNameLambda());
106+
additionalProperties.put("fnHandleDownload", new HandleDownloadLambda());
106107

107108
// importMapping.remove("Seq");
108109
// importMapping.remove("List");
@@ -156,8 +157,6 @@ public void processOpts() {
156157
supportingFiles.add(new SupportingFile("additionalTypeSerializers.mustache", invokerFolder,
157158
"AdditionalTypeSerializers.scala"));
158159
supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
159-
// supportingFiles.add(new SupportingFile("dateSerializers.mustache",
160-
// invokerFolder, "DateSerializers.scala"));
161160
}
162161

163162
@Override
@@ -173,7 +172,6 @@ public String getHelp() {
173172
@Override
174173
public String encodePath(String input) {
175174
String path = super.encodePath(input);
176-
177175
// The parameter names in the URI must be converted to the same case as
178176
// the method parameter.
179177
StringBuffer buf = new StringBuffer(path.length());
@@ -185,13 +183,55 @@ public String encodePath(String input) {
185183
return buf.toString();
186184
}
187185

186+
private PathMetadata encPath(String input) {
187+
String path = super.encodePath(input);
188+
ArrayList<String> pathParams = new ArrayList<>();
189+
190+
// The parameter names in the URI must be converted to the same case as
191+
// the method parameter.
192+
StringBuffer buf = new StringBuffer(path.length());
193+
Matcher matcher = Pattern.compile("[{](.*?)[}]").matcher(path);
194+
while (matcher.find()) {
195+
matcher.appendReplacement(buf, "\\${" + toParamName(matcher.group(0)) + "}");
196+
pathParams.add(matcher.group(0));
197+
}
198+
matcher.appendTail(buf);
199+
return new PathMetadata(buf.toString(), pathParams);
200+
}
201+
188202
@Override
189203
public CodegenOperation fromOperation(String path,
190204
String httpMethod,
191205
Operation operation,
192206
List<Server> servers) {
193207
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
194-
op.path = encodePath(path);
208+
209+
PathMetadata pathMetadata = encPath(path);
210+
211+
op.path = pathMetadata.getPath();
212+
213+
for (String pathParam : pathMetadata.getPathParams()) {
214+
CodegenParameter param = new CodegenParameter();
215+
param.isPathParam = true;
216+
param.baseName = pathParam;
217+
param.paramName = toParamName(pathParam);
218+
param.dataType = "String";
219+
param.required = true;
220+
221+
boolean alreadyExists = false;
222+
for (CodegenParameter existingParam : op.pathParams) {
223+
if (existingParam.baseName.equals(param.baseName) || existingParam.paramName.equals(param.paramName)) {
224+
alreadyExists = true;
225+
break;
226+
}
227+
}
228+
229+
if (!alreadyExists) {
230+
op.pathParams.add(param);
231+
op.allParams.add(param);
232+
}
233+
}
234+
195235
return op;
196236
}
197237

@@ -310,6 +350,30 @@ private boolean isEnumClass(final String importPath, final Map<String, ModelsMap
310350

311351
@Override
312352
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
353+
OperationMap ops = objs.getOperations();
354+
355+
// allModels.forEach(model -> {
356+
// if (model.getModel().name.equals("PluginStatus")) {
357+
// System.out.println("Found plugin status model");
358+
// System.out.println(model.getModel());
359+
// }
360+
// });
361+
362+
for (CodegenOperation operation : ops.getOperation()) {
363+
if (operation.returnType != null && !NO_JSON_CODEC_TYPES.contains(operation.returnType)) {
364+
String identifier = formatIdentifier(operation.returnType, false) + "Codec";
365+
String type = operation.returnType;
366+
jsonCodecNeedingTypes.put(identifier, type);
367+
}
368+
369+
if (operation.bodyParam != null && !NO_JSON_CODEC_TYPES.contains(operation.bodyParam.dataType)) {
370+
String identifier = formatIdentifier(operation.bodyParam.dataType, false) + "Codec";
371+
String type = operation.bodyParam.dataType;
372+
373+
jsonCodecNeedingTypes.put(identifier, type);
374+
}
375+
}
376+
313377
if (registerNonStandardStatusCodes) {
314378
try {
315379
OperationMap opsMap = objs.getOperations();
@@ -385,7 +449,14 @@ public String toParamName(String name) {
385449

386450
@Override
387451
public String toEnumName(CodegenProperty property) {
388-
return formatIdentifier(property.baseName, true);
452+
String identifier = formatIdentifier(property.baseName, true);
453+
454+
// remove backticks because there are no capitalized reserved words in Scala
455+
if (identifier.startsWith("`") && identifier.endsWith("`")) {
456+
return identifier.substring(1, identifier.length() - 1);
457+
} else {
458+
return identifier;
459+
}
389460
}
390461

391462
@Override
@@ -511,29 +582,6 @@ public Boolean getValue(Map<String, Object> additionalProperties) {
511582
}
512583
}
513584

514-
public static class JsonLibraryProperty extends StringProperty {
515-
private static final String JSON4S = "json4s";
516-
private static final String CIRCE = "circe";
517-
518-
public JsonLibraryProperty() {
519-
super("jsonLibrary", "Json library to use. Possible values are: json4s and circe.", JSON4S);
520-
}
521-
522-
@Override
523-
public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
524-
String value = getValue(additionalProperties);
525-
if (CIRCE.equals(value) || JSON4S.equals(value)) {
526-
additionalProperties.put(CIRCE, CIRCE.equals(value));
527-
additionalProperties.put(JSON4S, JSON4S.equals(value));
528-
} else {
529-
IllegalArgumentException exception = new IllegalArgumentException(
530-
"Invalid json library: " + value + ". Must be " + CIRCE + " " +
531-
"or " + JSON4S);
532-
throw exception;
533-
}
534-
}
535-
}
536-
537585
public static class PackageProperty extends StringProperty {
538586

539587
public PackageProperty() {
@@ -598,8 +646,41 @@ public String formatFragment(String fragment) {
598646
private class EnumEntryLambda extends CustomLambda {
599647
@Override
600648
public String formatFragment(String fragment) {
649+
if (fragment.isBlank()) {
650+
return "NotPresent";
651+
}
601652
return formatIdentifier(fragment, true);
602653
}
603654
}
604655

656+
private class CodecNameLambda extends CustomLambda {
657+
@Override
658+
public String formatFragment(String fragment) {
659+
// remove backticks because this is used as prefix for Codec generation
660+
return formatIdentifier(fragment, false).replace("`", "") + "Codec";
661+
}
662+
}
663+
664+
private static class HandleDownloadLambda extends CustomLambda {
665+
@Override
666+
public String formatFragment(String fragment) {
667+
if (fragment.equals("asJson[File]")) {
668+
return "asFile(File.createTempFile(\"download\", \".tmp\")).mapLeft(errStr => DeserializationException(errStr, new Exception(errStr)))";
669+
} else {
670+
return fragment;
671+
}
672+
}
673+
}
674+
675+
@Getter
676+
private static class PathMetadata {
677+
private final String path;
678+
private final ArrayList<String> pathParams;
679+
680+
PathMetadata(String path, ArrayList<String> pathParams) {
681+
this.path = path;
682+
this.pathParams = pathParams;
683+
}
684+
}
685+
605686
}

modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ org.openapitools.codegen.languages.ScalaLagomServerCodegen
131131
org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen
132132
org.openapitools.codegen.languages.ScalaSttpClientCodegen
133133
org.openapitools.codegen.languages.ScalaSttp4ClientCodegen
134+
org.openapitools.codegen.languages.ScalaSttp4JsoniterClientCodegen
134135
org.openapitools.codegen.languages.ScalazClientCodegen
135136
org.openapitools.codegen.languages.SpringCodegen
136137
org.openapitools.codegen.languages.StaticDocCodegen
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package {{invokerPackage}}
22

33
import java.net.{ URI, URISyntaxException }
4+
import com.github.plokhotnyuk.jsoniter_scala.core.*
45

5-
{{#circe}}
66
trait AdditionalTypeSerializers {
7-
import com.github.plokhotnyuk.jsoniter_scala._
87
9-
implicit final lazy val URICodec: JsonValueCodec[URI] = new JsonValueCodec[URI] {
10-
def nullValue: URI = null
11-
def decodeValue(in: JsonReader, default: URI): URI = ???
12-
def encodeValue(uri: URI, out: JsonWriter): Unit = ???
13-
}
14-
}
15-
{{/circe}}
8+
implicit final lazy val URICodec: JsonValueCodec[URI] = new JsonValueCodec[URI] {
9+
def nullValue: URI = null
10+
def decodeValue(in: JsonReader, default: URI): URI = ???
11+
def encodeValue(uri: URI, out: JsonWriter): Unit = ???
12+
}
13+
}

modules/openapi-generator/src/main/resources/scala-sttp4-jsoniter/api.mustache

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ package {{package}}
44
{{#imports}}
55
import {{import}}
66
{{/imports}}
7-
import {{invokerPackage}}.JsonSupport._
8-
import sttp.client4._
7+
import {{invokerPackage}}.JsonSupport.{*, given}
8+
import sttp.client4.jsoniter.*
9+
import sttp.client4.*
910
import sttp.model.Method
1011
1112
{{#operations}}
@@ -16,6 +17,7 @@ object {{classname}} {
1617
class {{classname}}(baseUrl: String) {
1718
1819
{{#operation}}
20+
1921
{{#javadocRenderer}}
2022
{{>javadoc}}
2123
{{/javadocRenderer}}
@@ -30,13 +32,17 @@ class {{classname}}(baseUrl: String) {
3032
.cookie("{{keyParamName}}", apiKey){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}{{^isMultipart}}
3133
.body(Map({{#formParams}}
3234
{{>paramFormCreation}}{{^-last}},{{/-last}}{{/formParams}}
33-
)){{/isMultipart}}{{#isMultipart}}
35+
).collect {
36+
case (key, Some(value)) => key -> value.toString
37+
case (key, value) if value != None => key -> value.toString
38+
}){{/isMultipart}}{{#isMultipart}}
3439
.multipartBody(Seq({{#formParams}}
35-
{{>paramMultipartCreation}}{{^-last}}, {{/-last}}{{/formParams}}
40+
{{>paramMultipartCreation}}{{/formParams}}
3641
).flatten){{/isMultipart}}{{/formParams.0}}{{#bodyParam}}
3742
.body({{paramName}}){{/bodyParam}}
38-
.response({{#separateErrorChannel}}{{^returnType}}asString.mapWithMetadata(ResponseAs.deserializeRightWithError(_ => Right(()))){{/returnType}}{{#returnType}}asJson[{{>operationReturnType}}]{{/returnType}}{{/separateErrorChannel}}{{^separateErrorChannel}}{{^returnType}}asString.mapWithMetadata(ResponseAs.deserializeRightWithError(_ => Right(()))).getRight{{/returnType}}{{#returnType}}asJson[{{>operationReturnType}}].getRight{{/returnType}}{{/separateErrorChannel}})
43+
.response({{#separateErrorChannel}}{{^returnType}}asString.mapWithMetadata(ResponseAs.deserializeRightWithError(_ => Right(()))){{/returnType}}{{#fnHandleDownload}}{{#returnType}}asJson[{{>operationReturnType}}]{{/returnType}}{{/fnHandleDownload}}{{/separateErrorChannel}}{{^separateErrorChannel}}{{^returnType}}asString.mapWithMetadata(ResponseAs.deserializeRightWithError(_ => Right(()))).getRight{{/returnType}}{{#returnType}}asJson[{{>operationReturnType}}].getRight{{/returnType}}{{/separateErrorChannel}})
3944
4045
{{/operation}}
46+
4147
}
4248
{{/operations}}

modules/openapi-generator/src/main/resources/scala-sttp4-jsoniter/build.sbt.mustache

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@ name := "{{artifactId}}"
33
organization := "{{groupId}}"
44

55
scalaVersion := "3.3.4"
6-
crossScalaVersions := Seq(scalaVersion.value, "2.13.15")
76

87
libraryDependencies ++= Seq(
9-
"com.softwaremill.sttp.client4" %% "core" % "{{sttpClientVersion}}",
10-
"com.softwaremill.sttp.client4" %% "jsoniter" % "{{sttpClientVersion}}",
11-
{{#joda}}
12-
"joda-time" % "joda-time" % "{{jodaTimeVersion}}",
13-
{{/joda}}
14-
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "{{jsoniterVersion}}",
8+
"com.softwaremill.sttp.client4" %% "core" % "{{sttpClientVersion}}",
9+
"com.softwaremill.sttp.client4" %% "jsoniter" % "{{sttpClientVersion}}",
10+
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "{{jsoniterVersion}}",
1511
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "{{jsoniterVersion}}" % "compile-internal",
16-
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-circe" % "{{jsoniterVersion}}"
12+
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-circe" % "{{jsoniterVersion}}"
1713
)
1814

1915
scalacOptions := Seq(
2016
"-unchecked",
2117
"-deprecation",
2218
"-feature"
2319
)
20+
21+
// REBUILT

0 commit comments

Comments
 (0)