diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java index 66620aff6..0e75cccf7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.boot.java.handlers; import java.util.List; +import java.util.Set; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ITypeBinding; @@ -18,6 +19,7 @@ import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.StringLiteral; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; /** @@ -44,9 +46,9 @@ public class AnnotationParamReconciler { if (this.paramName != null) { return; } - - String qname = typeBinding.getQualifiedName(); - if (!this.annotationType.equals(qname)) { + + Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding); + if (!allAnnotations.contains(this.annotationType)) { return; } @@ -62,8 +64,8 @@ public class AnnotationParamReconciler { return; } - String qname = typeBinding.getQualifiedName(); - if (!this.annotationType.equals(qname)) { + Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding); + if (!allAnnotations.contains(this.annotationType)) { return; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java index ff0a725ef..03b649aff 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java @@ -26,7 +26,6 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; -import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.util.text.IDocument; /** diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java index 2c07d5666..129a3c029 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java @@ -233,7 +233,7 @@ public class ValueSpelExpressionValidationTest { @Test public void testIncorrectSpelExpressionFoundOnSpelParamOfCachableAnnotation() throws Exception { - TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(condition=\"#{new String('hello world).toUpperCase()}\")"); + TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(condition=\"new String('hello world).toUpperCase()\")"); assertNotNull(doc); reconcileEngine.reconcile(doc, problemCollector); @@ -244,7 +244,7 @@ public class ValueSpelExpressionValidationTest { @Test public void testIncorrectSpelExpressionNotFoundOnNonSpelParamOfCachableAnnotation() throws Exception { - TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(keyGenerator=\"#{new String('hello world).toUpperCase()}\")"); + TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(keyGenerator=\"new String('hello world).toUpperCase()\")"); assertNotNull(doc); reconcileEngine.reconcile(doc, problemCollector); @@ -255,7 +255,7 @@ public class ValueSpelExpressionValidationTest { @Test public void testIncorrectSpelExpressionFoundOnSpelParamOfCachableAnnotationAmongOtherParams() throws Exception { - TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(keyGenerator=\"somekey\", condition=\"#{new String('hello world).toUpperCase()}\")"); + TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(keyGenerator=\"somekey\", condition=\"new String('hello world).toUpperCase()\")"); assertNotNull(doc); reconcileEngine.reconcile(doc, problemCollector); @@ -266,7 +266,7 @@ public class ValueSpelExpressionValidationTest { @Test public void testIncorrectSpelExpressionFoundOnMultipleSpelParamsOfCachableAnnotation() throws Exception { - TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(unless=\"#{new String('hello world).toUpperCase()}\", condition=\"#{new String('hello world).toUpperCase()}\")"); + TextDocument doc = prepareDocument("@Value(\"onField\")", "@Cacheable(unless=\"new String('hello world).toUpperCase()\", condition=\"new String('hello world).toUpperCase()\")"); assertNotNull(doc); reconcileEngine.reconcile(doc, problemCollector); @@ -275,6 +275,30 @@ public class ValueSpelExpressionValidationTest { assertEquals(2, problems.size()); } + @Test + public void testCorrectSpelExpressionFoundOnCustomAnnotation() throws Exception { + TextDocument doc = prepareDocument("@Value(\"onMethod\")", "@CustomEventListener(condition=\"new String('hello world').toUpperCase()\")"); + assertNotNull(doc); + + reconcileEngine.reconcile(doc, problemCollector); + + List problems = problemCollector.getCollectedProblems(); + assertEquals(0, problems.size()); + } + + @Test + public void testIncorrectSpelExpressionFoundOnCustomAnnotation() throws Exception { + TextDocument doc = prepareDocument("@Value(\"onMethod\")", "@CustomEventListener(condition=\"new String('hello world).toUpperCase()\")"); + assertNotNull(doc); + + reconcileEngine.reconcile(doc, problemCollector); + + List problems = problemCollector.getCollectedProblems(); + assertEquals(1, problems.size()); + } + + + private TextDocument prepareDocument(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception { String content = IOUtils.toString(new URI(docUri)); diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotations/src/main/java/org/test/CustomEventListener.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotations/src/main/java/org/test/CustomEventListener.java new file mode 100644 index 000000000..616b82e19 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotations/src/main/java/org/test/CustomEventListener.java @@ -0,0 +1,7 @@ +package org.test; + +import org.springframework.context.event.EventListener; + +@EventListener +public @interface CustomEventListener { +}