include method definition context to explain spel expressions
This commit is contained in:
@@ -56,6 +56,7 @@ import org.springframework.ide.vscode.boot.java.requestmapping.LiveAppURLSymbolP
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxHandlerCodeLensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxRouteHighlightProdivder;
|
||||
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringLiveChangeDetectionWatchdog;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueHoverProvider;
|
||||
@@ -118,6 +119,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
private DocumentSymbolHandler docSymbolProvider;
|
||||
private JdtSemanticTokensHandler semanticTokensHandler;
|
||||
private JdtInlayHintsHandler inlayHintsHandler;
|
||||
private SpelSemanticTokens spelSemanticTokens;
|
||||
|
||||
public BootJavaLanguageServerComponents(ApplicationContext appContext) {
|
||||
this.server = appContext.getBean(SimpleLanguageServer.class);
|
||||
@@ -175,8 +177,10 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
projectFinder,
|
||||
Duration.ofSeconds(5),
|
||||
sourceLinks);
|
||||
|
||||
spelSemanticTokens = appContext.getBean(SpelSemanticTokens.class);
|
||||
|
||||
codeLensHandler = createCodeLensEngine(springSymbolIndex, projectFinder, server);
|
||||
codeLensHandler = createCodeLensEngine(springSymbolIndex, projectFinder, server, spelSemanticTokens);
|
||||
|
||||
highlightsEngine = createDocumentHighlightEngine(appContext);
|
||||
documents.onDocumentHighlight(highlightsEngine);
|
||||
@@ -312,10 +316,10 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
return new BootJavaReferencesHandler(this, cuCache, projectFinder, providers);
|
||||
}
|
||||
|
||||
protected BootJavaCodeLensEngine createCodeLensEngine(SpringSymbolIndex index, JavaProjectFinder projectFinder, SimpleLanguageServer server) {
|
||||
protected BootJavaCodeLensEngine createCodeLensEngine(SpringSymbolIndex index, JavaProjectFinder projectFinder, SimpleLanguageServer server, SpelSemanticTokens spelSemanticTokens) {
|
||||
Collection<CodeLensProvider> codeLensProvider = new ArrayList<>();
|
||||
codeLensProvider.add(new WebfluxHandlerCodeLensProvider(index));
|
||||
codeLensProvider.add(new QueryCodeLensProvider(projectFinder, server));
|
||||
codeLensProvider.add(new QueryCodeLensProvider(projectFinder, server, spelSemanticTokens));
|
||||
|
||||
return new BootJavaCodeLensEngine(this, codeLensProvider);
|
||||
}
|
||||
|
||||
@@ -10,26 +10,35 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.spel.AnnotationParamSpelExtractor;
|
||||
import org.springframework.ide.vscode.boot.java.spel.AnnotationParamSpelExtractor.Snippet;
|
||||
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -42,39 +51,37 @@ import com.google.gson.JsonPrimitive;
|
||||
*/
|
||||
public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
|
||||
|
||||
protected static Logger logger = LoggerFactory.getLogger(QueryCodeLensProvider.class);
|
||||
|
||||
public static final String CMD_ENABLE_COPILOT_FEATURES = "sts/enable/copilot/features";
|
||||
public static final String EXPLAIN_SPEL_TITLE = "Explain Spel Expression using Copilot";
|
||||
public static final String EXPLAIN_QUERY_TITLE = "Explain Query using Copilot";
|
||||
|
||||
|
||||
private static final String QUERY = "Query";
|
||||
private static final String FQN_QUERY = "org.springframework.data.jpa.repository." + QUERY;
|
||||
private static final String SPEL_EXPRESSION_QUERY_PROMPT = "Explain the following SpEL Expression in detail: \n";
|
||||
private static final String JPQL_QUERY_PROMPT = "Explain the following JPQL query in detail. If the query contains any SpEL expressions, explain those parts as well: \n";
|
||||
private static final String HQL_QUERY_PROMPT = "Explain the following HQL query in detail. If the query contains any SpEL expressions, explain those parts as well: \n";
|
||||
private static final String DEFAULT_QUERY_PROMPT = "Explain the following query in detail: \n";
|
||||
private static final String CMD = "vscode-spring-boot.query.explain";
|
||||
|
||||
private static final String CMD = "vscode-spring-boot.query.explain";
|
||||
|
||||
private final AnnotationParamSpelExtractor[] spelExtractors = AnnotationParamSpelExtractor.SPEL_EXTRACTORS;
|
||||
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
|
||||
private SpelSemanticTokens spelSemanticTokens;
|
||||
|
||||
private static boolean showCodeLenses;
|
||||
|
||||
public QueryCodeLensProvider(JavaProjectFinder projectFinder, SimpleLanguageServer server) {
|
||||
|
||||
public QueryCodeLensProvider(JavaProjectFinder projectFinder, SimpleLanguageServer server, SpelSemanticTokens spelSemanticTokens) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.spelSemanticTokens = spelSemanticTokens;
|
||||
server.onCommand(CMD_ENABLE_COPILOT_FEATURES, params -> {
|
||||
if (params.getArguments().get(0) instanceof JsonPrimitive) {
|
||||
QueryCodeLensProvider.showCodeLenses = ((JsonPrimitive)params.getArguments().get(0)).getAsBoolean();
|
||||
QueryCodeLensProvider.showCodeLenses = ((JsonPrimitive) params.getArguments().get(0)).getAsBoolean();
|
||||
}
|
||||
return CompletableFuture.completedFuture(showCodeLenses);
|
||||
return CompletableFuture.completedFuture(showCodeLenses);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provideCodeLenses(CancelChecker cancelToken, TextDocument document, CompilationUnit cu,
|
||||
List<CodeLens> resultAccumulator) {
|
||||
if(!showCodeLenses) {
|
||||
if (!showCodeLenses) {
|
||||
return;
|
||||
}
|
||||
cu.accept(new ASTVisitor() {
|
||||
@@ -83,12 +90,15 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
Arrays.stream(spelExtractors).map(e -> e.getSpelRegion(node)).filter(o -> o.isPresent())
|
||||
.map(o -> o.get()).forEach(snippet -> {
|
||||
provideCodeLensForSpelExpression(cancelToken, node, document, snippet, resultAccumulator);
|
||||
String additionalContext = parseSpelAndFetchContext(cu, snippet.text());
|
||||
provideCodeLensForSpelExpression(cancelToken, node, document, snippet,
|
||||
additionalContext, resultAccumulator);
|
||||
});
|
||||
|
||||
if (isQueryAnnotation(node)) {
|
||||
String queryPrompt = determineQueryPrompt(document);
|
||||
provideCodeLensForQuery(cancelToken, node, document, node.getValue(), queryPrompt, resultAccumulator);
|
||||
provideCodeLensForQuery(cancelToken, node, document, node.getValue(), queryPrompt,
|
||||
resultAccumulator);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
@@ -96,9 +106,13 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
|
||||
|
||||
Arrays.stream(spelExtractors).map(e -> e.getSpelRegion(node)).filter(o -> o.isPresent())
|
||||
.map(o -> o.get()).forEach(snippet -> {
|
||||
provideCodeLensForSpelExpression(cancelToken, node, document, snippet, resultAccumulator);
|
||||
String additionalContext = parseSpelAndFetchContext(cu, snippet.text());
|
||||
provideCodeLensForSpelExpression(cancelToken, node, document, snippet, additionalContext,
|
||||
resultAccumulator);
|
||||
});
|
||||
|
||||
if (isQueryAnnotation(node)) {
|
||||
@@ -107,7 +121,8 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
if ("value".equals(pair.getName().getIdentifier())) {
|
||||
provideCodeLensForQuery(cancelToken, node, document, pair.getValue(), queryPrompt, resultAccumulator);
|
||||
provideCodeLensForQuery(cancelToken, node, document, pair.getValue(), queryPrompt,
|
||||
resultAccumulator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -119,20 +134,26 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
});
|
||||
}
|
||||
|
||||
protected void provideCodeLensForSpelExpression(CancelChecker cancelToken, Annotation node, TextDocument document, Snippet snippet,
|
||||
List<CodeLens> resultAccumulator) {
|
||||
protected void provideCodeLensForSpelExpression(CancelChecker cancelToken, Annotation node, TextDocument document,
|
||||
Snippet snippet, String additionalContext, List<CodeLens> resultAccumulator) {
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
if (snippet != null) {
|
||||
try {
|
||||
String context = additionalContext != null && !additionalContext.isEmpty() ? String.format(
|
||||
"""
|
||||
Finally, provide a brief summary of what the following method does, focusing on its role within the SpEL expression.
|
||||
The summary should mention key criteria the method checks but avoid detailed implementation steps.
|
||||
Please include this summary as an appendix to the main explanation, and avoid repeating information covered earlier.\n\n%s
|
||||
""",additionalContext) : "";
|
||||
|
||||
CodeLens codeLens = new CodeLens();
|
||||
codeLens.setRange(document.toRange(snippet.offset(), snippet.text().length()));
|
||||
|
||||
Command cmd = new Command();
|
||||
cmd.setTitle(EXPLAIN_SPEL_TITLE);
|
||||
cmd.setTitle(QueryType.SPEL.getTitle());
|
||||
cmd.setCommand(CMD);
|
||||
cmd.setArguments(ImmutableList.of(SPEL_EXPRESSION_QUERY_PROMPT + snippet.text()));
|
||||
cmd.setArguments(ImmutableList.of(QueryType.SPEL.getPrompt() + snippet.text() + "\n\n" + context));
|
||||
codeLens.setCommand(cmd);
|
||||
|
||||
resultAccumulator.add(codeLens);
|
||||
@@ -153,14 +174,14 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
codeLens.setRange(document.toRange(valueExp.getStartPosition(), valueExp.getLength()));
|
||||
|
||||
Command cmd = new Command();
|
||||
cmd.setTitle(EXPLAIN_QUERY_TITLE);
|
||||
cmd.setTitle(QueryType.DEFAULT.getTitle());
|
||||
cmd.setCommand(CMD);
|
||||
cmd.setArguments(ImmutableList.of(query + valueExp.toString()));
|
||||
codeLens.setCommand(cmd);
|
||||
|
||||
resultAccumulator.add(codeLens);
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
logger.error("Error providing code lens: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,14 +190,52 @@ public class QueryCodeLensProvider implements CodeLensProvider {
|
||||
return FQN_QUERY.equals(a.getTypeName().getFullyQualifiedName())
|
||||
|| QUERY.equals(a.getTypeName().getFullyQualifiedName());
|
||||
}
|
||||
|
||||
|
||||
private String determineQueryPrompt(TextDocument document) {
|
||||
Optional<IJavaProject> optProject = projectFinder.find(document.getId());
|
||||
if (optProject.isPresent()) {
|
||||
IJavaProject jp = optProject.get();
|
||||
return SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? HQL_QUERY_PROMPT : JPQL_QUERY_PROMPT;
|
||||
}
|
||||
return DEFAULT_QUERY_PROMPT;
|
||||
Optional<IJavaProject> optProject = projectFinder.find(document.getId());
|
||||
if (optProject.isPresent()) {
|
||||
IJavaProject jp = optProject.get();
|
||||
return SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? QueryType.HQL.getPrompt()
|
||||
: QueryType.JPQL.getPrompt();
|
||||
}
|
||||
return QueryType.DEFAULT.getPrompt();
|
||||
}
|
||||
|
||||
private String parseSpelAndFetchContext(CompilationUnit cu, String spelExpression) {
|
||||
List<SemanticTokenData> tokens = parseSpelExpression(spelExpression);
|
||||
Set<String> methodNames = extractMethodNames(tokens, spelExpression);
|
||||
List<String> context = collectMethodContexts(methodNames, cu);
|
||||
return String.join("\n", context);
|
||||
}
|
||||
|
||||
private List<SemanticTokenData> parseSpelExpression(String spelText) {
|
||||
try {
|
||||
return spelSemanticTokens.computeTokens(spelText, 0);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error computing tokens: " + e.getMessage());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<String> extractMethodNames(List<SemanticTokenData> tokens, String spelText) {
|
||||
return tokens.stream().filter(token -> "method".equals(token.type()))
|
||||
.map(token -> spelText.substring(token.start(), token.end())).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private List<String> collectMethodContexts(Set<String> methodNames, CompilationUnit cu) {
|
||||
List<String> methodContext = new ArrayList<>();
|
||||
for (String methodName : methodNames) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
if (node.getName().getIdentifier().equals(methodName)) {
|
||||
methodContext.add(node.toString());
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
return methodContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
public enum QueryType {
|
||||
SPEL("Explain SpEL Expression using Copilot", "Explain the following SpEL Expression with a clear summary first, followed by a breakdown of the expression with details: \n\n"),
|
||||
JPQL("Explain Query using Copilot", "Explain the following JPQL query with a clear summary first, followed by a detailed explanation. If the query contains any SpEL expressions, explain those parts as well: \n\n"),
|
||||
HQL("Explain Query using Copilot", "Explain the following HQL query with a clear summary first, followed by a detailed explanation. If the query contains any SpEL expressions, explain those parts as well: \n\n"),
|
||||
DEFAULT("Explain Query using Copilot", "Explain the following query with a clear summary first, followed by a detailed explanation: \n\n");
|
||||
|
||||
private final String title;
|
||||
private final String prompt;
|
||||
|
||||
QueryType(String title, String prompt) {
|
||||
this.title = title;
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.QueryCodeLensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.QueryType;
|
||||
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ExecuteCommandHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
@@ -66,6 +68,9 @@ public class QueryCodeLensProviderTest {
|
||||
@Autowired
|
||||
private SpringSymbolIndex indexer;
|
||||
private SimpleLanguageServer server;
|
||||
|
||||
@Autowired
|
||||
private SpelSemanticTokens spelSemanticTokens;
|
||||
|
||||
private ArgumentCaptor<ExecuteCommandHandler> commandHandlerCaptor;
|
||||
private QueryCodeLensProvider queryCodeLensProvider;
|
||||
@@ -78,7 +83,7 @@ public class QueryCodeLensProviderTest {
|
||||
String projectDir = directory.toURI().toString();
|
||||
server = mock(SimpleLanguageServer.class);
|
||||
commandHandlerCaptor = ArgumentCaptor.forClass(ExecuteCommandHandler.class);
|
||||
queryCodeLensProvider = new QueryCodeLensProvider(projectFinder, server);
|
||||
queryCodeLensProvider = new QueryCodeLensProvider(projectFinder, server, spelSemanticTokens);
|
||||
|
||||
// trigger project creation
|
||||
projectFinder.find(new TextDocumentIdentifier(projectDir)).get();
|
||||
@@ -102,9 +107,9 @@ public class QueryCodeLensProviderTest {
|
||||
|
||||
assertEquals(3, codeLenses.size());
|
||||
|
||||
assertTrue(containsCodeLens(codeLenses.get(0), QueryCodeLensProvider.EXPLAIN_QUERY_TITLE, 9, 8, 9, 108));
|
||||
assertTrue(containsCodeLens(codeLenses.get(1), QueryCodeLensProvider.EXPLAIN_QUERY_TITLE, 13, 8, 13, 39));
|
||||
assertTrue(containsCodeLens(codeLenses.get(2), QueryCodeLensProvider.EXPLAIN_QUERY_TITLE, 17, 14, 17, 92));
|
||||
assertTrue(containsCodeLens(codeLenses.get(0), QueryType.DEFAULT.getTitle(), 9, 8, 9, 108));
|
||||
assertTrue(containsCodeLens(codeLenses.get(1), QueryType.DEFAULT.getTitle(), 13, 8, 13, 39));
|
||||
assertTrue(containsCodeLens(codeLenses.get(2), QueryType.DEFAULT.getTitle(), 17, 14, 17, 92));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,11 +123,75 @@ public class QueryCodeLensProviderTest {
|
||||
TextDocumentInfo openedDoc = harness.openDocument(doc);
|
||||
|
||||
List<? extends CodeLens> codeLenses = harness.getCodeLenses(openedDoc);
|
||||
|
||||
String expectedPrompt = """
|
||||
Explain the following SpEL Expression with a clear summary first, followed by a breakdown of the expression with details: \n
|
||||
T(org.test.SpelController).isValidVersion('${app.version}') ? 'Valid Version' :'Invalid Version'
|
||||
|
||||
assertEquals(2, codeLenses.size());
|
||||
Finally, provide a brief summary of what the following method does, focusing on its role within the SpEL expression.
|
||||
The summary should mention key criteria the method checks but avoid detailed implementation steps.
|
||||
Please include this summary as an appendix to the main explanation, and avoid repeating information covered earlier.
|
||||
|
||||
assertTrue(containsCodeLens(codeLenses.get(0), QueryCodeLensProvider.EXPLAIN_SPEL_TITLE, 13, 17, 13, 111));
|
||||
assertTrue(containsCodeLens(codeLenses.get(1), QueryCodeLensProvider.EXPLAIN_SPEL_TITLE, 16, 11, 16, 142));
|
||||
public static boolean isValidVersion(String version){
|
||||
if (version.matches("\\\\d+\\\\.\\\\d+\\\\.\\\\d+")) {
|
||||
String[] parts=version.split("\\\\.");
|
||||
int major=Integer.parseInt(parts[0]);
|
||||
int minor=Integer.parseInt(parts[1]);
|
||||
int patch=Integer.parseInt(parts[2]);
|
||||
return (major > 3) || (major == 3 && (minor > 0 || (minor == 0 && patch >= 0)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
""";
|
||||
|
||||
assertEquals(3, codeLenses.size());
|
||||
|
||||
String actualPrompt = codeLenses.get(1).getCommand().getArguments().get(0).toString();
|
||||
|
||||
assertTrue(containsCodeLens(codeLenses.get(0), QueryType.SPEL.getTitle(), 13, 17, 13, 111));
|
||||
assertTrue(containsCodeLens(codeLenses.get(1), QueryType.SPEL.getTitle(), 16, 11, 16, 107));
|
||||
|
||||
assertEquals(expectedPrompt, actualPrompt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowCodeLensesTrueForSpelWithMultipleMethods() throws Exception {
|
||||
|
||||
// Simulate the command execution with true parameter
|
||||
setCommandParamsHandler(true);
|
||||
|
||||
String docUri = directory.toPath().resolve("src/main/java/org/test/SpelController.java").toUri().toString();
|
||||
TextDocumentInfo doc = harness.getOrReadFile(new File(new URI(docUri)), LanguageId.JAVA.getId());
|
||||
TextDocumentInfo openedDoc = harness.openDocument(doc);
|
||||
|
||||
List<? extends CodeLens> codeLenses = harness.getCodeLenses(openedDoc);
|
||||
|
||||
String expectedPrompt = """
|
||||
Explain the following SpEL Expression with a clear summary first, followed by a breakdown of the expression with details: \n
|
||||
T(org.test.SpelController).toUpperCase('hello') + ' ' + T(org.test.SpelController).concat('world', '!')
|
||||
|
||||
Finally, provide a brief summary of what the following method does, focusing on its role within the SpEL expression.
|
||||
The summary should mention key criteria the method checks but avoid detailed implementation steps.
|
||||
Please include this summary as an appendix to the main explanation, and avoid repeating information covered earlier.
|
||||
|
||||
public static String toUpperCase(String input){
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
public static String concat(String str1,String str2){
|
||||
return str1 + str2;
|
||||
}
|
||||
|
||||
""";
|
||||
|
||||
assertEquals(3, codeLenses.size());
|
||||
|
||||
String actualPrompt = codeLenses.get(2).getCommand().getArguments().get(0).toString();
|
||||
|
||||
assertTrue(containsCodeLens(codeLenses.get(2), QueryType.SPEL.getTitle(), 19, 11, 19, 114));
|
||||
|
||||
assertEquals(expectedPrompt, actualPrompt);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -14,8 +14,11 @@ public class SpelController {
|
||||
@Value(value="#{'${app.version}' matches '\\\\d+\\\\.\\\\d+\\\\.\\\\d+' ? '${app.version}' : 'Invalid Version'}")
|
||||
private String version;
|
||||
|
||||
@Value("#{T(org.springframework.samples.petclinic.owner.SpelController).isValidVersion('${app.version}') ? 'Valid Version' :'Invalid Version'}")
|
||||
@Value("#{T(org.test.SpelController).isValidVersion('${app.version}') ? 'Valid Version' :'Invalid Version'}")
|
||||
private String versionValidity;
|
||||
|
||||
@Value("#{T(org.test.SpelController).toUpperCase('hello') + ' ' + T(org.test.SpelController).concat('world', '!')}")
|
||||
private String greeting;
|
||||
|
||||
@GetMapping("/version")
|
||||
@ResponseBody
|
||||
@@ -39,5 +42,13 @@ public class SpelController {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String toUpperCase(String input) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
public static String concat(String str1, String str2) {
|
||||
return str1 + str2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,9 +92,6 @@ async function updateConfiguration(value: boolean) {
|
||||
|
||||
async function explainQueryWithCopilot() {
|
||||
commands.registerCommand('vscode-spring-boot.query.explain', async (userPrompt) => {
|
||||
console.log('spel.explain: ' + userPrompt);
|
||||
console.log('messages: ' + userPrompt);
|
||||
|
||||
await commands.executeCommand('workbench.action.chat.open', { query: userPrompt });
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user