From 537455dc7827f99650649f2edf8cfce2e05fe551 Mon Sep 17 00:00:00 2001
From: Dmitry Sboychakov <sboichakov@gmail.com>
Date: Mon, 4 Nov 2024 18:30:54 +0100
Subject: [PATCH 1/2] handle duplicate type names with postfix generation

---
 .../core/jackson/AbstractModelConverter.java  | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/AbstractModelConverter.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/AbstractModelConverter.java
index 3dc4788ee8..3a80d78c70 100644
--- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/AbstractModelConverter.java
+++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/AbstractModelConverter.java
@@ -18,6 +18,8 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public abstract class AbstractModelConverter implements ModelConverter {
     protected final ObjectMapper _mapper;
@@ -65,7 +67,28 @@ protected String _typeName(JavaType type, BeanDescription beanDesc) {
             return name;
         }
         name = _findTypeName(type, beanDesc);
+        // Check if the resolved type name already exists in the map
+        if (_resolvedTypeNames.containsValue(name)) {
+            // Determine if the type is from the Java standard library
+            final boolean isFromJava = type.getRawClass().getCanonicalName().contains("java.lang.");
+            // If the type is not a collection, map, primitive, or from Java standard library
+            if (!type.isCollectionLikeType() && !type.isMapLikeType() && !type.isPrimitive() && !isFromJava) {
+                // Iterate through the resolved type names to find conflicts
+                for (Map.Entry<JavaType, String> entry : _resolvedTypeNames.entrySet()) {
+                    JavaType key = entry.getKey();
+                    String value = entry.getValue();
+                    // If a conflict is found (same name but different type)
+                    if (value.equals(name)) {
+                        if (key != type) {
+                            // Generate a new name postfix to resolve the conflict
+                            name = genNamePostfix(name);
+                        }
+                    }
+                }
+            }
+        }
         _resolvedTypeNames.put(type, name);
+
         return name;
     }
 
@@ -120,4 +143,21 @@ protected boolean _isSetType(Class<?> cls) {
         }
         return false;
     }
+
+    private String genNamePostfix(String name) {
+        // Regular expression to match a number at the end of the string
+        Pattern pattern = Pattern.compile("(\\d+)$");
+        Matcher matcher = pattern.matcher(name);
+
+        if (matcher.find()) {
+            // Extract the number, increment it, and replace it in the name
+            String numberStr = matcher.group(1);
+            int number = Integer.parseInt(numberStr);
+            number++;
+            return name.substring(0, matcher.start(1)) + number;
+        } else {
+            // If no number at the end, append "2"
+            return name + "2";
+        }
+    }
 }

From 275ac876bd573b0a3a99d231790e07f863d00aea Mon Sep 17 00:00:00 2001
From: Dmitry Sboychakov <sboichakov@gmail.com>
Date: Mon, 4 Nov 2024 18:31:17 +0100
Subject: [PATCH 2/2] TypeNameResolver to handle member class names correctly

---
 .../io/swagger/v3/core/jackson/TypeNameResolver.java   | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/TypeNameResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/TypeNameResolver.java
index 808a6e94fb..266c66806b 100644
--- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/TypeNameResolver.java
+++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/TypeNameResolver.java
@@ -60,7 +60,15 @@ protected String nameForClass(Class<?> cls, Set<Options> options) {
     }
 
     protected String getNameOfClass(Class<?> cls) {
-        return useFqn?cls.getName():cls.getSimpleName();
+        if(useFqn){
+            return  cls.getName();
+        }
+        String simpleName = cls.getSimpleName();
+        if(cls.isMemberClass()){
+            String enclosingClsName = cls.getEnclosingClass().getSimpleName();
+            return String.format("%s%s", enclosingClsName, simpleName);
+        }
+        return simpleName;
     }
 
     protected String nameForGenericType(JavaType type, Set<Options> options) {