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