代码拆分

This commit is contained in:
oppofind 2019-12-22 01:28:55 +08:00
parent f24306c0bb
commit 4cb5604413
17 changed files with 1439 additions and 9 deletions

View File

@ -0,0 +1,131 @@
package com.power.doc.builder;
import com.power.common.util.CollectionUtil;
import com.power.common.util.StringUtil;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.model.ApiConfig;
import com.power.doc.model.CustomRespField;
import com.power.doc.model.SourceCodePath;
import com.power.doc.utils.JavaClassUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import static com.power.doc.constants.DocGlobalConstants.DEFAULT_SERVER_URL;
/**
* @author yu 2019/12/21.
*/
public class ProjectDocConfigBuilder {
private JavaProjectBuilder javaProjectBuilder;
private Map<String, JavaClass> classFilesMap = new ConcurrentHashMap<>();
private Map<String, CustomRespField> customRespFieldMap = new ConcurrentHashMap<>();
private String serverUrl;
private ApiConfig apiConfig;
public ProjectDocConfigBuilder(ApiConfig apiConfig, JavaProjectBuilder javaProjectBuilder) {
if (null == apiConfig) {
throw new NullPointerException("ApiConfig can't be null.");
}
this.apiConfig = apiConfig;
if (Objects.isNull(javaProjectBuilder)) {
javaProjectBuilder = new JavaProjectBuilder();
}
if (StringUtil.isEmpty(apiConfig.getServerUrl())) {
this.serverUrl = DEFAULT_SERVER_URL;
} else {
this.serverUrl = apiConfig.getServerUrl();
}
this.javaProjectBuilder = javaProjectBuilder;
this.loadJavaSource(apiConfig.getSourceCodePaths(),this.javaProjectBuilder);
this.initClassFilesMap(apiConfig);
this.initCustomResponseFieldsMap(apiConfig);
}
private void loadJavaSource(List<SourceCodePath> paths,JavaProjectBuilder builder) {
if (CollectionUtil.isEmpty(paths)) {
builder.addSourceTree(new File(DocGlobalConstants.PROJECT_CODE_PATH));
} else {
if (!paths.contains(DocGlobalConstants.PROJECT_CODE_PATH)) {
builder.addSourceTree(new File(DocGlobalConstants.PROJECT_CODE_PATH));
}
for (SourceCodePath path : paths) {
if (null == path) {
continue;
}
String strPath = path.getPath();
if (StringUtil.isNotEmpty(strPath)) {
strPath = strPath.replace("\\", "/");
builder.addSourceTree(new File(strPath));
}
}
}
}
private void initClassFilesMap(ApiConfig config) {
Collection<JavaClass> javaClasses = javaProjectBuilder.getClasses();
for (JavaClass cls : javaClasses) {
classFilesMap.put(cls.getFullyQualifiedName(), cls);
}
}
private void initCustomResponseFieldsMap(ApiConfig config){
if (CollectionUtil.isNotEmpty(config.getCustomResponseFields())) {
for (CustomRespField field : config.getCustomResponseFields()) {
customRespFieldMap.put(field.getName(), field);
}
}
}
public JavaClass getClassByName(String simpleName) {
JavaClass cls = javaProjectBuilder.getClassByName(simpleName);
List<JavaField> fieldList = JavaClassUtil.getFields(cls, 0);
// handle inner class
if (Objects.isNull(cls.getFields()) || fieldList.isEmpty()) {
cls = classFilesMap.get(simpleName);
} else {
List<JavaClass> classList = cls.getNestedClasses();
for (JavaClass javaClass : classList) {
classFilesMap.put(javaClass.getFullyQualifiedName(), javaClass);
}
}
return cls;
}
public JavaProjectBuilder getJavaProjectBuilder() {
return javaProjectBuilder;
}
public Map<String, JavaClass> getClassFilesMap() {
return classFilesMap;
}
public Map<String, CustomRespField> getCustomRespFieldMap() {
return customRespFieldMap;
}
public String getServerUrl() {
return serverUrl;
}
public ApiConfig getApiConfig() {
return apiConfig;
}
}

View File

@ -993,7 +993,7 @@ public class SourceBuilder {
boolean containsBrace = apiMethodDoc.getUrl().replace(DEFAULT_SERVER_URL, "").contains("{"); boolean containsBrace = apiMethodDoc.getUrl().replace(DEFAULT_SERVER_URL, "").contains("{");
Map<String, String> paramsMap = new LinkedHashMap<>(); Map<String, String> paramsMap = new LinkedHashMap<>();
Map<String, String> paramsComments = DocUtil.getParamsComments(method, DocTags.PARAM, null); Map<String, String> paramsComments = DocUtil.getParamsComments(method, DocTags.PARAM, null);
List<String> springMvcRequestAnnotations = SpringMvcRequestAnnotations.listSpringMvcRequestAnnotations(); List<String> springMvcRequestAnnotations = SpringMvcRequestAnnotationsEnum.listSpringMvcRequestAnnotations();
for (JavaParameter parameter : parameterList) { for (JavaParameter parameter : parameterList) {
JavaType javaType = parameter.getType(); JavaType javaType = parameter.getType();
String simpleTypeName = javaType.getValue(); String simpleTypeName = javaType.getValue();
@ -1272,7 +1272,7 @@ public class SourceBuilder {
if (paramAdded) { if (paramAdded) {
continue; continue;
} }
List<String> validatorAnnotations = DocValidatorAnnotations.listValidatorAnnotations(); List<String> validatorAnnotations = DocValidatorAnnotationEnum.listValidatorAnnotations();
if (REQUEST_PARAM.equals(annotationName) || if (REQUEST_PARAM.equals(annotationName) ||
DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) { DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) {
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP); AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);

View File

@ -1198,7 +1198,7 @@ public class SourceBuilders {
if (paramAdded) { if (paramAdded) {
continue; continue;
} }
List<String> validatorAnnotations = DocValidatorAnnotations.listValidatorAnnotations(); List<String> validatorAnnotations = DocValidatorAnnotationEnum.listValidatorAnnotations();
if (REQUEST_PARAM.equals(annotationName) || if (REQUEST_PARAM.equals(annotationName) ||
DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) { DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) {
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP); AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);

View File

@ -35,5 +35,15 @@ public class DocAnnotationConstants {
public static final String SHORT_REQUSRT_HEADER = "RequestHeader"; public static final String SHORT_REQUSRT_HEADER = "RequestHeader";
public static final String REQUEST_MAPPING = "RequestMapping";
private static final String GET_MAPPING = "GetMapping";
private static final String POST_MAPPING = "PostMapping";
private static final String PUT_MAPPING = "PutMapping";
private static final String DELETE_MAPPING = "DeleteMapping";
} }

View File

@ -104,4 +104,6 @@ public class DocGlobalConstants {
public static final String HTTP_POST = "POST"; public static final String HTTP_POST = "POST";
public static final String SHORT_MULTIPART_FILE_FULLY = "MultipartFile"; public static final String SHORT_MULTIPART_FILE_FULLY = "MultipartFile";
public static final String DEFAULT_SERVER_URL = "http://{server}";
} }

View File

@ -9,7 +9,7 @@ import java.util.List;
* *
* @author yu 2019/9/19. * @author yu 2019/9/19.
*/ */
public enum DocValidatorAnnotations { public enum DocValidatorAnnotationEnum {
NOT_EMPTY("NotEmpty"), NOT_EMPTY("NotEmpty"),
@ -50,13 +50,13 @@ public enum DocValidatorAnnotations {
private String value; private String value;
DocValidatorAnnotations(String value) { DocValidatorAnnotationEnum(String value) {
this.value = value; this.value = value;
} }
public static List<String> listValidatorAnnotations() { public static List<String> listValidatorAnnotations() {
List<String> annotations = new ArrayList<>(); List<String> annotations = new ArrayList<>();
for (DocValidatorAnnotations annotation : DocValidatorAnnotations.values()) { for (DocValidatorAnnotationEnum annotation : DocValidatorAnnotationEnum.values()) {
annotations.add(annotation.value); annotations.add(annotation.value);
} }
return annotations; return annotations;

View File

@ -0,0 +1,23 @@
package com.power.doc.constants;
/**
* @author yu 2019/12/21.
*/
public class SpringMvcAnnotations {
public static final String REQUEST_MAPPING = "RequestMapping";
public static final String GET_MAPPING = "GetMapping";
public static final String POST_MAPPING = "PostMapping";
public static final String PUT_MAPPING = "PutMapping";
public static final String DELETE_MAPPING = "DeleteMapping";
public static final String REQUEST_HERDER = "RequestHeader";
public static final String REQUEST_PARAM = "RequestParam";
public static final String REQUEST_BODY = "RequestBody";
}

View File

@ -6,7 +6,7 @@ import java.util.List;
/** /**
* @author yu 2019/12/20. * @author yu 2019/12/20.
*/ */
public enum SpringMvcRequestAnnotations { public enum SpringMvcRequestAnnotationsEnum {
PATH_VARIABLE("PathVariable"), PATH_VARIABLE("PathVariable"),
REQ_PARAM ("RequestParam"), REQ_PARAM ("RequestParam"),
@ -15,13 +15,13 @@ public enum SpringMvcRequestAnnotations {
; ;
private String value; private String value;
SpringMvcRequestAnnotations(String value) { SpringMvcRequestAnnotationsEnum(String value) {
this.value = value; this.value = value;
} }
public static List<String> listSpringMvcRequestAnnotations() { public static List<String> listSpringMvcRequestAnnotations() {
List<String> annotations = new ArrayList<>(); List<String> annotations = new ArrayList<>();
for (SpringMvcRequestAnnotations annotation : SpringMvcRequestAnnotations.values()) { for (SpringMvcRequestAnnotationsEnum annotation : SpringMvcRequestAnnotationsEnum.values()) {
annotations.add(annotation.value); annotations.add(annotation.value);
} }
return annotations; return annotations;

View File

@ -0,0 +1,9 @@
package com.power.doc.constants;
/**
* @author yu 2019/12/22.
*/
public class ValidatorAnnotations {
public static final String VALID = "Valid";
}

View File

@ -0,0 +1,306 @@
package com.power.doc.helper;
import com.power.common.util.JsonFormatUtil;
import com.power.common.util.StringUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.constants.DocAnnotationConstants;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.constants.DocTags;
import com.power.doc.model.ApiReturn;
import com.power.doc.model.CustomRespField;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.power.doc.utils.JavaClassUtil;
import com.power.doc.utils.JavaFieldUtil;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.JavaMethod;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author yu 2019/12/21.
*/
public class JsonBuildHelper {
/**
* build return json
*
* @param method The JavaMethod object
* @return String
*/
public static String buildReturnJson(JavaMethod method, ProjectDocConfigBuilder builder) {
if ("void".equals(method.getReturnType().getFullyQualifiedName())) {
return "This api return nothing.";
}
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
String returnType = apiReturn.getGenericCanonicalName();
String typeName = apiReturn.getSimpleName();
return JsonFormatUtil.formatJson(buildJson(typeName, returnType, true, 0, new HashMap<>(),builder));
}
/**
* @param typeName type name
* @param genericCanonicalName genericCanonicalName
* @param isResp Response flag
* @param counter Recursive counter
* @return String
*/
private static String buildJson(String typeName, String genericCanonicalName,
boolean isResp, int counter, Map<String, String> registryClasses, ProjectDocConfigBuilder builder) {
if (registryClasses.containsKey(typeName) && counter > registryClasses.size()) {
return "{\"$ref\":\"...\"}";
}
registryClasses.put(typeName, typeName);
if (DocClassUtil.isMvcIgnoreParams(typeName)) {
if (DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName)) {
return "Forward or redirect to a page view.";
} else {
return "Error restful return.";
}
}
if (DocClassUtil.isPrimitive(typeName)) {
return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName));
}
StringBuilder data0 = new StringBuilder();
JavaClass cls = builder.getClassByName(typeName);
data0.append("{");
String[] globGicName = DocClassUtil.getSimpleGicName(genericCanonicalName);
StringBuilder data = new StringBuilder();
if (DocClassUtil.isCollection(typeName) || DocClassUtil.isArray(typeName)) {
data.append("[");
if (globGicName.length == 0) {
data.append("{\"object\":\"any object\"}");
data.append("]");
return data.toString();
}
String gNameTemp = globGicName[0];
String gName = DocClassUtil.isArray(typeName) ? gNameTemp.substring(0, gNameTemp.indexOf("[")) : globGicName[0];
if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(gName)) {
data.append("{\"waring\":\"You may use java.util.Object instead of display generics in the List\"}");
} else if (DocClassUtil.isPrimitive(gName)) {
data.append(DocUtil.jsonValueByType(gName)).append(",");
data.append(DocUtil.jsonValueByType(gName));
} else if (gName.contains("<")) {
String simple = DocClassUtil.getSimpleName(gName);
String json = buildJson(simple, gName, isResp, counter + 1, registryClasses,builder);
data.append(json);
} else if (DocClassUtil.isCollection(gName)) {
data.append("\"any object\"");
} else {
String json = buildJson(gName, gName, isResp, counter + 1, registryClasses,builder);
data.append(json);
}
data.append("]");
return data.toString();
} else if (DocClassUtil.isMap(typeName)) {
String gNameTemp = genericCanonicalName;
String[] getKeyValType = DocClassUtil.getMapKeyValueType(gNameTemp);
if (getKeyValType.length == 0) {
data.append("{\"mapKey\":{}}");
return data.toString();
}
if (!DocGlobalConstants.JAVA_STRING_FULLY.equals(getKeyValType[0])) {
throw new RuntimeException("Map's key can only use String for json,but you use " + getKeyValType[0]);
}
String gicName = gNameTemp.substring(gNameTemp.indexOf(",") + 1, gNameTemp.lastIndexOf(">"));
if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(gicName)) {
data.append("{").append("\"mapKey\":").append("{\"waring\":\"You may use java.util.Object for Map value; smart-doc can't be handle.\"}").append("}");
} else if (DocClassUtil.isPrimitive(gicName)) {
data.append("{").append("\"mapKey1\":").append(DocUtil.jsonValueByType(gicName)).append(",");
data.append("\"mapKey2\":").append(DocUtil.jsonValueByType(gicName)).append("}");
} else if (gicName.contains("<")) {
String simple = DocClassUtil.getSimpleName(gicName);
String json = buildJson(simple, gicName, isResp, counter + 1, registryClasses,builder);
data.append("{").append("\"mapKey\":").append(json).append("}");
} else {
data.append("{").append("\"mapKey\":").append(buildJson(gicName, gNameTemp, isResp, counter + 1, registryClasses,builder)).append("}");
}
return data.toString();
} else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(typeName)) {
if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(typeName)) {
data.append("{\"object\":\" any object\"},");
// throw new RuntimeException("Please do not return java.lang.Object directly in api interface.");
}
} else {
List<JavaField> fields = JavaClassUtil.getFields(cls, 0);
boolean isGenerics = JavaFieldUtil.checkGenerics(fields);
int i = 0;
out:
for (JavaField field : fields) {
String subTypeName = field.getType().getFullyQualifiedName();
String fieldName = field.getName();
if ("this$0".equals(fieldName) ||
"serialVersionUID".equals(fieldName) ||
DocClassUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field);
if (!isResp) {
if (tagsMap.containsKey(DocTags.IGNORE)) {
continue out;
}
}
List<JavaAnnotation> annotations = field.getAnnotations();
for (JavaAnnotation annotation : annotations) {
String annotationName = annotation.getType().getSimpleName();
if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(annotationName) && isResp) {
continue out;
} else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName) && isResp) {
if (null != annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP)) {
if (Boolean.FALSE.toString().equals(annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP).toString())) {
continue out;
}
} else if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.NAME_PROP).toString());
}
} else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(annotationName) && isResp) {
if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString());
}
}
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = field.getType().getGenericCanonicalName();
data0.append("\"").append(fieldName).append("\":");
if (DocClassUtil.isPrimitive(subTypeName)) {
String fieldValue = "";
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
fieldValue = tagsMap.get(DocTags.MOCK);
if ("String".equals(typeSimpleName)) {
fieldValue = DocUtil.handleJsonStr(fieldValue);
}
} else {
fieldValue = DocUtil.getValByTypeAndFieldName(typeSimpleName, field.getName());
}
CustomRespField customResponseField = builder.getCustomRespFieldMap().get(fieldName);
if (null != customResponseField) {
Object val = customResponseField.getValue();
if (null != val) {
if ("String".equals(typeSimpleName)) {
data0.append(DocUtil.handleJsonStr(String.valueOf(val))).append(",");
} else {
data0.append(val).append(",");
}
} else {
data0.append(fieldValue).append(",");
}
} else {
data0.append(fieldValue).append(",");
}
} else {
if (DocClassUtil.isCollection(subTypeName) || DocClassUtil.isArray(subTypeName)) {
fieldGicName = DocClassUtil.isArray(subTypeName) ? fieldGicName.substring(0, fieldGicName.indexOf("[")) : fieldGicName;
if (DocClassUtil.getSimpleGicName(fieldGicName).length == 0) {
data0.append("{\"object\":\"any object\"},");
continue out;
}
String gicName = DocClassUtil.getSimpleGicName(fieldGicName)[0];
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName)) {
data0.append("[").append("\"").append(buildJson(gicName, fieldGicName, isResp, counter + 1, registryClasses,builder)).append("\"]").append(",");
} else if (DocGlobalConstants.JAVA_LIST_FULLY.equals(gicName)) {
data0.append("{\"object\":\"any object\"},");
} else if (gicName.length() == 1) {
if (globGicName.length == 0) {
data0.append("{\"object\":\"any object\"},");
continue out;
}
String gicName1 = (i < globGicName.length) ? globGicName[i] : globGicName[globGicName.length - 1];
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("[").append("\"").append(buildJson(gicName1, gicName1, isResp, counter + 1, registryClasses,builder)).append("\"]").append(",");
} else {
if (!typeName.equals(gicName1)) {
data0.append("[").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, counter + 1, registryClasses,builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else {
if (!typeName.equals(gicName)) {
if (DocClassUtil.isMap(gicName)) {
data0.append("[{\"mapKey\":{}}],");
continue out;
}
data0.append("[").append(buildJson(gicName, fieldGicName, isResp, counter + 1, registryClasses,builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else if (DocClassUtil.isMap(subTypeName)) {
if (DocClassUtil.isMap(fieldGicName)) {
data0.append("{").append("\"mapKey\":{}},");
continue out;
}
String gicName = fieldGicName.substring(fieldGicName.indexOf(",") + 1, fieldGicName.indexOf(">"));
if (gicName.length() == 1) {
String gicName1 = (i < globGicName.length) ? globGicName[i] : globGicName[globGicName.length - 1];
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("{").append("\"mapKey\":\"").append(buildJson(gicName1, gicName1, isResp, counter + 1, registryClasses,builder)).append("\"},");
} else {
if (!typeName.equals(gicName1)) {
data0.append("{").append("\"mapKey\":").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, counter + 1, registryClasses,builder)).append("},");
} else {
data0.append("{\"mapKey\":{}},");
}
}
} else {
data0.append("{").append("\"mapKey\":").append(buildJson(gicName, fieldGicName, isResp, counter + 1, registryClasses,builder)).append("},");
}
} else if (subTypeName.length() == 1) {
if (!typeName.equals(genericCanonicalName)) {
String gicName = globGicName[i];
if (DocClassUtil.isPrimitive(gicName)) {
data0.append(DocUtil.jsonValueByType(gicName)).append(",");
} else {
String simple = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simple, gicName, isResp, counter + 1, registryClasses,builder)).append(",");
}
} else {
data0.append("{\"waring\":\"You may have used non-display generics.\"},");
}
i++;
} else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
if (isGenerics) {
data0.append("{\"object\":\"any object\"},");
} else if (i < globGicName.length) {
String gicName = globGicName[i];
if (!typeName.equals(genericCanonicalName)) {
if (DocClassUtil.isPrimitive(gicName)) {
data0.append("\"").append(buildJson(gicName, genericCanonicalName, isResp, counter + 1, registryClasses,builder)).append("\",");
} else {
String simpleName = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simpleName, gicName, isResp, counter + 1, registryClasses,builder)).append(",");
}
} else {
data0.append("{\"waring\":\"You may have used non-display generics.\"},");
}
} else {
data0.append("{\"waring\":\"You may have used non-display generics.\"},");
}
if (!isGenerics) i++;
} else if (typeName.equals(subTypeName)) {
data0.append("{\"$ref\":\"...\"}").append(",");
} else {
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(subTypeName);
if (!isResp && javaClass.isEnum()) {
Object value = JavaClassUtil.getEnumValue(javaClass, Boolean.FALSE);
data0.append(value).append(",");
} else {
data0.append(buildJson(subTypeName, fieldGicName,isResp, counter + 1, registryClasses,builder)).append(",");
}
}
}
}
}
if (data0.toString().contains(",")) {
data0.deleteCharAt(data0.lastIndexOf(","));
}
data0.append("}");
return data0.toString();
}
}

View File

@ -0,0 +1,305 @@
package com.power.doc.helper;
import com.power.common.util.CollectionUtil;
import com.power.common.util.StringUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.constants.DocAnnotationConstants;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.constants.DocTags;
import com.power.doc.model.ApiParam;
import com.power.doc.model.CustomRespField;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.power.doc.utils.JavaClassUtil;
import com.power.doc.utils.JavaFieldUtil;
import com.thoughtworks.qdox.model.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND;
/**
* @author yu 2019/12/21.
*/
public class ParamsBuildHelper {
public static List<ApiParam> buildParams(String className, String pre, int i, String isRequired,
Map<String, CustomRespField> responseFieldMap, boolean isResp,
Map<String, String> registryClasses,ProjectDocConfigBuilder projectBuilder) {
if (StringUtil.isEmpty(className)) {
throw new RuntimeException("Class name can't be null or empty.");
}
// Check circular reference
List<ApiParam> paramList = new ArrayList<>();
if (registryClasses.containsKey(className) && i > registryClasses.size()) {
return paramList;
}
// Registry class
registryClasses.put(className, className);
String simpleName = DocClassUtil.getSimpleName(className);
String[] globGicName = DocClassUtil.getSimpleGicName(className);
JavaClass cls = projectBuilder.getClassByName(simpleName);
List<JavaField> fields = JavaClassUtil.getFields(cls, 0);
int n = 0;
if (DocClassUtil.isPrimitive(simpleName)) {
paramList.addAll(primitiveReturnRespComment(DocClassUtil.processTypeNameForParams(simpleName)));
} else if (DocClassUtil.isCollection(simpleName) || DocClassUtil.isArray(simpleName)) {
if (!DocClassUtil.isCollection(globGicName[0])) {
String gicName = globGicName[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
paramList.addAll(buildParams(gicName, pre, i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else if (DocClassUtil.isMap(simpleName)) {
if (globGicName.length == 2) {
paramList.addAll(buildParams(globGicName[1], pre, i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(className)) {
ApiParam param = ApiParam.of().setField(pre + "any object").setType("object");
if (StringUtil.isEmpty(isRequired)) {
param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION);
} else {
param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setRequired(false).setVersion(DocGlobalConstants.DEFAULT_VERSION);
}
paramList.add(param);
} else {
boolean isGenerics = JavaFieldUtil.checkGenerics(fields);
out:
for (JavaField field : fields) {
String fieldName = field.getName();
String subTypeName = field.getType().getFullyQualifiedName();
if ("this$0".equals(fieldName) ||
"serialVersionUID".equals(fieldName) ||
DocClassUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = field.getType().getGenericCanonicalName();
List<JavaAnnotation> javaAnnotations = field.getAnnotations();
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field);
String since = DocGlobalConstants.DEFAULT_VERSION;//since tag value
if (!isResp) {
pre:
if (tagsMap.containsKey(DocTags.IGNORE)) {
continue out;
} else if (tagsMap.containsKey(DocTags.SINCE)) {
since = tagsMap.get(DocTags.SINCE);
}
} else {
if (tagsMap.containsKey(DocTags.SINCE)) {
since = tagsMap.get(DocTags.SINCE);
}
}
boolean strRequired = false;
int annotationCounter = 0;
an:
for (JavaAnnotation annotation : javaAnnotations) {
String annotationName = annotation.getType().getSimpleName();
if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(annotationName) && isResp) {
continue out;
} else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName) && isResp) {
if (null != annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP)) {
if (Boolean.FALSE.toString().equals(annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP).toString())) {
continue out;
}
} else if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.NAME_PROP).toString());
}
} else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(annotationName) && isResp) {
if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString());
}
} else if (DocClassUtil.isJSR303Required(annotationName)) {
strRequired = true;
annotationCounter++;
break an;
}
}
if (annotationCounter < 1) {
doc:
if (tagsMap.containsKey(DocTags.REQUIRED)) {
strRequired = true;
break doc;
}
}
//cover comment
CustomRespField customResponseField = responseFieldMap.get(field.getName());
String comment;
if (null != customResponseField && StringUtil.isNotEmpty(customResponseField.getDesc())) {
comment = customResponseField.getDesc();
} else {
comment = field.getComment();
}
if (StringUtil.isNotEmpty(comment)) {
comment = DocUtil.replaceNewLineToHtmlBr(comment);
}
if (DocClassUtil.isPrimitive(subTypeName)) {
ApiParam param = ApiParam.of().setField(pre + fieldName);
String processedType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase());
param.setType(processedType);
if (StringUtil.isNotEmpty(comment)) {
commonHandleParam(paramList, param, isRequired, comment, since, strRequired);
} else {
commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired);
}
} else {
ApiParam param = ApiParam.of().setField(pre + fieldName);
JavaClass javaClass = projectBuilder.getClassByName(subTypeName);
String enumComments = javaClass.getComment();
if (StringUtil.isNotEmpty(enumComments) && javaClass.isEnum()) {
enumComments = DocUtil.replaceNewLineToHtmlBr(enumComments);
comment = comment + "(See: " + enumComments + ")";
}
String processedType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase());
param.setType(processedType);
if (!isResp && javaClass.isEnum()) {
List<JavaMethod> methods = javaClass.getMethods();
int index = 0;
String reTypeName = "string";
enumOut:
for (JavaMethod method : methods) {
JavaType type = method.getReturnType();
reTypeName = type.getCanonicalName();
List<JavaAnnotation> javaAnnotationList = method.getAnnotations();
for (JavaAnnotation annotation : javaAnnotationList) {
if (annotation.getType().getSimpleName().contains("JsonValue")) {
break enumOut;
}
}
if (CollectionUtil.isEmpty(javaAnnotations) && index < 1) {
break enumOut;
}
index++;
}
param.setType(DocClassUtil.processTypeNameForParams(reTypeName));
}
if (StringUtil.isNotEmpty(comment)) {
commonHandleParam(paramList, param, isRequired, comment, since, strRequired);
} else {
commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired);
}
StringBuilder preBuilder = new StringBuilder();
for (int j = 0; j < i; j++) {
preBuilder.append(DocGlobalConstants.FIELD_SPACE);
}
preBuilder.append("└─");
if (DocClassUtil.isMap(subTypeName)) {
String gNameTemp = field.getType().getGenericCanonicalName();
if (DocClassUtil.isMap(gNameTemp)) {
ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object")
.setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param1);
continue;
}
String valType = DocClassUtil.getMapKeyValueType(gNameTemp)[1];
if (!DocClassUtil.isPrimitive(valType)) {
if (valType.length() == 1) {
String gicName = (n < globGicName.length) ? globGicName[n] : globGicName[globGicName.length - 1];
if (!DocClassUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
paramList.addAll(buildParams(gicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else {
paramList.addAll(buildParams(valType, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
}
} else if (DocClassUtil.isCollection(subTypeName)) {
String gNameTemp = field.getType().getGenericCanonicalName();
String[] gNameArr = DocClassUtil.getSimpleGicName(gNameTemp);
if (gNameArr.length == 0) {
continue out;
}
String gName = DocClassUtil.getSimpleGicName(gNameTemp)[0];
if (!DocClassUtil.isPrimitive(gName)) {
if (!simpleName.equals(gName) && !gName.equals(simpleName)) {
if (gName.length() == 1) {
int len = globGicName.length;
if (len > 0) {
String gicName = (n < len) ? globGicName[n] : globGicName[len - 1];
if (!DocClassUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
paramList.addAll(buildParams(gicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
}
} else {
paramList.addAll(buildParams(gName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
}
}
} 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")
.setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param1);
} else if (!simpleName.equals(className)) {
if (n < globGicName.length) {
String gicName = globGicName[n];
String simple = DocClassUtil.getSimpleName(gicName);
if (DocClassUtil.isPrimitive(simple)) {
//do nothing
} else if (gicName.contains("<")) {
if (DocClassUtil.isCollection(simple)) {
String gName = DocClassUtil.getSimpleGicName(gicName)[0];
if (!DocClassUtil.isPrimitive(gName)) {
paramList.addAll(buildParams(gName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else if (DocClassUtil.isMap(simple)) {
String valType = DocClassUtil.getMapKeyValueType(gicName)[1];
if (!DocClassUtil.isPrimitive(valType)) {
paramList.addAll(buildParams(valType, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else {
paramList.addAll(buildParams(gicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else {
paramList.addAll(buildParams(gicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else {
paramList.addAll(buildParams(subTypeName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
n++;
}
} else if (DocClassUtil.isArray(subTypeName)) {
fieldGicName = fieldGicName.substring(0, fieldGicName.indexOf("["));
if (className.equals(fieldGicName)) {
//do nothing
} else if (!DocClassUtil.isPrimitive(fieldGicName)) {
paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
} else if (simpleName.equals(subTypeName)) {
//do nothing
} else {
if (!javaClass.isEnum()) {
paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), i + 1, isRequired, responseFieldMap, isResp, registryClasses,projectBuilder));
}
}
}
}
}
return paramList;
}
public static List<ApiParam> primitiveReturnRespComment(String typeName) {
StringBuilder comments = new StringBuilder();
comments.append("The api directly returns the ").append(typeName).append(" type value.");
ApiParam apiParam = ApiParam.of().setField("No field")
.setType(typeName).setDesc(comments.toString()).setVersion(DocGlobalConstants.DEFAULT_VERSION);
List<ApiParam> paramList = new ArrayList<>();
paramList.add(apiParam);
return paramList;
}
private static void commonHandleParam(List<ApiParam> paramList, ApiParam param, String isRequired, String comment, String since, boolean strRequired) {
if (StringUtil.isEmpty(isRequired)) {
param.setDesc(comment).setVersion(since);
paramList.add(param);
} else {
param.setDesc(comment).setVersion(since).setRequired(strRequired);
paramList.add(param);
}
}
}

View File

@ -0,0 +1,104 @@
package com.power.doc.template;
import com.power.common.util.CollectionUtil;
import com.power.common.util.StringUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.helper.ParamsBuildHelper;
import com.power.doc.model.*;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* @author yu 2019/12/21.
*/
public interface FrameworkDocBuildTemplate {
default String createDocRenderHeaders(List<ApiReqHeader> headers, boolean isAdoc) {
StringBuilder builder = new StringBuilder();
if (CollectionUtil.isEmpty(headers)) {
headers = new ArrayList<>(0);
}
for (ApiReqHeader header : headers) {
if (isAdoc) {
builder.append("|");
}
builder.append(header.getName()).append("|")
.append(header.getType()).append("|")
.append(header.getDesc()).append("|")
.append(header.isRequired()).append("|")
.append(header.getSince()).append("\n");
}
return builder.toString();
}
default void handleApiDoc(JavaClass cls, List<ApiDoc> apiDocList, List<ApiMethodDoc> apiMethodDocs, int order, boolean isUseMD5) {
String controllerName = cls.getName();
ApiDoc apiDoc = new ApiDoc();
apiDoc.setOrder(order);
apiDoc.setName(controllerName);
apiDoc.setAlias(controllerName);
if (isUseMD5) {
String name = DocUtil.handleId(apiDoc.getName());
apiDoc.setAlias(name);
}
apiDoc.setDesc(cls.getComment());
apiDoc.setList(apiMethodDocs);
apiDocList.add(apiDoc);
}
default List<ApiParam> buildReturnApiParams(JavaMethod method, String controllerName, ProjectDocConfigBuilder projectBuilder) {
if ("void".equals(method.getReturnType().getFullyQualifiedName())) {
return null;
}
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
String returnType = apiReturn.getGenericCanonicalName();
String typeName = apiReturn.getSimpleName();
if (this.ignoreReturnObject(typeName)) {
throw new RuntimeException("Smart-doc can't support " + typeName + " as method return in " + controllerName);
}
if (DocClassUtil.isPrimitive(typeName)) {
return ParamsBuildHelper.primitiveReturnRespComment(DocClassUtil.processTypeNameForParams(typeName));
}
if (DocClassUtil.isCollection(typeName)) {
if (returnType.contains("<")) {
String gicName = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">"));
if (DocClassUtil.isPrimitive(gicName)) {
return ParamsBuildHelper.primitiveReturnRespComment("array of " + DocClassUtil.processTypeNameForParams(gicName));
}
return ParamsBuildHelper.buildParams(gicName, "", 0, null, projectBuilder.getCustomRespFieldMap(), true, new HashMap<>(), projectBuilder);
} else {
return null;
}
}
if (DocClassUtil.isMap(typeName)) {
String[] keyValue = DocClassUtil.getMapKeyValueType(returnType);
if (keyValue.length == 0) {
return null;
}
if (DocClassUtil.isPrimitive(keyValue[1])) {
return ParamsBuildHelper.primitiveReturnRespComment("key value");
}
return ParamsBuildHelper.buildParams(keyValue[1], "", 0, null, projectBuilder.getCustomRespFieldMap(), true, new HashMap<>(), projectBuilder);
}
if (StringUtil.isNotEmpty(returnType)) {
return ParamsBuildHelper.buildParams(returnType, "", 0, null, projectBuilder.getCustomRespFieldMap(), true, new HashMap<>(), projectBuilder);
}
return null;
}
List<ApiDoc> getApiData(ProjectDocConfigBuilder projectBuilder);
boolean ignoreReturnObject(String typeName);
}

View File

@ -0,0 +1,420 @@
package com.power.doc.template;
import com.power.common.util.JsonFormatUtil;
import com.power.common.util.StringUtil;
import com.power.common.util.UrlUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.constants.*;
import com.power.doc.helper.JsonBuildHelper;
import com.power.doc.helper.ParamsBuildHelper;
import com.power.doc.model.*;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUrlUtil;
import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.expression.AnnotationValue;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND;
import static com.power.doc.constants.DocTags.IGNORE;
/**
* @author yu 2019/12/21.
*/
public class SpringBootDocBuildTemplate implements FrameworkDocBuildTemplate {
private List<ApiReqHeader> headers;
@Override
public List<ApiDoc> getApiData(ProjectDocConfigBuilder projectBuilder) {
ApiConfig apiConfig = projectBuilder.getApiConfig();
this.headers = apiConfig.getRequestHeaders();
List<ApiDoc> apiDocList = new ArrayList<>();
int order = 0;
for (JavaClass cls : projectBuilder.getJavaProjectBuilder().getClasses()) {
if (checkController(cls)) {
if (StringUtil.isNotEmpty(apiConfig.getPackageFilters())) {
if (DocUtil.isMatch(apiConfig.getPackageFilters(), cls.getCanonicalName())) {
order++;
List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls,apiConfig,projectBuilder);
this.handleApiDoc(cls, apiDocList, apiMethodDocs,order,apiConfig.isMd5EncryptedHtmlName());
}
} else {
order++;
List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls,apiConfig,projectBuilder);
this.handleApiDoc(cls, apiDocList, apiMethodDocs,order,apiConfig.isMd5EncryptedHtmlName());
}
}
}
return apiDocList;
}
@Override
public boolean ignoreReturnObject(String typeName) {
if (DocClassUtil.isMvcIgnoreParams(typeName)) {
if (DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName)) {
return true;
}
}
return false;
}
private List<ApiMethodDoc> buildControllerMethod(final JavaClass cls,ApiConfig apiConfig,ProjectDocConfigBuilder projectBuilder) {
String clazName = cls.getCanonicalName();
List<JavaAnnotation> classAnnotations = cls.getAnnotations();
String baseUrl = "";
for (JavaAnnotation annotation : classAnnotations) {
String annotationName = annotation.getType().getName();
if (DocAnnotationConstants.REQUEST_MAPPING.equals(annotationName) || DocGlobalConstants.REQUEST_MAPPING_FULLY.equals(annotationName)) {
baseUrl = StringUtil.removeQuotes(annotation.getNamedParameter("value").toString());
}
}
List<JavaMethod> methods = cls.getMethods();
List<ApiMethodDoc> methodDocList = new ArrayList<>(methods.size());
int methodOrder = 0;
for (JavaMethod method : methods) {
List<ApiReqHeader> apiReqHeaders = new ArrayList<>();
if (method.getModifiers().contains("private")) {
continue;
}
if (StringUtil.isEmpty(method.getComment()) && apiConfig.isStrict()) {
throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName());
}
methodOrder++;
ApiMethodDoc apiMethodDoc = new ApiMethodDoc();
apiMethodDoc.setOrder(methodOrder);
apiMethodDoc.setDesc(method.getComment());
apiMethodDoc.setName(method.getName());
String methodUid = DocUtil.handleId(clazName + method.getName()) ;
apiMethodDoc.setMethodId(methodUid);
String apiNoteValue = DocUtil.getNormalTagComments(method, DocTags.API_NOTE, cls.getName());
if (StringUtil.isEmpty(apiNoteValue)) {
apiNoteValue = method.getComment();
}
String authorValue = DocUtil.getNormalTagComments(method, DocTags.AUTHOR, cls.getName());
if (apiConfig.isShowAuthor() && StringUtil.isNotEmpty(authorValue)) {
apiMethodDoc.setAuthor(authorValue);
}
apiMethodDoc.setDetail(apiNoteValue);
List<JavaAnnotation> annotations = method.getAnnotations();
String url = null;
String methodType = null;
boolean isPostMethod = false;
int methodCounter = 0;
for (JavaAnnotation annotation : annotations) {
String annotationName = annotation.getType().getName();
if (SpringMvcAnnotations.REQUEST_MAPPING.equals(annotationName) || DocGlobalConstants.REQUEST_MAPPING_FULLY.equals(annotationName)) {
url = DocUtil.handleMappingValue(annotation);
Object nameParam = annotation.getNamedParameter("method");
if (null != nameParam) {
methodType = nameParam.toString();
methodType = DocUtil.handleHttpMethod(methodType);
if ("POST".equals(methodType) || "PUT".equals(methodType)) {
isPostMethod = true;
}
} else {
methodType = Methods.GET.getValue();
}
methodCounter++;
} else if (SpringMvcAnnotations.GET_MAPPING.equals(annotationName) || DocGlobalConstants.GET_MAPPING_FULLY.equals(annotationName)) {
url = DocUtil.handleMappingValue(annotation);
methodType = Methods.GET.getValue();
methodCounter++;
} else if (SpringMvcAnnotations.POST_MAPPING.equals(annotationName) || DocGlobalConstants.POST_MAPPING_FULLY.equals(annotationName)) {
url = DocUtil.handleMappingValue(annotation);
methodType = Methods.POST.getValue();
methodCounter++;
isPostMethod = true;
} else if (SpringMvcAnnotations.PUT_MAPPING.equals(annotationName) || DocGlobalConstants.PUT_MAPPING_FULLY.equals(annotationName)) {
url = DocUtil.handleMappingValue(annotation);
methodType = Methods.PUT.getValue();
methodCounter++;
} else if (SpringMvcAnnotations.DELETE_MAPPING.equals(annotationName) || DocGlobalConstants.DELETE_MAPPING_FULLY.equals(annotationName)) {
url = DocUtil.handleMappingValue(annotation);
methodType = Methods.DELETE.getValue();
methodCounter++;
}
}
for (JavaParameter javaParameter : method.getParameters()) {
List<JavaAnnotation> javaAnnotations = javaParameter.getAnnotations();
String className = method.getDeclaringClass().getCanonicalName();
Map<String, String> paramMap = DocUtil.getParamsComments(method, DocTags.PARAM, className);
String paramName = javaParameter.getName();
ApiReqHeader apiReqHeader;
for (JavaAnnotation annotation : javaAnnotations) {
String annotationName = annotation.getType().getName();
if (SpringMvcAnnotations.REQUEST_HERDER.equals(annotationName)) {
apiReqHeader = new ApiReqHeader();
Map<String, Object> requestHeaderMap = annotation.getNamedParameterMap();
if (requestHeaderMap.get(DocAnnotationConstants.VALUE_PROP) != null) {
apiReqHeader.setName(StringUtil.removeQuotes((String) requestHeaderMap.get(DocAnnotationConstants.VALUE_PROP)));
} else {
apiReqHeader.setName(paramName);
}
StringBuilder desc = new StringBuilder();
String comments = paramMap.get(paramName);
desc.append(comments);
if (requestHeaderMap.get(DocAnnotationConstants.DEFAULT_VALUE_PROP) != null) {
desc.append("(defaultValue: ")
.append(StringUtil.removeQuotes((String) requestHeaderMap.get(DocAnnotationConstants.DEFAULT_VALUE_PROP)))
.append(")");
}
apiReqHeader.setDesc(desc.toString());
if (requestHeaderMap.get(DocAnnotationConstants.REQUIRED_PROP) != null) {
apiReqHeader.setRequired(!Boolean.FALSE.toString().equals(requestHeaderMap.get(DocAnnotationConstants.REQUIRED_PROP)));
} else {
apiReqHeader.setRequired(true);
}
String typeName = javaParameter.getType().getValue().toLowerCase();
apiReqHeader.setType(DocClassUtil.processTypeNameForParams(typeName));
apiReqHeaders.add(apiReqHeader);
break;
}
}
}
apiMethodDoc.setRequestHeaders(apiReqHeaders);
if (methodCounter > 0) {
// if ("void".equals(method.getReturnType().getFullyQualifiedName())) {
// throw new RuntimeException(method.getName() + " method in " + cls.getCanonicalName() + " can't be return type 'void'");
// }
if (null != method.getTagByName(IGNORE)) {
continue;
}
url = StringUtil.removeQuotes(url);
String[] urls = url.split(",");
if (urls.length > 1) {
url = DocUrlUtil.getMvcUrls(projectBuilder.getServerUrl(),baseUrl, Arrays.asList(urls));
} else {
url = UrlUtil.simplifyUrl(projectBuilder.getServerUrl() + "/" + baseUrl + "/" + url);
}
apiMethodDoc.setType(methodType);
apiMethodDoc.setUrl(url);
List<ApiParam> requestParams = requestParams(method, DocTags.PARAM, cls.getCanonicalName(),projectBuilder);
apiMethodDoc.setRequestParams(requestParams);
String requestJson = buildReqJson(method,apiMethodDoc,isPostMethod);
if (StringUtil.isNotEmpty(requestJson) && !requestJson.startsWith("http")) {
requestJson = JsonFormatUtil.formatJson(requestJson);
}
apiMethodDoc.setRequestUsage(requestJson);
apiMethodDoc.setResponseUsage(JsonBuildHelper.buildReturnJson(method,projectBuilder));
List<ApiParam> responseParams = buildReturnApiParams(method, cls.getGenericFullyQualifiedName(),projectBuilder);
apiMethodDoc.setResponseParams(responseParams);
List<ApiReqHeader> allApiReqHeaders;
if (this.headers != null) {
allApiReqHeaders = Stream.of(this.headers, apiReqHeaders)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
} else {
allApiReqHeaders = apiReqHeaders;
}
//reduce create in template
apiMethodDoc.setHeaders(this.createDocRenderHeaders(allApiReqHeaders, apiConfig.isAdoc()));
apiMethodDoc.setRequestHeaders(allApiReqHeaders);
methodDocList.add(apiMethodDoc);
}
}
return methodDocList;
}
String buildReqJson(JavaMethod method, ApiMethodDoc apiMethodDoc, Boolean isPostMethod){
return null;
}
/**
* Get tag
*
* @param javaMethod The JavaMethod method
* @param tagName The doc tag name
* @param className The class name
* @return String
*/
private List<ApiParam> requestParams(final JavaMethod javaMethod, final String tagName, final String className,ProjectDocConfigBuilder builder) {
boolean isStrict = builder.getApiConfig().isStrict();
Map<String, CustomRespField> responseFieldMap = new HashMap<>();
Map<String, String> paramTagMap = DocUtil.getParamsComments(javaMethod, tagName, className);
List<JavaParameter> parameterList = javaMethod.getParameters();
if (parameterList.size() < 1) {
return null;
}
List<ApiParam> paramList = new ArrayList<>();
int requestBodyCounter = 0;
List<ApiParam> reqBodyParamsList = new ArrayList<>();
out:
for (JavaParameter parameter : parameterList) {
boolean paramAdded = false;
String paramName = parameter.getName();
String typeName = parameter.getType().getGenericCanonicalName();
String simpleName = parameter.getType().getValue().toLowerCase();
String fullTypeName = parameter.getType().getFullyQualifiedName();
JavaClass javaClass = builder.getClassByName(fullTypeName);
if (!DocClassUtil.isMvcIgnoreParams(typeName)) {
if (!paramTagMap.containsKey(paramName) && DocClassUtil.isPrimitive(fullTypeName) && isStrict) {
throw new RuntimeException("ERROR: Unable to find javadoc @param for actual param \""
+ paramName + "\" in method " + javaMethod.getName() + " from " + className);
}
String comment = paramTagMap.get(paramName);
if (StringUtil.isEmpty(comment)) {
comment = NO_COMMENTS_FOUND;
}
List<JavaAnnotation> annotations = parameter.getAnnotations();
if (annotations.size() == 0) {
//default set required is true
if (DocClassUtil.isCollection(fullTypeName) || DocClassUtil.isArray(fullTypeName)) {
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
String gicName = gicNameArr[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
String typeTemp = "";
if (DocClassUtil.isPrimitive(gicName)) {
typeTemp = " of " + DocClassUtil.processTypeNameForParams(gicName);
ApiParam param = ApiParam.of().setField(paramName)
.setType(DocClassUtil.processTypeNameForParams(simpleName) + typeTemp)
.setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
} else {
ApiParam param = ApiParam.of().setField(paramName)
.setType(DocClassUtil.processTypeNameForParams(simpleName) + typeTemp)
.setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
paramList.addAll(ParamsBuildHelper.buildParams(gicNameArr[0], "└─", 1, "true", responseFieldMap, false, new HashMap<>(),builder));
}
} else if (DocClassUtil.isPrimitive(simpleName)) {
ApiParam param = ApiParam.of().setField(paramName)
.setType(DocClassUtil.processTypeNameForParams(simpleName))
.setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
} else if (DocGlobalConstants.JAVA_MAP_FULLY.equals(typeName)) {
ApiParam param = ApiParam.of().setField(paramName)
.setType("map").setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
} else if (javaClass.isEnum()) {
ApiParam param = ApiParam.of().setField(paramName)
.setType("string").setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
} else {
paramList.addAll(ParamsBuildHelper.buildParams(fullTypeName, "", 0, "true", responseFieldMap, false, new HashMap<>(),builder));
}
}
for (JavaAnnotation annotation : annotations) {
String required = "true";
AnnotationValue annotationRequired = annotation.getProperty(DocAnnotationConstants.REQUIRED_PROP);
if (null != annotationRequired) {
required = annotationRequired.toString();
}
String annotationName = annotation.getType().getName();
if (SpringMvcAnnotations.REQUEST_BODY.equals(annotationName) || (ValidatorAnnotations.VALID.equals(annotationName) && annotations.size() == 1)) {
if (requestBodyCounter > 0) {
throw new RuntimeException("You have use @RequestBody Passing multiple variables for method "
+ javaMethod.getName() + " in " + className + ",@RequestBody annotation could only bind one variables.");
}
if (DocClassUtil.isPrimitive(fullTypeName)) {
ApiParam bodyParam = ApiParam.of()
.setField(paramName).setType(DocClassUtil.processTypeNameForParams(simpleName))
.setDesc(comment).setRequired(Boolean.valueOf(required));
reqBodyParamsList.add(bodyParam);
} else {
if (DocClassUtil.isCollection(fullTypeName) || DocClassUtil.isArray(fullTypeName)) {
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
String gicName = gicNameArr[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
if (DocClassUtil.isPrimitive(gicName)) {
ApiParam bodyParam = ApiParam.of()
.setField(paramName).setType(DocClassUtil.processTypeNameForParams(simpleName))
.setDesc(comment).setRequired(Boolean.valueOf(required)).setVersion(DocGlobalConstants.DEFAULT_VERSION);
reqBodyParamsList.add(bodyParam);
} else {
reqBodyParamsList.addAll(ParamsBuildHelper.buildParams(gicNameArr[0], "", 0, "true", responseFieldMap, false, new HashMap<>(),builder));
}
} else if (DocClassUtil.isMap(fullTypeName)) {
if (DocGlobalConstants.JAVA_MAP_FULLY.equals(typeName)) {
ApiParam apiParam = ApiParam.of().setField(paramName).setType("map")
.setDesc(comment).setRequired(Boolean.valueOf(required)).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(apiParam);
continue out;
}
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
reqBodyParamsList.addAll(ParamsBuildHelper.buildParams(gicNameArr[1], "", 0, "true", responseFieldMap, false, new HashMap<>(),builder));
} else {
reqBodyParamsList.addAll(ParamsBuildHelper.buildParams(typeName, "", 0, "true", responseFieldMap, false, new HashMap<>(),builder));
}
}
requestBodyCounter++;
} else {
if (paramAdded) {
continue;
}
List<String> validatorAnnotations = DocValidatorAnnotationEnum.listValidatorAnnotations();
if (SpringMvcAnnotations.REQUEST_PARAM.equals(annotationName) ||
DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) {
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);
if (null != annotationValue) {
paramName = StringUtil.removeQuotes(annotationValue.toString());
}
AnnotationValue annotationOfName = annotation.getProperty(DocAnnotationConstants.NAME_PROP);
if (null != annotationOfName) {
paramName = StringUtil.removeQuotes(annotationOfName.toString());
}
ApiParam param = ApiParam.of().setField(paramName)
.setType(DocClassUtil.processTypeNameForParams(simpleName))
.setDesc(comment).setRequired(Boolean.valueOf(required)).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
paramAdded = true;
} else if (validatorAnnotations.contains(annotationName)) {
ApiParam param = ApiParam.of().setField(paramName)
.setType(DocClassUtil.processTypeNameForParams(simpleName))
.setDesc(comment).setRequired(Boolean.valueOf(required)).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param);
paramAdded = true;
} else {
continue;
}
}
}
}
}
if (requestBodyCounter > 0) {
paramList.addAll(reqBodyParamsList);
return paramList;
}
return paramList;
}
/**
* check controller
*
* @param cls
* @return
*/
private boolean checkController(JavaClass cls) {
List<JavaAnnotation> classAnnotations = cls.getAnnotations();
for (JavaAnnotation annotation : classAnnotations) {
String annotationName = annotation.getType().getName();
if (DocAnnotationConstants.SHORT_CONTROLLER.equals(annotationName)
|| DocAnnotationConstants.SHORT_REST_CONTROLLER.equals(annotationName)
|| DocGlobalConstants.REST_CONTROLLER_FULLY.equals(annotationName)
|| DocGlobalConstants.CONTROLLER_FULLY.equals(annotationName)
) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,26 @@
package com.power.doc.utils;
import com.power.common.util.StringUtil;
import com.power.common.util.UrlUtil;
import java.util.List;
/**
* @author yu 2019/12/22.
*/
public class DocUrlUtil {
public static String getMvcUrls(String baseServer, String baseUrl, List<String> urls) {
StringBuilder sb = new StringBuilder();
int size = urls.size();
for (int i = 0; i < size; i++) {
String url = baseServer + "/" + baseUrl + "/" + StringUtil.trimBlank(urls.get(i))
.replace("[", "").replace("]", "");
sb.append(UrlUtil.simplifyUrl(url));
if (i < size - 1) {
sb.append(";\t");
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,67 @@
package com.power.doc.utils;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import java.util.ArrayList;
import java.util.List;
/**
* Handle JavaClass
* @author yu 2019/12/21.
*/
public class JavaClassUtil {
/**
* Get fields
*
* @param cls1 The JavaClass object
* @param i Recursive counter
* @return list of JavaField
*/
public static List<JavaField> getFields(JavaClass cls1, int i) {
List<JavaField> fieldList = new ArrayList<>();
if (null == cls1) {
return fieldList;
} else if ("Object".equals(cls1.getSimpleName()) || "Timestamp".equals(cls1.getSimpleName()) ||
"Date".equals(cls1.getSimpleName()) || "Locale".equals(cls1.getSimpleName())) {
return fieldList;
} else {
JavaClass pcls = cls1.getSuperJavaClass();
fieldList.addAll(getFields(pcls, i));
fieldList.addAll(cls1.getFields());
}
return fieldList;
}
/**
* get enum value
* @param javaClass enum class
* @param returnEnum is return method
* @return
*/
public static Object getEnumValue(JavaClass javaClass, boolean returnEnum) {
List<JavaField> javaFields = javaClass.getEnumConstants();
Object value = null;
int index = 0;
for (JavaField javaField : javaFields) {
String simpleName = javaField.getType().getSimpleName();
StringBuilder valueBuilder = new StringBuilder();
valueBuilder.append("\"").append(javaField.getName()).append("\"").toString();
if (returnEnum) {
value = valueBuilder.toString();
return value;
}
if (!DocClassUtil.isPrimitive(simpleName) && index < 1) {
if (null != javaField.getEnumConstantArguments()) {
value = javaField.getEnumConstantArguments().get(0);
} else {
value = valueBuilder.toString();
}
}
index++;
}
return value;
}
}

View File

@ -0,0 +1,26 @@
package com.power.doc.utils;
import com.thoughtworks.qdox.model.JavaField;
import java.util.List;
/**
* @author yu 2019/12/21.
*/
public class JavaFieldUtil {
/**
*
* @param fields
* @return
*/
public static boolean checkGenerics(List<JavaField> fields) {
checkGenerics:
for (JavaField field : fields) {
if (field.getType().getFullyQualifiedName().length() == 1) {
return true;
}
}
return false;
}
}

View File

@ -29,6 +29,7 @@ public class DocClassUtilTest {
@Test @Test
public void testProcessReturnType() { public void testProcessReturnType() {
String typeName = "org.springframework.web.context.request.async.WebAsyncTask"; String typeName = "org.springframework.web.context.request.async.WebAsyncTask";
System.out.println(typeName.hashCode());
ApiReturn apiReturn = DocClassUtil.processReturnType(typeName); ApiReturn apiReturn = DocClassUtil.processReturnType(typeName);
System.out.println(apiReturn.getGenericCanonicalName()); System.out.println(apiReturn.getGenericCanonicalName());
System.out.println(apiReturn.getSimpleName()); System.out.println(apiReturn.getSimpleName());