Fix the parsing error that the subclass does not define the generic type when the subclass inherits a generic parent class.

This commit is contained in:
yusun4 2020-09-24 00:20:58 +08:00
parent ea3cf02c05
commit b20e873422
8 changed files with 117 additions and 40 deletions

View File

@ -99,6 +99,7 @@ When you need to use smart-doc to generate more API document information, you ca
"recursionLimit":7,// Set the number of recursive executions to avoid stack overflow, the default is 7
"responseFieldToUnderline":true,//convert response field to underline
"allInOneDocFileName":"index.html",//Customize the output document name
"displayActualType":false,//display actual type of generic,
"requestExample":"true",//Whether to display the request example in the document, the default value is true.
"responseExample":"true",//Whether to display the response example in the document, the default is true.
"ignoreRequestParams":[ //The request parameter object will be discarded when generating the document.@since 1.9.2

View File

@ -102,6 +102,7 @@ smart-doc官方目前已经开发完成[maven插件](https://gitee.com/smart-doc
"allInOneDocFileName":"index.html",//自定义设置输出文档名称, @since 1.9.0
"requestExample":"true",//是否将请求示例展示在文档中默认true@since 1.9.0
"responseExample":"true",//是否将响应示例展示在文档中默认为true@since 1.9.0
"displayActualType":false,//配置true会在注释栏自动显示泛型的真实类型短类名@since 1.9.6
"ignoreRequestParams":[ //忽略请求参数对象,把不想生成文档的参数对象屏蔽掉,@since 1.9.2
"org.springframework.ui.ModelMap"
],

View File

@ -101,8 +101,8 @@ public class FormDataBuildHelper {
for (DocJavaField docField : fields) {
JavaField field = docField.getJavaField();
String fieldName = field.getName();
String subTypeName = field.getType().getFullyQualifiedName();
String fieldGicName = field.getType().getGenericCanonicalName();
String subTypeName = docField.getFullyQualifiedName();
String fieldGicName = docField.getGenericCanonicalName();
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(subTypeName);
if (field.isStatic() || "this$0".equals(fieldName) ||
JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) {

View File

@ -40,6 +40,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* @author yu 2019/12/21.
*/
@ -107,12 +109,7 @@ public class JsonBuildHelper {
data0.append("{");
String[] globGicName = DocClassUtil.getSimpleGicName(genericCanonicalName);
//添加泛型对应关系
if (cls != null && null != cls.getTypeParameters()) {
List<JavaTypeVariable<JavaGenericDeclaration>> variables = cls.getTypeParameters();
for (int i = 0; i < cls.getTypeParameters().size() && i<globGicName.length; i++) {
genericMap.put(variables.get(i).getName(), globGicName[i]);
}
}
JavaClassUtil.genericParamMap(genericMap, cls, globGicName);
StringBuilder data = new StringBuilder();
if (JavaClassValidateUtil.isCollection(typeName) || JavaClassValidateUtil.isArray(typeName)) {
data.append("[");
@ -175,7 +172,7 @@ public class JsonBuildHelper {
out:
for (DocJavaField docField : fields) {
JavaField field = docField.getJavaField();
String subTypeName = field.getType().getFullyQualifiedName();
String subTypeName = docField.getFullyQualifiedName();
String fieldName = field.getName();
if (field.isStatic() || "this$0".equals(fieldName) ||
JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) {
@ -214,7 +211,7 @@ public class JsonBuildHelper {
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = field.getType().getGenericCanonicalName();
String fieldGicName = docField.getGenericCanonicalName();
data0.append("\"").append(fieldName).append("\":");
if (JavaClassValidateUtil.isPrimitive(subTypeName)) {
String fieldValue = "";
@ -354,4 +351,6 @@ public class JsonBuildHelper {
data0.append("}");
return data0.toString();
}
}

View File

@ -68,18 +68,14 @@ public class ParamsBuildHelper {
boolean isShowJavaType = projectBuilder.getApiConfig().getShowJavaType();
boolean requestFieldToUnderline = projectBuilder.getApiConfig().isRequestFieldToUnderline();
boolean responseFieldToUnderline = projectBuilder.getApiConfig().isResponseFieldToUnderline();
boolean displayActualType = projectBuilder.getApiConfig().isDisplayActualType();
// Registry class
registryClasses.put(className, className);
String simpleName = DocClassUtil.getSimpleName(className);
String[] globGicName = DocClassUtil.getSimpleGicName(className);
JavaClass cls = projectBuilder.getClassByName(simpleName);
//如果存在泛型 则将泛型与类名的对应关系存起来
if (cls != null && null != cls.getTypeParameters()) {
List<JavaTypeVariable<JavaGenericDeclaration>> variables = cls.getTypeParameters();
for (int i = 0; i < cls.getTypeParameters().size() && i<globGicName.length; i++) {
genericMap.put(variables.get(i).getName(), globGicName[i]);
}
}
JavaClassUtil.genericParamMap(genericMap, cls, globGicName);
List<DocJavaField> fields = JavaClassUtil.getFields(cls, 0, new HashSet<>());
if (JavaClassValidateUtil.isPrimitive(simpleName)) {
String processedType = isShowJavaType ? simpleName : DocClassUtil.processTypeNameForParams(simpleName.toLowerCase());
@ -106,15 +102,13 @@ public class ParamsBuildHelper {
param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setRequired(false).setVersion(DocGlobalConstants.DEFAULT_VERSION);
}
paramList.add(param);
}
else {
} else {
boolean isGenerics = JavaFieldUtil.checkGenerics(fields);
out:
for (DocJavaField docField : fields) {
JavaField field = docField.getJavaField();
String fieldName = field.getName();
String subTypeName = field.getType().getFullyQualifiedName();
String subTypeName = docField.getFullyQualifiedName();
if (field.isStatic() || "this$0".equals(fieldName) ||
JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
@ -127,7 +121,7 @@ public class ParamsBuildHelper {
fieldName = StringUtil.camelToUnderline(fieldName);
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = field.getType().getGenericCanonicalName();
String fieldGicName = docField.getGenericCanonicalName();
List<JavaAnnotation> javaAnnotations = docField.getAnnotations();
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field, docField);
@ -249,6 +243,9 @@ public class ParamsBuildHelper {
}
param.setType(DocGlobalConstants.ENUM);
}
if (typeSimpleName.length() == 1 && displayActualType) {
comment = comment + "(" + JavaClassUtil.getClassSimpleName(subTypeName) + ")";
}
//如果已经设置返回类型 不需要再次设置
if (param.getType() == null) {
String processedType;
@ -289,12 +286,12 @@ public class ParamsBuildHelper {
preBuilder.append(DocGlobalConstants.FIELD_SPACE);
}
preBuilder.append("└─");
int fieldPid = paramList.size()+pid;
int fieldPid = paramList.size() + pid;
if (JavaClassValidateUtil.isMap(subTypeName)) {
String gNameTemp = field.getType().getGenericCanonicalName();
if (JavaClassValidateUtil.isMap(gNameTemp)) {
ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object")
.setId(paramList.size()+1).setPid(fieldPid)
.setId(paramList.size() + 1).setPid(fieldPid)
.setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param1);
continue;
@ -339,8 +336,7 @@ public class ParamsBuildHelper {
}
}
}
} else
if (subTypeName.length() == 1 || DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
} else if (subTypeName.length() == 1 || DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
if (isGenerics && DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object")
.setId(paramList.size())

View File

@ -240,6 +240,11 @@ public class ApiConfig {
*/
private List<String> ignoreRequestParams;
/**
* display actual type of generic
* @since 1.9.6
*/
private boolean displayActualType;
public String getServerUrl() {
return serverUrl;
@ -525,4 +530,12 @@ public class ApiConfig {
public void setIgnoreRequestParams(List<String> ignoreRequestParams) {
this.ignoreRequestParams = ignoreRequestParams;
}
public boolean isDisplayActualType() {
return displayActualType;
}
public void setDisplayActualType(boolean displayActualType) {
this.displayActualType = displayActualType;
}
}

View File

@ -54,6 +54,16 @@ public class DocJavaField {
*/
private List<JavaAnnotation> annotations;
/**
* field fullyQualifiedName
*/
private String fullyQualifiedName;
/**
* field genericCanonicalName
*/
private String genericCanonicalName;
public static DocJavaField builder() {
return new DocJavaField();
}
@ -76,6 +86,24 @@ public class DocJavaField {
return this;
}
public String getFullyQualifiedName() {
return fullyQualifiedName;
}
public DocJavaField setFullyQualifiedName(String fullyQualifiedName) {
this.fullyQualifiedName = fullyQualifiedName;
return this;
}
public String getGenericCanonicalName() {
return genericCanonicalName;
}
public DocJavaField setGenericCanonicalName(String genericCanonicalName) {
this.genericCanonicalName = genericCanonicalName;
return this;
}
public List<DocletTag> getDocletTags() {
if (docletTags == null) {
return new ArrayList<>();

View File

@ -38,6 +38,8 @@ import com.thoughtworks.qdox.model.impl.DefaultJavaParameterizedType;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
/**
@ -105,14 +107,25 @@ public class JavaClassUtil {
fieldList.addAll(getFields(javaClass, counter, addedFields));
}
}
Map<String, JavaType> javaTypes = getActualTypesMap(cls1);
List<DocJavaField> docJavaFields = new ArrayList<>();
List<JavaTypeVariable<JavaGenericDeclaration>> variables = cls1.getTypeParameters();
for (JavaField javaField : cls1.getFields()) {
String fieldName = javaField.getName();
if (addedFields.contains(fieldName)) {
continue;
}
String gicName = javaField.getType().getGenericCanonicalName();
String subTypeName = javaField.getType().getFullyQualifiedName();
if (subTypeName.length() == 1) {
JavaType type = javaTypes.get(subTypeName);
subTypeName = type.getFullyQualifiedName();
gicName = type.getGenericCanonicalName();
}
addedFields.add(fieldName);
docJavaFields.add(DocJavaField.builder().setComment(javaField.getComment()).setJavaField(javaField));
docJavaFields.add(DocJavaField.builder().setComment(javaField.getComment())
.setJavaField(javaField).setFullyQualifiedName(subTypeName)
.setGenericCanonicalName(gicName));
}
fieldList.addAll(docJavaFields);
}
@ -156,7 +169,6 @@ public class JavaClassUtil {
}
public static String getEnumParams(JavaClass javaClass) {
List<JavaField> javaFields = javaClass.getEnumConstants();
StringBuilder stringBuilder = new StringBuilder();
for (JavaField javaField : javaFields) {
@ -171,7 +183,6 @@ public class JavaClassUtil {
stringBuilder.append(",");
}
}
stringBuilder.append(")");
}
stringBuilder.append("<br/>");
@ -199,7 +210,7 @@ public class JavaClassUtil {
public static String getClassSimpleName(String className) {
if (className.contains(".")) {
int index = className.lastIndexOf(".");
className = className.substring(index + 1, className.length());
className = className.substring(index + 1);
}
if (className.contains("[")) {
int index = className.indexOf("[");
@ -214,27 +225,47 @@ public class JavaClassUtil {
* @param javaClass JavaClass
* @return JavaClass
*/
public static JavaClass getActualType(JavaClass javaClass) {
public static JavaType getActualType(JavaClass javaClass) {
return getActualTypes(javaClass).get(0);
}
/**
* get Actual type list
*
* @param javaClass JavaClass
* @param javaType JavaClass
* @return JavaClass
*/
public static List<JavaClass> getActualTypes(JavaClass javaClass) {
if (null == javaClass) {
public static List<JavaType> getActualTypes(JavaType javaType) {
if (null == javaType) {
return new ArrayList<>(0);
}
List<JavaClass> javaClassList = new ArrayList<>();
List<JavaType> actualTypes = ((DefaultJavaParameterizedType) javaClass).getActualTypeArguments();
actualTypes.forEach(javaType -> {
JavaClass actualClass = (JavaClass) javaType;
javaClassList.add(actualClass);
});
return javaClassList;
String typeName = javaType.getGenericFullyQualifiedName();
if (typeName.contains("<")) {
return ((JavaParameterizedType) javaType).getActualTypeArguments();
}
return new ArrayList<>(0);
}
/**
* get Actual type map
*
* @param javaClass JavaClass
* @return Map
*/
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) {
return genericMap;
}
List<JavaType> javaTypes = getActualTypes(javaClass);
for (int i = 0; i < variables.size(); i++) {
if (javaTypes.size() > 0) {
genericMap.put(variables.get(i).getName(), javaTypes.get(i));
}
}
return genericMap;
}
/**
@ -372,4 +403,12 @@ public class JavaClassUtil {
}
return annotationValueList;
}
public static void genericParamMap(Map<String, String> genericMap, JavaClass cls, String[] globGicName) {
if (cls != null && null != cls.getTypeParameters()) {
List<JavaTypeVariable<JavaGenericDeclaration>> variables = cls.getTypeParameters();
for (int i = 0; i < cls.getTypeParameters().size() && i<globGicName.length; i++) {
genericMap.put(variables.get(i).getName(), globGicName[i]);
}
}
}
}