1 package io.swagger.v3.core.util;
2
3 import com.fasterxml.jackson.annotation.JsonInclude;
4 import com.fasterxml.jackson.core.JsonFactory;
5 import com.fasterxml.jackson.databind.BeanDescription;
6 import com.fasterxml.jackson.databind.DeserializationFeature;
7 import com.fasterxml.jackson.databind.JsonSerializer;
8 import com.fasterxml.jackson.databind.Module;
9 import com.fasterxml.jackson.databind.ObjectMapper;
10 import com.fasterxml.jackson.databind.SerializationConfig;
11 import com.fasterxml.jackson.databind.SerializationFeature;
12 import com.fasterxml.jackson.databind.module.SimpleModule;
13 import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
14 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
15 import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
16 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
17 import io.swagger.v3.core.jackson.SchemaSerializer;
18 import io.swagger.v3.core.jackson.mixin.ComponentsMixin;
19 import io.swagger.v3.core.jackson.mixin.DateSchemaMixin;
20 import io.swagger.v3.core.jackson.mixin.ExtensionsMixin;
21 import io.swagger.v3.core.jackson.mixin.OpenAPIMixin;
22 import io.swagger.v3.core.jackson.mixin.OperationMixin;
23 import io.swagger.v3.oas.models.Components;
24 import io.swagger.v3.oas.models.ExternalDocumentation;
25 import io.swagger.v3.oas.models.OpenAPI;
26 import io.swagger.v3.oas.models.Operation;
27 import io.swagger.v3.oas.models.PathItem;
28 import io.swagger.v3.oas.models.Paths;
29 import io.swagger.v3.oas.models.callbacks.Callback;
30 import io.swagger.v3.oas.models.examples.Example;
31 import io.swagger.v3.oas.models.headers.Header;
32 import io.swagger.v3.oas.models.info.Contact;
33 import io.swagger.v3.oas.models.info.Info;
34 import io.swagger.v3.oas.models.info.License;
35 import io.swagger.v3.oas.models.links.Link;
36 import io.swagger.v3.oas.models.links.LinkParameter;
37 import io.swagger.v3.oas.models.media.DateSchema;
38 import io.swagger.v3.oas.models.media.DateTimeSchema;
39 import io.swagger.v3.oas.models.media.Encoding;
40 import io.swagger.v3.oas.models.media.EncodingProperty;
41 import io.swagger.v3.oas.models.media.MediaType;
42 import io.swagger.v3.oas.models.media.Schema;
43 import io.swagger.v3.oas.models.media.XML;
44 import io.swagger.v3.oas.models.parameters.Parameter;
45 import io.swagger.v3.oas.models.parameters.RequestBody;
46 import io.swagger.v3.oas.models.responses.ApiResponse;
47 import io.swagger.v3.oas.models.responses.ApiResponses;
48 import io.swagger.v3.oas.models.security.OAuthFlow;
49 import io.swagger.v3.oas.models.security.OAuthFlows;
50 import io.swagger.v3.oas.models.security.Scopes;
51 import io.swagger.v3.oas.models.security.SecurityScheme;
52 import io.swagger.v3.oas.models.servers.Server;
53 import io.swagger.v3.oas.models.servers.ServerVariable;
54 import io.swagger.v3.oas.models.servers.ServerVariables;
55 import io.swagger.v3.oas.models.tags.Tag;
56
57 import java.util.LinkedHashMap;
58 import java.util.Map;
59
60 public class ObjectMapperFactory {
61
62     protected static ObjectMapper createJson() {
63         return create(null);
64     }
65
66     protected static ObjectMapper createYaml() {
67         YAMLFactory factory = new YAMLFactory();
68         factory.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
69         factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
70         factory.enable(YAMLGenerator.Feature.SPLIT_LINES);
71         factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
72
73         return create(factory);
74     }
75
76     private static ObjectMapper create(JsonFactory jsonFactory) {
77         ObjectMapper mapper = jsonFactory == null ? new ObjectMapper() : new ObjectMapper(jsonFactory);
78
79         // handle ref schema serialization skipping all other props
80         mapper.registerModule(new SimpleModule() {
81             @Override
82             public void setupModule(SetupContext context) {
83                 super.setupModule(context);
84                 context.addBeanSerializerModifier(new BeanSerializerModifier() {
85                     @Override
86                     public JsonSerializer<?> modifySerializer(
87                             SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
88                         if (Schema.class.isAssignableFrom(desc.getBeanClass())) {
89                             return new SchemaSerializer((JsonSerializer<Object>) serializer);
90                         }
91                         return serializer;
92                     }
93                 });
94             }
95         });
96
97         Module deserializerModule = new DeserializationModule();
98         mapper.registerModule(deserializerModule);
99         mapper.registerModule(new JavaTimeModule());
100
101         Map<Class<?>, Class<?>> sourceMixins = new LinkedHashMap<>();
102
103         sourceMixins.put(ApiResponses.class, ExtensionsMixin.class);
104         sourceMixins.put(ApiResponse.class, ExtensionsMixin.class);
105         sourceMixins.put(Callback.class, ExtensionsMixin.class);
106         sourceMixins.put(Components.class, ComponentsMixin.class);
107         sourceMixins.put(Contact.class, ExtensionsMixin.class);
108         sourceMixins.put(Encoding.class, ExtensionsMixin.class);
109         sourceMixins.put(EncodingProperty.class, ExtensionsMixin.class);
110         sourceMixins.put(Example.class, ExtensionsMixin.class);
111         sourceMixins.put(ExternalDocumentation.class, ExtensionsMixin.class);
112         sourceMixins.put(Header.class, ExtensionsMixin.class);
113         sourceMixins.put(Info.class, ExtensionsMixin.class);
114         sourceMixins.put(License.class, ExtensionsMixin.class);
115         sourceMixins.put(Link.class, ExtensionsMixin.class);
116         sourceMixins.put(LinkParameter.class, ExtensionsMixin.class);
117         sourceMixins.put(MediaType.class, ExtensionsMixin.class);
118         sourceMixins.put(OAuthFlow.class, ExtensionsMixin.class);
119         sourceMixins.put(OAuthFlows.class, ExtensionsMixin.class);
120         sourceMixins.put(OpenAPI.class, OpenAPIMixin.class);
121         sourceMixins.put(Operation.class, OperationMixin.class);
122         sourceMixins.put(Parameter.class, ExtensionsMixin.class);
123         sourceMixins.put(PathItem.class, ExtensionsMixin.class);
124         sourceMixins.put(Paths.class, ExtensionsMixin.class);
125         sourceMixins.put(RequestBody.class, ExtensionsMixin.class);
126         sourceMixins.put(Scopes.class, ExtensionsMixin.class);
127         sourceMixins.put(SecurityScheme.class, ExtensionsMixin.class);
128         sourceMixins.put(Server.class, ExtensionsMixin.class);
129         sourceMixins.put(ServerVariable.class, ExtensionsMixin.class);
130         sourceMixins.put(ServerVariables.class, ExtensionsMixin.class);
131         sourceMixins.put(Tag.class, ExtensionsMixin.class);
132         sourceMixins.put(XML.class, ExtensionsMixin.class);
133         sourceMixins.put(Schema.class, ExtensionsMixin.class);
134         sourceMixins.put(DateSchema.class, DateSchemaMixin.class);
135
136         mapper.setMixIns(sourceMixins);
137         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
138         mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
139         mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
140         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
141         mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
142         mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
143
144         return mapper;
145     }
146
147     public static ObjectMapper buildStrictGenericObjectMapper() {
148         ObjectMapper mapper = new ObjectMapper();
149         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
150         mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
151         mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
152         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
153         mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
154         try {
155             mapper.configure(DeserializationFeature.valueOf("FAIL_ON_TRAILING_TOKENS"), true);
156         } catch (Throwable e) {
157             // add only if supported by Jackson version 2.9+
158         }
159         mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
160         return mapper;
161     }
162
163 }
164