From 0aac955d20dbebbdc40193efa1e73f11a85c5bd2 Mon Sep 17 00:00:00 2001 From: linwumingshi <linwumingshi@gmail.com> Date: Wed, 13 Mar 2024 16:31:26 +0800 Subject: [PATCH] fix: :bug: fix the Generics typeName or returnType error --- .../com/ly/doc/helper/JsonBuildHelper.java | 6 +- .../java/com/ly/doc/utils/JavaClassUtil.java | 83 +++++++++++++++---- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/ly/doc/helper/JsonBuildHelper.java b/src/main/java/com/ly/doc/helper/JsonBuildHelper.java index bf736fd5..2ee4aa61 100644 --- a/src/main/java/com/ly/doc/helper/JsonBuildHelper.java +++ b/src/main/java/com/ly/doc/helper/JsonBuildHelper.java @@ -92,10 +92,8 @@ public static String buildReturnJson(DocJavaMethod docJavaMethod, ProjectDocConf Map<String, JavaType> actualTypesMap = docJavaMethod.getActualTypesMap(); String returnType = apiReturn.getGenericCanonicalName(); if (Objects.nonNull(actualTypesMap)) { - for (Map.Entry<String, JavaType> entry : actualTypesMap.entrySet()) { - typeName = typeName.replace(entry.getKey(), entry.getValue().getCanonicalName()); - returnType = returnType.replace(entry.getKey(), entry.getValue().getCanonicalName()); - } + typeName = JavaClassUtil.getGenericsNameByActualTypesMap(typeName, actualTypesMap); + returnType = JavaClassUtil.getGenericsNameByActualTypesMap(returnType, actualTypesMap); } if (JavaClassValidateUtil.isPrimitive(typeName)) { if (DocGlobalConstants.JAVA_STRING_FULLY.equals(typeName)) { diff --git a/src/main/java/com/ly/doc/utils/JavaClassUtil.java b/src/main/java/com/ly/doc/utils/JavaClassUtil.java index 4a4230b2..4869a323 100644 --- a/src/main/java/com/ly/doc/utils/JavaClassUtil.java +++ b/src/main/java/com/ly/doc/utils/JavaClassUtil.java @@ -157,7 +157,7 @@ private static List<DocJavaField> getFields(JavaClass cls1, int counter, Map<Str List<JavaMethod> javaMethods = cls1.getMethods(); for (JavaMethod method : javaMethods) { String methodName = method.getName(); - if (method.getAnnotations().size() < 1) { + if (method.getAnnotations().isEmpty()) { continue; } int paramSize = method.getParameters().size(); @@ -335,7 +335,7 @@ public static Object getEnumValue(JavaClass javaClass, boolean formDataEnum) { for (JavaField javaField : javaFields) { String simpleName = javaField.getType().getSimpleName(); StringBuilder valueBuilder = new StringBuilder(); - valueBuilder.append("\"").append(javaField.getName()).append("\"").toString(); + valueBuilder.append("\"").append(javaField.getName()).append("\""); if (formDataEnum) { value = valueBuilder.toString(); return value; @@ -360,7 +360,7 @@ public static String getEnumParams(JavaClass javaClass) { // string comment String exception = javaField.getInitializationExpression(); // add a separator to Enum values for display better. - if (stringBuilder.length() > 0){ + if (stringBuilder.length() > 0) { stringBuilder.append(", "); } stringBuilder.append(javaField.getName()); @@ -544,12 +544,12 @@ public static List<JavaType> getActualTypes(JavaType javaType) { public static Map<String, JavaType> getActualTypesMap(JavaClass javaClass) { Map<String, JavaType> genericMap = new HashMap<>(10); List<JavaTypeVariable<JavaGenericDeclaration>> variables = javaClass.getTypeParameters(); - if (variables.size() < 1) { + if (variables.isEmpty()) { return genericMap; } List<JavaType> javaTypes = getActualTypes(javaClass); for (int i = 0; i < variables.size(); i++) { - if (javaTypes.size() > 0) { + if (!javaTypes.isEmpty()) { genericMap.put(variables.get(i).getName(), javaTypes.get(i)); } } @@ -592,7 +592,7 @@ public static Set<String> getParamGroupJavaClass(JavaAnnotation javaAnnotation) addGroupClass(annotationValueList, javaClassList); String simpleAnnotationName = javaAnnotation.getType().getValue(); // add default group - if (javaClassList.size() == 0 && JavaClassValidateUtil.isJSR303Required(simpleAnnotationName)) { + if (javaClassList.isEmpty() && JavaClassValidateUtil.isJSR303Required(simpleAnnotationName)) { javaClassList.add("javax.validation.groups.Default"); } return javaClassList; @@ -602,16 +602,16 @@ public static String getClassTagsValue(final JavaClass cls, final String tagName if (StringUtil.isNotEmpty(tagName)) { StringBuilder result = new StringBuilder(); List<DocletTag> tags = cls.getTags(); - for (int i = 0; i < tags.size(); i++) { - if (!tagName.equals(tags.get(i).getName())) { + for (DocletTag tag : tags) { + if (!tagName.equals(tag.getName())) { continue; } - String value = tags.get(i).getValue(); + String value = tag.getValue(); if (StringUtil.isEmpty(value) && checkComments) { throw new RuntimeException("ERROR: #" + cls.getName() + "() - bad @" + tagName + " javadoc from " + cls.getName() + ", must be add comment if you use it."); } - if (tagName.equals(tags.get(i).getName())) { + if (tagName.equals(tag.getName())) { if (result.length() > 0) { result.append(","); } @@ -721,15 +721,15 @@ public static void genericParamMap(Map<String, String> genericMap, JavaClass cls return; } List<JavaTypeVariable<JavaGenericDeclaration>> variables = cls.getTypeParameters(); - if (variables.size() > 0) { + if (!variables.isEmpty()) { for (int i = 0; i < cls.getTypeParameters().size() && i < globGicName.length; i++) { genericMap.put(variables.get(i).getName(), globGicName[i]); } return; } try { - Class c = Class.forName(cls.getCanonicalName()); - TypeVariable[] tValue = c.getTypeParameters(); + Class<?> c = Class.forName(cls.getCanonicalName()); + TypeVariable<?>[] tValue = c.getTypeParameters(); for (int i = 0; i < tValue.length && i < globGicName.length; i++) { genericMap.put(tValue[i].getName(), globGicName[i]); } @@ -803,8 +803,11 @@ public static Map<String, String> getJsonIgnoresProp(JavaAnnotation annotation, /** - * @param javaField - * @return + * getFieldGenericType by ClassLoader + * + * @param javaField JavaField + * @param classLoader ClassLoader + * @return fieldGenericType */ private static String getFieldGenericType(JavaField javaField, ClassLoader classLoader) { if (JavaClassValidateUtil.isPrimitive(javaField.getType().getGenericCanonicalName()) @@ -813,7 +816,7 @@ private static String getFieldGenericType(JavaField javaField, ClassLoader class } String name = javaField.getName(); try { - Class c; + Class<?> c; if (Objects.nonNull(classLoader)) { c = classLoader.loadClass(javaField.getDeclaringClass().getCanonicalName()); } else { @@ -846,4 +849,52 @@ private static String getReturnGenericType(JavaMethod javaMethod, ClassLoader cl return null; } } + + + /** + * Replaces generic type parameters in a given type name with their corresponding actual types, + * based on the provided mapping. + * + * @param originalName the original type name containing generic type parameters + * @param actualTypesMap a mapping of generic type parameter names to their corresponding actual types + * @return the type name with generic type parameters replaced by their actual types + */ + public static String getGenericsNameByActualTypesMap(String originalName, Map<String, JavaType> actualTypesMap) { + // Find the index of the last left angle bracket '<' and the first right angle bracket '>' + int typeNameLastLeftIndex = originalName.lastIndexOf('<'); + int typeNameFirstRightIndex = originalName.indexOf('>', typeNameLastLeftIndex); + + // If both angle brackets are found + if (typeNameLastLeftIndex > 0 && typeNameFirstRightIndex > 0) { + // Extract the substring containing the generics + String genericsString = originalName.substring(typeNameLastLeftIndex + 1, typeNameFirstRightIndex); + String[] generics = genericsString.split(","); + + // StringBuilder to build the replaced string + StringBuilder resultString = new StringBuilder(); + // Append the portion of originalName before the generics, including the '<' + resultString.append(originalName, 0, typeNameLastLeftIndex + 1); + + // Replace each generic type + for (String generic : generics) { + // Trim the generic type to remove leading/trailing whitespaces + String trimmedGeneric = generic.trim(); + // Look up the mapped type in the actualTypesMap + JavaType mappedType = actualTypesMap.get(trimmedGeneric); + // If a mapping is found, append the mapped type; otherwise, keep the original generic type + resultString.append(mappedType != null ? mappedType.getCanonicalName() : trimmedGeneric); + // Append a comma after each replaced generic type + resultString.append(","); + } + // Remove the trailing comma + resultString.setLength(resultString.length() - 1); + // Append the portion of originalName after the generics, including the '>' + resultString.append(originalName, typeNameFirstRightIndex, originalName.length()); + + return resultString.toString(); + } + // Return originalName unchanged if no generics are found + return originalName; + } + }