From 75f2b2977d91c7081cc6bff48f96a0c23ba9abbd Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Thu, 6 Jun 2024 09:41:05 +0200 Subject: [PATCH] Micronaut: Code completion support for values of 'Mapping' annotation. --- ...ronautJavaMappingPropertiesCompletion.java | 112 ++++++++++++++++++ .../db/MicronautEndpointRequestProvider.java | 2 +- .../modules/micronaut/resources/layer.xml | 1 + .../editor/java/JavaCompletionCollector.java | 5 +- .../java/lsp/server/protocol/ServerTest.java | 2 +- 5 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaMappingPropertiesCompletion.java diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaMappingPropertiesCompletion.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaMappingPropertiesCompletion.java new file mode 100644 index 000000000000..b10b09a688af --- /dev/null +++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaMappingPropertiesCompletion.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.micronaut.completion; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.processing.Completion; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import org.netbeans.modules.micronaut.db.Utils; + +/** + * + * @author Dusan Balek + */ +public class MicronautJavaMappingPropertiesCompletion implements Processor { + + private static final Set supportedAnnotationTypes = Set.of("io.micronaut.context.annotation.Mapper.Mapping"); + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + + @Override + public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { + if (member != null && annotation != null) { + TypeMirror tm = element.asType(); + if (tm.getKind() == TypeKind.EXECUTABLE) { + TypeMirror type = null; + switch (member.getSimpleName().toString()) { + case "from": + List paramTypes = ((ExecutableType) tm).getParameterTypes(); + if (paramTypes.size() == 1) { + type = paramTypes.get(0); + } + break; + case "to": + type = ((ExecutableType) tm).getReturnType(); + break; + } + if (type != null && type.getKind() == TypeKind.DECLARED) { + TypeElement te = (TypeElement) ((DeclaredType) type).asElement(); + if (Utils.getAnnotation(te.getAnnotationMirrors(), "io.micronaut.serde.annotation.Serdeable") != null) { + String format = "\"%s\""; + return ElementFilter.fieldsIn(te.getEnclosedElements()).stream().map(ve -> { + return new Completion() { + @Override + public String getValue() { + return String.format(format, ve.getSimpleName().toString()); + } + @Override + public String getMessage() { + return null; + } + }; + }).collect(Collectors.toList()); + } + } + } + } + return Collections.emptyList(); + } + + @Override + public Set getSupportedOptions() { + return Collections.emptySet(); + } + + @Override + public Set getSupportedAnnotationTypes() { + return supportedAnnotationTypes; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public void init(ProcessingEnvironment processingEnv) { + } +} diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEndpointRequestProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEndpointRequestProvider.java index 5ce9f1ce39c8..2f14265c86be 100644 --- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEndpointRequestProvider.java +++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEndpointRequestProvider.java @@ -179,7 +179,7 @@ private static void fillJSON(CompilationInfo info, int level, String name, Varia sb.append(" "); } if (name != null) { - sb.append('"').append(name).append("\":"); + sb.append('"').append(name).append("\": "); } TypeMirror tm = ve.asType(); if (tm.getKind() == TypeKind.TYPEVAR) { diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml index 8c556364e888..e801397ba84c 100644 --- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml +++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml @@ -26,6 +26,7 @@ + diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java index 91c22e93384a..cd61d9094104 100644 --- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java +++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java @@ -630,7 +630,8 @@ public Completion createAttributeValueItem(CompilationInfo info, String value, S if (ts.moveNext() && ts.offset() <= offset) { switch (ts.token().id()) { case STRING_LITERAL: - textEdit = new TextEdit(ts.offset(), offset, value); + int end = ts.offset() + ts.token().length() == offset + 1 ? offset + 1 : offset; + textEdit = new TextEdit(ts.offset(), end, value); break; case MULTILINE_STRING_LITERAL: String[] tokenLines = ts.token().text().toString().split("\n"); @@ -651,7 +652,7 @@ public Completion createAttributeValueItem(CompilationInfo info, String value, S } } Builder builder = CompletionCollector.newBuilder(label) - .kind(Completion.Kind.Text) + .kind(Completion.Kind.Value) .sortText(value) .insertTextFormat(Completion.TextFormat.PlainText) .documentation(documentation); diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index 78b327fbec90..f12c947d386c 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -5107,7 +5107,7 @@ public void testAnnotationCompletion() throws Exception { server.getTextDocumentService().didChange(new DidChangeTextDocumentParams(id, Arrays.asList(new TextDocumentContentChangeEvent(new Range(new Position(0, 19), new Position(0, 19)), 0, "alue=\"\"")))); completion = server.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(0, 25))).get(); actualItems = completion.getRight().getItems().stream().map(ci -> ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList()); - assertTrue(actualItems.contains("Text:\"empty-statement\"")); + assertTrue(actualItems.contains("Value:\"empty-statement\"")); } interface Validator {