Skip to content

Commit 5379791

Browse files
committed
do not use 'multi' wrapper in model
1 parent 15a0645 commit 5379791

File tree

3 files changed

+188
-11
lines changed

3 files changed

+188
-11
lines changed

src/main/groovy/com/github/hauner/openapi/spring/converter/ApiConverter.groovy

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class ApiConverter {
6262
private DataTypeConverter dataTypeConverter
6363
private ResultDataTypeWrapper dataTypeWrapper
6464
private SingleDataTypeWrapper singleDataTypeWrapper
65+
private MultiDataTypeWrapper multiDataTypeWrapper
6566
private MappingFinder mappingFinder
6667
private ApiOptions options
6768

@@ -75,6 +76,7 @@ class ApiConverter {
7576
dataTypeConverter = new DataTypeConverter(this.options)
7677
dataTypeWrapper = new ResultDataTypeWrapper(this.options)
7778
singleDataTypeWrapper = new SingleDataTypeWrapper(this.options)
79+
multiDataTypeWrapper = new MultiDataTypeWrapper(this.options)
7880
mappingFinder = new MappingFinder (typeMappings: this.options.typeMappings)
7981
}
8082

@@ -235,11 +237,16 @@ class ApiConverter {
235237

236238
private ModelRequestBody createRequestBody (String contentType, SchemaInfo info, boolean required, DataTypes dataTypes) {
237239
DataType dataType = dataTypeConverter.convert (info, dataTypes)
238-
DataType singleDataType = singleDataTypeWrapper.wrap (dataType, info)
240+
DataType changedType
241+
if (!info.isArray ()) {
242+
changedType = singleDataTypeWrapper.wrap (dataType, info)
243+
} else {
244+
changedType = multiDataTypeWrapper.wrap (dataType, info)
245+
}
239246

240247
new ModelRequestBody(
241248
contentType: contentType,
242-
requestBodyType: singleDataType,
249+
requestBodyType: changedType,
243250
required: required)
244251
}
245252

@@ -282,8 +289,13 @@ class ApiConverter {
282289
resolver: resolver)
283290

284291
DataType dataType = dataTypeConverter.convert (info, dataTypes)
285-
DataType singleDataType = singleDataTypeWrapper.wrap (dataType, info)
286-
DataType resultDataType = dataTypeWrapper.wrap (singleDataType, info)
292+
DataType changedType
293+
if (!info.isArray ()) {
294+
changedType = singleDataTypeWrapper.wrap (dataType, info)
295+
} else {
296+
changedType = multiDataTypeWrapper.wrap (dataType, info)
297+
}
298+
DataType resultDataType = dataTypeWrapper.wrap (changedType, info)
287299

288300
def resp = new ModelResponse (
289301
contentType: contentType,

src/main/groovy/com/github/hauner/openapi/spring/converter/MappingFinder.groovy

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import com.github.hauner.openapi.spring.converter.mapping.TypeMapping
2929

3030
/**
3131
* find mapping in type mapping list for a schema info.
32-
*
32+
*
3333
* @author Martin Hauner
3434
*/
3535
class MappingFinder {
@@ -129,7 +129,16 @@ class MappingFinder {
129129
}
130130

131131
}
132-
132+
133+
class MultiTypeMatcher extends BaseVisitor {
134+
135+
@Override
136+
boolean match (TypeMapping mapping) {
137+
mapping.sourceTypeName == 'multi'
138+
}
139+
140+
}
141+
133142
class AddParameterMatcher extends BaseVisitor {
134143

135144
@Override
@@ -185,7 +194,7 @@ class MappingFinder {
185194

186195
filterMappings (new TypeMatcher (schema: info), ep)
187196
}
188-
197+
189198
/**
190199
* find any matching (global) io mapping for the given schema info.
191200
*
@@ -285,7 +294,7 @@ class MappingFinder {
285294

286295
[]
287296
}
288-
297+
289298
/**
290299
* find (global) single type mapping.
291300
*
@@ -295,14 +304,51 @@ class MappingFinder {
295304
List<Mapping> findSingleMapping (SchemaInfo info) {
296305
List<Mapping> ep = filterMappings (new SingleTypeMatcher (schema: info), typeMappings)
297306

298-
299307
if (!ep.empty) {
300308
return ep
301309
}
302310

303311
[]
304312
}
305-
313+
314+
/**
315+
* find endpoint multi type mapping.
316+
*
317+
* @param info schema info of the OpenAPI schema.
318+
* @return the multi type mapping.
319+
*/
320+
List<Mapping> findEndpointMultiMapping (SchemaInfo info) {
321+
List<Mapping> ep = filterMappings (new EndpointMatcher (schema: info), typeMappings)
322+
323+
def matcher = new MultiTypeMatcher (schema: info)
324+
def result = ep.findAll {
325+
it.matches (matcher)
326+
}
327+
328+
if (!result.empty) {
329+
return result
330+
}
331+
332+
[]
333+
}
334+
335+
/**
336+
* find (global) multi type mapping.
337+
*
338+
* @param info schema info of the OpenAPI schema.
339+
* @return the multi type mapping.
340+
*/
341+
List<Mapping> findMultiMapping (SchemaInfo info) {
342+
List<Mapping> ep = filterMappings (new MultiTypeMatcher (schema: info), typeMappings)
343+
344+
345+
if (!ep.empty) {
346+
return ep
347+
}
348+
349+
[]
350+
}
351+
306352
/**
307353
* check if the given endpoint should b excluded.
308354
*
@@ -339,5 +385,5 @@ class MappingFinder {
339385
it.childMappings
340386
}
341387
}
342-
388+
343389
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2020 the original authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.github.hauner.openapi.spring.converter
18+
19+
import com.github.hauner.openapi.spring.converter.mapping.AmbiguousTypeMappingException
20+
import com.github.hauner.openapi.spring.converter.mapping.Mapping
21+
import com.github.hauner.openapi.spring.converter.mapping.TargetType
22+
import com.github.hauner.openapi.spring.converter.mapping.TargetTypeMapping
23+
import com.github.hauner.openapi.spring.model.datatypes.DataType
24+
import com.github.hauner.openapi.spring.model.datatypes.MappedCollectionDataType
25+
import com.github.hauner.openapi.spring.model.datatypes.NoneDataType
26+
import com.github.hauner.openapi.spring.model.datatypes.SingleDataType
27+
28+
/**
29+
* replaces a collection wrapper with the 'multi' data mapping.
30+
*
31+
* Used to replace the collection wrapper at Responses or RequestBody's with {@code Flux<>} or
32+
* similar types.
33+
*
34+
* @author Martin Hauner
35+
*/
36+
class MultiDataTypeWrapper {
37+
38+
private ApiOptions options
39+
private MappingFinder finder
40+
41+
MultiDataTypeWrapper (ApiOptions options) {
42+
this.options = options
43+
this.finder = new MappingFinder(typeMappings: options.typeMappings)
44+
}
45+
46+
/**
47+
* replaces an (converted) array data type with a multi data type (like {@code Flux< >})
48+
* wrapping the collection item.
49+
*
50+
* If the configuration for the result type is 'plain' or not defined the source data type
51+
* is not changed.
52+
*
53+
* @param dataType the data type to wrap
54+
* @param schemaInfo the open api type with context information
55+
* @return the resulting java data type
56+
*/
57+
DataType wrap (DataType dataType, SchemaInfo schemaInfo) {
58+
if (!schemaInfo.isArray ()) {
59+
return dataType
60+
}
61+
62+
def targetType = getMultiDataType (schemaInfo)
63+
if (!targetType) {
64+
return dataType
65+
}
66+
67+
if (targetType.typeName == 'plain') {
68+
return dataType
69+
}
70+
71+
DataType item = dataType.item
72+
73+
def multiType = new MappedCollectionDataType (
74+
type: targetType.name,
75+
pkg: targetType.pkg,
76+
item: item
77+
)
78+
return multiType
79+
}
80+
81+
private TargetType getMultiDataType (SchemaInfo info) {
82+
// check endpoint multi mapping
83+
List<Mapping> endpointMatches = finder.findEndpointMultiMapping (info)
84+
85+
if (!endpointMatches.empty) {
86+
87+
if (endpointMatches.size () != 1) {
88+
throw new AmbiguousTypeMappingException (endpointMatches)
89+
}
90+
91+
TargetType target = (endpointMatches.first() as TargetTypeMapping).targetType
92+
if (target) {
93+
return target
94+
}
95+
}
96+
97+
// find global multi mapping
98+
List<Mapping> typeMatches = finder.findMultiMapping (info)
99+
if (typeMatches.isEmpty ()) {
100+
return null
101+
}
102+
103+
if (typeMatches.size () != 1) {
104+
throw new AmbiguousTypeMappingException (typeMatches)
105+
}
106+
107+
def match = typeMatches.first () as TargetTypeMapping
108+
return match.targetType
109+
}
110+
111+
private DataType checkNone (DataType dataType) {
112+
if (dataType instanceof NoneDataType) {
113+
return dataType.wrappedInResult ()
114+
}
115+
116+
dataType
117+
}
118+
119+
}

0 commit comments

Comments
 (0)