Skip to content

Commit 9bca46d

Browse files
authored
Merge pull request #31 from Forgus/20200215
v20200215
2 parents d1f9b6b + 26fff42 commit 9bca46d

File tree

6 files changed

+134
-149
lines changed

6 files changed

+134
-149
lines changed

resources/META-INF/plugin.xml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<idea-plugin>
22
<id>site.forgus.plugins.api-generator</id>
33
<name>Api Generator</name>
4-
<version>2021.02.11</version>
5-
<vendor email="wenbin1876@gmail.com">孤峰,泽恩</vendor>
4+
<version>2021.02.15</version>
5+
<vendor email="wenbin1876@gmail.com">孤峰</vendor>
66

77
<description><![CDATA[
88
<em>Api开发利器,接口文档自动生成</em><br><br>
@@ -43,7 +43,6 @@
4343
<li>自动识别类,生成markdown文档或上传到YApi</li>
4444
<li>支持List、Set、Collection等数据结构,支持嵌套泛型解析</li>
4545
<li>支持@NotNull、@ResponseBody等常用注解的解析,基于json5生成YApi文档</li>
46-
<li>支持解析依赖的jar包源码(maven管理)读取doc</li>
4746
</ul><br>
4847
用法:<br>
4948
<ul><li>将光标定位到方法区域或者类名,鼠标右键单击"Generate Api".</li></ul><br>
@@ -98,14 +97,14 @@
9897
]]></description>
9998

10099
<change-notes><![CDATA[
101-
<em>2021.02.11</em><br>
100+
<em>2021.02.15</em><br>
102101
<ul>
103-
<li>支持解析依赖jar的源码doc</li>
102+
<li>支持第三方jar包源码注释的解析。</li>
103+
<li>修复没有注释的方法无法上传文档的问题。</li>
104104
</ul>
105-
106105
<em>2021.02.10</em><br>
107106
<ul>
108-
<li>支持常用swagger注解和@JsonFormat注解。</li>
107+
<li>支持常用swagger注解和@JsonFormat注解的解析。</li>
109108
<li>生成的接口名不再带有请求方法。</li>
110109
<li>修复嵌套泛型解析不正确的问题。</li>
111110
</ul>

src/site/forgus/plugins/apigenerator/ApiGenerateAction.java

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import org.apache.commons.lang.StringUtils;
1919
import org.apache.maven.model.Model;
2020
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
21-
import org.jetbrains.annotations.NotNull;
2221
import site.forgus.plugins.apigenerator.config.ApiGeneratorConfig;
2322
import site.forgus.plugins.apigenerator.constant.TypeEnum;
2423
import site.forgus.plugins.apigenerator.constant.WebAnnotation;
@@ -32,7 +31,6 @@
3231
import site.forgus.plugins.apigenerator.yapi.model.*;
3332
import site.forgus.plugins.apigenerator.yapi.sdk.YApiSdk;
3433

35-
import javax.swing.*;
3634
import java.io.*;
3735
import java.nio.charset.StandardCharsets;
3836
import java.util.*;
@@ -122,19 +120,13 @@ private void uploadHttpMethodsToYApi(Project project, PsiClass psiClass) throws
122120
}
123121
config.getState().projectId = projectId;
124122
}
123+
Map<String, YApiCat> catNameMap = getCatNameMap();
125124
PsiMethod[] methods = psiClass.getMethods();
126-
boolean uploadSuccess = false;
127125
for (PsiMethod method : methods) {
128126
if (hasMappingAnnotation(method)) {
129-
uploadToYApi(project, method);
130-
uploadSuccess = true;
127+
uploadToYApi(project, method,catNameMap);
131128
}
132129
}
133-
if (uploadSuccess) {
134-
NotificationUtil.infoNotify("Upload api success.", project);
135-
return;
136-
}
137-
NotificationUtil.infoNotify("Upload api failed, reason:\n not REST api.", project);
138130
}
139131

140132
private void generateMarkdownForInterface(Project project, PsiElement referenceAt, PsiClass selectedClass) {
@@ -253,6 +245,29 @@ private void uploadToYApi(Project project, PsiMethod psiMethod) throws IOExcepti
253245
}
254246
}
255247

248+
private void uploadToYApi(Project project, PsiMethod psiMethod,Map<String, YApiCat> catNameMap) throws IOException {
249+
YApiInterfaceWrapper yApiInterfaceWrapper = buildYApiInterface(psiMethod);
250+
if (YApiInterfaceWrapper.RespCodeEnum.FAILED.equals(yApiInterfaceWrapper.getRespCode())) {
251+
NotificationUtil.errorNotify("Resolve api failed, reason:" + yApiInterfaceWrapper.getRespMsg(), project);
252+
return;
253+
}
254+
if(YApiInterfaceWrapper.RespCodeEnum.ERROR.equals(yApiInterfaceWrapper.getRespCode())) {
255+
String json = new Gson().toJson(yApiInterfaceWrapper.getErrorInfo());
256+
String reqData = Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8));
257+
HttpUtil.doPost("http://forgus.vicp.io/log",reqData);
258+
NotificationUtil.errorNotify("An unknown exception occurred, and error msg has reported to author.", project);
259+
return;
260+
}
261+
if(YApiInterfaceWrapper.RespCodeEnum.SUCCESS.equals(yApiInterfaceWrapper.getRespCode())) {
262+
YApiResponse yApiResponse = YApiSdk.saveInterface(config.getState().yApiServerUrl, yApiInterfaceWrapper.getYApiInterface());
263+
if (yApiResponse.getErrcode() != 0) {
264+
NotificationUtil.errorNotify("Upload api failed, cause:" + yApiResponse.getErrmsg(), project);
265+
return;
266+
}
267+
NotificationUtil.infoNotify("Upload api success.", project);
268+
}
269+
}
270+
256271
private YApiInterfaceWrapper buildYApiInterface(PsiMethod psiMethod) {
257272
try {
258273
PsiClass containingClass = psiMethod.getContainingClass();
@@ -285,11 +300,68 @@ private YApiInterfaceWrapper buildYApiInterface(PsiMethod psiMethod) {
285300
}
286301
}
287302
yApiInterface.setReq_query(listYApiQueries(methodInfo.getRequestFields(), requestMethodEnum));
288-
Map<String, YApiCat> catNameMap = getCatNameMap();
289-
PsiDocComment classDesc = containingClass.getDocComment();
290-
yApiInterface.setCatid(getCatId(catNameMap, classDesc));
291-
yApiInterface.setTitle(methodInfo.getDesc());
303+
yApiInterface.setCatid(getCatId(getCatNameMap(),containingClass.getDocComment()));
304+
yApiInterface.setPath(buildPath(classRequestMapping, methodMapping));
305+
yApiInterface.setTitle(StringUtils.isEmpty(methodInfo.getDesc()) ? yApiInterface.getPath() : methodInfo.getDesc());
306+
if (containResponseBodyAnnotation(psiMethod.getAnnotations()) || controller.getText().contains("Rest")) {
307+
yApiInterface.setReq_headers(Collections.singletonList(YApiHeader.json()));
308+
yApiInterface.setRes_body(JsonUtil.buildJson5(methodInfo.getResponse()));
309+
} else {
310+
yApiInterface.setReq_headers(Collections.singletonList(YApiHeader.form()));
311+
yApiInterface.setRes_body_type(ResponseBodyTypeEnum.RAW.getValue());
312+
yApiInterface.setRes_body("");
313+
}
314+
yApiInterface.setReq_params(listYApiPathVariables(methodInfo.getRequestFields()));
315+
yApiInterface.setDesc(Objects.nonNull(yApiInterface.getDesc()) ? yApiInterface.getDesc() : "<pre><code data-language=\"java\" class=\"java\">" + getMethodDesc(psiMethod) + "</code> </pre>");
316+
return YApiInterfaceWrapper.success(yApiInterface);
317+
}catch (Exception e) {
318+
Map<String,Object> errorInfo = new HashMap<>();
319+
//TODO errorInfo
320+
errorInfo.put("plugin_version","2021.02.15");
321+
errorInfo.put("_cause",e.getMessage());
322+
errorInfo.put("_trace",buildTraceStr(e));
323+
errorInfo.put("method_text",buildMethodSnapshot(psiMethod));
324+
// errorInfo.put("return_text",buildReturnText(psiMethod));
325+
// errorInfo.put("param_text",buildParamText(psiMethod));
326+
return YApiInterfaceWrapper.error(errorInfo);
327+
}
328+
}
329+
330+
private YApiInterfaceWrapper buildYApiInterface(PsiMethod psiMethod,Map<String, YApiCat> catNameMap) {
331+
try {
332+
PsiClass containingClass = psiMethod.getContainingClass();
333+
PsiAnnotation controller = null;
334+
PsiAnnotation classRequestMapping = null;
335+
for (PsiAnnotation annotation : containingClass.getAnnotations()) {
336+
String text = annotation.getText();
337+
if (text.endsWith(WebAnnotation.Controller)) {
338+
controller = annotation;
339+
} else if (text.contains(WebAnnotation.RequestMapping)) {
340+
classRequestMapping = annotation;
341+
}
342+
}
343+
if (controller == null) {
344+
return YApiInterfaceWrapper.failed("Invalid Class File!");
345+
}
346+
MethodInfo methodInfo = new MethodInfo(psiMethod);
347+
PsiAnnotation methodMapping = getMethodMapping(psiMethod);
348+
YApiInterface yApiInterface = new YApiInterface();
349+
yApiInterface.setToken(config.getState().projectToken);
350+
RequestMethodEnum requestMethodEnum = getMethodFromAnnotation(methodMapping);
351+
yApiInterface.setMethod(requestMethodEnum.name());
352+
if (methodInfo.getParamStr().contains(WebAnnotation.RequestBody)) {
353+
yApiInterface.setReq_body_type(RequestBodyTypeEnum.JSON.getValue());
354+
yApiInterface.setReq_body_other(JsonUtil.buildJson5(getRequestBodyParam(methodInfo.getRequestFields())));
355+
} else {
356+
if (yApiInterface.getMethod().equals(RequestMethodEnum.POST.name())) {
357+
yApiInterface.setReq_body_type(RequestBodyTypeEnum.FORM.getValue());
358+
yApiInterface.setReq_body_form(listYApiForms(methodInfo.getRequestFields()));
359+
}
360+
}
361+
yApiInterface.setReq_query(listYApiQueries(methodInfo.getRequestFields(), requestMethodEnum));
362+
yApiInterface.setCatid(getCatId(getCatNameMap(),containingClass.getDocComment()));
292363
yApiInterface.setPath(buildPath(classRequestMapping, methodMapping));
364+
yApiInterface.setTitle(StringUtils.isEmpty(methodInfo.getDesc()) ? yApiInterface.getPath() : methodInfo.getDesc());
293365
if (containResponseBodyAnnotation(psiMethod.getAnnotations()) || controller.getText().contains("Rest")) {
294366
yApiInterface.setReq_headers(Collections.singletonList(YApiHeader.json()));
295367
yApiInterface.setRes_body(JsonUtil.buildJson5(methodInfo.getResponse()));
@@ -304,7 +376,7 @@ private YApiInterfaceWrapper buildYApiInterface(PsiMethod psiMethod) {
304376
}catch (Exception e) {
305377
Map<String,Object> errorInfo = new HashMap<>();
306378
//TODO errorInfo
307-
errorInfo.put("plugin_version","2021.02.10");
379+
errorInfo.put("plugin_version","2021.02.15");
308380
errorInfo.put("_cause",e.getMessage());
309381
errorInfo.put("_trace",buildTraceStr(e));
310382
errorInfo.put("method_text",buildMethodSnapshot(psiMethod));

src/site/forgus/plugins/apigenerator/normal/FieldFactory.java

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.intellij.openapi.project.Project;
55
import com.intellij.psi.*;
66
import com.intellij.psi.util.PsiUtil;
7-
import org.apache.commons.lang.StringUtils;
87
import site.forgus.plugins.apigenerator.config.ApiGeneratorConfig;
98
import site.forgus.plugins.apigenerator.constant.TypeEnum;
109
import site.forgus.plugins.apigenerator.constant.WebAnnotation;
@@ -18,8 +17,6 @@
1817
*/
1918
public class FieldFactory {
2019

21-
private static List<String> requiredTexts = Arrays.asList("@NotNull", "@NotBlank", "@NotEmpty", "@PathVariable");
22-
2320
public static FieldInfo buildPsiType(Project project, PsiType psiType) {
2421
FieldInfo fieldInfo = new FieldInfo();
2522
fieldInfo.fieldType= FieldType.PSI_TYPE;
@@ -47,7 +44,7 @@ public static FieldInfo buildField(Project project,String name, PsiType psiType,
4744
fieldInfo.fieldType = FieldType.FIELD;
4845
fieldInfo.project = project;
4946
fieldInfo.config = ServiceManager.getService(project,ApiGeneratorConfig.class);
50-
RequireAndRange requireAndRange = getRequireAndRange(annotations);
47+
RequireAndRange requireAndRange = FieldUtil.getRequireAndRange(annotations);
5148
String fieldName = getParamName(name, annotations);
5249
fieldInfo.name = fieldName == null ? "N/A" : fieldName;
5350
fieldInfo.psiType = psiType;
@@ -77,7 +74,7 @@ public static FieldInfo buildFieldWithParent(Project project,FieldInfo parent,St
7774
fieldInfo.fieldType = FieldType.FIELD;
7875
fieldInfo.project = project;
7976
fieldInfo.config = ServiceManager.getService(project,ApiGeneratorConfig.class);
80-
RequireAndRange requireAndRange = getRequireAndRange(annotations);
77+
RequireAndRange requireAndRange = FieldUtil.getRequireAndRange(annotations);
8178
String fieldName = getParamName(name, annotations);
8279
fieldInfo.name = fieldName == null ? "N/A" : fieldName;
8380
fieldInfo.psiType = psiType;
@@ -174,74 +171,6 @@ private static Map<PsiTypeParameter, PsiType> resolveGenerics(PsiType psiType){
174171
return new HashMap<>();
175172
}
176173

177-
private static RequireAndRange getRequireAndRange(PsiAnnotation[] annotations) {
178-
if (annotations.length == 0) {
179-
return RequireAndRange.instance();
180-
}
181-
boolean require = false;
182-
String min = "";
183-
String max = "";
184-
String range = "N/A";
185-
for (PsiAnnotation annotation : annotations) {
186-
if (isParamRequired(annotation)) {
187-
require = true;
188-
break;
189-
}
190-
}
191-
for (PsiAnnotation annotation : annotations) {
192-
String qualifiedName = annotation.getText();
193-
if (qualifiedName.contains("Length") || qualifiedName.contains("Range") || qualifiedName.contains("Size")) {
194-
PsiAnnotationMemberValue minValue = annotation.findAttributeValue("min");
195-
if (minValue != null) {
196-
min = minValue.getText();
197-
break;
198-
}
199-
}
200-
if (qualifiedName.contains("Min")) {
201-
PsiAnnotationMemberValue minValue = annotation.findAttributeValue("value");
202-
if (minValue != null) {
203-
min = minValue.getText();
204-
break;
205-
}
206-
}
207-
}
208-
for (PsiAnnotation annotation : annotations) {
209-
String qualifiedName = annotation.getText();
210-
if (qualifiedName.contains("Length") || qualifiedName.contains("Range") || qualifiedName.contains("Size")) {
211-
PsiAnnotationMemberValue maxValue = annotation.findAttributeValue("max");
212-
if (maxValue != null) {
213-
max = maxValue.getText();
214-
break;
215-
}
216-
}
217-
if (qualifiedName.contains("Max")) {
218-
PsiAnnotationMemberValue maxValue = annotation.findAttributeValue("value");
219-
if (maxValue != null) {
220-
max = maxValue.getText();
221-
break;
222-
}
223-
}
224-
}
225-
if (StringUtils.isNotEmpty(min) || StringUtils.isNotEmpty(max)) {
226-
range = "[" + min + "," + max + "]";
227-
}
228-
return new RequireAndRange(require, range);
229-
}
230-
231-
private static boolean isParamRequired(PsiAnnotation annotation) {
232-
String annotationText = annotation.getText();
233-
if (annotationText.contains(WebAnnotation.RequestParam)) {
234-
PsiNameValuePair[] psiNameValuePairs = annotation.getParameterList().getAttributes();
235-
for (PsiNameValuePair psiNameValuePair : psiNameValuePairs) {
236-
if ("required".equals(psiNameValuePair.getName()) && "false".equals(psiNameValuePair.getLiteralValue())) {
237-
return false;
238-
}
239-
}
240-
return true;
241-
}
242-
return requiredTexts.contains(annotationText.split("\\(")[0]);
243-
}
244-
245174
private static String getParamName(String name, PsiAnnotation[] annotations) {
246175
PsiAnnotation requestParamAnnotation = getRequestParamAnnotation(annotations);
247176
if (requestParamAnnotation == null) {

src/site/forgus/plugins/apigenerator/normal/FieldInfo.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -155,24 +155,18 @@ public void resolveChildren() {
155155
if (psiClass == null) {
156156
return;
157157
}
158-
try {
159-
160-
if (psiClass instanceof ClsClassImpl){
161-
String sourcePath = ((PsiJavaFileStubImpl) ((ClsClassImpl) psiClass).getStub().getParentStub())
162-
.getPsi().getViewProvider().getVirtualFile().toString()
163-
.replace(".jar!", "-sources.jar!");
164-
sourcePath = sourcePath.substring(0, sourcePath.length() - 5)+"java";
165-
VirtualFile virtualFile =
166-
VirtualFileManager.getInstance().findFileByUrl(sourcePath);
167-
FileViewProvider fileViewProvider = new SingleRootFileViewProvider(PsiManager.getInstance(project), virtualFile);
168-
PsiFile psiFile1 = new PsiJavaFileImpl(fileViewProvider);
169-
psiClass = PsiTreeUtil.findChildOfAnyType(psiFile1.getOriginalElement(), PsiClass.class);
170-
}
171-
172-
}catch (Exception e){
173-
e.printStackTrace();
158+
//兼容第三方jar包
159+
if (psiClass instanceof ClsClassImpl){
160+
String sourcePath = ((PsiJavaFileStubImpl) ((ClsClassImpl) psiClass).getStub().getParentStub())
161+
.getPsi().getViewProvider().getVirtualFile().toString()
162+
.replace(".jar!", "-sources.jar!");
163+
sourcePath = sourcePath.substring(0, sourcePath.length() - 5)+"java";
164+
VirtualFile virtualFile =
165+
VirtualFileManager.getInstance().findFileByUrl(sourcePath);
166+
FileViewProvider fileViewProvider = new SingleRootFileViewProvider(PsiManager.getInstance(project), virtualFile);
167+
PsiFile psiFile1 = new PsiJavaFileImpl(fileViewProvider);
168+
psiClass = PsiTreeUtil.findChildOfAnyType(psiFile1.getOriginalElement(), PsiClass.class);
174169
}
175-
176170
for (PsiField psiField : psiClass.getAllFields()) {
177171
if (config.getState().excludeFields.contains(psiField.getName())) {
178172
continue;
@@ -183,8 +177,6 @@ public void resolveChildren() {
183177
FieldInfo fieldInfo = FieldFactory.buildFieldWithParent(project,this,psiField.getName(), realFieldType,DesUtil.getDescription(psiField), psiField.getAnnotations());
184178
children.add(fieldInfo);
185179
}
186-
return;
187180
}
188-
return;
189181
}
190182
}

src/site/forgus/plugins/apigenerator/util/FieldUtil.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.intellij.psi.util.PsiUtil;
66
import org.apache.commons.lang.StringUtils;
77
import site.forgus.plugins.apigenerator.constant.JacksonAnnotation;
8+
import site.forgus.plugins.apigenerator.constant.SwaggerAnnotation;
89
import site.forgus.plugins.apigenerator.constant.WebAnnotation;
910
import site.forgus.plugins.apigenerator.normal.FieldInfo;
1011
import site.forgus.plugins.apigenerator.normal.RequireAndRange;
@@ -60,7 +61,18 @@ private static boolean isParamRequired(PsiAnnotation annotation) {
6061
}
6162
return true;
6263
}
63-
return requiredTexts.contains(annotationText.split("\\(")[0]);
64+
if(requiredTexts.contains(annotationText.split("\\(")[0])) {
65+
return true;
66+
}
67+
if(annotationText.contains(SwaggerAnnotation.ApiModelProperty)) {
68+
PsiNameValuePair[] psiNameValuePairs = annotation.getParameterList().getAttributes();
69+
for (PsiNameValuePair psiNameValuePair : psiNameValuePairs) {
70+
if ("required".equals(psiNameValuePair.getName()) && "true".equals(psiNameValuePair.getLiteralValue())) {
71+
return true;
72+
}
73+
}
74+
}
75+
return false;
6476
}
6577

6678
public static RequireAndRange getRequireAndRange(PsiAnnotation[] annotations) {

0 commit comments

Comments
 (0)