Skip to content

Commit b06fdb5

Browse files
authored
fix(kotlin): add JsonCreator/JsonValue to Jackson enums (#22535)
* fix(kotlin): add JsonCreator/JsonValue for numeric enums * Regenerate samples * Update title in numeric enum YAML file * rename test
1 parent 5f28987 commit b06fdb5

File tree

5 files changed

+77
-5
lines changed

5 files changed

+77
-5
lines changed

modules/openapi-generator/src/main/resources/kotlin-client/enum_class.mustache

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ import com.squareup.moshi.Json
77
import com.squareup.moshi.JsonClass
88
{{/moshi}}
99
{{#jackson}}
10+
import com.fasterxml.jackson.annotation.JsonCreator
1011
{{#enumUnknownDefaultCase}}
1112
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue
1213
{{/enumUnknownDefaultCase}}
1314
import com.fasterxml.jackson.annotation.JsonProperty
15+
import com.fasterxml.jackson.annotation.JsonValue
16+
import kotlin.jvm.JvmStatic
1417
{{/jackson}}
1518
{{#kotlinx_serialization}}
1619
import kotlinx.serialization.SerialName
@@ -52,7 +55,7 @@ import kotlinx.serialization.*
5255
@JsonClass(generateAdapter = false)
5356
{{/moshi}}
5457
{{/multiplatform}}
55-
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}enum class {{classname}}({{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}val value: {{{dataType}}}) {
58+
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}enum class {{classname}}({{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}{{#jackson}}@get:JsonValue {{/jackson}}val value: {{{dataType}}}) {
5659
{{#allowableValues}}{{#enumVars}}
5760
{{^multiplatform}}
5861
{{#moshi}}
@@ -103,7 +106,9 @@ import kotlinx.serialization.*
103106
/**
104107
* Returns a valid [{{classname}}] for [data], null otherwise.
105108
*/
106-
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun decode(data: kotlin.Any?): {{classname}}? = data?.let {
109+
{{#jackson}}@JvmStatic
110+
@JsonCreator
111+
{{/jackson}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun decode(data: kotlin.Any?): {{classname}}? = data?.let {
107112
val normalizedData = "$it".lowercase()
108113
values().firstOrNull { value ->
109114
it == value || normalizedData == "$value".lowercase()
@@ -146,4 +151,4 @@ internal object {{classname}}Serializer : KSerializer<{{classname}}> {
146151
}
147152
}
148153
{{/isString}}{{/enumUnknownDefaultCase}}
149-
{{/kotlinx_serialization}}
154+
{{/kotlinx_serialization}}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,32 @@ public void testIntArrayToEnum() throws IOException {
688688
TestUtils.assertFileContains(modelKt, "enum class DaysOfWeek(val value: kotlin.Int)");
689689
}
690690

691+
@Test
692+
public void testJacksonEnumsUseJsonCreator() throws IOException {
693+
File output = Files.createTempDirectory("test").toFile();
694+
output.deleteOnExit();
695+
696+
final CodegenConfigurator configurator = new CodegenConfigurator()
697+
.setGeneratorName("kotlin")
698+
.setLibrary("jvm-retrofit2")
699+
.setAdditionalProperties(new HashMap<>() {{
700+
put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson");
701+
put(CodegenConstants.MODEL_PACKAGE, "model");
702+
}})
703+
.setInputSpec("src/test/resources/3_0/kotlin/issue22534-kotlin-numeric-enum.yaml")
704+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
705+
706+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
707+
DefaultGenerator generator = new DefaultGenerator();
708+
709+
generator.opts(clientOptInput).generate();
710+
711+
final Path enumKt = Paths.get(output + "/src/main/kotlin/model/ExampleNumericEnum.kt");
712+
713+
TestUtils.assertFileContains(enumKt, "@get:JsonValue");
714+
TestUtils.assertFileContains(enumKt, "@JsonCreator");
715+
}
716+
691717
@Test(description = "convert an empty model to object")
692718
public void emptyModelKotlinxSerializationTest() throws IOException {
693719
final Schema<?> schema = new ObjectSchema()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
openapi: 3.0.0
2+
info:
3+
title: 'Issue 22534 Jackson numeric enum regression'
4+
version: latest
5+
paths:
6+
'/example':
7+
get:
8+
operationId: getExample
9+
responses:
10+
'200':
11+
description: Success
12+
content:
13+
application/json:
14+
schema:
15+
$ref: '#/components/schemas/ExampleModel'
16+
components:
17+
schemas:
18+
ExampleModel:
19+
required:
20+
- source
21+
type: object
22+
properties:
23+
source:
24+
$ref: '#/components/schemas/ExampleNumericEnum'
25+
ExampleNumericEnum:
26+
type: integer
27+
format: int32
28+
enum:
29+
- -1
30+
- 0
31+
- 1

samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/models/StringEnumRef.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@
1616
package org.openapitools.client.models
1717

1818

19+
import com.fasterxml.jackson.annotation.JsonCreator
1920
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue
2021
import com.fasterxml.jackson.annotation.JsonProperty
22+
import com.fasterxml.jackson.annotation.JsonValue
23+
import kotlin.jvm.JvmStatic
2124

2225
/**
2326
*
2427
*
2528
* Values: success,failure,unclassified,unknown_default_open_api
2629
*/
2730

28-
enum class StringEnumRef(val value: kotlin.String) {
31+
enum class StringEnumRef(@get:JsonValue val value: kotlin.String) {
2932

3033
@JsonProperty(value = "success")
3134
success("success"),
@@ -57,6 +60,8 @@ enum class StringEnumRef(val value: kotlin.String) {
5760
/**
5861
* Returns a valid [StringEnumRef] for [data], null otherwise.
5962
*/
63+
@JvmStatic
64+
@JsonCreator
6065
fun decode(data: kotlin.Any?): StringEnumRef? = data?.let {
6166
val normalizedData = "$it".lowercase()
6267
values().firstOrNull { value ->

samples/client/echo_api/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/models/StringEnumRef.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@
1616
package org.openapitools.client.models
1717

1818

19+
import com.fasterxml.jackson.annotation.JsonCreator
1920
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue
2021
import com.fasterxml.jackson.annotation.JsonProperty
22+
import com.fasterxml.jackson.annotation.JsonValue
23+
import kotlin.jvm.JvmStatic
2124

2225
/**
2326
*
2427
*
2528
* Values: success,failure,unclassified,unknown_default_open_api
2629
*/
2730

28-
enum class StringEnumRef(val value: kotlin.String) {
31+
enum class StringEnumRef(@get:JsonValue val value: kotlin.String) {
2932

3033
@JsonProperty(value = "success")
3134
success("success"),
@@ -57,6 +60,8 @@ enum class StringEnumRef(val value: kotlin.String) {
5760
/**
5861
* Returns a valid [StringEnumRef] for [data], null otherwise.
5962
*/
63+
@JvmStatic
64+
@JsonCreator
6065
fun decode(data: kotlin.Any?): StringEnumRef? = data?.let {
6166
val normalizedData = "$it".lowercase()
6267
values().firstOrNull { value ->

0 commit comments

Comments
 (0)