@@ -42,6 +42,7 @@ import com.github.hauner.openapi.spring.model.datatypes.IntegerDataType
4242import com.github.hauner.openapi.spring.model.datatypes.LongDataType
4343import com.github.hauner.openapi.spring.model.datatypes.NoneDataType
4444import com.github.hauner.openapi.spring.model.datatypes.OffsetDateTimeDataType
45+ import com.github.hauner.openapi.spring.model.datatypes.LazyDataType
4546import com.github.hauner.openapi.spring.model.datatypes.SetDataType
4647import com.github.hauner.openapi.spring.model.datatypes.StringDataType
4748import com.github.hauner.openapi.spring.model.datatypes.StringEnumDataType
@@ -55,9 +56,12 @@ import com.github.hauner.openapi.spring.model.datatypes.StringEnumDataType
5556class DataTypeConverter {
5657
5758 private ApiOptions options
59+ private List<SchemaInfo > current
60+
5861
5962 DataTypeConverter (ApiOptions options ) {
6063 this . options = options
64+ this . current = []
6165 }
6266
6367 DataType none () {
@@ -74,19 +78,28 @@ class DataTypeConverter {
7478 * @return the resulting java data type
7579 */
7680 DataType convert (SchemaInfo dataTypeInfo , DataTypes dataTypes ) {
81+ if (isLoop (dataTypeInfo)) {
82+ return new LazyDataType (info : dataTypeInfo, dataTypes : dataTypes)
83+ }
84+
85+ push (dataTypeInfo)
7786
87+ DataType result
7888 if (dataTypeInfo. isRefObject ()) {
79- createRefDataType(dataTypeInfo, dataTypes)
89+ result = createRefDataType(dataTypeInfo, dataTypes)
8090
8191 } else if (dataTypeInfo. isArray ()) {
82- createArrayDataType (dataTypeInfo, dataTypes)
92+ result = createArrayDataType (dataTypeInfo, dataTypes)
8393
8494 } else if (dataTypeInfo. isObject ()) {
85- createObjectDataType (dataTypeInfo, dataTypes)
95+ result = createObjectDataType (dataTypeInfo, dataTypes)
8696
8797 } else {
88- createSimpleDataType (dataTypeInfo, dataTypes)
98+ result = createSimpleDataType (dataTypeInfo, dataTypes)
8999 }
100+
101+ pop ()
102+ result
90103 }
91104
92105 private DataType createArrayDataType (SchemaInfo schemaInfo , DataTypes dataTypes ) {
@@ -250,7 +263,7 @@ class DataTypeConverter {
250263 enumType
251264 }
252265
253- TargetType getMappedDataType (SchemaType schemaType ) {
266+ private TargetType getMappedDataType (SchemaType schemaType ) {
254267 // check endpoint mappings
255268 List<Mapping > endpointMatches = schemaType. matchEndpointMapping (options. typeMappings)
256269 if (! endpointMatches. empty) {
@@ -293,4 +306,40 @@ class DataTypeConverter {
293306 return match. targetType
294307 }
295308
309+ /**
310+ * push the current schema info.
311+ *
312+ * Pushes the given {@code info } onto the in-progress data type stack. It is used to detect
313+ * $ref loops.
314+ *
315+ * @param info the schema info that is currently processed
316+ */
317+ private void push (SchemaInfo info ) {
318+ current. push (info)
319+ }
320+
321+ /**
322+ * pop the current schema info.
323+ *
324+ */
325+ private void pop () {
326+ current. pop ()
327+ }
328+
329+ /**
330+ * detect $ref loop.
331+ *
332+ * returns true if the given {@code info } is currently processed, false otherwise. True indicates
333+ * a $ref loop.
334+ *
335+ * @param info the schema info that is currently processed
336+ * @return
337+ */
338+ private boolean isLoop (SchemaInfo info ) {
339+ def found = current. find {
340+ it. name == info. name
341+ }
342+ found != null
343+ }
344+
296345}
0 commit comments