Given a Spring Boot project that uses the springdoc-openapi library to expose an OpenAPI (Swagger) endpoint documenting the Spring MVC controller endpoints of the project.
One of the enums in the project uses @JsonValue
from Jackson on a field to change the JSON representation of the enum. This enum field is exposed as a getter using the @Getter
annotation from Project Lombok:
@Getter
public enum Suit {
HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");
@JsonValue
private final String name;
Suit(String name) { this.name = name; }
}
However, despite the Jackson representation being based on the field, the enum representation returned by the OpenAPI endpoint uses the toString
value of the enum
instead:
"suit": {
"type": "string",
"enum": [
"HEARTS",
"DIAMONDS",
"CLUBS",
"SPADES"
]
}
Expected:
"suit": {
"type": "string",
"enum": [
"Hearts",
"Diamonds",
"Clubs",
"Spades"
]
}
Based on springdoc-openapi#1244 and swagger-core#3998, it's clear that the @JsonValue
annotation needs to be applied to the method, and not the field. However, neither the above attempted approach, nor the following, work:
@Getter @JsonValue
public enum Suit {
HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");
private final String name;
Suit(String name) { this.name = name; }
}
How can this enum be exposed with the proper values in Swagger, while still using Lombok to generate the getter?
The solution is to tell Lombok to use the annotation on the generated getter method, using @Getter(onMethod_ = @JsonValue)
on the field.
public enum Suit {
HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");
@Getter(onMethod_ = @JsonValue)
private final String name;
Suit(String name) { this.name = name; }
}
The onMethod
property is documented in the @Getter and @Setter and the onX documentation:
To put annotations on the generated method, you can use
onMethod=@__({@AnnotationsHere})
. […] For more details see the documentation on the onX feature.
The syntax is a little strange and depends on the javac you are using.
On javac7, to use any of the 3onX
features, you must wrap the annotations to be applied to the constructor / method / parameter in@__(@AnnotationGoesHere)
. To apply multiple annotations, use@__({@Annotation1, @Annotation2})
. The annotations can themselves obviously have parameters as well.
On javac8 and up, you add an underscore afteronMethod
,onParam
, oronConstructor
.