You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by db...@apache.org on 2022/03/09 07:42:47 UTC

[netbeans] branch master updated: SQL completion for Query annotations added. (#3722)

This is an automated email from the ASF dual-hosted git repository.

dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 0bf3845  SQL completion for Query annotations added. (#3722)
0bf3845 is described below

commit 0bf384595621bae2b38c943d8face1198afa9831
Author: Dusan Balek <du...@oracle.com>
AuthorDate: Wed Mar 9 08:42:34 2022 +0100

    SQL completion for Query annotations added. (#3722)
---
 enterprise/micronaut/nbproject/project.xml         |  8 +++
 .../MicronautDataCompletionCollector.java          |  8 +++
 .../MicronautDataCompletionProvider.java           |  5 ++
 .../completion/MicronautDataCompletionTask.java    | 81 +++++++++++++++++++---
 ide/db.sql.editor/nbproject/project.properties     |  2 +-
 ide/db.sql.editor/nbproject/project.xml            |  1 +
 .../completion/ETCompletionContextResolver.java    | 22 +++++-
 .../nbcode/nbproject/platform.properties           |  3 -
 8 files changed, 114 insertions(+), 16 deletions(-)

diff --git a/enterprise/micronaut/nbproject/project.xml b/enterprise/micronaut/nbproject/project.xml
index e6d3c51..1cec8be 100644
--- a/enterprise/micronaut/nbproject/project.xml
+++ b/enterprise/micronaut/nbproject/project.xml
@@ -119,6 +119,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.modules.db.sql.editor</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.53</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.modules.editor.codetemplates</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
index 3f5abd0..34a0b1f 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
@@ -22,6 +22,7 @@ import java.util.function.Consumer;
 import javax.swing.text.Document;
 import org.netbeans.api.editor.mimelookup.MimeRegistration;
 import org.netbeans.api.lsp.Completion;
+import org.netbeans.spi.editor.completion.CompletionItem;
 import org.netbeans.spi.lsp.CompletionCollector;
 
 /**
@@ -47,6 +48,13 @@ public class MicronautDataCompletionCollector implements CompletionCollector {
             public Completion createFinderMethodNameItem(String prefix, String name, int offset) {
                 return CompletionCollector.newBuilder(prefix + name).kind(Completion.Kind.Method).sortText(String.format("%04d%s", 10, name)).build();
             }
+            @Override
+            public Completion createSQLItem(CompletionItem item) {
+                return CompletionCollector.newBuilder(item.getInsertPrefix().toString())
+                        .insertText(item.getInsertPrefix().toString().replace("\"", "\\\""))
+                        .kind(Completion.Kind.Property)
+                        .build();
+            }
         }).stream().forEach(consumer);
         return true;
     }
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java
index 074657f..867c54d 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java
@@ -95,6 +95,11 @@ public final class MicronautDataCompletionProvider implements CompletionProvider
                             .sortText(name)
                             .build();
                 }
+
+                @Override
+                public CompletionItem createSQLItem(CompletionItem item) {
+                    return item;
+                }
             }));
             resultSet.setAnchorOffset(task.getAnchorOffset());
             resultSet.finish();
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java
index 4bfda64..92d1160 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java
@@ -38,6 +38,7 @@ import java.util.prefs.PreferenceChangeListener;
 import java.util.prefs.Preferences;
 import java.util.regex.Pattern;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
@@ -46,7 +47,10 @@ import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.ElementFilter;
 import javax.lang.model.util.Types;
+import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.db.explorer.ConnectionManager;
 import org.netbeans.api.editor.mimelookup.MimeLookup;
 import org.netbeans.api.java.lexer.JavaTokenId;
 import org.netbeans.api.java.source.CompilationController;
@@ -55,11 +59,16 @@ import org.netbeans.api.java.source.JavaSource;
 import org.netbeans.api.java.source.TreeUtilities;
 import org.netbeans.api.java.source.TypeUtilities;
 import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.modules.db.sql.editor.api.completion.SQLCompletion;
+import org.netbeans.modules.db.sql.editor.api.completion.SQLCompletionContext;
+import org.netbeans.modules.db.sql.editor.api.completion.SQLCompletionResultSet;
 import org.netbeans.modules.parsing.api.ParserManager;
 import org.netbeans.modules.parsing.api.ResultIterator;
 import org.netbeans.modules.parsing.api.Source;
 import org.netbeans.modules.parsing.api.UserTask;
 import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.openide.text.NbDocument;
 import org.openide.util.Exceptions;
 import org.openide.util.WeakListeners;
 
@@ -69,8 +78,10 @@ import org.openide.util.WeakListeners;
  */
 public class MicronautDataCompletionTask {
 
-    private static final String REPOSITORY_ANNOTATION_NAME = "io.micronaut.data.annotation.Repository";
+    private static final String JPA_REPOSITORY_ANNOTATION_NAME = "io.micronaut.data.annotation.Repository";
+    private static final String JDBC_REPOSITORY_ANNOTATION_NAME = "io.micronaut.data.jdbc.annotation.JdbcRepository";
     private static final String REPOSITORY_TYPE_NAME = "io.micronaut.data.repository.GenericRepository";
+    private static final String QUERY_ANNOTATION_TYPE_NAME = "io.micronaut.data.annotation.Query";
     private static final String GET = "get";
     private static final List<String> QUERY_PATTERNS = new ArrayList<>(Arrays.asList("find", "get", "query", "read", "retrieve", "search"));
     private static final List<String> SPECIAL_QUERY_PATTERNS = new ArrayList<>(Arrays.asList("count", "countDistinct", "delete", "exists", "update"));
@@ -114,6 +125,7 @@ public class MicronautDataCompletionTask {
     public static interface ItemFactory<T> {
         T createFinderMethodItem(String name, String returnType, int offset);
         T createFinderMethodNameItem(String prefix, String name, int offset);
+        T createSQLItem(CompletionItem item);
     }
 
     public <T> List<T> query(Document doc, int caretOffset, ItemFactory<T> factory) {
@@ -133,9 +145,15 @@ public class MicronautDataCompletionTask {
                     int len = anchorOffset - ts.offset();
                     if (len > 0 && ts.token().length() >= len) {
                         if (ts.token().id() == JavaTokenId.IDENTIFIER || ts.token().id().primaryCategory().startsWith("keyword") ||
-                                ts.token().id().primaryCategory().startsWith("string") || ts.token().id().primaryCategory().equals("literal")) {
+                                 ts.token().id().primaryCategory().equals("literal")) {
                             prefix = ts.token().text().toString().substring(0, len);
                             anchorOffset = ts.offset();
+                        } else if (ts.token().id() == JavaTokenId.STRING_LITERAL) {
+                            prefix = ts.token().text().toString().substring(1, ts.token().length() - 1);
+                            anchorOffset = ts.offset() + 1;
+                        } else if (ts.token().id() == JavaTokenId.MULTILINE_STRING_LITERAL) {
+                            prefix = ts.token().text().toString().substring(3, len);
+                            anchorOffset = ts.offset() + 3;
                         }
                     }
                     Consumer consumer = (namePrefix, name, type) -> {
@@ -147,12 +165,12 @@ public class MicronautDataCompletionTask {
                     switch (path.getLeaf().getKind()) {
                         case CLASS:
                         case INTERFACE:
-                            resolve(cc, path, prefix, true, consumer);
+                            resolveFinderMethods(cc, path, prefix, true, consumer);
                             break;
                         case METHOD:
                             Tree returnType = ((MethodTree) path.getLeaf()).getReturnType();
                             if (returnType != null && findLastNonWhitespaceToken(ts, (int) sp.getEndPosition(path.getCompilationUnit(), returnType), anchorOffset) == null) {
-                                resolve(cc, path.getParentPath(), prefix, false, consumer);
+                                resolveFinderMethods(cc, path.getParentPath(), prefix, false, consumer);
                             }
                             break;
                         case VARIABLE:
@@ -160,11 +178,17 @@ public class MicronautDataCompletionTask {
                             if (type != null && findLastNonWhitespaceToken(ts, (int) sp.getEndPosition(path.getCompilationUnit(), type), anchorOffset) == null) {
                                 TreePath parentPath = path.getParentPath();
                                 if (parentPath.getLeaf().getKind() == Tree.Kind.CLASS || parentPath.getLeaf().getKind() == Tree.Kind.INTERFACE) {
-                                    resolve(cc, parentPath, prefix, false, consumer);
+                                    resolveFinderMethods(cc, parentPath, prefix, false, consumer);
                                 }
                             }
                             break;
-
+                        case STRING_LITERAL:
+                            if (path.getParentPath().getLeaf().getKind() == Tree.Kind.ASSIGNMENT && path.getParentPath().getParentPath().getLeaf().getKind() == Tree.Kind.ANNOTATION) {
+                                resolveQueryAnnotation(cc, path.getParentPath().getParentPath(), prefix, caretOffset - anchorOffset, item -> {
+                                    items.add(factory.createSQLItem(item));
+                                });
+                            }
+                            break;
                     }
                 }
             });
@@ -178,7 +202,43 @@ public class MicronautDataCompletionTask {
         return anchorOffset;
     }
 
-    private <T> void resolve(CompilationController cc, TreePath path, String prefix, boolean full, Consumer consumer) throws IOException {
+    private <T> void resolveQueryAnnotation(CompilationController cc, TreePath path, String prefix, int off, java.util.function.Consumer<CompletionItem> consumer) throws IOException {
+        cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+        Element el = cc.getTrees().getElement(path);
+        if (el instanceof TypeElement) {
+            if (QUERY_ANNOTATION_TYPE_NAME.contentEquals(((TypeElement) el).getQualifiedName())) {
+                TreePath clsPath = cc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, path);
+                if (clsPath != null && checkForRepositoryAnnotation(cc.getTrees().getElement(clsPath).getAnnotationMirrors(), false, new HashSet<>())) {
+                    SQLCompletionContext ctx = SQLCompletionContext.empty()
+                            .setStatement(prefix)
+                            .setOffset(off)
+                            .setDatabaseConnection(ConnectionManager.getDefault().getPreferredConnection(true));
+                    SQLCompletion completion = SQLCompletion.create(ctx);
+                    SQLCompletionResultSet resultSet = SQLCompletionResultSet.create();
+                    completion.query(resultSet, (component, offset, text) -> {
+                        final int caretOffset = component.getCaretPosition();
+                        final StyledDocument document = (StyledDocument) component.getDocument();
+                        try {
+                            NbDocument.runAtomicAsUser(document, () -> {
+                                try {
+                                    int documentOffset = anchorOffset + offset;
+                                    document.remove(documentOffset, caretOffset - documentOffset);
+                                    document.insertString(documentOffset, text.replace("\"", "\\\""), null);
+                                } catch (BadLocationException ex) {
+                                }
+                            });
+                        } catch (BadLocationException ex) {
+                        }
+                    });
+                    for (CompletionItem item : resultSet.getItems()) {
+                        consumer.accept(item);
+                    }
+                }
+            }
+        }
+    }
+
+    private <T> void resolveFinderMethods(CompilationController cc, TreePath path, String prefix, boolean full, Consumer consumer) throws IOException {
         cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
         TypeUtilities tu = cc.getTypeUtilities();
         TypeElement entity = getEntityFor(cc, path);
@@ -257,7 +317,7 @@ public class MicronautDataCompletionTask {
     private static TypeElement getEntityFor(CompilationInfo info, TreePath path) {
         TypeElement te = (TypeElement) info.getTrees().getElement(path);
         if (te.getModifiers().contains(Modifier.ABSTRACT)) {
-            if (checkForRepositoryAnnotation(te.getAnnotationMirrors(), new HashSet<>())) {
+            if (checkForRepositoryAnnotation(te.getAnnotationMirrors(), true, new HashSet<>())) {
                 Types types = info.getTypes();
                 TypeMirror repositoryType = types.erasure(info.getElements().getTypeElement(REPOSITORY_TYPE_NAME).asType());
                 for (TypeMirror iface : te.getInterfaces()) {
@@ -276,10 +336,11 @@ public class MicronautDataCompletionTask {
         return null;
     }
 
-    private static boolean checkForRepositoryAnnotation(List<? extends AnnotationMirror> annotations, HashSet<TypeElement> checked) {
+    private static boolean checkForRepositoryAnnotation(List<? extends AnnotationMirror> annotations, boolean jpa, HashSet<TypeElement> checked) {
         for (AnnotationMirror annotation : annotations) {
             TypeElement annotationElement = (TypeElement) annotation.getAnnotationType().asElement();
-            if (REPOSITORY_ANNOTATION_NAME.contentEquals(annotationElement.getQualifiedName()) || checked.add(annotationElement) && checkForRepositoryAnnotation(annotationElement.getAnnotationMirrors(), checked)) {
+            String repositoryAnnotationName = jpa ? JPA_REPOSITORY_ANNOTATION_NAME : JDBC_REPOSITORY_ANNOTATION_NAME;
+            if (repositoryAnnotationName.contentEquals(annotationElement.getQualifiedName()) || checked.add(annotationElement) && checkForRepositoryAnnotation(annotationElement.getAnnotationMirrors(), jpa, checked)) {
                 return true;
             }
         }
diff --git a/ide/db.sql.editor/nbproject/project.properties b/ide/db.sql.editor/nbproject/project.properties
index b2c7928..8cb5ace 100644
--- a/ide/db.sql.editor/nbproject/project.properties
+++ b/ide/db.sql.editor/nbproject/project.properties
@@ -17,7 +17,7 @@
 
 javac.compilerargs=-Xlint -Xlint:-serial
 javac.source=1.8
-spec.version.base=1.52.0
+spec.version.base=1.53.0
 
 # org-netbeans-core: for /xml/lookups in the default fs
 #   (needed in order to load database connections from the SFS)
diff --git a/ide/db.sql.editor/nbproject/project.xml b/ide/db.sql.editor/nbproject/project.xml
index 90faa55..b171216 100644
--- a/ide/db.sql.editor/nbproject/project.xml
+++ b/ide/db.sql.editor/nbproject/project.xml
@@ -333,6 +333,7 @@
             </test-dependencies>
             <friend-packages>
                 <friend>com.sun.tools.odb</friend>
+                <friend>org.netbeans.modules.micronaut</friend>
                 <friend>org.netbeans.modules.php.editor</friend>
                 <package>org.netbeans.modules.db.sql.editor.api.completion</package>
             </friend-packages>
diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/ETCompletionContextResolver.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/ETCompletionContextResolver.java
index f486719..d1f35e2 100644
--- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/ETCompletionContextResolver.java
+++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/editor/completion/ETCompletionContextResolver.java
@@ -21,9 +21,13 @@ package org.netbeans.modules.j2ee.persistence.editor.completion;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
 import javax.swing.text.BadLocationException;
 import org.eclipse.persistence.jpa.jpql.parser.DefaultJPQLGrammar;
 import org.eclipse.persistence.jpa.jpql.tools.ContentAssistProposals;
@@ -81,7 +85,10 @@ public class ETCompletionContextResolver implements CompletionContextResolver {
         } else if("NamedQuery".equals(annotationName)){//NOI18N
             completeJPQLContext(ctx, parsedNN, nnattr, result);
         } else if("Query".equals(annotationName) && parsedNN.getAttributesList().size() == 1){//NOI18N
-            completeJPQLContext(ctx, parsedNN, nnattr, result);
+            Element cls = ctx.getJavaClass();
+            if (cls == null || !checkForRepositoryAnnotation(cls.getAnnotationMirrors(), new HashSet<>())) {
+                completeJPQLContext(ctx, parsedNN, nnattr, result);
+            }
         }
         
         
@@ -219,7 +226,18 @@ public class ETCompletionContextResolver implements CompletionContextResolver {
             return false;
         }
     }
-    
+
+    private static boolean checkForRepositoryAnnotation(List<? extends AnnotationMirror> annotations, HashSet<TypeElement> checked) {
+        for (AnnotationMirror annotation : annotations) {
+            TypeElement annotationElement = (TypeElement) annotation.getAnnotationType().asElement();
+            if (REPOSITORY_ANNOTATION_NAME.contentEquals(annotationElement.getQualifiedName()) || checked.add(annotationElement) && checkForRepositoryAnnotation(annotationElement.getAnnotationMirrors(), checked)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static final String REPOSITORY_ANNOTATION_NAME = "io.micronaut.data.jdbc.annotation.JdbcRepository";
 
     private static final boolean DEBUG = Boolean.getBoolean("debug." + ETCompletionContextResolver.class.getName());
 }
diff --git a/java/java.lsp.server/nbcode/nbproject/platform.properties b/java/java.lsp.server/nbcode/nbproject/platform.properties
index 870107f..15e5470 100644
--- a/java/java.lsp.server/nbcode/nbproject/platform.properties
+++ b/java/java.lsp.server/nbcode/nbproject/platform.properties
@@ -113,10 +113,7 @@ disabled.modules=\
     org.netbeans.modules.css.prep,\
     org.netbeans.modules.css.visual,\
     org.netbeans.modules.db.kit,\
-    org.netbeans.modules.db.core,\
-    org.netbeans.modules.db.dataview,\
     org.netbeans.modules.db.mysql,\
-    org.netbeans.modules.db.sql.editor,\
     org.netbeans.modules.db.sql.visualeditor,\
     org.netbeans.modules.deadlock.detector,\
     org.netbeans.modules.debugger.jpda.ant,\

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists