Skip to content

Commit 3e8a32d

Browse files
committed
Feature/JAX-RS - refer to class and method hierarchies when searching for annotations #277
1 parent 5dc40c4 commit 3e8a32d

File tree

3 files changed

+100
-31
lines changed

3 files changed

+100
-31
lines changed

java/src/main/java/org/digma/intellij/plugin/idea/psi/java/JavaLanguageUtils.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,20 @@
55
import com.intellij.openapi.project.Project;
66
import com.intellij.openapi.roots.ProjectFileIndex;
77
import com.intellij.openapi.vfs.VirtualFile;
8-
import com.intellij.psi.*;
8+
import com.intellij.psi.PsiAnnotation;
9+
import com.intellij.psi.PsiClass;
10+
import com.intellij.psi.PsiElement;
11+
import com.intellij.psi.PsiExpression;
12+
import com.intellij.psi.PsiExpressionList;
13+
import com.intellij.psi.PsiField;
14+
import com.intellij.psi.PsiFile;
15+
import com.intellij.psi.PsiJavaFile;
16+
import com.intellij.psi.PsiLiteral;
17+
import com.intellij.psi.PsiLiteralExpression;
18+
import com.intellij.psi.PsiLocalVariable;
19+
import com.intellij.psi.PsiManager;
20+
import com.intellij.psi.PsiMethod;
21+
import com.intellij.psi.PsiReferenceExpression;
922
import com.intellij.psi.impl.source.PsiClassReferenceType;
1023
import com.intellij.testFramework.LightVirtualFile;
1124
import org.digma.intellij.plugin.index.DocumentInfoIndex;
@@ -192,8 +205,6 @@ public static boolean isMethodWithNoArguments(@NotNull PsiElement psiElement,@No
192205
}
193206

194207

195-
196-
197208
@Nullable
198209
public static String getValueFromFirstArgument(@NotNull PsiExpressionList argumentList) {
199210
PsiExpression[] psiExpressions = argumentList.getExpressions();

java/src/main/java/org/digma/intellij/plugin/idea/psi/java/JaxrsFramework.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
import com.intellij.psi.PsiFile;
99
import com.intellij.psi.PsiMethod;
1010
import com.intellij.psi.search.GlobalSearchScope;
11-
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
12-
import com.intellij.util.Query;
1311
import org.digma.intellij.plugin.log.Log;
1412
import org.digma.intellij.plugin.model.discovery.DocumentInfo;
1513
import org.digma.intellij.plugin.model.discovery.EndpointInfo;
1614
import org.digma.intellij.plugin.model.discovery.MethodInfo;
1715
import org.jetbrains.annotations.NotNull;
1816

17+
import java.util.Arrays;
1918
import java.util.List;
2019
import java.util.Objects;
2120
import java.util.stream.Collectors;
@@ -77,39 +76,48 @@ public void endpointDiscovery(@NotNull PsiFile psiFile, @NotNull DocumentInfo do
7776
return;
7877
}
7978

80-
httpMethodsAnnotations.forEach(currAnnotation -> {
81-
Query<PsiMethod> psiMethodsOfHttpMethodInFile = AnnotatedElementsSearch.searchPsiMethods(currAnnotation.getPsiClass(), GlobalSearchScope.fileScope(psiFile));
79+
List<PsiClass> allClassesInFile = JavaPsiUtils.getClassesWithin(psiFile);
80+
for (PsiClass currClass : allClassesInFile) {
81+
final PsiAnnotation controllerPathAnnotation = JavaPsiUtils.findNearestAnnotation(currClass, JAX_RS_PATH_ANNOTATION_STR);
8282

83-
for (PsiMethod currPsiMethod : psiMethodsOfHttpMethodInFile) {
84-
PsiClass controllerClass = currPsiMethod.getContainingClass();
85-
if (controllerClass == null) {
86-
continue; // very unlikely
87-
}
88-
PsiAnnotation controllerAnnotation = controllerClass.getAnnotation(JAX_RS_PATH_ANNOTATION_STR);
89-
if (controllerAnnotation == null) {
90-
continue; // skip this method, since its class is not a controller
91-
}
92-
String endpointUriPrefix = JavaLanguageUtils.getPsiAnnotationAttributeValue(controllerAnnotation, "value");
93-
94-
String endpointUriSuffix = "";
95-
PsiAnnotation methodPathAnnotation = currPsiMethod.getAnnotation(JAX_RS_PATH_ANNOTATION_STR); // optional annotation on method
96-
if (methodPathAnnotation != null) {
97-
endpointUriSuffix = JavaLanguageUtils.getPsiAnnotationAttributeValue(methodPathAnnotation, "value");
83+
List<PsiMethod> methodsInClass = Arrays.asList(currClass.getMethods());
84+
for (PsiMethod currPsiMethod : methodsInClass) {
85+
final PsiAnnotation methodPathAnnotation = JavaPsiUtils.findNearestAnnotation(currPsiMethod, JAX_RS_PATH_ANNOTATION_STR);
86+
if (methodPathAnnotation == null && controllerPathAnnotation == null) {
87+
continue; // skip since could not find annotation of @Path, in either class and or method
9888
}
9989

100-
String endpointFullUri = JavaUtils.combineUri(endpointUriPrefix, endpointUriSuffix);
90+
for (JavaAnnotation currExpectedAnnotation : httpMethodsAnnotations) {
91+
PsiAnnotation httpMethodAnnotation = JavaPsiUtils.findNearestAnnotation(currPsiMethod, currExpectedAnnotation.getClassNameFqn());
92+
if (httpMethodAnnotation == null) {
93+
continue; // skipping since could not find annotation of HTTP Method, such as @GET
94+
}
95+
String endpointFullUri = combinePaths(controllerPathAnnotation, methodPathAnnotation);
10196

102-
String httpEndpointCodeObjectId = createHttpEndpointCodeObjectId(currAnnotation, endpointFullUri);
97+
String httpEndpointCodeObjectId = createHttpEndpointCodeObjectId(currExpectedAnnotation, endpointFullUri);
10398

104-
EndpointInfo endpointInfo = new EndpointInfo(httpEndpointCodeObjectId, JavaLanguageUtils.createJavaMethodCodeObjectId(currPsiMethod), documentInfo.getFileUri());
105-
Log.log(LOGGER::debug, "Found endpoint info '{}' for method '{}'", endpointInfo.getId(), endpointInfo.getContainingMethodId());
99+
EndpointInfo endpointInfo = new EndpointInfo(httpEndpointCodeObjectId, JavaLanguageUtils.createJavaMethodCodeObjectId(currPsiMethod), documentInfo.getFileUri());
100+
Log.log(LOGGER::debug, "Found endpoint info '{}' for method '{}'", endpointInfo.getId(), endpointInfo.getContainingMethodId());
106101

107-
MethodInfo methodInfo = documentInfo.getMethods().get(endpointInfo.getContainingMethodId());
108-
//this method must exist in the document info
109-
Objects.requireNonNull(methodInfo, "method info " + endpointInfo.getContainingMethodId() + " must exist in DocumentInfo for " + documentInfo.getFileUri());
110-
methodInfo.addEndpoint(endpointInfo);
102+
MethodInfo methodInfo = documentInfo.getMethods().get(endpointInfo.getContainingMethodId());
103+
//this method must exist in the document info
104+
Objects.requireNonNull(methodInfo, "method info " + endpointInfo.getContainingMethodId() + " must exist in DocumentInfo for " + documentInfo.getFileUri());
105+
methodInfo.addEndpoint(endpointInfo);
106+
}
111107
}
112-
});
108+
}
109+
}
110+
111+
protected static String combinePaths(PsiAnnotation annotOfPrefix, PsiAnnotation annotOfSuffix) {
112+
String prefixStr = "";
113+
if (annotOfPrefix != null) {
114+
prefixStr = JavaLanguageUtils.getPsiAnnotationAttributeValue(annotOfPrefix, "value");
115+
}
116+
String suffixStr = "";
117+
if (annotOfSuffix != null) {
118+
suffixStr = JavaLanguageUtils.getPsiAnnotationAttributeValue(annotOfSuffix, "value");
119+
}
120+
return JavaUtils.combineUri(prefixStr, suffixStr);
113121
}
114122

115123
@NotNull

java/src/main/kotlin/org/digma/intellij/plugin/idea/psi/java/JavaPsiUtils.kt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package org.digma.intellij.plugin.idea.psi.java
22

3+
import com.intellij.psi.PsiAnnotation
34
import com.intellij.psi.PsiClass
5+
import com.intellij.psi.PsiFile
6+
import com.intellij.psi.PsiJavaFile
7+
import com.intellij.psi.PsiMethod
48
import org.jetbrains.annotations.NotNull
9+
import org.jetbrains.annotations.Nullable
510

611
class JavaPsiUtils {
712

@@ -33,5 +38,50 @@ class JavaPsiUtils {
3338
return prevCLass
3439
}
3540
}
41+
42+
@JvmStatic
43+
@NotNull
44+
fun getClassesWithin(psiFile: PsiFile): List<PsiClass> {
45+
//it must be a PsiJavaFile so casting should be ok
46+
val psiJavaFile = psiFile as PsiJavaFile
47+
return psiJavaFile.classes.asList()
48+
}
49+
50+
@JvmStatic
51+
@Nullable
52+
fun findNearestAnnotation(psiMethod: PsiMethod, annotationFqn: String): PsiAnnotation? {
53+
val annotClass = psiMethod.getAnnotation(annotationFqn)
54+
if (annotClass != null) {
55+
return annotClass
56+
}
57+
58+
val superMethods = psiMethod.findSuperMethods(false)
59+
superMethods.forEach {
60+
val theAnnotation = it.getAnnotation(annotationFqn)
61+
if (theAnnotation != null) {
62+
return theAnnotation
63+
}
64+
}
65+
return null
66+
}
67+
68+
@JvmStatic
69+
@Nullable
70+
fun findNearestAnnotation(psiClass: PsiClass, annotationFqn: String): PsiAnnotation? {
71+
val annotClass = psiClass.getAnnotation(annotationFqn)
72+
if (annotClass != null) {
73+
return annotClass
74+
}
75+
76+
val superClasses = psiClass.supers
77+
superClasses.forEach {
78+
val theAnnotation = it.getAnnotation(annotationFqn)
79+
if (theAnnotation != null) {
80+
return theAnnotation
81+
}
82+
}
83+
return null
84+
}
85+
3686
}
3787
}

0 commit comments

Comments
 (0)