Skip to content

Commit e7350ab

Browse files
authored
Merge pull request #3352 from swagger-api/fix_3124
refs #3124 - enums as ref
2 parents 59440bb + e5db854 commit e7350ab

File tree

6 files changed

+158
-1
lines changed

6 files changed

+158
-1
lines changed

modules/swagger-annotations/src/main/java/io/swagger/v3/oas/annotations/media/Schema.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@
309309
*/
310310
boolean hidden() default false;
311311

312+
/**
313+
* Allows enums to be resolved as a reference to a scheme added to components section.
314+
*
315+
* @since 2.0.11
316+
* @return whether or not this must be resolved as a reference
317+
*/
318+
boolean enumAsRef() default false;
319+
312320
/**
313321
* An array of the sub types inheriting from this model.
314322
*/

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ public class ModelResolver extends AbstractModelConverter implements ModelConver
8787
Logger LOGGER = LoggerFactory.getLogger(ModelResolver.class);
8888

8989
public static final String SET_PROPERTY_OF_COMPOSED_MODEL_AS_SIBLING = "composed-model-properties-as-sibiling";
90+
public static final String SET_PROPERTY_OF_ENUMS_AS_REF = "enums-as-ref";
9091

9192
public static boolean composedModelPropertiesAsSibling = System.getProperty(SET_PROPERTY_OF_COMPOSED_MODEL_AS_SIBLING) != null ? true : false;
93+
public static boolean enumsAsRef = System.getProperty(SET_PROPERTY_OF_ENUMS_AS_REF) != null ? true : false;
9294

9395
public ModelResolver(ObjectMapper mapper) {
9496
super(mapper);
@@ -319,6 +321,15 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
319321
schema.setItems(model);
320322
return schema;
321323
}
324+
if (type.isEnumType() &&
325+
(resolvedSchemaAnnotation != null && resolvedSchemaAnnotation.enumAsRef()) ||
326+
ModelResolver.enumsAsRef
327+
) {
328+
// Store off the ref and add the enum as a top-level model
329+
context.defineModel(name, model, annotatedType, null);
330+
// Return the model as a ref only property
331+
model = new Schema().$ref(name);
332+
}
322333
return model;
323334
}
324335

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public static boolean hasSchemaAnnotation(io.swagger.v3.oas.annotations.media.Sc
9595
&& schema.discriminatorMapping().length == 0
9696
&& schema.extensions().length == 0
9797
&& !schema.hidden()
98+
&& !schema.enumAsRef()
9899
) {
99100
return false;
100101
}
@@ -260,7 +261,9 @@ else if (thisSchema == null || thatSchema == null) {
260261
if (thisSchema.hidden() != thatSchema.hidden()) {
261262
return false;
262263
}
263-
264+
if (thisSchema.enumAsRef() != thatSchema.enumAsRef()) {
265+
return false;
266+
}
264267
if (!thisSchema.implementation().equals(thatSchema.implementation())) {
265268
return false;
266269
}
@@ -1724,6 +1727,14 @@ public boolean hidden() {
17241727
return patch.hidden();
17251728
}
17261729

1730+
@Override
1731+
public boolean enumAsRef() {
1732+
if (master.enumAsRef() || !patch.enumAsRef()) {
1733+
return master.enumAsRef();
1734+
}
1735+
return patch.enumAsRef();
1736+
}
1737+
17271738
@Override
17281739
public Class<?>[] subTypes() {
17291740
if (master.subTypes().length > 0 || patch.subTypes().length == 0) {

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package io.swagger.v3.core.converting;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import io.swagger.v3.core.converter.AnnotatedType;
5+
import io.swagger.v3.core.converter.ModelConverterContextImpl;
36
import io.swagger.v3.core.converter.ModelConverters;
7+
import io.swagger.v3.core.jackson.ModelResolver;
48
import io.swagger.v3.core.matchers.SerializationMatchers;
59
import io.swagger.v3.core.oas.models.ModelWithEnumField;
610
import io.swagger.v3.core.oas.models.ModelWithEnumProperty;
11+
import io.swagger.v3.core.oas.models.ModelWithEnumRefProperty;
712
import io.swagger.v3.oas.models.media.Schema;
813
import io.swagger.v3.oas.models.media.StringSchema;
14+
import org.testng.annotations.AfterTest;
15+
import org.testng.annotations.BeforeMethod;
916
import org.testng.annotations.Test;
1017

1118
import java.util.Arrays;
@@ -15,6 +22,23 @@
1522
import static org.testng.Assert.assertTrue;
1623

1724
public class EnumPropertyTest {
25+
26+
private ModelResolver modelResolver;
27+
private ModelConverterContextImpl context;
28+
29+
@BeforeMethod
30+
public void setup() {
31+
ModelResolver.enumsAsRef = false;
32+
modelResolver = new ModelResolver(new ObjectMapper());
33+
context = new ModelConverterContextImpl(modelResolver);
34+
}
35+
36+
37+
@AfterTest
38+
public void afterTest() {
39+
ModelResolver.enumsAsRef = false;
40+
}
41+
1842
@Test(description = "it should read a model with an enum property")
1943
public void testEnumProperty() {
2044
final Map<String, Schema> models = ModelConverters.getInstance().read(ModelWithEnumProperty.class);
@@ -58,4 +82,62 @@ public void testExtractEnumReturnType() {
5882
final StringSchema stringProperty = (StringSchema) enumProperty;
5983
assertEquals(stringProperty.getEnum(), Arrays.asList("PRIVATE", "PUBLIC", "SYSTEM", "INVITE_ONLY"));
6084
}
85+
86+
@Test(description = "it should read a model with an enum property as a reference")
87+
public void testEnumRefProperty() {
88+
Schema schema = context.resolve(new AnnotatedType(ModelWithEnumRefProperty.class));
89+
final Map<String, Schema> models = context.getDefinedModels();
90+
final String yaml = "ModelWithEnumRefProperty:\n" +
91+
" type: object\n" +
92+
" properties:\n" +
93+
" a:\n" +
94+
" $ref: '#/components/schemas/TestEnum'\n" +
95+
" b:\n" +
96+
" $ref: '#/components/schemas/TestEnum'\n" +
97+
" c:\n" +
98+
" $ref: '#/components/schemas/TestSecondEnum'\n" +
99+
" d:\n" +
100+
" type: string\n" +
101+
" enum:\n" +
102+
" - A_PRIVATE\n" +
103+
" - A_PUBLIC\n" +
104+
" - A_SYSTEM\n" +
105+
" - A_INVITE_ONLY\n" +
106+
"TestEnum:\n" +
107+
" type: string\n" +
108+
" enum:\n" +
109+
" - PRIVATE\n" +
110+
" - PUBLIC\n" +
111+
" - SYSTEM\n" +
112+
" - INVITE_ONLY\n" +
113+
"TestSecondEnum:\n" +
114+
" type: string\n" +
115+
" enum:\n" +
116+
" - A_PRIVATE\n" +
117+
" - A_PUBLIC\n" +
118+
" - A_SYSTEM\n" +
119+
" - A_INVITE_ONLY\n";
120+
SerializationMatchers.assertEqualsToYaml(models, yaml);
121+
}
122+
123+
@Test(description = "it should read a model with an enum property as a reference, set via static var or sys prop")
124+
public void testEnumRefPropertyGlobal() {
125+
ModelResolver.enumsAsRef = true;
126+
Schema schema = context.resolve(new AnnotatedType(ModelWithEnumProperty.class));
127+
final Map<String, Schema> models = context.getDefinedModels();
128+
final String yaml = "ModelWithEnumProperty:\n" +
129+
" type: object\n" +
130+
" properties:\n" +
131+
" enumValue:\n" +
132+
" $ref: '#/components/schemas/TestEnum'\n" +
133+
"TestEnum:\n" +
134+
" type: string\n" +
135+
" enum:\n" +
136+
" - PRIVATE\n" +
137+
" - PUBLIC\n" +
138+
" - SYSTEM\n" +
139+
" - INVITE_ONLY\n";
140+
SerializationMatchers.assertEqualsToYaml(models, yaml);
141+
ModelResolver.enumsAsRef = false;
142+
}
61143
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
5+
public class ModelWithEnumRefProperty {
6+
private TestEnum a;
7+
private TestEnum b;
8+
9+
@Schema(enumAsRef = true)
10+
public TestSecondEnum c;
11+
12+
public TestSecondEnum d;
13+
14+
@Schema(enumAsRef = true)
15+
public TestEnum getA() {
16+
return a;
17+
}
18+
19+
public void setA(TestEnum e) {
20+
this.a = a;
21+
}
22+
23+
@Schema(enumAsRef = true)
24+
public TestEnum getB() {
25+
return b;
26+
}
27+
28+
public void setB(TestEnum b) {
29+
this.b = b;
30+
}
31+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.swagger.v3.core.oas.models;
2+
3+
import javax.xml.bind.annotation.XmlEnum;
4+
import javax.xml.bind.annotation.XmlEnumValue;
5+
import javax.xml.bind.annotation.XmlType;
6+
7+
@XmlType
8+
@XmlEnum(String.class)
9+
public enum TestSecondEnum {
10+
@XmlEnumValue("A_PRIVATE") A_PRIVATE,
11+
@XmlEnumValue("A_PUBLIC") A_PUBLIC,
12+
@XmlEnumValue("A_SYSTEM") A_SYSTEM,
13+
@XmlEnumValue("A_INVITE_ONLY") A_INVITE_ONLY;
14+
}

0 commit comments

Comments
 (0)