diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.classpath b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.classpath new file mode 100644 index 000000000..7a69f73fa --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.classpath @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.gitignore b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.gitignore new file mode 100644 index 000000000..726d8ae39 --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.gitignore @@ -0,0 +1,43 @@ +#Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +release.properties +.flattened-pom.xml + +# Eclipse +#.project +#.classpath +.settings/ +bin/ + +# IntelliJ +.idea +*.ipr +*.iml +*.iws + +# NetBeans +nb-configuration.xml + +# Visual Studio Code +.vscode +.factorypath + +# OSX +.DS_Store + +# Vim +*.swp +*.swo + +# patch +*.orig +*.rej + +# Local environment +.env + +# Plugin directory +/.quarkus/cli/plugins/ diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.project b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.project new file mode 100644 index 000000000..557480f1c --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/.project @@ -0,0 +1,23 @@ + + + quarkus-builditems + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/pom.xml b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/pom.xml new file mode 100644 index 000000000..cd6dfe7dd --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + org.acme + quarkus-builditems + 1.0.0-SNAPSHOT + + 3.11.0 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.3.1 + true + 3.1.2 + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-junit5 + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + native + + + native + + + + false + native + + + + diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/BadBuildItem.java b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/BadBuildItem.java new file mode 100644 index 000000000..85960e7bb --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/BadBuildItem.java @@ -0,0 +1,6 @@ +package org.acme.builditems; + +import io.quarkus.builder.item.MultiBuildItem; + +public class BadBuildItem extends MultiBuildItem { +} \ No newline at end of file diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/GoodBuildItem.java b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/GoodBuildItem.java new file mode 100644 index 000000000..8cf3a6604 --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/java/org/acme/builditems/GoodBuildItem.java @@ -0,0 +1,6 @@ +package org.acme.builditems; + +import io.quarkus.builder.item.SimpleBuildItem; + +public final class GoodBuildItem extends SimpleBuildItem { +} \ No newline at end of file diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/resources/application.properties b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus.test/projects/maven/quarkus-builditems/src/main/resources/application.properties new file mode 100644 index 000000000..e69de29bb diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml index 5a0a50a01..36b961e0e 100644 --- a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml @@ -19,6 +19,13 @@ + + + + + + + diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/QuarkusConstants.java b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/QuarkusConstants.java index 3f84dc801..4d784b62f 100644 --- a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/QuarkusConstants.java +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/QuarkusConstants.java @@ -56,10 +56,9 @@ public class QuarkusConstants { public static final String SCHEDULED_ANNOTATION_DELAY_UNIT = "delayUnit"; public static final String SCHEDULED_ANNOTATION_DELAYED = "delayed"; - public static final String[] SCHEDULED_SUPPORTED_PARTICIPANT_MEMBERS = { - SCHEDULED_ANNOTATION_CRON, SCHEDULED_ANNOTATION_EVERY, SCHEDULED_ANNOTATION_DELAY, - SCHEDULED_ANNOTATION_DELAYED, SCHEDULED_ANNOTATION_DELAY_UNIT - }; + public static final String[] SCHEDULED_SUPPORTED_PARTICIPANT_MEMBERS = { SCHEDULED_ANNOTATION_CRON, + SCHEDULED_ANNOTATION_EVERY, SCHEDULED_ANNOTATION_DELAY, SCHEDULED_ANNOTATION_DELAYED, + SCHEDULED_ANNOTATION_DELAY_UNIT }; public static final String SCHEDULED_ANNOTATION_CONCURRENT_EXECUTION = "concurrentExecution"; public static final String SCHEDULED_ANNOTATION_SKIP_EXECUTION_IF = "skipExecutionIf"; @@ -132,6 +131,10 @@ public class QuarkusConstants { public static final String QUARKUS_RUNTIME_CLASS_NAME = "io.quarkus.runtime.LaunchMode"; + public static final String QUARKUS_BUILD_ITEM_CLASS_NAME = "io.quarkus.builder.item.BuildItem"; + + public static final String QUARKUS_DIAGNOSTIC_SOURCE = "quarkus"; + private QuarkusConstants() { } } \ No newline at end of file diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/QuarkusBuildItemErrorCode.java b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/QuarkusBuildItemErrorCode.java new file mode 100644 index 000000000..5c26b2c75 --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/QuarkusBuildItemErrorCode.java @@ -0,0 +1,28 @@ +/******************************************************************************* +* Copyright (c) 2024 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.jdt.internal.quarkus.builditems; + +import org.eclipse.lsp4mp.jdt.core.java.diagnostics.IJavaErrorCode; + +/** + * Represents error codes for validation issues in classes inheriting + * io.quarkus.builder.item.BuildItem. + */ +public enum QuarkusBuildItemErrorCode implements IJavaErrorCode { + + InvalidModifierBuildItem; + + @Override + public String getCode() { + return name(); + } +} diff --git a/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/java/QuarkusBuildItemASTVisitor.java b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/java/QuarkusBuildItemASTVisitor.java new file mode 100644 index 000000000..21e900cd8 --- /dev/null +++ b/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/builditems/java/QuarkusBuildItemASTVisitor.java @@ -0,0 +1,101 @@ +/******************************************************************************* +* Copyright (c) 2024 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.jdt.internal.quarkus.builditems.java; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4mp.commons.DocumentFormat; +import org.eclipse.lsp4mp.jdt.core.java.diagnostics.JavaDiagnosticsContext; +import org.eclipse.lsp4mp.jdt.core.java.validators.JavaASTValidator; +import org.eclipse.lsp4mp.jdt.core.utils.JDTTypeUtils; + +import com.redhat.microprofile.jdt.internal.quarkus.QuarkusConstants; +import com.redhat.microprofile.jdt.internal.quarkus.builditems.QuarkusBuildItemErrorCode; + +/** + * Validates io.quarkus.builder.item.BuildItem subclasses. + *
    + *
  • checks if the BuildItem is final or abstract
  • + *
+ */ +public class QuarkusBuildItemASTVisitor extends JavaASTValidator { + + private static final String INVALID_MODIFIER = "BuildItem class %2$s%1$s%2$s must either be declared final or abstract"; + + @Override + public boolean isAdaptedForDiagnostics(JavaDiagnosticsContext context, IProgressMonitor monitor) + throws CoreException { + // Collection of diagnostics for Quarkus Build Items is done only if + // io.quarkus.builder.item.BuildItem is on the classpath + IJavaProject javaProject = context.getJavaProject(); + return JDTTypeUtils.findType(javaProject, QuarkusConstants.QUARKUS_BUILD_ITEM_CLASS_NAME) != null; + } + + @Override + public boolean visit(TypeDeclaration node) { + if (isBuildItem(node)) { + validateBuildItem(node, super.getContext()); + } + return super.visit(node); + } + + /** + * Returns true if the given type declaration extends + * 'io.quarkus.builder.item.BuildItem' class and false otherwise. + * + * @param typeDeclaration the type declaration. + * @return true if the given type declaration extends + * 'io.quarkus.builder.item.BuildItem' class and false otherwise. + */ + private static boolean isBuildItem(TypeDeclaration typeDeclaration) { + ITypeBinding typeBinding = typeDeclaration.resolveBinding(); + if (typeBinding != null) { + return extendsClass(typeBinding, QuarkusConstants.QUARKUS_BUILD_ITEM_CLASS_NAME); + } + return false; + } + + private void validateBuildItem(TypeDeclaration typeDeclaration, JavaDiagnosticsContext context) { + if (isValidBuildItem(typeDeclaration)) { + return; + } + super.addDiagnostic(createDiagnosticMessage(typeDeclaration, context.getDocumentFormat()), + QuarkusConstants.QUARKUS_DIAGNOSTIC_SOURCE, typeDeclaration, + QuarkusBuildItemErrorCode.InvalidModifierBuildItem, DiagnosticSeverity.Error); + } + + private static boolean isValidBuildItem(TypeDeclaration typeDeclaration) { + int flags = typeDeclaration.getModifiers(); + return Modifier.isStatic(flags) || Modifier.isFinal(flags); + } + + private static String createDiagnosticMessage(TypeDeclaration classType, DocumentFormat documentFormat) { + String quote = DocumentFormat.Markdown.equals(documentFormat) ? "`" : "'"; + return String.format(INVALID_MODIFIER, classType.getName().getIdentifier(), quote); + } + + private static boolean extendsClass(ITypeBinding typeBinding, String classNameToCheck) { + ITypeBinding superClass = typeBinding.getSuperclass(); + while (superClass != null) { + if (superClass.getQualifiedName().equals(classNameToCheck)) { + return true; + } + superClass = superClass.getSuperclass(); + } + return false; + } +} \ No newline at end of file