Skip to content

Commit 6d46422

Browse files
refactor(kotlin): remove unknown default enum case for inline operation enums in multiplatform library (#24521)
1 parent 8e4d0d4 commit 6d46422

7 files changed

Lines changed: 258 additions & 57 deletions

File tree

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

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
import static org.openapitools.codegen.CodegenConstants.*;
9595
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
9696
import static org.openapitools.codegen.utils.DiscriminatorUtils.*;
97-
import static org.openapitools.codegen.utils.EnumUtils.getEnumValues;
97+
import static org.openapitools.codegen.utils.EnumUtils.*;
9898
import static org.openapitools.codegen.utils.OnceLogger.once;
9999
import static org.openapitools.codegen.utils.StringUtils.*;
100100

@@ -6842,31 +6842,59 @@ protected List<Map<String, Object>> buildEnumVars(List<Object> values, String da
68426842
}
68436843

68446844
if (enumUnknownDefaultCase) {
6845-
// If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.
6846-
// With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.
6847-
Map<String, Object> enumVar = new HashMap<>();
6848-
String enumName = enumUnknownDefaultCaseName;
6849-
6850-
String enumValue = isDataTypeString(dataType)
6851-
? enumUnknownDefaultCaseName
6852-
: // This is a dummy value that attempts to avoid collisions with previously specified cases.
6853-
// Int.max / 192
6854-
// The number 192 that is used to calculate this random value, is the Swift Evolution proposal for frozen/non-frozen enums.
6855-
// [SE-0192](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md)
6856-
// Since this functionality was born in the Swift 5 generator and latter on broth to all generators
6857-
// https://github.com/OpenAPITools/openapi-generator/pull/11013
6858-
String.valueOf(11184809);
6859-
6860-
enumVar.put(ENUM_NAME, toEnumVarName(enumName, dataType));
6861-
enumVar.put(ENUM_VALUE, toEnumValue(enumValue, dataType));
6862-
enumVar.put(ENUM_IS_STRING, isDataTypeString(dataType));
6863-
// TODO: add isNumeric
6864-
enumVars.add(enumVar);
6845+
injectEnumUnknownDefaultCase(enumVars, dataType);
68656846
}
68666847

68676848
return enumVars;
68686849
}
68696850

6851+
/**
6852+
* If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.
6853+
* This adds a default case to the enum, {@link DefaultCodegen#enumUnknownDefaultCaseName}, that can be used as a fallback for unknown values.
6854+
*
6855+
* @param enumVars the enumVars
6856+
* @param dataType the data type of the enum parameter
6857+
*/
6858+
private void injectEnumUnknownDefaultCase(List<Map<String, Object>> enumVars, String dataType) {
6859+
Map<String, Object> enumVar = new HashMap<>();
6860+
String enumName = enumUnknownDefaultCaseName;
6861+
6862+
String enumValue = isDataTypeString(dataType)
6863+
? enumUnknownDefaultCaseName
6864+
: // This is a dummy value that attempts to avoid collisions with previously specified cases.
6865+
// Int.max / 192
6866+
// The number 192 that is used to calculate this random value, is the Swift Evolution proposal for frozen/non-frozen enums.
6867+
// [SE-0192](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md)
6868+
// Since this functionality was born in the Swift 5 generator and latter on broth to all generators
6869+
// https://github.com/OpenAPITools/openapi-generator/pull/11013
6870+
String.valueOf(11184809);
6871+
6872+
enumVar.put(ENUM_NAME, toEnumVarName(enumName, dataType));
6873+
enumVar.put(ENUM_VALUE, toEnumValue(enumValue, dataType));
6874+
enumVar.put(ENUM_IS_STRING, isDataTypeString(dataType));
6875+
// TODO: add isNumeric
6876+
enumVars.add(enumVar);
6877+
}
6878+
6879+
/**
6880+
* Removes any injected default enum value that was created with {@link DefaultCodegen#injectEnumUnknownDefaultCase}
6881+
* from an operation's non-body enum parameters. This can for example be of interest when generating client code
6882+
* where a fallback is superfluous for a value that is only sent and never received.
6883+
*
6884+
* @param operation operation to be processed
6885+
*/
6886+
protected void removeEnumUnknownDefaultCase(CodegenOperation operation) {
6887+
for (CodegenParameter param : operation.allParams) {
6888+
if (!param.isBodyParam && param.isEnum && hasEnumVars(param.allowableValues)) {
6889+
List<Map<String, Object>> enumVars = getEnumVars(param.allowableValues);
6890+
if (enumVars != null) {
6891+
String unknownName = toEnumVarName(enumUnknownDefaultCaseName, param.dataType);
6892+
enumVars.removeIf(ev -> unknownName.equals(ev.get(ENUM_NAME)));
6893+
}
6894+
}
6895+
}
6896+
}
6897+
68706898
protected void postProcessEnumVars(List<Map<String, Object>> enumVars) {
68716899
Collections.reverse(enumVars);
68726900
enumVars.forEach(v -> {

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@
3939
import java.util.stream.Collectors;
4040
import java.util.stream.Stream;
4141

42-
import lombok.Getter;
43-
import lombok.Setter;
4442
import org.openapitools.codegen.CliOption;
4543
import org.openapitools.codegen.CodegenConstants;
4644
import org.openapitools.codegen.CodegenModel;
@@ -60,6 +58,9 @@
6058
import org.openapitools.codegen.templating.mustache.ReplaceAllLambda;
6159

6260
import static java.util.Collections.sort;
61+
import static org.openapitools.codegen.CodegenConstants.ENUM_NAME;
62+
import static org.openapitools.codegen.utils.EnumUtils.getEnumVars;
63+
import static org.openapitools.codegen.utils.EnumUtils.hasEnumVars;
6364

6465
/**
6566
* <p>Mustache templates are located in
@@ -1146,9 +1147,26 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
11461147
}
11471148
}
11481149
objs.put("isResponseFile", isResponseFile);
1150+
removeEnumUnknownDefaultCaseFromOperationParameters(objs);
11491151
return objs;
11501152
}
11511153

1154+
/**
1155+
* Removes any injected unknown default enum value that stem from {@link DefaultCodegen#enumUnknownDefaultCase}
1156+
* from an operation's enum parameters.
1157+
* Applies to the {@value KotlinClientCodegen#MULTIPLATFORM} library since it generates enums locally within the api,
1158+
* and there we have no need for a defined fallback, since it is values that we only send.
1159+
*
1160+
* @param objs the map containing all the defined operations
1161+
*/
1162+
private void removeEnumUnknownDefaultCaseFromOperationParameters(OperationsMap objs) {
1163+
if (enumUnknownDefaultCase && library.equals(MULTIPLATFORM)) {
1164+
for (CodegenOperation operation : objs.getOperations().getOperation()) {
1165+
removeEnumUnknownDefaultCase(operation);
1166+
}
1167+
}
1168+
}
1169+
11521170
private static boolean isMultipartType(List<Map<String, String>> consumes) {
11531171
Map<String, String> firstType = consumes.get(0);
11541172
if (firstType != null) {

modules/openapi-generator/src/main/resources/kotlin-client/libraries/multiplatform/api.mustache

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,10 @@ import kotlinx.serialization.encoding.*
4343
*/
4444
@Serializable
4545
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}enum class {{enumName}}{{operationIdCamelCase}}({{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}val value: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}kotlin.String{{/isContainer}}) {
46-
{{^enumUnknownDefaultCase}}
4746
{{#allowableValues}}{{#enumVars}}
4847
@SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
49-
{{&name}}({{{value}}}){{^-last}},{{/-last}}
48+
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
5049
{{/enumVars}}{{/allowableValues}}
51-
{{/enumUnknownDefaultCase}}
52-
{{#enumUnknownDefaultCase}}
53-
{{#allowableValues}}{{#enumVars}}{{^-last}}
54-
@SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
55-
{{&name}}({{{value}}}),
56-
{{/-last}}{{/enumVars}}{{/allowableValues}}
57-
{{/enumUnknownDefaultCase}}
5850
}
5951

6052
{{/isEnum}}

0 commit comments

Comments
 (0)