Reputation: 753
I have a field in my Rest API (Implemented in Jersey
+ Jackson
+ Bean Validation
) which is a closed set of numeric values. For example, an Employee rank, which can be one of the following values: 1,2,5,7
. And no, defining a matching String for each of the values is not an option.
I'm trying to get the generated Swagger
docs to present a numeric enum for those value. I've tried the following:
@ApiModelProperty(allowableValues = "1,2,5,7") Integer employeeRank
. Swagger-UI
did not show any enum, only after changing the type of employeeRank
to String
. So unfortunately, allowableValues
only works with with a String parameter, which I don't want my model to be. employeeRank must be an Integer.Defining an Enum:
@JsonSerialize(using = BlockSize.OrderTypeSerializer.class)
@JsonDeserialize(using = BlockSize.OrderTypeDeserializer.class)
public enum EmployeeRank {
ONW(1),
TWO(2),
FIVE(5),
SEVEN(7)
int rank;
EmployeeRank(int rank) {
this.rank = rank;
}
@JsonValue
public int getRank() {
return rank;
}
public class RankSerializer extends JsonSerializer<EmployeeRank> {
@Override
public void serialize(EmployeeRank rank, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeFieldName("rank");
generator.writeNumber(rank.getRank());
generator.writeEndObject();
}
}
public class RankDeserializer extends JsonDeserializer<EmployeeRank> {
@Override
public EmployeeRank deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
int val =jsonParser.getValueAsInt();
if (val == 1) {
return ONE;
}
if (val == 2) {
return TWO;
}
if (val == 5) {
return FIVE;
}
if (val == 7) {
return SEVEN;
}
throw new IOException("Illiegal rank value " + val);
}
}
With no luck. Swagger-UI
presents the enum as the enum names (ONE,TWO,FIVE,SEVEN)
toString
on EmployeeRank
to return the rank number as string, with or without JsonValue
annotation on the method. Didn't have any effect. This seems like a pretty trivial task to define a numeric set of values in Jersey with Swagger to understand it. Any idea?
Below is my ResourceConfig:
resourceConfig.packages(true, ResponseWrapper.class.getPackage().getName());
resourceConfig.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
resourceConfig.property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
resourceConfig.register(ApiListingResource.class);
resourceConfig.register(SwaggerSerializers.class);
resourceConfig.register(EncodingFilter.class);
resourceConfig.register(GZipEncoder.class);
resourceConfig.register(DeflateEncoder.class);
resourceConfig.register(JacksonFeature.class);
resourceConfig.register(MultiPartFeature.class);
resourceConfig.register(ValidationConfigurationContextResolver.class);
And My Swagger initializer:
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("3.0");
beanConfig.setSchemes(new String[]{"https"});
beanConfig.setHost("localhost");
beanConfig.setBasePath("/api");
beanConfig.setPrettyPrint(true);
beanConfig.setResourcePackage(ApiLevel.class.getPackage().getName());
beanConfig.setScan(true);
UPDATE
With the suggestion of @fehguy, I upgraded to Jackson 2.7
. And there is some progress. Please consider the following enum:
public enum Status {
@JsonProperty("hello")
ENUM1,
@JsonProperty("world")
ENUM2;
}
Running the following main application works:
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Status user = Status.ENUM1;
System.out.println(mapper.writeValueAsString(user));
}
Output is "hello", which is exactly what I needed.
However, Swagger-UI
still shows the enum values. Maybe it doesn't process JsonProperty
annotation on enum values?
Upvotes: 4
Views: 2232
Reputation: 1167
If you want to customize enum values and generate swagger specification file with them (swagger-ui uses this file) you can do the following.
ObjectMapper
before you create an instance of BeanConfig
:import io.swagger.util.Json;
//...
Json.mapper().configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
BeanConfig beanConfig = new BeanConfig();
//...
toString
method in your enum and add methods annotated with @JsonCreator
and @JsonValue
:public enum Status {
ENUM1("hello"),
ENUM2("world");
private final String value;
Status(final String value) {
this.value = value;
}
@JsonCreator
public static Rank fromString(final String value) {
return EnumSet.allOf(Status.class).stream()
.filter(s -> s.value == value)
.findFirst().orElse(null);
}
@JsonValue
public String getValue() {
return value;
}
@Override
public String toString() {
return value;
}
}
A simple code example can be found on GitHub.
Upvotes: -1
Reputation: 6824
This is a Jackson configuration problem. Take a look at using the @JsonProperty
annotation in 2.6.2 or later, which will let you set the friendly name for the enum.
Upvotes: 2