This commit is contained in:
oppofind 2020-10-17 21:53:08 +08:00
parent f1c3608b7e
commit d19732ad1c
10 changed files with 410 additions and 382 deletions

View File

@ -65,8 +65,8 @@ public class RpcDocBuilderTemplate extends BaseDocBuilderTemplate {
mapper.binding(TemplateVariable.DESC.getVariable(), rpcDoc.getDesc());
mapper.binding(TemplateVariable.NAME.getVariable(), rpcDoc.getName());
mapper.binding(TemplateVariable.LIST.getVariable(), rpcDoc.getList());
mapper.binding(TemplateVariable.PROTOCOL.getVariable(), rpcDoc.getProtocol());
mapper.binding(TemplateVariable.AUTHOR.getVariable(), rpcDoc.getAuthor());
mapper.binding(TemplateVariable.PROTOCOL.getVariable(), rpcDoc.getProtocol());
mapper.binding(TemplateVariable.VERSION.getVariable(), rpcDoc.getVersion());
mapper.binding(TemplateVariable.URI.getVariable(), rpcDoc.getUri());
FileUtil.nioWriteFile(mapper.render(), config.getOutPath() + FILE_SEPARATOR + rpcDoc.getShortName() + fileExtension);
@ -128,9 +128,9 @@ public class RpcDocBuilderTemplate extends BaseDocBuilderTemplate {
*/
public RpcApiAllData getApiData(ApiConfig config, JavaProjectBuilder javaProjectBuilder) {
RpcApiAllData apiAllData = new RpcApiAllData();
apiAllData.setLanguage(config.getLanguage().getCode());
apiAllData.setProjectName(config.getProjectName());
apiAllData.setProjectId(DocUtil.generateId(config.getProjectName()));
apiAllData.setLanguage(config.getLanguage().getCode());
apiAllData.setApiDocList(listOfApiData(config, javaProjectBuilder));
apiAllData.setErrorCodeList(errorCodeDictToList(config));
apiAllData.setRevisionLogs(config.getRevisionLogs());

View File

@ -148,10 +148,10 @@ public class RpcHtmlBuilder {
apiTemplate.binding(TemplateVariable.DESC.getVariable(), rpcDoc.getDesc());
apiTemplate.binding(TemplateVariable.NAME.getVariable(), rpcDoc.getName());
apiTemplate.binding(TemplateVariable.LIST.getVariable(), rpcDoc.getList());
apiTemplate.binding(TemplateVariable.PROTOCOL.getVariable(),rpcDoc.getProtocol());
apiTemplate.binding(TemplateVariable.AUTHOR.getVariable(),rpcDoc.getAuthor());
apiTemplate.binding(TemplateVariable.VERSION.getVariable(),rpcDoc.getVersion());
apiTemplate.binding(TemplateVariable.URI.getVariable(),rpcDoc.getUri());
apiTemplate.binding(TemplateVariable.PROTOCOL.getVariable(), rpcDoc.getProtocol());
apiTemplate.binding(TemplateVariable.AUTHOR.getVariable(), rpcDoc.getAuthor());
apiTemplate.binding(TemplateVariable.VERSION.getVariable(), rpcDoc.getVersion());
apiTemplate.binding(TemplateVariable.URI.getVariable(), rpcDoc.getUri());
String html = MarkDownUtil.toHtml(apiTemplate.render());
htmlApiDoc = BeetlTemplateUtil.getByName(HTML_API_DOC_TPL);
@ -159,7 +159,7 @@ public class RpcHtmlBuilder {
htmlApiDoc.binding(TemplateVariable.TITLE.getVariable(), rpcDoc.getDesc());
htmlApiDoc.binding(TemplateVariable.CREATE_TIME.getVariable(), strTime);
htmlApiDoc.binding(TemplateVariable.VERSION.getVariable(), now);
FileUtil.nioWriteFile(htmlApiDoc.render(), outPath + FILE_SEPARATOR + rpcDoc.getAlias() + ".html");
FileUtil.nioWriteFile(htmlApiDoc.render(), outPath + FILE_SEPARATOR + rpcDoc.getShortName() + ".html");
}
}
@ -191,22 +191,25 @@ public class RpcHtmlBuilder {
*/
private static void buildDependency(ApiConfig config) {
List<RpcApiDependency> apiDependencies = config.getRpcApiDependencies();
Template template;
if (CollectionUtil.isNotEmpty(config.getRpcApiDependencies())) {
String rpcConfig = config.getRpcConsumerConfig();
String rpcConfigConfigContent = null;
if (Objects.nonNull(rpcConfig)) {
rpcConfigConfigContent = FileUtil.getFileContent(rpcConfig);
}
Template template = BeetlTemplateUtil.getByName(RPC_DEPENDENCY_MD_TPL);
template = BeetlTemplateUtil.getByName(RPC_DEPENDENCY_MD_TPL);
template.binding(TemplateVariable.RPC_CONSUMER_CONFIG.getVariable(), rpcConfigConfigContent);
template.binding(TemplateVariable.DEPENDENCY_LIST.getVariable(), apiDependencies);
String dictHtml = MarkDownUtil.toHtml(template.render());
Template dictTpl = BeetlTemplateUtil.getByName(HTML_API_DOC_TPL);
dictTpl.binding(TemplateVariable.VERSION.getVariable(), now);
dictTpl.binding(TemplateVariable.TITLE.getVariable(), DICT_EN_TITLE);
dictTpl.binding(TemplateVariable.HTML.getVariable(), dictHtml);
dictTpl.binding(TemplateVariable.CREATE_TIME.getVariable(), DateTimeUtil.long2Str(now, DateTimeUtil.DATE_FORMAT_SECOND));
FileUtil.nioWriteFile(dictTpl.render(), config.getOutPath() + FILE_SEPARATOR + "dependency.html");
} else {
template = BeetlTemplateUtil.getByName(RPC_DEPENDENCY_EMPTY_MD_TPL);
}
String dictHtml = MarkDownUtil.toHtml(template.render());
Template dictTpl = BeetlTemplateUtil.getByName(HTML_API_DOC_TPL);
dictTpl.binding(TemplateVariable.VERSION.getVariable(), now);
dictTpl.binding(TemplateVariable.TITLE.getVariable(), DICT_EN_TITLE);
dictTpl.binding(TemplateVariable.HTML.getVariable(), dictHtml);
dictTpl.binding(TemplateVariable.CREATE_TIME.getVariable(), DateTimeUtil.long2Str(now, DateTimeUtil.DATE_FORMAT_SECOND));
FileUtil.nioWriteFile(dictTpl.render(), config.getOutPath() + FILE_SEPARATOR + "dependency.html");
}
}

View File

@ -67,7 +67,7 @@ public class RpcMarkdownBuilder {
List<RpcApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder);
if (config.isAllInOne()) {
String version = config.isCoverOld() ? "" : "-V" + DateTimeUtil.long2Str(System.currentTimeMillis(), DATE_FORMAT);
builderTemplate.buildAllInOne(apiDocList, config, javaProjectBuilder, RPC_ALL_IN_ONE_MD_TPL, "DubboAllInOne" + version + ".md");
builderTemplate.buildAllInOne(apiDocList, config, javaProjectBuilder, RPC_ALL_IN_ONE_MD_TPL, "rpc-all" + version + ".md");
} else {
builderTemplate.buildApiDoc(apiDocList, config, RPC_API_DOC_MD_TPL, API_EXTENSION);
builderTemplate.buildErrorCodeDoc(config, ERROR_CODE_LIST_MD_TPL, ERROR_CODE_LIST_MD);

View File

@ -61,6 +61,8 @@ public interface DocGlobalConstants {
String RPC_DEPENDENCY_MD_TPL = "dubbo/DubboApiDependency.md";
String RPC_DEPENDENCY_EMPTY_MD_TPL = "dubbo/DubboApiDependencyEmpty.md";
String RPC_API_DOC_MD_TPL = "dubbo/Dubbo.md";
String RPC_ALL_IN_ONE_MD_TPL = "dubbo/DubboAllInOne.md";

View File

@ -1,356 +1,356 @@
/*
* smart-doc https://github.com/shalousun/smart-doc
*
* Copyright (C) 2018-2020 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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.ApiConfig;
import com.power.doc.model.ApiReturn;
import com.power.doc.model.CustomRespField;
import com.power.doc.model.DocJavaField;
import com.power.doc.utils.*;
import com.thoughtworks.qdox.model.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* @author yu 2019/12/21.
*/
public class JsonBuildHelper {
/**
* build return json
*
* @param method The JavaMethod object
* @param builder ProjectDocConfigBuilder builder
* @return String
*/
public static String buildReturnJson(JavaMethod method, ProjectDocConfigBuilder builder) {
if (method.getReturns().isVoid()) {
return "This api return nothing.";
}
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
String returnType = JavaClassUtil.javaTypeFormat(apiReturn.getGenericCanonicalName());
String typeName = apiReturn.getSimpleName();
return JsonFormatUtil.formatJson(buildJson(typeName, returnType, Boolean.TRUE, 0, new HashMap<>(), builder));
}
/**
* @param typeName type name
* @param genericCanonicalName genericCanonicalName
* @param isResp Response flag
* @param counter Recursive counter
* @param registryClasses class container
* @param builder project config builder
* @return String
*/
public static String buildJson(String typeName, String genericCanonicalName,
boolean isResp, int counter, Map<String, String> registryClasses, ProjectDocConfigBuilder builder) {
//存储泛型所对应的实体类
Map<String, String> genericMap = new HashMap<>(10);
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(typeName);
ApiConfig apiConfig = builder.getApiConfig();
if (counter > apiConfig.getRecursionLimit()) {
return "{\"$ref\":\"...\"}";
}
if (registryClasses.containsKey(typeName) && counter > registryClasses.size()) {
return "{\"$ref\":\"...\"}";
}
int nextLevel = counter + 1;
registryClasses.put(typeName, typeName);
if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,builder.getApiConfig().getIgnoreRequestParams())) {
if (DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName)) {
return "Forward or redirect to a page view.";
} else {
return "Error restful return.";
}
}
if (JavaClassValidateUtil.isPrimitive(typeName)) {
return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName));
}
if (javaClass.isEnum()) {
return String.valueOf(JavaClassUtil.getEnumValue(javaClass, Boolean.FALSE));
}
boolean skipTransientField = apiConfig.isSkipTransientField();
StringBuilder data0 = new StringBuilder();
JavaClass cls = builder.getClassByName(typeName);
data0.append("{");
String[] globGicName = DocClassUtil.getSimpleGicName(genericCanonicalName);
//添加泛型对应关系
JavaClassUtil.genericParamMap(genericMap, cls, globGicName);
StringBuilder data = new StringBuilder();
if (JavaClassValidateUtil.isCollection(typeName) || JavaClassValidateUtil.isArray(typeName)) {
data.append("[");
if (globGicName.length == 0) {
data.append("{\"object\":\"any object\"}");
data.append("]");
return data.toString();
}
String gNameTemp = globGicName[0];
String gName = JavaClassValidateUtil.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 (JavaClassValidateUtil.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, nextLevel, registryClasses, builder);
data.append(json);
} else if (JavaClassValidateUtil.isCollection(gName)) {
data.append("\"any object\"");
} else {
String json = buildJson(gName, gName, isResp, nextLevel, registryClasses, builder);
data.append(json);
}
data.append("]");
return data.toString();
} else if (JavaClassValidateUtil.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 (JavaClassValidateUtil.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, nextLevel, 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)) {
data.append("{\"object\":\" any object\"},");
// throw new RuntimeException("Please do not return java.lang.Object directly in api interface.");
} else {
boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline();
boolean responseFieldToUnderline = builder.getApiConfig().isResponseFieldToUnderline();
List<DocJavaField> fields = JavaClassUtil.getFields(cls, 0, new HashSet<>());
boolean isGenerics = JavaFieldUtil.checkGenerics(fields);
out:
for (DocJavaField docField : fields) {
JavaField field = docField.getJavaField();
String subTypeName = docField.getFullyQualifiedName();
String fieldName = field.getName();
if (field.isStatic() || "this$0".equals(fieldName) ||
JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
if (field.isTransient() && skipTransientField) {
continue;
}
if ((responseFieldToUnderline && isResp) || (requestFieldToUnderline && !isResp)) {
fieldName = StringUtil.camelToUnderline(fieldName);
}
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field, docField);
if (!isResp) {
if (tagsMap.containsKey(DocTags.IGNORE)) {
continue out;
}
}
List<JavaAnnotation> annotations = docField.getAnnotations();
for (JavaAnnotation annotation : annotations) {
String annotationName = annotation.getType().getValue();
if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(annotationName)) {
continue out;
} else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName)) {
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)) {
if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString());
}
}
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = docField.getGenericCanonicalName();
data0.append("\"").append(fieldName).append("\":");
if (JavaClassValidateUtil.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 (JavaClassValidateUtil.isCollection(subTypeName) || JavaClassValidateUtil.isArray(subTypeName)) {
if (globGicName.length > 0 && "java.util.List".equals(fieldGicName)) {
fieldGicName = fieldGicName + "<T>";
}
fieldGicName = JavaClassValidateUtil.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, nextLevel, 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 = genericMap.get(gicName) == null ? globGicName[0] : genericMap.get(gicName);
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("[").append("\"").append(buildJson(gicName1, gicName1, isResp, nextLevel, registryClasses, builder)).append("\"]").append(",");
} else {
if (!typeName.equals(gicName1)) {
data0.append("[").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, nextLevel, registryClasses, builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else {
if (!typeName.equals(gicName)) {
if (JavaClassValidateUtil.isMap(gicName)) {
data0.append("[{\"mapKey\":{}}],");
continue out;
}
data0.append("[").append(buildJson(gicName, fieldGicName, isResp, nextLevel, registryClasses, builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else if (JavaClassValidateUtil.isMap(subTypeName)) {
if (JavaClassValidateUtil.isMap(fieldGicName)) {
data0.append("{").append("\"mapKey\":{}},");
continue out;
}
String gicName = fieldGicName.substring(fieldGicName.indexOf(",") + 1, fieldGicName.indexOf(">"));
if (gicName.length() == 1) {
String gicName1 = genericMap.get(gicName) == null ? globGicName[0] : genericMap.get(gicName);
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("{").append("\"mapKey\":\"").append(buildJson(gicName1, gicName1, isResp, nextLevel, registryClasses, builder)).append("\"},");
} else {
if (!typeName.equals(gicName1)) {
data0.append("{").append("\"mapKey\":").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, nextLevel, registryClasses, builder)).append("},");
} else {
data0.append("{\"mapKey\":{}},");
}
}
} else {
data0.append("{").append("\"mapKey\":").append(buildJson(gicName, fieldGicName, isResp, nextLevel, registryClasses, builder)).append("},");
}
} else if (subTypeName.length() == 1) {
if (!typeName.equals(genericCanonicalName)) {
String gicName = genericMap.get(subTypeName) == null ? globGicName[0] : genericMap.get(subTypeName);
if (JavaClassValidateUtil.isPrimitive(gicName)) {
data0.append(DocUtil.jsonValueByType(gicName)).append(",");
} else {
String simple = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simple, gicName, isResp, nextLevel, registryClasses, builder)).append(",");
}
} else {
data0.append("{\"waring\":\"You may have used non-display generics.\"},");
}
} else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
if (isGenerics) {
data0.append("{\"object\":\"any object\"},");
} else if (globGicName.length > 0) {
String gicName = genericMap.get(subTypeName) == null ? globGicName[0] : genericMap.get(subTypeName);
if (!typeName.equals(genericCanonicalName)) {
if (JavaClassValidateUtil.isPrimitive(gicName)) {
data0.append("\"").append(buildJson(gicName, genericCanonicalName, isResp, nextLevel, registryClasses, builder)).append("\",");
} else {
String simpleName = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simpleName, gicName, isResp, nextLevel, 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.\"},");
}
} else if (typeName.equals(subTypeName)) {
data0.append("{\"$ref\":\"...\"}").append(",");
} else {
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, nextLevel, registryClasses, builder)).append(",");
}
}
}
}
}
if (data0.toString().contains(",")) {
data0.deleteCharAt(data0.lastIndexOf(","));
}
data0.append("}");
return data0.toString();
}
}
/*
* smart-doc https://github.com/shalousun/smart-doc
*
* Copyright (C) 2018-2020 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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.ApiConfig;
import com.power.doc.model.ApiReturn;
import com.power.doc.model.CustomRespField;
import com.power.doc.model.DocJavaField;
import com.power.doc.utils.*;
import com.thoughtworks.qdox.model.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* @author yu 2019/12/21.
*/
public class JsonBuildHelper {
/**
* build return json
*
* @param method The JavaMethod object
* @param builder ProjectDocConfigBuilder builder
* @return String
*/
public static String buildReturnJson(JavaMethod method, ProjectDocConfigBuilder builder) {
if (method.getReturns().isVoid()) {
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, Boolean.TRUE, 0, new HashMap<>(), builder));
}
/**
* @param typeName type name
* @param genericCanonicalName genericCanonicalName
* @param isResp Response flag
* @param counter Recursive counter
* @param registryClasses class container
* @param builder project config builder
* @return String
*/
public static String buildJson(String typeName, String genericCanonicalName,
boolean isResp, int counter, Map<String, String> registryClasses, ProjectDocConfigBuilder builder) {
//存储泛型所对应的实体类
Map<String, String> genericMap = new HashMap<>(10);
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(typeName);
ApiConfig apiConfig = builder.getApiConfig();
if (counter > apiConfig.getRecursionLimit()) {
return "{\"$ref\":\"...\"}";
}
if (registryClasses.containsKey(typeName) && counter > registryClasses.size()) {
return "{\"$ref\":\"...\"}";
}
int nextLevel = counter + 1;
registryClasses.put(typeName, typeName);
if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,builder.getApiConfig().getIgnoreRequestParams())) {
if (DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName)) {
return "Forward or redirect to a page view.";
} else {
return "Error restful return.";
}
}
if (JavaClassValidateUtil.isPrimitive(typeName)) {
return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName));
}
if (javaClass.isEnum()) {
return String.valueOf(JavaClassUtil.getEnumValue(javaClass, Boolean.FALSE));
}
boolean skipTransientField = apiConfig.isSkipTransientField();
StringBuilder data0 = new StringBuilder();
JavaClass cls = builder.getClassByName(typeName);
data0.append("{");
String[] globGicName = DocClassUtil.getSimpleGicName(genericCanonicalName);
//添加泛型对应关系
JavaClassUtil.genericParamMap(genericMap, cls, globGicName);
StringBuilder data = new StringBuilder();
if (JavaClassValidateUtil.isCollection(typeName) || JavaClassValidateUtil.isArray(typeName)) {
data.append("[");
if (globGicName.length == 0) {
data.append("{\"object\":\"any object\"}");
data.append("]");
return data.toString();
}
String gNameTemp = globGicName[0];
String gName = JavaClassValidateUtil.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 (JavaClassValidateUtil.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, nextLevel, registryClasses, builder);
data.append(json);
} else if (JavaClassValidateUtil.isCollection(gName)) {
data.append("\"any object\"");
} else {
String json = buildJson(gName, gName, isResp, nextLevel, registryClasses, builder);
data.append(json);
}
data.append("]");
return data.toString();
} else if (JavaClassValidateUtil.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 (JavaClassValidateUtil.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, nextLevel, 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)) {
data.append("{\"object\":\" any object\"},");
// throw new RuntimeException("Please do not return java.lang.Object directly in api interface.");
} else {
boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline();
boolean responseFieldToUnderline = builder.getApiConfig().isResponseFieldToUnderline();
List<DocJavaField> fields = JavaClassUtil.getFields(cls, 0, new HashSet<>());
boolean isGenerics = JavaFieldUtil.checkGenerics(fields);
out:
for (DocJavaField docField : fields) {
JavaField field = docField.getJavaField();
String subTypeName = docField.getFullyQualifiedName();
String fieldName = field.getName();
if (field.isStatic() || "this$0".equals(fieldName) ||
JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
if (field.isTransient() && skipTransientField) {
continue;
}
if ((responseFieldToUnderline && isResp) || (requestFieldToUnderline && !isResp)) {
fieldName = StringUtil.camelToUnderline(fieldName);
}
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field, docField);
if (!isResp) {
if (tagsMap.containsKey(DocTags.IGNORE)) {
continue out;
}
}
List<JavaAnnotation> annotations = docField.getAnnotations();
for (JavaAnnotation annotation : annotations) {
String annotationName = annotation.getType().getValue();
if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(annotationName)) {
continue out;
} else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName)) {
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)) {
if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) {
fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString());
}
}
}
String typeSimpleName = field.getType().getSimpleName();
String fieldGicName = docField.getGenericCanonicalName();
data0.append("\"").append(fieldName).append("\":");
if (JavaClassValidateUtil.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 (JavaClassValidateUtil.isCollection(subTypeName) || JavaClassValidateUtil.isArray(subTypeName)) {
if (globGicName.length > 0 && "java.util.List".equals(fieldGicName)) {
fieldGicName = fieldGicName + "<T>";
}
fieldGicName = JavaClassValidateUtil.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, nextLevel, 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 = genericMap.get(gicName) == null ? globGicName[0] : genericMap.get(gicName);
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("[").append("\"").append(buildJson(gicName1, gicName1, isResp, nextLevel, registryClasses, builder)).append("\"]").append(",");
} else {
if (!typeName.equals(gicName1)) {
data0.append("[").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, nextLevel, registryClasses, builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else {
if (!typeName.equals(gicName)) {
if (JavaClassValidateUtil.isMap(gicName)) {
data0.append("[{\"mapKey\":{}}],");
continue out;
}
data0.append("[").append(buildJson(gicName, fieldGicName, isResp, nextLevel, registryClasses, builder)).append("]").append(",");
} else {
data0.append("[{\"$ref\":\"..\"}]").append(",");
}
}
} else if (JavaClassValidateUtil.isMap(subTypeName)) {
if (JavaClassValidateUtil.isMap(fieldGicName)) {
data0.append("{").append("\"mapKey\":{}},");
continue out;
}
String gicName = fieldGicName.substring(fieldGicName.indexOf(",") + 1, fieldGicName.indexOf(">"));
if (gicName.length() == 1) {
String gicName1 = genericMap.get(gicName) == null ? globGicName[0] : genericMap.get(gicName);
if (DocGlobalConstants.JAVA_STRING_FULLY.equals(gicName1)) {
data0.append("{").append("\"mapKey\":\"").append(buildJson(gicName1, gicName1, isResp, nextLevel, registryClasses, builder)).append("\"},");
} else {
if (!typeName.equals(gicName1)) {
data0.append("{").append("\"mapKey\":").append(buildJson(DocClassUtil.getSimpleName(gicName1), gicName1, isResp, nextLevel, registryClasses, builder)).append("},");
} else {
data0.append("{\"mapKey\":{}},");
}
}
} else {
data0.append("{").append("\"mapKey\":").append(buildJson(gicName, fieldGicName, isResp, nextLevel, registryClasses, builder)).append("},");
}
} else if (subTypeName.length() == 1) {
if (!typeName.equals(genericCanonicalName)) {
String gicName = genericMap.get(subTypeName) == null ? globGicName[0] : genericMap.get(subTypeName);
if (JavaClassValidateUtil.isPrimitive(gicName)) {
data0.append(DocUtil.jsonValueByType(gicName)).append(",");
} else {
String simple = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simple, gicName, isResp, nextLevel, registryClasses, builder)).append(",");
}
} else {
data0.append("{\"waring\":\"You may have used non-display generics.\"},");
}
} else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) {
if (isGenerics) {
data0.append("{\"object\":\"any object\"},");
} else if (globGicName.length > 0) {
String gicName = genericMap.get(subTypeName) == null ? globGicName[0] : genericMap.get(subTypeName);
if (!typeName.equals(genericCanonicalName)) {
if (JavaClassValidateUtil.isPrimitive(gicName)) {
data0.append("\"").append(buildJson(gicName, genericCanonicalName, isResp, nextLevel, registryClasses, builder)).append("\",");
} else {
String simpleName = DocClassUtil.getSimpleName(gicName);
data0.append(buildJson(simpleName, gicName, isResp, nextLevel, 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.\"},");
}
} else if (typeName.equals(subTypeName)) {
data0.append("{\"$ref\":\"...\"}").append(",");
} else {
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, nextLevel, registryClasses, builder)).append(",");
}
}
}
}
}
if (data0.toString().contains(",")) {
data0.deleteCharAt(data0.lastIndexOf(","));
}
data0.append("}");
return data0.toString();
}
}

View File

@ -97,7 +97,7 @@ public interface IDocBuildTemplate<T> {
return null;
}
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
String returnType = JavaClassUtil.javaTypeFormat(apiReturn.getGenericCanonicalName());
String returnType = apiReturn.getGenericCanonicalName();
String typeName = apiReturn.getSimpleName();
if (this.ignoreReturnObject(typeName,projectBuilder.getApiConfig().getIgnoreRequestParams())) {
return null;

View File

@ -22,7 +22,6 @@
*/
package com.power.doc.template;
import com.google.gson.Gson;
import com.power.common.util.StringUtil;
import com.power.common.util.ValidateUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
@ -283,7 +282,7 @@ public class RpcDocBuildTemplate implements IDocBuildTemplate<RpcApiDoc> {
StringBuilder methodBuilder = new StringBuilder();
JavaType returnType = method.getReturnType();
String simpleReturn = returnType.getCanonicalName();
String returnClass = JavaClassUtil.javaTypeFormat(returnType.getGenericCanonicalName());
String returnClass = returnType.getGenericCanonicalName();
returnClass = returnClass.replace(simpleReturn, JavaClassUtil.getClassSimpleName(simpleReturn));
String[] arrays = DocClassUtil.getSimpleGicName(returnClass);
for (String str : arrays) {
@ -292,7 +291,14 @@ public class RpcDocBuildTemplate implements IDocBuildTemplate<RpcApiDoc> {
}
String[] generics = str.split("[<,]");
for (String generic : generics) {
returnClass = returnClass.replaceAll(generic, JavaClassUtil.getClassSimpleName(generic));
if (generic.contains("extends")) {
String className = generic.substring(generic.lastIndexOf(" ")+1);
returnClass = returnClass.replace(className, JavaClassUtil.getClassSimpleName(className));
}
if (generic.length() != 1 && !generic.contains("extends")) {
returnClass = returnClass.replaceAll(generic, JavaClassUtil.getClassSimpleName(generic));
}
}
}
methodBuilder.append(returnClass).append(" ");

View File

@ -239,7 +239,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
JavaType javaType = parameter.getType();
String paramName = parameter.getName();
String typeName = javaType.getFullyQualifiedName();
String gicTypeName = JavaClassUtil.javaTypeFormat(javaType.getGenericCanonicalName());
String gicTypeName = javaType.getGenericCanonicalName();
String commentClass = paramsComments.get(paramName);
//ignore request params

View File

@ -0,0 +1,17 @@
# Add dependency
```
<dependency>
<groupId>Your api group</groupId>
<artifactId>Your api artifactId</artifactId>
<version>1.0.0</version>
</dependency>
```
Consumer config
```
dubbo:
registry:
protocol: zookeeper
address: localhost:2181
```

View File

@ -24,17 +24,17 @@
<%
for(api in apiDocList){
%>
<li class="chapter " data-level="${api.alias}" data-path="${api.alias}.html">
<a href="javascript:void(0)" onclick="go('${api.alias}', '${api.desc}');">${api.order+1} ${api.desc}</a>
<li class="chapter " data-level="${api.shortName}" data-path="${api.shortName}.html">
<a href="javascript:void(0)" onclick="go('${api.shortName}', '${api.desc}');">${api.order+1} ${api.desc}</a>
<ul class="articles">
<%
for(doc in api.list){
%>
<li class="chapter " data-level="${api.alias}" data-path="${api.alias}.html">
<li class="chapter " data-level="${api.shortName}" data-path="${api.shortName}.html">
<%if(doc.deprecated){%>
<a href="javascript:void(0)" onclick="go('${api.alias}', '${doc.desc}');">${api.order+1}.${doc.order}&nbsp;<span class="line-through">${doc.desc}</span></a></li>
<a href="javascript:void(0)" onclick="go('${api.shortName}', '${doc.desc}');">${api.order+1}.${doc.order}&nbsp;<span class="line-through">${doc.desc}</span></a></li>
<%}else{%>
<a href="javascript:void(0)" onclick="go('${api.alias}', '${doc.desc}');">${api.order+1}.${doc.order}&nbsp;${doc.desc}</a></li>
<a href="javascript:void(0)" onclick="go('${api.shortName}', '${doc.desc}');">${api.order+1}.${doc.order}&nbsp;${doc.desc}</a></li>
<%}%>
<%}%>
</ul>