Allow SPEL or Property Holder in the cron parameter of @Scheduled
This commit is contained in:
@@ -58,7 +58,7 @@ public class JdtCronReconciler implements JdtAstReconciler {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null && "cron".equals(name)) {
|
||||
if (name != null && "cron".equals(name) && JdtCronSemanticTokensProvider.isCronExpression(pair.getValue())) {
|
||||
QueryJdtAstReconciler.reconcileExpression(cronReconciler, pair.getValue(), problemCollector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TextBlock;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
|
||||
@@ -68,7 +71,7 @@ public class JdtCronSemanticTokensProvider implements JdtSemanticTokensProvider
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
if (name != null && "cron".equals(name)) {
|
||||
if (name != null && "cron".equals(name) && isCronExpression(pair.getValue())) {
|
||||
JdtDataQuerySemanticTokensProvider.computeTokensForExpression(tokensProvider, pair.getValue()).forEach(collector::accept);
|
||||
}
|
||||
}
|
||||
@@ -81,5 +84,20 @@ public class JdtCronSemanticTokensProvider implements JdtSemanticTokensProvider
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isCronExpression(Expression e) {
|
||||
String value = null;
|
||||
if (e instanceof StringLiteral sl) {
|
||||
value = sl.getLiteralValue();
|
||||
} else if (e instanceof TextBlock tb) {
|
||||
value = tb.getLiteralValue();
|
||||
}
|
||||
value = value.trim();
|
||||
if (value.startsWith("#{") || value.startsWith("${")) {
|
||||
// Either SPEL or Property Holder
|
||||
return false;
|
||||
}
|
||||
return value != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@ public final class AnnotationParamSpelExtractor {
|
||||
new AnnotationParamSpelExtractor(SPRING_POST_FILTER, "value", "", ""),
|
||||
|
||||
new AnnotationParamSpelExtractor(SPRING_CONDITIONAL_ON_EXPRESSION, null, "", ""),
|
||||
new AnnotationParamSpelExtractor(SPRING_CONDITIONAL_ON_EXPRESSION, "value", "", "")
|
||||
new AnnotationParamSpelExtractor(SPRING_CONDITIONAL_ON_EXPRESSION, "value", "", ""),
|
||||
|
||||
new AnnotationParamSpelExtractor(Annotations.SCHEDULED, "cron", "#{", "}"),
|
||||
};
|
||||
|
||||
|
||||
@@ -125,10 +127,16 @@ public final class AnnotationParamSpelExtractor {
|
||||
private Optional<Snippet> fromStringLiteral(StringLiteral valueExp) {
|
||||
String value = valueExp.getEscapedValue();
|
||||
value = value.substring(1, value.length() - 1);
|
||||
if (value != null && value.startsWith(paramValuePrefix) && value.endsWith(paramValuePostfix)) {
|
||||
String spelText = value.substring(paramValuePrefix.length(), value.length() - paramValuePostfix.length());
|
||||
int offset = valueExp.getStartPosition() + paramValuePrefix.length() + 1;
|
||||
return Optional.of(new Snippet(spelText, offset));
|
||||
if (value != null) {
|
||||
int startIdx = value.indexOf(paramValuePrefix);
|
||||
if (startIdx >= 0) {
|
||||
int endIdx = value.lastIndexOf(paramValuePostfix);
|
||||
if (endIdx >= 0) {
|
||||
String spelText = value.substring(startIdx + paramValuePrefix.length(), endIdx);
|
||||
int offset = valueExp.getStartPosition() + startIdx + paramValuePrefix.length() + 1;
|
||||
return Optional.of(new Snippet(spelText, offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -274,4 +274,5 @@ public class CronSemanticTokensTest {
|
||||
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(24, 25, "operator", new String[0])); // -
|
||||
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(25, 30, "enum", new String[0])); // MARCH
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,6 +87,46 @@ public class JdtCronReconcilerTest {
|
||||
editor.assertProblems();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noErrors_PropertyHolder() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
public class A {
|
||||
|
||||
@Scheduled(cron = " ${demo.cron} ")
|
||||
void foo() {}
|
||||
|
||||
}
|
||||
""";
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/A.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noErrors_SPEL() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
public class A {
|
||||
|
||||
@Scheduled(cron = " #{demo.cron} ")
|
||||
void foo() {}
|
||||
|
||||
}
|
||||
""";
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/A.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems();
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorsReported_1() throws Exception {
|
||||
String source = """
|
||||
|
||||
@@ -367,4 +367,56 @@ public class JdtCronSemanticTokensProviderTest {
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(142, 147, "enum", new String[0]));
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("MARCH");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noTokens_SPEL() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
public class A {
|
||||
|
||||
@Scheduled(cron=" #{demo.cron} ")
|
||||
void foo() {}
|
||||
|
||||
}
|
||||
""";
|
||||
|
||||
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/A.java").toUri()
|
||||
.toASCIIString();
|
||||
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "A.java", jp);
|
||||
|
||||
assertThat(cu).isNotNull();
|
||||
|
||||
List<SemanticTokenData> tokens = computeTokens(cu);
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void noTokens_PropertyHolder() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
public class A {
|
||||
|
||||
@Scheduled(cron=" ${demo.cron} ")
|
||||
void foo() {}
|
||||
|
||||
}
|
||||
""";
|
||||
|
||||
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/A.java").toUri()
|
||||
.toASCIIString();
|
||||
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "A.java", jp);
|
||||
|
||||
assertThat(cu).isNotNull();
|
||||
|
||||
List<SemanticTokenData> tokens = computeTokens(cu);
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,5 +154,43 @@ public class JdtSpelSemanticTokensProviderTest {
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("'[a-zA-Z\\s]+'");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void leadingAndTrailingSpaces() throws Exception {
|
||||
String source = """
|
||||
package my.package
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
public class A {
|
||||
|
||||
@Scheduled(cron=" #{demo.cron} ")
|
||||
void foo() {}
|
||||
|
||||
}
|
||||
""";
|
||||
|
||||
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/A.java").toUri()
|
||||
.toASCIIString();
|
||||
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "A.java", jp);
|
||||
|
||||
assertThat(cu).isNotNull();
|
||||
|
||||
List<SemanticTokenData> tokens = computeTokens(cu);
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(3);
|
||||
|
||||
SemanticTokenData token = tokens.get(0);
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(121, 125, "variable", new String[0]));
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("demo");
|
||||
|
||||
token = tokens.get(1);
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(125, 126, "operator", new String[0]));
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo(".");
|
||||
|
||||
token = tokens.get(2);
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(126, 130, "property", new String[0]));
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("cron");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user