Skip to content

Commit 63ab0e6

Browse files
Jason Vossfrantuma
Jason Voss
authored andcommitted
fix #3998 model schema enum values of jackson fields and private methods
1 parent ef7df86 commit 63ab0e6

File tree

9 files changed

+133
-6
lines changed

9 files changed

+133
-6
lines changed

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

+22-6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import javax.xml.bind.annotation.XmlSchema;
7878
import java.io.IOException;
7979
import java.lang.annotation.Annotation;
80+
import java.lang.reflect.Field;
8081
import java.lang.reflect.InvocationTargetException;
8182
import java.lang.reflect.Method;
8283
import java.lang.reflect.Type;
@@ -955,20 +956,33 @@ protected boolean _isOptionalType(JavaType propType) {
955956
.contains(propType.getRawClass().getCanonicalName());
956957
}
957958

959+
/**
960+
* Adds each enum property value to the model schema
961+
*
962+
* @param propClass the enum class for which to add properties
963+
* @param property the schema to add properties to
964+
*/
958965
protected void _addEnumProps(Class<?> propClass, Schema property) {
959966
final boolean useIndex = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX);
960967
final boolean useToString = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
961968

962-
963-
Optional<Method> jsonValueMethod = Arrays.stream(propClass.getMethods())
969+
Optional<Method> jsonValueMethod = Arrays.stream(propClass.getDeclaredMethods())
964970
.filter(m -> m.isAnnotationPresent(JsonValue.class))
965971
.filter(m -> m.getAnnotation(JsonValue.class).value())
966972
.findFirst();
967973

974+
Optional<Field> jsonValueField = Arrays.stream(propClass.getDeclaredFields())
975+
.filter(f -> f.isAnnotationPresent(JsonValue.class))
976+
.filter(f -> f.getAnnotation(JsonValue.class).value())
977+
.findFirst();
978+
979+
jsonValueMethod.ifPresent(m -> m.setAccessible(true));
980+
jsonValueField.ifPresent(m -> m.setAccessible(true));
968981
@SuppressWarnings("unchecked")
969982
Class<Enum<?>> enumClass = (Class<Enum<?>>) propClass;
970983

971984
Enum<?>[] enumConstants = enumClass.getEnumConstants();
985+
972986
if (enumConstants != null) {
973987
String[] enumValues = _intr.findEnumValues(propClass, enumConstants,
974988
new String[enumConstants.length]);
@@ -977,11 +991,13 @@ protected void _addEnumProps(Class<?> propClass, Schema property) {
977991
String n;
978992

979993
String enumValue = enumValues[en.ordinal()];
980-
String s = jsonValueMethod.flatMap(m -> ReflectionUtils.safeInvoke(m, en))
981-
.map(Object::toString).orElse(null);
994+
String methodValue = jsonValueMethod.flatMap(m -> ReflectionUtils.safeInvoke(m, en)).map(Object::toString).orElse(null);
995+
String fieldValue = jsonValueField.flatMap(f -> ReflectionUtils.safeGet(f, en)).map(Object::toString).orElse(null);
982996

983-
if (s != null) {
984-
n = s;
997+
if (methodValue != null) {
998+
n = methodValue;
999+
} else if (fieldValue != null) {
1000+
n = fieldValue;
9851001
} else if (enumValue != null) {
9861002
n = enumValue;
9871003
} else if (useIndex) {

modules/swagger-core/src/main/java/io/swagger/v3/core/util/ReflectionUtils.java

+23
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,35 @@ public static boolean isSystemType(JavaType type) {
435435
return type.isArrayType();
436436
}
437437

438+
/**
439+
* A utility method to get an optional containing result from method or empty optional if unable to access
440+
*
441+
* @param method from reflect, a method of a class or interface
442+
* @param obj the class object in which the method exists
443+
* @param args varags of the parameters passed to the method
444+
* @return the result of the method, or empty conditional
445+
*/
438446
public static Optional<Object> safeInvoke(Method method, Object obj, Object... args) {
439447
try {
440448
return Optional.ofNullable(method.invoke(obj, args));
441449
} catch (IllegalAccessException | InvocationTargetException e) {
442450
return Optional.empty();
443451
}
452+
}
453+
454+
/**
455+
* A utility method to get an optional containing value of field or empty optional if unable to access
456+
*
457+
* @param field from reflect, a field of a class or interface
458+
* @param obj the class object in which the field exists
459+
* @return optional containing the value of the field on the specified object, or empty optional
460+
*/
461+
public static Optional<Object> safeGet(Field field, Object obj) {
462+
try {
463+
return Optional.ofNullable(field.get(obj));
464+
} catch (IllegalAccessException e) {
465+
return Optional.empty();
466+
}
444467

445468
}
446469
}

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

+15
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,20 @@ public void testExtractJacksonEnumFields() {
219219
assertTrue(thirdEnumProperty instanceof StringSchema);
220220
final StringSchema thirdStringProperty = (StringSchema) thirdEnumProperty;
221221
assertEquals(thirdStringProperty.getEnum(), Arrays.asList("2", "4", "6"));
222+
223+
final Schema fourthEnumProperty = (Schema) model.getProperties().get("fourthEnumValue");
224+
assertTrue(fourthEnumProperty instanceof StringSchema);
225+
final StringSchema fourthStringProperty = (StringSchema) fourthEnumProperty;
226+
assertEquals(fourthEnumProperty.getEnum(), Arrays.asList("one", "two", "three"));
227+
228+
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"));
232+
233+
final Schema sixthEnumProperty = (Schema) model.getProperties().get("sixthEnumValue");
234+
assertTrue(sixthEnumProperty instanceof StringSchema);
235+
final StringSchema sixthStringProperty = (StringSchema) sixthEnumProperty;
236+
assertEquals(sixthEnumProperty.getEnum(), Arrays.asList("one", "two", "three"));
222237
}
223238
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.fasterxml.jackson.annotation.JsonValue;
44

5+
/**
6+
* Enum holds values different from names. Schema model will derive Integer value from jackson annotation JsonValue on public method.
7+
*/
58
public enum JacksonNumberValueEnum {
69
FIRST(2),
710
SECOND(4),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
/**
6+
* Enum holds values different from names. Schema model will derive Integer value from jackson annotation JsonValue on private field.
7+
*/
8+
public enum JacksonNumberValueFieldEnum {
9+
FIRST(2),
10+
SECOND(4),
11+
THIRD(6);
12+
13+
@JsonValue
14+
private final int value;
15+
16+
JacksonNumberValueFieldEnum(int value) {
17+
this.value = value;
18+
}
19+
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.fasterxml.jackson.annotation.JsonValue;
44

5+
/**
6+
* Enum holds values different from names. Schema model will derive String value from jackson annotation JsonValue on public method.
7+
*/
58
public enum JacksonValueEnum {
69
FIRST("one"),
710
SECOND("two"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
/**
6+
* Enum holds values different from names. Schema model will derive String value from jackson annotation JsonValue on private field.
7+
*/
8+
public enum JacksonValueFieldEnum {
9+
FIRST("one"),
10+
SECOND("two"),
11+
THIRD("three");
12+
13+
@JsonValue
14+
private final String value;
15+
16+
JacksonValueFieldEnum(String value) {
17+
this.value = value;
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
/**
6+
* Enum holds values different from names. Schema model will derive String value from jackson annotation JsonValue on private method.
7+
*/
8+
public enum JacksonValuePrivateEnum {
9+
FIRST("one"),
10+
SECOND("two"),
11+
THIRD("three");
12+
13+
private final String value;
14+
15+
JacksonValuePrivateEnum(String value) {
16+
this.value = value;
17+
}
18+
19+
@JsonValue
20+
private String getValue() {
21+
return value;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package io.swagger.v3.core.oas.models;
22

3+
/**
4+
* Class of different enums for testing schema model
5+
*/
36
public class ModelWithJacksonEnumField {
47
public JacksonPropertyEnum firstEnumValue;
58
public JacksonValueEnum secondEnumValue;
69
public JacksonNumberValueEnum thirdEnumValue;
10+
public JacksonValueFieldEnum fourthEnumValue;
11+
public JacksonNumberValueFieldEnum fifthEnumValue;
12+
public JacksonValuePrivateEnum sixthEnumValue;
713
}

0 commit comments

Comments
 (0)