From ec8897870023d6ee0930823cccda9a75d91e70d7 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 14 May 2025 21:45:28 +0200 Subject: [PATCH] Don't re-trigger Java validation for all opened Java files when a Java file is saved. Signed-off-by: azerr --- ...MicroProfilePropertiesListenerManager.java | 49 ++++++++++++++++++- .../ls/java/JavaFileTextDocumentService.java | 22 ++++++--- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/MicroProfilePropertiesListenerManager.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/MicroProfilePropertiesListenerManager.java index 359fff529..2d2f5405a 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/MicroProfilePropertiesListenerManager.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/MicroProfilePropertiesListenerManager.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; @@ -27,12 +28,15 @@ import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IElementChangedListener; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaElementDelta; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.lsp4mp.commons.MicroProfilePropertiesChangeEvent; import org.eclipse.lsp4mp.commons.MicroProfilePropertiesScope; import org.eclipse.lsp4mp.jdt.core.IMicroProfilePropertiesChangedListener; @@ -146,11 +150,17 @@ public boolean visit(IResourceDelta delta) throws CoreException { if (resource == null) { return false; } + + // Step 5: Process folders, files, and projects as needed switch (resource.getType()) { case IResource.ROOT: + return true; case IResource.PROJECT: + IProject project = (IProject) resource; + return project.isAccessible() && project.hasNature(JavaCore.NATURE_ID); case IResource.FOLDER: - return resource.isAccessible(); + // Ignore folder which belongs to Java output file location (ex: target/classes) + return resource.isAccessible() && !isInOutput(resource); case IResource.FILE: IFile file = (IFile) resource; if (isJavaFile(file) && isFileContentChanged(delta)) { @@ -171,6 +181,43 @@ public boolean visit(IResourceDelta delta) throws CoreException { return false; } + /** + * Returns true if the given (folder) resource is in the Java output location + * (ex : /target/classes) and false otherwise (ex: src/main/java). + * + * @param resource the folder resource. + * @return true if the given (folder) resource is in the Java output location + * (ex : /target/classes) and false otherwise (ex: src/main/java). + * @throws JavaModelException + */ + private static boolean isInOutput(IResource resource) throws JavaModelException { + + IJavaProject javaProject = JavaCore.create(resource.getProject()); + IPath resourcePath = resource.getFullPath(); + + // Exclude resources in the main output location (e.g.,/ProjectName/bin) + IPath outputLocation = javaProject.getOutputLocation(); + IPath outputFullPath = ResourcesPlugin.getWorkspace().getRoot().getFolder(outputLocation).getFullPath(); + if (outputFullPath.isPrefixOf(resourcePath)) { + return true; + } + + // Exclude resources in custom output locations (if any) + for (IPackageFragmentRoot root : javaProject.getPackageFragmentRoots()) { + if (root.getKind() == IPackageFragmentRoot.K_SOURCE) { + IPath customOutput = root.getRawClasspathEntry().getOutputLocation(); + if (customOutput != null) { + IPath customFullPath = ResourcesPlugin.getWorkspace().getRoot().getFolder(customOutput) + .getFullPath(); + if (customFullPath.isPrefixOf(resourcePath)) { + return true; + } + } + } + } + return false; + } + private void fireAsyncEvent(MicroProfilePropertiesChangeEvent event) { // IMPORTANT: The LSP notification 'microprofile/propertiesChanged' must be // executed diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java index c3c3454f3..74b7b1316 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java @@ -64,7 +64,6 @@ import org.eclipse.lsp4mp.ls.commons.TextDocument; import org.eclipse.lsp4mp.ls.commons.ValidatorDelayer; import org.eclipse.lsp4mp.ls.commons.client.CommandKind; -import org.eclipse.lsp4mp.ls.commons.client.ExtendedCompletionCapabilities; import org.eclipse.lsp4mp.ls.java.JavaTextDocuments.JavaTextDocument; import org.eclipse.lsp4mp.ls.properties.IPropertiesModelProvider; import org.eclipse.lsp4mp.model.Node; @@ -93,7 +92,8 @@ public class JavaFileTextDocumentService extends AbstractTextDocumentService { private ValidatorDelayer validatorDelayer; public JavaFileTextDocumentService(MicroProfileLanguageServer microprofileLanguageServer, - IPropertiesModelProvider propertiesModelProvider, SharedSettings sharedSettings, JavaTextDocuments javaTextDocuments) { + IPropertiesModelProvider propertiesModelProvider, SharedSettings sharedSettings, + JavaTextDocuments javaTextDocuments) { super(microprofileLanguageServer, sharedSettings); this.propertiesModelProvider = propertiesModelProvider; this.documents = javaTextDocuments; @@ -125,8 +125,17 @@ public void didClose(DidCloseTextDocumentParams params) { @Override public void didSave(DidSaveTextDocumentParams params) { + // Do nothing.. + + // Since the beginning of the MP LS project, + // saving a Java file triggers validation for all open Java files, + // which can negatively impact performance. + // As there's no comment explaining the reason for this behavior, + // we are disabling this feature. + // validate all opened java files which belong to a MicroProfile project - triggerValidationForAll(null); + // triggerValidationForAll(null); + } // ------------------------------ Completion ------------------------------ @@ -167,8 +176,9 @@ public CompletableFuture, CompletionList>> completio JavaCursorContextResult cursorContext = completionResult.getCursorContext(); // calculate the snippet completion items based on the context - List snippetCompletionItems = documents.getSnippetRegistry().getCompletionItems(document, finalizedCompletionOffset, - canSupportMarkdown, snippetsSupported, (context, model) -> { + List snippetCompletionItems = documents.getSnippetRegistry().getCompletionItems( + document, finalizedCompletionOffset, canSupportMarkdown, snippetsSupported, + (context, model) -> { if (context != null && context instanceof SnippetContextForJava) { return ((SnippetContextForJava) context) .isMatch(new JavaSnippetCompletionContext(projectInfo, cursorContext)); @@ -339,7 +349,7 @@ private void validate(JavaTextDocument javaTextDocument, boolean delay) { /** * Validate the given opened Java file. * - * @param document the opened Java file. + * @param document the opened Java file. */ private void triggerValidationFor(JavaTextDocument document) { document.executeIfInMicroProfileProject((projectinfo, cancelChecker) -> {