diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/codeAction/CodeActionHandler.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/codeAction/CodeActionHandler.java index ca3b0245..8c1aad29 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/codeAction/CodeActionHandler.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/codeAction/CodeActionHandler.java @@ -44,6 +44,7 @@ import org.eclipse.lsp4jakarta.jdt.core.cdi.ConflictProducesInjectQuickFix; import org.eclipse.lsp4jakarta.jdt.core.cdi.ManagedBeanConstants; import org.eclipse.lsp4jakarta.jdt.core.cdi.ManagedBeanConstructorQuickFix; +import org.eclipse.lsp4jakarta.jdt.core.cdi.ManagedBeanNoArgConstructorQuickFix; import org.eclipse.lsp4jakarta.jdt.core.cdi.ManagedBeanQuickFix; import org.eclipse.lsp4jakarta.jdt.core.cdi.ScopeDeclarationQuickFix; import org.eclipse.lsp4jakarta.jdt.core.di.DependencyInjectionConstants; @@ -58,7 +59,6 @@ import org.eclipse.lsp4jakarta.jdt.core.servlet.ListenerImplementationQuickFix; import org.eclipse.lsp4jakarta.jdt.core.servlet.ServletConstants; import org.eclipse.lsp4jakarta.jdt.core.persistence.DeleteConflictMapKeyQuickFix; -import org.eclipse.lsp4jakarta.jdt.core.persistence.PersistenceConstants; import org.eclipse.lsp4jakarta.jdt.core.JakartaCorePlugin; /** @@ -102,6 +102,7 @@ public List codeAction(JakartaJavaCodeActionParams params, JDTUtils ConflictProducesInjectQuickFix ConflictProducesInjectQuickFix = new ConflictProducesInjectQuickFix(); BeanValidationQuickFix BeanValidationQuickFix = new BeanValidationQuickFix(); ManagedBeanConstructorQuickFix ManagedBeanConstructorQuickFix = new ManagedBeanConstructorQuickFix(); + ManagedBeanNoArgConstructorQuickFix ManagedBeanNoArgConstructorQuickFix = new ManagedBeanNoArgConstructorQuickFix(); JsonbAnnotationQuickFix JsonbAnnotationQuickFix = new JsonbAnnotationQuickFix(); ScopeDeclarationQuickFix ScopeDeclarationQuickFix = new ScopeDeclarationQuickFix(); RemoveInjectAnnotationQuickFix RemoveInjectAnnotationQuickFix = new RemoveInjectAnnotationQuickFix(); @@ -162,6 +163,9 @@ public List codeAction(JakartaJavaCodeActionParams params, JDTUtils if (diagnostic.getCode().getLeft().equals(ManagedBeanConstants.DIAGNOSTIC_CODE_PRODUCES_INJECT)) { codeActions.addAll(ConflictProducesInjectQuickFix.getCodeActions(context, diagnostic, monitor)); } + if (diagnostic.getCode().getLeft().equals(ManagedBeanConstants.DIAGNOSTIC_CODE_INVALID_INJECT_PARAM)) { + codeActions.addAll(RemoveInjectAnnotationQuickFix.getCodeActions(context, diagnostic, monitor)); + } if (diagnostic.getCode().getLeft().equals(BeanValidationConstants.DIAGNOSTIC_CODE_STATIC) || diagnostic.getCode().getLeft() .equals(BeanValidationConstants.DIAGNOSTIC_CODE_INVALID_TYPE)) { @@ -169,6 +173,7 @@ public List codeAction(JakartaJavaCodeActionParams params, JDTUtils } if (diagnostic.getCode().getLeft().equals(ManagedBeanConstants.CONSTRUCTOR_DIAGNOSTIC_CODE)) { codeActions.addAll(ManagedBeanConstructorQuickFix.getCodeActions(context, diagnostic, monitor)); + codeActions.addAll(ManagedBeanNoArgConstructorQuickFix.getCodeActions(context, diagnostic, monitor)); } if (diagnostic.getCode().getLeft().equals(JsonbConstants.DIAGNOSTIC_CODE_ANNOTATION)) { codeActions.addAll(JsonbAnnotationQuickFix.getCodeActions(context, diagnostic, monitor)); @@ -192,6 +197,7 @@ public List codeAction(JakartaJavaCodeActionParams params, JDTUtils codeActions.addAll(RemoveInjectAnnotationQuickFix.getCodeActions(context, diagnostic, monitor)); codeActions.addAll(RemoveStaticModifierQuickFix.getCodeActions(context, diagnostic, monitor)); } + } catch (CoreException e) { e.printStackTrace(); } diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanConstants.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanConstants.java index 07514d04..9e56b1e8 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanConstants.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanConstants.java @@ -26,6 +26,7 @@ public class ManagedBeanConstants { public static final String DISPOSES = "Disposes"; public static final String OBSERVES = "Observes"; public static final String OBSERVES_ASYNC = "ObservesAsync"; + public static final String DEPENDENT = "Dependent"; public static final String DIAGNOSTIC_SOURCE = "jakarta-cdi"; diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanDiagnosticsCollector.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanDiagnosticsCollector.java index 483ddb1c..0fd404e9 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanDiagnosticsCollector.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanDiagnosticsCollector.java @@ -17,10 +17,8 @@ import java.util.Set; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.TreeSet; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IAnnotation; @@ -248,7 +246,19 @@ else if (!hasParameterizedInjectConstructor) CONSTRUCTOR_DIAGNOSTIC_CODE); diagnostics.add(diagnostic); } - + } + } + + /** + * If a managed bean class is of generic type, it must be annotated with @Dependent + */ + if (isManagedBean) { + boolean isClassGeneric = type.getTypeParameters().length != 0; + + if (isClassGeneric && managedBeanAnnotations.stream() + .anyMatch(annotation -> !annotation.equals("Dependent"))) { + diagnostics.add(createDiagnostic(type, unit, "Managed bean class of generic type must have scope @dependent.", + DIAGNOSTIC_CODE)); } } diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanNoArgConstructorQuickFix.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanNoArgConstructorQuickFix.java new file mode 100644 index 00000000..8024cc92 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/cdi/ManagedBeanNoArgConstructorQuickFix.java @@ -0,0 +1,84 @@ +/******************************************************************************* +* Copyright (c) 2021 IBM Corporation. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0. +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Hani Damlaj +*******************************************************************************/ + +package org.eclipse.lsp4jakarta.jdt.core.cdi; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.internal.corext.dom.Bindings; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4jakarta.jdt.codeAction.IJavaCodeActionParticipant; +import org.eclipse.lsp4jakarta.jdt.codeAction.JavaCodeActionContext; +import org.eclipse.lsp4jakarta.jdt.codeAction.proposal.AddConstructorProposal; +import org.eclipse.lsp4jakarta.jdt.codeAction.proposal.ChangeCorrectionProposal; +import org.eclipse.lsp4jakarta.jdt.core.persistence.PersistenceConstants; + +public class ManagedBeanNoArgConstructorQuickFix implements IJavaCodeActionParticipant { + + @Override + public List getCodeActions(JavaCodeActionContext context, Diagnostic diagnostic, + IProgressMonitor monitor) throws CoreException { + ASTNode node = context.getCoveredNode(); + IBinding parentType = getBinding(node); + if (parentType != null) { + List codeActions = new ArrayList<>(); + + codeActions.addAll(addConstructor(diagnostic, context, parentType)); + + + return codeActions; + } + return null; + } + + protected static IBinding getBinding(ASTNode node) { + if (node.getParent() instanceof VariableDeclarationFragment) { + VariableDeclarationFragment fragment = (VariableDeclarationFragment) node.getParent(); + return ((VariableDeclarationFragment) node.getParent()).resolveBinding(); + } + return Bindings.getBindingOfParentType(node); + } + + private List addConstructor(Diagnostic diagnostic, JavaCodeActionContext context, IBinding parentType) throws CoreException { + List codeActions = new ArrayList<>(); + + // option for protected constructor + String name = "Add a no-arg protected constructor to this class"; + ChangeCorrectionProposal proposal = new AddConstructorProposal(name, + context.getCompilationUnit(), context.getASTRoot(), parentType, 0); + CodeAction codeAction = context.convertToCodeAction(proposal, diagnostic); + + if (codeAction != null) { + codeActions.add(codeAction); + } + + // option for public constructor + name = "Add a no-arg public constructor to this class"; + proposal = new AddConstructorProposal(name, + context.getCompilationUnit(), context.getASTRoot(), parentType, 0, "public"); + codeAction = context.convertToCodeAction(proposal, diagnostic); + + if (codeAction != null) { + codeActions.add(codeAction); + } + + return codeActions; + } +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionConstants.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionConstants.java index 12c93a7d..3056b242 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionConstants.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionConstants.java @@ -13,6 +13,10 @@ package org.eclipse.lsp4jakarta.jdt.core.di; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import org.eclipse.lsp4j.DiagnosticSeverity; public class DependencyInjectionConstants { diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionDiagnosticsCollector.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionDiagnosticsCollector.java index 257da76f..f380708c 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionDiagnosticsCollector.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/core/di/DependencyInjectionDiagnosticsCollector.java @@ -15,8 +15,6 @@ package org.eclipse.lsp4jakarta.jdt.core.di; -import static org.eclipse.lsp4jakarta.jdt.core.di.DependencyInjectionConstants.DIAGNOSTIC_SOURCE; -import static org.eclipse.lsp4jakarta.jdt.core.di.DependencyInjectionConstants.SEVERITY; import static org.eclipse.lsp4jakarta.jdt.core.di.DependencyInjectionConstants.*; import java.util.ArrayList; @@ -37,7 +35,6 @@ import org.eclipse.lsp4jakarta.jdt.core.JDTUtils; import org.eclipse.lsp4jakarta.jdt.core.JakartaCorePlugin; import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IMethod; /** * @@ -93,7 +90,6 @@ public void collectDiagnostics(ICompilationUnit unit, List diagnosti alltypes = unit.getAllTypes(); for (IType type : alltypes) { allAnnotations = type.getAnnotations(); - IField[] allFields = type.getFields(); for (IField field : allFields) { int fieldFlags = field.getFlags(); @@ -164,7 +160,6 @@ public void collectDiagnostics(ICompilationUnit unit, List diagnosti for (IType type : alltypes) { List constructorMethods = Arrays.stream(type.getMethods()).filter(this::isConstructorMethod) .collect(Collectors.toList()); - // there are no constructors if (constructorMethods.size() == 0) return; @@ -173,6 +168,7 @@ public void collectDiagnostics(ICompilationUnit unit, List diagnosti int numInjectedConstructors = 0; List injectedConstructors = new ArrayList(); for (IMethod m : constructorMethods) { + hasInjectConstructor = Arrays.stream(m.getAnnotations()) .map(annotation -> annotation.getElementName()) .anyMatch(annotation -> annotation.equals("Inject"));