When deserializing a response, if enums are used, and the enum value doesn't match with the enum name, an exception is thrown by moshi stating that the enum doesn't match expected values.
E.g.:
status: {
type: "string",
description: "Order Status",
enum: [
"Placed",
"Approved",
"Delivered"
]
}
When deserializing, it fails with: expected one of [placed, approved, delivered] but was Placed at path $.status
This happens because moshi's EnumJsonAdapter doesn't use the enum's getValue and instead either uses a Json annotation or name().
2.3.1
swagger-codegen generate -l kotlin -i swagger.yaml -o tmp
Change on Petstore swagger spec any enum from lowercase to capitalized.
A solution would be to add the Json annotation to each enum value. Another one to override the name method to return the value instead. One more is to provide a EnumJsonAdapter to moshi that can correctly decode the generated enums.
An alternative to the proposed @Json(name = "…")
would be an @JsonValue on the only field. It would be consistent with the output of Enums for Java. The result would looks as simple as that:
import com.fasterxml.jackson.annotation.JsonValue
enum class Status(@JsonValue val value: kotlin.String) {
AVAILABLE("available"),
PENDING("pending"),
SOLD("sold");
}
@florianhof does Moshi work with Jackson annotations?
Oh I just improve my knowledge and realize we are probably not in the same context...
For our spring-boot web-service, manually editing the generated enum with @JsonValue solved the problem. I tried this to surround the problem. Then I switch to generate java/jersey code, which obviously also works. I doubt that Moshi's annotation would be taken into account.
For Kotlin with Moshi library (an advantage mainly for Android, but slower), then Jackson's annotations are certainly of no use.
So looks like two (or more) templates are required for kotlin. :-(
But there are already two templates: _kotlin-client_ and _kotlin-server_. Only _kotlin-client_ was annotated with Moshi's Json(name="...").
A light alternative for at least _kotlin-server_ (and should not hurt _kotlin-client_) would be to define toString to return the value:
override fun toString() = value
Then Jackson can be configured with READ_ENUMS_USING_TO_STRING and WRITE_ENUMS_USING_TO_STRING (with spring, something like _spring.jackson.serialization.READ_ENUMS_USING_TO_STRING: true_ in an _application.yml_). This solution is not invasive and flexible. I can only recommand to add this toString. It is in the sense described in the javadoc. By the way, Swagger calls toString to lists the possible values of an enum, so that's nicely coherent. :-)
The pure Jackson solution, reserved for _kotlin-server_ if Jackson is available, would be to annotate either value or toString with @JsonValue.
@florianhof having a toString override doesn't resolve templating issues when users want multiple serialization frameworks. The generator would have to support serialization frameworks as an option, which it currently doesn't.
Most helpful comment
An alternative to the proposed
@Json(name = "…")would be an
@JsonValueon the only field. It would be consistent with the output of Enums for Java. The result would looks as simple as that: