1717package com.github.hauner.openapi.spring.converter
1818
1919import com.github.hauner.openapi.spring.converter.mapping.AddParameterTypeMapping
20+ import com.github.hauner.openapi.spring.converter.mapping.AmbiguousTypeMappingException
21+ import com.github.hauner.openapi.spring.converter.mapping.EndpointTypeMapping
2022import com.github.hauner.openapi.spring.converter.mapping.Mapping
2123import com.github.hauner.openapi.spring.converter.mapping.MappingSchema
2224import com.github.hauner.openapi.spring.converter.mapping.TargetType
@@ -26,6 +28,7 @@ import com.github.hauner.openapi.spring.converter.schema.SchemaInfo
2628import com.github.hauner.openapi.spring.model.Api
2729import com.github.hauner.openapi.spring.model.DataTypes
2830import com.github.hauner.openapi.spring.model.Endpoint
31+ import com.github.hauner.openapi.spring.model.Interface
2932import com.github.hauner.openapi.spring.model.RequestBody as ModelRequestBody
3033import com.github.hauner.openapi.spring.model.datatypes.MappedDataType
3134import com.github.hauner.openapi.spring.model.datatypes.ObjectDataType
@@ -57,16 +60,17 @@ import io.swagger.v3.oas.models.responses.ApiResponses
5760@Slf4j
5861class ApiConverter {
5962 public static final String MULTIPART = " multipart/form-data"
63+ public static final String INTERFACE_DEFAULT_NAME = ' '
6064
6165 private DataTypeConverter dataTypeConverter
6266 private ApiOptions options
6367
6468 class MappingSchemaEndpoint implements MappingSchema {
65- Endpoint endpoint
69+ String path
6670
6771 @Override
6872 String getPath () {
69- endpoint . path
73+ path
7074 }
7175
7276 @Override
@@ -98,40 +102,62 @@ class ApiConverter {
98102 */
99103 Api convert (OpenAPI api ) {
100104 def target = new Api ()
101-
102- collectInterfaces (api, target)
103- addEndpointsToInterfaces (api, target)
104-
105+ createInterfaces (api, target)
105106 target
106107 }
107108
108- private Map<String , PathItem > addEndpointsToInterfaces (OpenAPI api , Api target ) {
109+ private void createInterfaces (OpenAPI api , Api target ) {
110+ def resolver = new RefResolver (api. components)
111+ Map<String , Interface > interfaces = new HashMap<> ()
109112
110113 api. paths. each { Map.Entry <String , PathItem > pathEntry ->
111114 String path = pathEntry. key
112115 PathItem pathItem = pathEntry. value
113116
114- def operations = new OperationCollector (). collect (pathItem)
117+ def operations = new OperationCollector ()
118+ .collect (pathItem)
119+
115120 operations. each { httpOperation ->
116- def itf = target. getInterface (getInterfaceName (httpOperation))
121+ Interface itf = createInterface (path, httpOperation, interfaces)
122+ Endpoint ep = createEndpoint (path, httpOperation, target. models, resolver)
123+ if (ep) {
124+ itf. endpoints. add (ep)
125+ }
126+ }
127+ }
117128
118- Endpoint ep = new Endpoint ( path : path,
119- method : (httpOperation as HttpMethodTrait ) . httpMethod)
129+ target . interfaces = interfaces . values () as List< Interface >
130+ }
120131
121- try {
122- def resolver = new RefResolver (api . components )
132+ private Interface createInterface ( String path , def operation , Map< String , Interface > interfaces ) {
133+ def targetInterfaceName = getInterfaceName (operation, isExcluded (path) )
123134
124- collectParameters (httpOperation. parameters, ep, target. models, resolver)
125- collectRequestBody (httpOperation. requestBody, ep, target. models, resolver)
126- collectResponses (httpOperation. responses, ep, target. models, resolver)
135+ def itf = interfaces. get (targetInterfaceName)
136+ if (itf) {
137+ return itf
138+ }
127139
128- itf. endpoints. add (ep)
140+ itf = new Interface (
141+ pkg : [options. packageName, ' api' ]. join (' .' ),
142+ name : targetInterfaceName
143+ )
129144
130- } catch (UnknownDataTypeException e) {
131- log. error (" failed to parse endpoint {} {} because of: '{}'" ,
132- ep. path, ep. method, e. message)
133- }
134- }
145+ interfaces. put (targetInterfaceName, itf)
146+ itf
147+ }
148+
149+ private Endpoint createEndpoint (String path , def operation , DataTypes dataTypes , RefResolver resolver ) {
150+ Endpoint ep = new Endpoint (path : path, method : (operation as HttpMethodTrait ). httpMethod)
151+
152+ try {
153+ collectParameters (operation. parameters, ep, dataTypes, resolver)
154+ collectRequestBody (operation. requestBody, ep, dataTypes, resolver)
155+ collectResponses (operation. responses, ep, dataTypes, resolver)
156+ ep
157+
158+ } catch (UnknownDataTypeException e) {
159+ log. error (" failed to parse endpoint {} {} because of: '{}'" , ep. path, ep. method, e. message)
160+ null
135161 }
136162 }
137163
@@ -277,13 +303,13 @@ class ApiConverter {
277303
278304 private List<Mapping > findAdditionalParameter (Endpoint ep ) {
279305 def addMappings = options. typeMappings. findAll {
280- it. matches (Mapping.Level . ENDPOINT , new MappingSchemaEndpoint (endpoint : ep))
306+ it. matches (Mapping.Level . ENDPOINT , new MappingSchemaEndpoint (path : ep. path ))
281307 }. collectMany {
282308 it. childMappings
283309 }. findAll {
284310 it. matches (Mapping.Level . ADD , null as MappingSchema )
285311 }
286- addMappings
312+ addMappings as List< Mapping >
287313 }
288314
289315 private String getInlineRequestBodyName (String path ) {
@@ -298,17 +324,35 @@ class ApiConverter {
298324 new Response (responseType : dataTypeConverter. none ())
299325 }
300326
301- private void collectInterfaces (OpenAPI api , Api target ) {
302- target. interfaces = new InterfaceCollector (options)
303- .collect (api. paths)
327+ private boolean isExcluded (String path ) {
328+ def endpointMatches = options. typeMappings. findAll {
329+ it. matches (Mapping.Level . ENDPOINT , new MappingSchemaEndpoint (path : path))
330+ }
331+
332+ if (! endpointMatches. empty) {
333+ if (endpointMatches. size () != 1 ) {
334+ throw new AmbiguousTypeMappingException (endpointMatches)
335+ }
336+
337+ def match = endpointMatches. first () as EndpointTypeMapping
338+ return match. exclude
339+ }
340+
341+ false
304342 }
305343
306- private String getInterfaceName (def operation ) {
307- if (! hasTags (operation)) {
308- return InterfaceCollector . INTERFACE_DEFAULT_NAME
344+ private String getInterfaceName (def op , boolean excluded ) {
345+ String targetInterfaceName = INTERFACE_DEFAULT_NAME
346+
347+ if (hasTags (op)) {
348+ targetInterfaceName = op. tags. first ()
349+ }
350+
351+ if (excluded) {
352+ targetInterfaceName + = ' Excluded'
309353 }
310354
311- operation . tags . first ()
355+ targetInterfaceName
312356 }
313357
314358 private boolean hasTags (op ) {
0 commit comments