Skip to content

Commit 817cbaf

Browse files
T3rm1frantuma
authored andcommitted
feat: Support other types than string in enum schemas
1 parent ea72ba7 commit 817cbaf

File tree

5 files changed

+92
-15
lines changed

5 files changed

+92
-15
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
335335
}
336336

337337
if (model == null && type.isEnumType()) {
338+
@SuppressWarnings("unchecked")
339+
Class<Enum<?>> rawEnumClass = (Class<Enum<?>>) type.getRawClass();
340+
model = _createSchemaForEnum(rawEnumClass);
338341
model = openapi31 ? new JsonSchema().typesItem("string") : new StringSchema();
339342
_addEnumProps(type.getRawClass(), model);
340343
isPrimitive = true;
@@ -1359,6 +1362,79 @@ protected void _addEnumProps(Class<?> propClass, Schema property) {
13591362
}
13601363
}
13611364

1365+
/**
1366+
* Adds each enum property value to the model schema
1367+
*
1368+
* @param enumClass the enum class for which to add properties
1369+
*/
1370+
protected Schema _createSchemaForEnum(Class<Enum<?>> enumClass) {
1371+
boolean useIndex = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX);
1372+
boolean useToString = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
1373+
1374+
Optional<Method> jsonValueMethod = Arrays.stream(enumClass.getDeclaredMethods())
1375+
.filter(m -> m.isAnnotationPresent(JsonValue.class))
1376+
.filter(m -> m.getAnnotation(JsonValue.class).value())
1377+
.findFirst();
1378+
1379+
Optional<Field> jsonValueField = Arrays.stream(enumClass.getDeclaredFields())
1380+
.filter(f -> f.isAnnotationPresent(JsonValue.class))
1381+
.filter(f -> f.getAnnotation(JsonValue.class).value())
1382+
.findFirst();
1383+
1384+
Schema schema = null;
1385+
if (jsonValueField.isPresent()) {
1386+
jsonValueField.get().setAccessible(true);
1387+
PrimitiveType primitiveType = PrimitiveType.fromType(jsonValueField.get().getType());
1388+
if (primitiveType != null) {
1389+
schema = primitiveType.createProperty();
1390+
}
1391+
} else if (jsonValueMethod.isPresent()) {
1392+
jsonValueMethod.get().setAccessible(true);
1393+
PrimitiveType primitiveType = PrimitiveType.fromType(jsonValueMethod.get().getReturnType());
1394+
if (primitiveType != null) {
1395+
schema = primitiveType.createProperty();
1396+
}
1397+
}
1398+
if (schema == null) {
1399+
schema = new StringSchema();
1400+
}
1401+
1402+
Enum<?>[] enumConstants = enumClass.getEnumConstants();
1403+
1404+
if (enumConstants != null) {
1405+
String[] enumValues = _intr.findEnumValues(enumClass, enumConstants,
1406+
new String[enumConstants.length]);
1407+
1408+
for (Enum<?> en : enumConstants) {
1409+
Field enumField = ReflectionUtils.findField(en.name(), enumClass);
1410+
if (null != enumField && enumField.isAnnotationPresent(Hidden.class)) {
1411+
continue;
1412+
}
1413+
1414+
String enumValue = enumValues[en.ordinal()];
1415+
Object methodValue = jsonValueMethod.flatMap(m -> ReflectionUtils.safeInvoke(m, en)).orElse(null);
1416+
Object fieldValue = jsonValueField.flatMap(f -> ReflectionUtils.safeGet(f, en)).orElse(null);
1417+
1418+
Object n;
1419+
if (methodValue != null) {
1420+
n = methodValue;
1421+
} else if (fieldValue != null) {
1422+
n = fieldValue;
1423+
} else if (enumValue != null) {
1424+
n = enumValue;
1425+
} else if (useIndex) {
1426+
n = String.valueOf(en.ordinal());
1427+
} else if (useToString) {
1428+
n = en.toString();
1429+
} else {
1430+
n = _intr.findEnumValue(en);
1431+
}
1432+
schema.addEnumItemObject(n);
1433+
}
1434+
}
1435+
return schema;
1436+
}
1437+
13621438
protected boolean ignore(final Annotated member, final XmlAccessorType xmlAccessorTypeAnnotation, final String propName, final Set<String> propertiesToIgnore) {
13631439
return ignore(member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, null);
13641440
}

modules/swagger-core/src/test/java/io/swagger/v3/core/converting/EnumPropertyTest.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.swagger.v3.core.oas.models.ModelWithEnumProperty;
1313
import io.swagger.v3.core.oas.models.ModelWithEnumRefProperty;
1414
import io.swagger.v3.core.oas.models.ModelWithJacksonEnumField;
15+
import io.swagger.v3.oas.models.media.IntegerSchema;
1516
import io.swagger.v3.oas.models.media.Schema;
1617
import io.swagger.v3.oas.models.media.StringSchema;
1718
import org.testng.annotations.AfterTest;
@@ -216,23 +217,23 @@ public void testExtractJacksonEnumFields() {
216217
assertEquals(secondStringProperty.getEnum(), Arrays.asList("one", "two", "three"));
217218

218219
final Schema thirdEnumProperty = (Schema) model.getProperties().get("thirdEnumValue");
219-
assertTrue(thirdEnumProperty instanceof StringSchema);
220-
final StringSchema thirdStringProperty = (StringSchema) thirdEnumProperty;
221-
assertEquals(thirdStringProperty.getEnum(), Arrays.asList("2", "4", "6"));
220+
assertTrue(thirdEnumProperty instanceof IntegerSchema);
221+
final IntegerSchema thirdStringProperty = (IntegerSchema) thirdEnumProperty;
222+
assertEquals(thirdStringProperty.getEnum(), Arrays.asList(2, 4, 6));
222223

223224
final Schema fourthEnumProperty = (Schema) model.getProperties().get("fourthEnumValue");
224225
assertTrue(fourthEnumProperty instanceof StringSchema);
225226
final StringSchema fourthStringProperty = (StringSchema) fourthEnumProperty;
226-
assertEquals(fourthEnumProperty.getEnum(), Arrays.asList("one", "two", "three"));
227+
assertEquals(fourthStringProperty.getEnum(), Arrays.asList("one", "two", "three"));
227228

228229
final Schema fifthEnumProperty = (Schema) model.getProperties().get("fifthEnumValue");
229-
assertTrue(fifthEnumProperty instanceof StringSchema);
230-
final StringSchema fifthStringProperty = (StringSchema) fifthEnumProperty;
231-
assertEquals(fifthEnumProperty.getEnum(), Arrays.asList("2", "4", "6"));
230+
assertTrue(fifthEnumProperty instanceof IntegerSchema);
231+
final IntegerSchema fifthStringProperty = (IntegerSchema) fifthEnumProperty;
232+
assertEquals(fifthStringProperty.getEnum(), Arrays.asList(2, 4, 6));
232233

233234
final Schema sixthEnumProperty = (Schema) model.getProperties().get("sixthEnumValue");
234235
assertTrue(sixthEnumProperty instanceof StringSchema);
235236
final StringSchema sixthStringProperty = (StringSchema) sixthEnumProperty;
236-
assertEquals(sixthEnumProperty.getEnum(), Arrays.asList("one", "two", "three"));
237+
assertEquals(sixthStringProperty.getEnum(), Arrays.asList("one", "two", "three"));
237238
}
238239
}

modules/swagger-core/src/test/java/io/swagger/v3/core/oas/models/JacksonNumberValueEnum.java renamed to modules/swagger-core/src/test/java/io/swagger/v3/core/oas/models/JacksonIntegerValueEnum.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66
/**
77
* Enum holds values different from names. Schema model will derive Integer value from jackson annotation JsonValue on public method.
88
*/
9-
public enum JacksonNumberValueEnum {
9+
public enum JacksonIntegerValueEnum {
1010
FIRST(2),
1111
SECOND(4),
1212
THIRD(6),
1313
@Hidden HIDDEN(-1);
1414

1515
private final int value;
1616

17-
JacksonNumberValueEnum(int value) {
17+
JacksonIntegerValueEnum(int value) {
1818
this.value = value;
1919
}
2020

2121
@JsonValue
22-
public Number getValue() {
22+
public Integer getValue() {
2323
return value;
2424
}
2525
}

modules/swagger-core/src/test/java/io/swagger/v3/core/oas/models/JacksonNumberValueFieldEnum.java renamed to modules/swagger-core/src/test/java/io/swagger/v3/core/oas/models/JacksonIntegerValueFieldEnum.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/**
77
* Enum holds values different from names. Schema model will derive Integer value from jackson annotation JsonValue on private field.
88
*/
9-
public enum JacksonNumberValueFieldEnum {
9+
public enum JacksonIntegerValueFieldEnum {
1010
FIRST(2),
1111
SECOND(4),
1212
THIRD(6),
@@ -15,7 +15,7 @@ public enum JacksonNumberValueFieldEnum {
1515
@JsonValue
1616
private final int value;
1717

18-
JacksonNumberValueFieldEnum(int value) {
18+
JacksonIntegerValueFieldEnum(int value) {
1919
this.value = value;
2020
}
2121
}

modules/swagger-core/src/test/java/io/swagger/v3/core/oas/models/ModelWithJacksonEnumField.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
public class ModelWithJacksonEnumField {
77
public JacksonPropertyEnum firstEnumValue;
88
public JacksonValueEnum secondEnumValue;
9-
public JacksonNumberValueEnum thirdEnumValue;
9+
public JacksonIntegerValueEnum thirdEnumValue;
1010
public JacksonValueFieldEnum fourthEnumValue;
11-
public JacksonNumberValueFieldEnum fifthEnumValue;
11+
public JacksonIntegerValueFieldEnum fifthEnumValue;
1212
public JacksonValuePrivateEnum sixthEnumValue;
1313
}

0 commit comments

Comments
 (0)