Skip to content

Commit adb4337

Browse files
committed
implement null example serialization
1 parent 06890d4 commit adb4337

File tree

10 files changed

+370
-11
lines changed

10 files changed

+370
-11
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.swagger.v3.core.jackson;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.databind.JsonSerializer;
6+
import com.fasterxml.jackson.databind.SerializerProvider;
7+
import com.fasterxml.jackson.databind.ser.ResolvableSerializer;
8+
import io.swagger.v3.oas.models.media.MediaType;
9+
10+
import java.io.IOException;
11+
12+
public class MediaTypeSerializer extends JsonSerializer<MediaType> implements ResolvableSerializer {
13+
14+
private JsonSerializer<Object> defaultSerializer;
15+
16+
public MediaTypeSerializer(JsonSerializer<Object> serializer) {
17+
defaultSerializer = serializer;
18+
}
19+
20+
@Override
21+
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
22+
if (defaultSerializer instanceof ResolvableSerializer) {
23+
((ResolvableSerializer) defaultSerializer).resolve(serializerProvider);
24+
}
25+
}
26+
27+
@Override
28+
public void serialize(
29+
MediaType value, JsonGenerator jgen, SerializerProvider provider)
30+
throws IOException {
31+
32+
if (value.getExampleSetFlag() && value.getExample() == null) {
33+
jgen.writeStartObject();
34+
defaultSerializer.unwrappingSerializer(null).serialize(value, jgen, provider);
35+
jgen.writeNullField("example");
36+
jgen.writeEndObject();
37+
} else {
38+
defaultSerializer.serialize(value, jgen, provider);
39+
}
40+
}
41+
}
42+
43+

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,6 @@ private boolean resolveSubtypes(Schema model, BeanDescription bean, ModelConvert
13721372
.additionalProperties(subtypeModel.getAdditionalProperties())
13731373
.description(subtypeModel.getDescription())
13741374
.discriminator(subtypeModel.getDiscriminator())
1375-
.example(subtypeModel.getExample())
13761375
.exclusiveMaximum(subtypeModel.getExclusiveMaximum())
13771376
.exclusiveMinimum(subtypeModel.getExclusiveMinimum())
13781377
.externalDocs(subtypeModel.getExternalDocs())
@@ -1398,6 +1397,9 @@ private boolean resolveSubtypes(Schema model, BeanDescription bean, ModelConvert
13981397
.xml(subtypeModel.getXml())
13991398
.extensions(subtypeModel.getExtensions());
14001399

1400+
if (subtypeModel.getExample() != null || subtypeModel.getExampleSetFlag()) {
1401+
composedSchema.example(subtypeModel.getExample());
1402+
}
14011403
composedSchema.setEnum(subtypeModel.getEnum());
14021404
} else {
14031405
composedSchema = (ComposedSchema) subtypeModel;

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,22 @@ public void serialize(
3030
Schema value, JsonGenerator jgen, SerializerProvider provider)
3131
throws IOException {
3232

33-
// handle ref schema serialization skipping all other props
3433
if (StringUtils.isBlank(value.get$ref())) {
35-
defaultSerializer.serialize(value, jgen, provider);
34+
35+
if (value.getExampleSetFlag() && value.getExample() == null) {
36+
jgen.writeStartObject();
37+
defaultSerializer.unwrappingSerializer(null).serialize(value, jgen, provider);
38+
jgen.writeNullField("example");
39+
jgen.writeEndObject();
40+
} else {
41+
defaultSerializer.serialize(value, jgen, provider);
42+
}
43+
3644
} else {
45+
// handle ref schema serialization skipping all other props
3746
jgen.writeStartObject();
3847
jgen.writeStringField("$ref", value.get$ref());
3948
jgen.writeEndObject();
4049
}
4150
}
42-
}
51+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ public abstract class MediaTypeMixin {
1818
@JsonIgnore
1919
public abstract boolean getExampleSetFlag();
2020

21-
@JsonInclude(JsonInclude.Include.CUSTOM)
21+
@JsonInclude(value = JsonInclude.Include.NON_NULL, content = JsonInclude.Include.ALWAYS)
2222
public abstract Object getExample();
2323
}

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@
77

88
import java.util.Map;
99

10-
/*
11-
TODO: this handles deserialization, but not serialization of "explicit" null value (as we are serializing non null fields)
12-
to handle it, a custom schema serializer / JsonFilter / BeanSerializerModifier must be added, using non null for all fields except example where the flag would
13-
be checked to serialize or skip null example field.
14-
*/
1510
public abstract class SchemaMixin {
1611

1712
@JsonAnyGetter
@@ -23,6 +18,6 @@ public abstract class SchemaMixin {
2318
@JsonIgnore
2419
public abstract boolean getExampleSetFlag();
2520

26-
@JsonInclude(JsonInclude.Include.CUSTOM)
21+
@JsonInclude(value = JsonInclude.Include.NON_NULL, content = JsonInclude.Include.ALWAYS)
2722
public abstract Object getExample();
2823
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
1515
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
1616
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
17+
import io.swagger.v3.core.jackson.MediaTypeSerializer;
1718
import io.swagger.v3.core.jackson.SchemaSerializer;
1819
import io.swagger.v3.core.jackson.mixin.ComponentsMixin;
1920
import io.swagger.v3.core.jackson.mixin.DateSchemaMixin;
@@ -89,6 +90,8 @@ public JsonSerializer<?> modifySerializer(
8990
SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
9091
if (Schema.class.isAssignableFrom(desc.getBeanClass())) {
9192
return new SchemaSerializer((JsonSerializer<Object>) serializer);
93+
} else if (MediaType.class.isAssignableFrom(desc.getBeanClass())) {
94+
return new MediaTypeSerializer((JsonSerializer<Object>) serializer);
9295
}
9396
return serializer;
9497
}

modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.swagger.v3.core.serialization;
22

3+
import io.swagger.v3.core.matchers.SerializationMatchers;
34
import io.swagger.v3.core.util.Json;
5+
import io.swagger.v3.core.util.ResourceUtils;
6+
import io.swagger.v3.core.util.Yaml;
47
import io.swagger.v3.oas.models.OpenAPI;
58
import io.swagger.v3.oas.models.Operation;
69
import io.swagger.v3.oas.models.PathItem;
@@ -67,4 +70,20 @@ public void testSerializeASpecWithResponseReferences() throws Exception {
6770
assertEquals(rebuilt.getPaths().get("/health").getGet().getResponses().get("200"), expectedResponse);
6871

6972
}
73+
74+
@Test
75+
public void testSerializeNullExample() throws Exception {
76+
final String yaml = ResourceUtils.loadClassResource(getClass(), "specFiles/null-example.yaml");
77+
OpenAPI deser = Yaml.mapper().readValue(yaml, OpenAPI.class);
78+
SerializationMatchers.assertEqualsToYaml(deser, yaml);
79+
80+
}
81+
82+
@Test
83+
public void testSerializeNullInSchemaExample() throws Exception {
84+
final String yaml = ResourceUtils.loadClassResource(getClass(), "specFiles/null-in-schema-example.yaml");
85+
OpenAPI deser = Yaml.mapper().readValue(yaml, OpenAPI.class);
86+
SerializationMatchers.assertEqualsToYaml(deser, yaml);
87+
88+
}
7089
}

0 commit comments

Comments
 (0)