Skip to content

Commit 95d2522

Browse files
authored
Merge pull request #3553 from joschi/issue-3552
Support for overriding enum values with @JsonProperty or @JsonValue
2 parents ad4434b + b31e47a commit 95d2522

File tree

7 files changed

+112
-2
lines changed

7 files changed

+112
-2
lines changed

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

+22-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.annotation.JsonProperty;
88
import com.fasterxml.jackson.annotation.JsonTypeInfo;
99
import com.fasterxml.jackson.annotation.JsonUnwrapped;
10+
import com.fasterxml.jackson.annotation.JsonValue;
1011
import com.fasterxml.jackson.annotation.JsonView;
1112
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
1213
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@@ -80,6 +81,7 @@
8081
import java.util.LinkedHashMap;
8182
import java.util.List;
8283
import java.util.Map;
84+
import java.util.Optional;
8385
import java.util.Set;
8486
import java.util.stream.Collectors;
8587
import java.util.stream.Stream;
@@ -933,11 +935,29 @@ protected void _addEnumProps(Class<?> propClass, Schema property) {
933935
final boolean useIndex = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX);
934936
final boolean useToString = _mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
935937

938+
939+
Optional<Method> jsonValueMethod = Arrays.stream(propClass.getMethods())
940+
.filter(m -> m.isAnnotationPresent(JsonValue.class))
941+
.filter(m -> m.getAnnotation(JsonValue.class).value())
942+
.findFirst();
943+
936944
@SuppressWarnings("unchecked")
937945
Class<Enum<?>> enumClass = (Class<Enum<?>>) propClass;
938-
for (Enum<?> en : enumClass.getEnumConstants()) {
946+
947+
Enum<?>[] enumConstants = enumClass.getEnumConstants();
948+
String[] enumValues = _intr.findEnumValues(propClass, enumConstants, new String[enumConstants.length]);
949+
950+
for (Enum<?> en : enumConstants) {
939951
String n;
940-
if (useIndex) {
952+
953+
String enumValue = enumValues[en.ordinal()];
954+
String s = jsonValueMethod.flatMap(m -> ReflectionUtils.safeInvoke(m, en)).map(Object::toString).orElse(null);
955+
956+
if (s != null) {
957+
n = s;
958+
} else if (enumValue != null) {
959+
n = enumValue;
960+
} else if (useIndex) {
941961
n = String.valueOf(en.ordinal());
942962
} else if (useToString) {
943963
n = en.toString();

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

+11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.lang.annotation.Annotation;
1010
import java.lang.reflect.Constructor;
1111
import java.lang.reflect.Field;
12+
import java.lang.reflect.InvocationTargetException;
1213
import java.lang.reflect.Method;
1314
import java.lang.reflect.Modifier;
1415
import java.lang.reflect.Type;
@@ -17,6 +18,7 @@
1718
import java.util.Collections;
1819
import java.util.HashSet;
1920
import java.util.List;
21+
import java.util.Optional;
2022
import java.util.Set;
2123

2224
public class ReflectionUtils {
@@ -373,4 +375,13 @@ public static boolean isSystemType(JavaType type) {
373375
}
374376
return false;
375377
}
378+
379+
public static Optional<Object> safeInvoke(Method method, Object obj, Object... args) {
380+
try {
381+
return Optional.ofNullable(method.invoke(obj, args));
382+
} catch (IllegalAccessException | InvocationTargetException e) {
383+
return Optional.empty();
384+
}
385+
386+
}
376387
}

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

+22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.swagger.v3.core.oas.models.ModelWithEnumField;
1111
import io.swagger.v3.core.oas.models.ModelWithEnumProperty;
1212
import io.swagger.v3.core.oas.models.ModelWithEnumRefProperty;
13+
import io.swagger.v3.core.oas.models.ModelWithJacksonEnumField;
1314
import io.swagger.v3.oas.models.media.Schema;
1415
import io.swagger.v3.oas.models.media.StringSchema;
1516
import org.testng.annotations.AfterTest;
@@ -156,4 +157,25 @@ public void testEnumRefPropertyGlobalNotAffectingNonEnums() {
156157
SerializationMatchers.assertEqualsToYaml(models, yaml);
157158
ModelResolver.enumsAsRef = false;
158159
}
160+
161+
@Test(description = "it should extract enum values from fields using JsonProperty and JsonValue")
162+
public void testExtractJacksonEnumFields() {
163+
final Map<String, Schema> models = ModelConverters.getInstance().read(ModelWithJacksonEnumField.class);
164+
final Schema model = models.get("ModelWithJacksonEnumField");
165+
166+
final Schema firstEnumProperty = (Schema) model.getProperties().get("firstEnumValue");
167+
assertTrue(firstEnumProperty instanceof StringSchema);
168+
final StringSchema stringProperty = (StringSchema) firstEnumProperty;
169+
assertEquals(stringProperty.getEnum(), Arrays.asList("p1", "p2", "SYSTEM", "INVITE_ONLY"));
170+
171+
final Schema secondEnumProperty = (Schema) model.getProperties().get("secondEnumValue");
172+
assertTrue(secondEnumProperty instanceof StringSchema);
173+
final StringSchema secondStringProperty = (StringSchema) secondEnumProperty;
174+
assertEquals(secondStringProperty.getEnum(), Arrays.asList("one", "two", "three"));
175+
176+
final Schema thirdEnumProperty = (Schema) model.getProperties().get("thirdEnumValue");
177+
assertTrue(thirdEnumProperty instanceof StringSchema);
178+
final StringSchema thirdStringProperty = (StringSchema) thirdEnumProperty;
179+
assertEquals(thirdStringProperty.getEnum(), Arrays.asList("2", "4", "6"));
180+
}
159181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
public enum JacksonNumberValueEnum {
6+
FIRST(2),
7+
SECOND(4),
8+
THIRD(6);
9+
10+
private final int value;
11+
12+
JacksonNumberValueEnum(int value) {
13+
this.value = value;
14+
}
15+
16+
@JsonValue
17+
public Number getValue() {
18+
return value;
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
public enum JacksonPropertyEnum {
6+
@JsonProperty("p1") PRIVATE,
7+
@JsonProperty("p2") PUBLIC,
8+
SYSTEM,
9+
INVITE_ONLY
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
public enum JacksonValueEnum {
6+
FIRST("one"),
7+
SECOND("two"),
8+
THIRD("three");
9+
10+
private final String value;
11+
12+
JacksonValueEnum(String value) {
13+
this.value = value;
14+
}
15+
16+
@JsonValue
17+
public String getValue() {
18+
return value;
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
public class ModelWithJacksonEnumField {
4+
public JacksonPropertyEnum firstEnumValue;
5+
public JacksonValueEnum secondEnumValue;
6+
public JacksonNumberValueEnum thirdEnumValue;
7+
}

0 commit comments

Comments
 (0)