diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/cdi/Utils.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/cdi/Utils.java deleted file mode 100644 index 7ddb26f2..00000000 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/cdi/Utils.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021, 2023 IBM Corporation and others. - * - * 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.lsp4jakarta.jdt.internal.cdi; - -import static org.eclipse.lsp4jakarta.jdt.internal.cdi.Constants.SCOPES; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.jdt.core.IAnnotatable; -import org.eclipse.jdt.core.IType; - -/** - * CDI Utilities. - */ -public class Utils { - /** - * Detects if a class is a managed bean by looking for a bean defining - * annotation. - * - * @param type the type representing the potential bean class - * @return true if the class has a bean defining annotation. - */ - static boolean isManagedBean(IType type) { - return getScopeAnnotations(type, SCOPES).size() > 0; - } - - /** - * Returns the list of recognised defining annotations applied to a - * class. - * - * @param type the type representing the class - * @param scopes list of defining annotations - * @return list of recognised defining annotations applied to a class - */ - public static List getScopeAnnotations(IAnnotatable type, Set scopes) { - try { - // Construct a stream of only the annotations applied to the type that are also - // recognised annotations found in scopes. - return Arrays.stream(type.getAnnotations()).map(annotation -> annotation.getElementName()).filter(scopes::contains).distinct().collect(Collectors.toList()); - - } catch (Exception e) { - return Collections. emptyList(); - } - } -} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/ManagedBean.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/ManagedBean.java new file mode 100644 index 00000000..a5c20b13 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/ManagedBean.java @@ -0,0 +1,341 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.jdt.internal.core.java; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.ILocalVariable; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IPackageDeclaration; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.lsp4jakarta.jdt.core.JakartaCorePlugin; + +/** + * Provides Managed Bean related utilities. + */ +public class ManagedBean { + + /** + * Constants. + */ + public static final String MANAGED_BEAN_ANNOTATION = "javax.annotation.ManagedBean"; + public static final String VETOED_ANNOTATION = "jakarta.enterprise.inject.Vetoed"; + public static final String DECORATOR_ANNOTATION = "jakarta.decorator.Decorator"; + public static final String INJECT_ANNOTATION = "jakarta.inject.Inject"; + public static final String EXTENSION_SERVICE_IFACE = "jakarta.enterprise.inject.spi.Extension"; + + /** + * Returns true if the input type object is a managed bean. False, otherwise. + * See: CDI Specification + * + * @param type The type object to process. + * + * @return True if the input type object is a managed bean. False, otherwise. + * + * @throws JavaModelException + */ + public static boolean isManagedBean(IType type) throws JavaModelException { + // Check if the type is an inner class.; + if (isInnerClass(type)) { + return false; + } + + // Check if the type is an abstract class or is not annotated with @Decorator. + if (isAbstractClass(type) && !isAnnotatedClass(type, DECORATOR_ANNOTATION)) { + return false; + } + + // Check if the type implements jakarta.enterprise.inject.spi.Extension + if (implementsExtends(type, EXTENSION_SERVICE_IFACE)) { + return false; + } + + // Check if the type is annotated @Vetoed or in a package annotated @Vetoed. + if (isAnnotatedClass(type, VETOED_ANNOTATION) || isPackageMetadataAnnotated(type, VETOED_ANNOTATION)) { + return false; + } + + // Check if the type does not have a constructor with no parameters or the class declares a constructor that is not annotated @Inject. + if (!containsValidConstructor(type)) { + return false; + } + + return true; + } + + /** + * Returns true if the input variable is a managed bean. + * + * @param variable The method/initializer local variable object to process. + * + * @return True if the input variable is a managed bean. + * + * @throws JavaModelException + */ + public static boolean isManagedBean(ILocalVariable variable) throws JavaModelException { + IType variableType = variableSignatureToType(variable); + return isManagedBean(variableType); + } + + /** + * Converts an ILocalVariable object to an IType object. + * + * @param variable The local variable object to convert. + * + * @return The IType object representing the input ILocalVariable object. + */ + public static IType variableSignatureToType(ILocalVariable variable) { + IType varType = null; + + IMember declaringMember = variable.getDeclaringMember(); + if (declaringMember != null) { + IType declaringType = declaringMember.getDeclaringType(); + try { + String typeSig = variable.getTypeSignature(); + String typeName = Signature.toString(typeSig); + varType = getChildITypeByName(declaringType, typeName); + if (varType == null) { + IJavaProject jProject = declaringType.getJavaProject(); + varType = jProject.findType(typeName); + String sn = Signature.toString(typeSig); + varType = declaringType.getType(sn); + } + } catch (Exception e) { + JakartaCorePlugin.logException("Unable to convert an ILocalVariable to IType", e); + } + } + + return varType; + } + + /** + * Returns true if the class represented by the input type object is an inner class. False, otherwise. + * + * @param type The type object to check. + * + * @return True if the class represented by the input type object is an inner class. False, otherwise. + * + * @throws JavaModelException + */ + public static boolean isInnerClass(IType type) throws JavaModelException { + // A Non-static member class is an inner class. + return type.isMember() && !Flags.isStatic(type.getFlags()); + } + + /** + * Returns true if the class represented by the input type object is an abstract class. False Otherwise. + * + * @param iType The type object to check. + * @return True if the class represented by the input type object is an abstract class. False Otherwise. + * + * @throws JavaModelException + */ + public static boolean isAbstractClass(IType iType) throws JavaModelException { + boolean isAbstractClass = Flags.isAbstract(iType.getFlags()); + return isAbstractClass; + } + + /** + * Returns true if the class represented by the input type object has an annotation that matches + * the input annotation. False, otherwise. + * + * @param iType The type object to check. + * @param annotation The annotation to find. + * + * @return True if the class represented by the input type object has an annotation that matches + * the input annotation. False, otherwise. + * + * @throws JavaModelException + */ + public static boolean isAnnotatedClass(IType iType, String annotation) throws JavaModelException { + IAnnotation[] annotations = iType.getAnnotations(); + for (int i = 0; i < annotations.length; i++) { + String[][] resolvedType = iType.resolveType(annotations[i].getElementName()); + if (resolvedType != null && resolvedType.length != 0) { + String[] annotationParts = resolvedType[0]; + String resolvedAnnotation = String.join(".", annotationParts); + if (annotation.equals(resolvedAnnotation)) { + return true; + } + } + } + + return false; + } + + /** + * Returns true if the class represented by the input type object or its parent type object(s) implement + * or extends the input type . False, otherwise. + * + * @param type The type object to check. + * @param objName The interface to find. + * + * @return True if the class represented by the input type object or its parent type object(s) implement + * or extends the input type . False, otherwise. + * + * @throws JavaModelException + */ + public static boolean implementsExtends(IType type, String name) throws JavaModelException { + + String resolvedClassName = getFullyQualifiedClassName(type, type.getElementName()); + if (resolvedClassName != null) { + if (name.equals(resolvedClassName)) { + return true; + } + } + + String[] interfaces = type.getSuperInterfaceNames(); + for (int i = 0; i < interfaces.length; i++) { + IType childType = getChildITypeByName(type, interfaces[i]); + if (childType != null) { + return implementsExtends(childType, name); + } + } + + String superClass = type.getSuperclassName(); + if (superClass != null) { + IType childType = getChildITypeByName(type, superClass); + if (childType != null) { + return implementsExtends(childType, name); + } + } + + return false; + } + + /** + * Returns true if the package in which the input type class resides is annotated + * with the specified annotation (package-info.java). False, otherwise. + * + * @param type The type object to check. + * @param annotation The annotation to find. + * + * @return True if the package in which the input type class resides is annotated + * with the specified annotation (package-info.java). False, otherwise. + */ + public static boolean isPackageMetadataAnnotated(IType type, String annotation) { + IPackageFragment packageFragment = type.getPackageFragment(); + ICompilationUnit compilationUnit = packageFragment.getCompilationUnit("package-info.java"); + if (compilationUnit.exists()) { + IPackageDeclaration packageDeclaration = compilationUnit.getPackageDeclaration(packageFragment.getElementName()); + IAnnotation foundAnnotation = packageDeclaration.getAnnotation(annotation); + + if (foundAnnotation != null && !foundAnnotation.exists()) { + return true; + } + } + return false; + } + + /** + * Returns a list of constructors associated with the class represented by the input type object. + * + * @param type The type object to check. + * + * @return A list of constructors associated with the class represented by the input type object. + * + * @throws JavaModelException + */ + public static ArrayList getConstructors(IType type) throws JavaModelException { + ArrayList constructors = new ArrayList(); + IMethod[] methods = type.getMethods(); + for (int i = 0; i < methods.length; i++) { + boolean isConstructor = methods[i].isConstructor(); + if (isConstructor) { + constructors.add(methods[i]); + } + } + return constructors; + + } + + /** + * Returns true if the class represented by the input type object contains a default constructor or + * a constructor with the jakarta.inject.Inject annotation. + * + * @param type The type object to check. + * + * @return True if the class represented by the input type object contains a default constructor or + * a constructor with the jakarta.inject.Inject annotation. + * + * @throws JavaModelException + */ + public static boolean containsValidConstructor(IType type) throws JavaModelException { + List constructors = getConstructors(type); + + for (IMethod constructor : constructors) { + if (constructor.getNumberOfParameters() == 0) { + return true; + } + IAnnotation injectAnnotation = constructor.getAnnotation(INJECT_ANNOTATION); + if (injectAnnotation != null && injectAnnotation.exists()) { + return true; + } + } + + return false; + } + + /** + * Returns the IType associated with the input class name or null if not found. + * + * @param parentType The parent type object to check. + * @param simpleName The simple name of the class within the specified parent type. + * + * @return The IType associated with the input class name or null if not found. + * + * @throws JavaModelException + */ + public static IType getChildITypeByName(IType parentType, String simpleName) throws JavaModelException { + IType iType = null; + String resolvedClassName = getFullyQualifiedClassName(parentType, simpleName); + + if (resolvedClassName != null) { + IJavaProject jProject = parentType.getJavaProject(); + iType = jProject.findType(resolvedClassName); + } + + return iType; + } + + /** + * Returns a fully qualified class name based on the input class name or null if the simple name cannot be resolved. + * + * @param parentType The parent type object to check. + * @param simpleName The simple name of the class within the specified parent type. + * + * @return The IType associated with the input class name or null if not found. + * + * @throws JavaModelException + */ + public static String getFullyQualifiedClassName(IType parentType, String simpleName) throws JavaModelException { + String resolvedClassName = null; + String[][] resolvedType = parentType.resolveType(simpleName); + + if (resolvedType != null && resolvedType.length != 0) { + String[] classParts = resolvedType[0]; + resolvedClassName = String.join(".", classParts); + } + + return resolvedClassName; + } +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/Primitive.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/Primitive.java new file mode 100644 index 00000000..4ab60b8e --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/core/java/Primitive.java @@ -0,0 +1,73 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.jdt.internal.core.java; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.core.ILocalVariable; +import org.eclipse.jdt.core.Signature; + +public class Primitive { + + /** + * Primitive wrapper type set. + */ + private static final Map> wrappers; + static { + Map> types = new HashMap>(); + types.put("Long", Integer.class); + types.put("Short", Short.class); + types.put("Long", Long.class); + types.put("Float", Float.class); + types.put("Double", Double.class); + types.put("Byte", Byte.class); + types.put("Character", Character.class); + types.put("Boolean", Boolean.class); + wrappers = Collections.unmodifiableMap(types); + } + + /** + * Returns true if the input class is a primitive type. False, otherwise. + * + * @param typeName The name associated with the input type. + * @return True if the input class is a primitive type. False, otherwise. + */ + public static boolean isPrimitive(String typeName) { + return wrappers.containsKey(typeName); + } + + /** + * Returns true if the input variable is a primitive type. False, otherwise. + * + * @param variable + * @return + */ + public static boolean isPrimitive(ILocalVariable variable) { + // Handle primitives. + String signature = variable.getTypeSignature(); + int signatureKind = Signature.getTypeSignatureKind(signature); + if (signatureKind == Signature.BASE_TYPE_SIGNATURE) { + return true; + } + + // Handle primitive wrappers. + if (isPrimitive(Signature.toString(signature))) { + return true; + } + + return false; + } + +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/DependencyInjectionDiagnosticsParticipant.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/DependencyInjectionDiagnosticsParticipant.java index 217856b6..31a4f43f 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/DependencyInjectionDiagnosticsParticipant.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/DependencyInjectionDiagnosticsParticipant.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2021, 2023 IBM Corporation and others. +* Copyright (c) 2021, 2024 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -26,6 +26,7 @@ import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; +import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; @@ -39,6 +40,8 @@ import org.eclipse.lsp4jakarta.jdt.core.utils.PositionUtils; import org.eclipse.lsp4jakarta.jdt.internal.DiagnosticUtils; import org.eclipse.lsp4jakarta.jdt.internal.Messages; +import org.eclipse.lsp4jakarta.jdt.internal.core.java.ManagedBean; +import org.eclipse.lsp4jakarta.jdt.internal.core.java.Primitive; import org.eclipse.lsp4jakarta.jdt.internal.core.ls.JDTUtilsLSImpl; /** @@ -82,37 +85,35 @@ && containsAnnotation(type, field.getAnnotations(), INJECT_FQ_NAME)) { List injectedConstructors = new ArrayList(); IMethod[] allMethods = type.getMethods(); for (IMethod method : allMethods) { + + Range range = PositionUtils.toNameRange(method, context.getUtils()); int methodFlag = method.getFlags(); - boolean isFinal = Flags.isFinal(methodFlag); - boolean isAbstract = Flags.isAbstract(methodFlag); - boolean isStatic = Flags.isStatic(methodFlag); - boolean isGeneric = method.getTypeParameters().length != 0; - Range range = PositionUtils.toNameRange(method, - context.getUtils()); if (containsAnnotation(type, method.getAnnotations(), INJECT_FQ_NAME)) { if (DiagnosticUtils.isConstructorMethod(method)) injectedConstructors.add(method); - if (isFinal) { + if (Flags.isFinal(methodFlag)) { String msg = Messages.getMessage("InjectNoFinalMethod"); diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, ErrorCode.InvalidInjectAnnotationOnFinalMethod, DiagnosticSeverity.Error)); } - if (isAbstract) { + + if (Flags.isAbstract(methodFlag)) { String msg = Messages.getMessage("InjectNoAbstractMethod"); diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, ErrorCode.InvalidInjectAnnotationOnAbstractMethod, DiagnosticSeverity.Error)); } - if (isStatic) { + + if (Flags.isStatic(methodFlag)) { String msg = Messages.getMessage("InjectNoStaticMethod"); diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, ErrorCode.InvalidInjectAnnotationOnStaticMethod, DiagnosticSeverity.Error)); } - if (isGeneric) { + if (method.getTypeParameters().length != 0) { String msg = Messages.getMessage("InjectNoGenericMethod"); diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, ErrorCode.InvalidInjectAnnotationOnGenericMethod, @@ -121,7 +122,9 @@ && containsAnnotation(type, field.getAnnotations(), INJECT_FQ_NAME)) { } } - // if more than one 'inject' constructor, add diagnostic to all constructors + // https://jakarta.ee/specifications/cdi/3.0/jakarta-cdi-spec-3.0.html#declaring_bean_constructor: + // "If a bean class has more than one constructor annotated @Inject, the container automatically + // detects the problem and treats it as a definition error." if (injectedConstructors.size() > 1) { String msg = Messages.getMessage("InjectMoreThanOneConstructor"); for (IMethod method : injectedConstructors) { @@ -132,6 +135,19 @@ && containsAnnotation(type, field.getAnnotations(), INJECT_FQ_NAME)) { DiagnosticSeverity.Error)); } } + + // https://jakarta.ee/specifications/cdi/3.0/jakarta-cdi-spec-3.0.html#declaring_bean_constructor: + // "A bean constructor may have any number of parameters. All parameters of a bean constructor + // are injection points." + for (IMethod constructor : injectedConstructors) { + if (constructor.getNumberOfParameters() > 0) { + ILocalVariable[] params = constructor.getParameters(); + for (int i = 0; i < params.length; i++) { + ILocalVariable param = params[i]; + getInjectionPointDiagnostics(diagnostics, context, uri, param); + } + } + } } return diagnostics; @@ -147,4 +163,77 @@ private boolean containsAnnotation(IType type, IAnnotation[] annotations, String } }); } + + /** + * Obtains the injections point diagnostics for the given local variable. + * + * @param diagnostics The list of diagnostics to update. + * @param context The diagnostics context associated with this call. + * @param uri The URI associated with the file being processed. + * @param variable The ILocalVariable object being processed. + * @return + * @throws JavaModelException + */ + private void getInjectionPointDiagnostics(List diagnostics, JavaDiagnosticsContext context, String uri, ILocalVariable variable) { + try { + // Note: Although, these checks apply to all managed bean parameters that are injections points, + // some of these checks may not apply to other non-managed beans that are injectable. + // Further consideration is required. + Range range = PositionUtils.toNameRange(variable, context.getUtils()); + IType variableType = ManagedBean.variableSignatureToType(variable); + + // Check if the type is a primitive. + if (Primitive.isPrimitive(variable)) { + String msg = Messages.getMessage("InjectionPointInvalidPrimitiveBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidPrimitiveBean, + DiagnosticSeverity.Warning)); + + // Primitive types are special. The checks that follow do not apply to them and/or may cause errors. + return; + } + + // Check if the type is an inner class. + if (ManagedBean.isInnerClass(variableType)) { + String msg = Messages.getMessage("InjectionPointInvalidInnerClassBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidInnerClassBean, + DiagnosticSeverity.Warning)); + } + + // Check if the type is an abstract class or is not annotated with @Decorator. + if (ManagedBean.isAbstractClass(variableType) && !ManagedBean.isAnnotatedClass(variableType, ManagedBean.DECORATOR_ANNOTATION)) { + String msg = Messages.getMessage("InjectionPointInvalidAbstractClassBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidAbstractClassBean, + DiagnosticSeverity.Warning)); + } + + // Check if the type implements jakarta.enterprise.inject.spi.Extension + if (ManagedBean.implementsExtends(variableType, ManagedBean.EXTENSION_SERVICE_IFACE)) { + String msg = Messages.getMessage("InjectionPointInvalidExtensionProviderBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidExtensionProviderBean, + DiagnosticSeverity.Warning)); + } + + // Check if the type is annotated @Vetoed or in a package annotated @Vetoed. + if (ManagedBean.isAnnotatedClass(variableType, ManagedBean.VETOED_ANNOTATION) || ManagedBean.isPackageMetadataAnnotated(variableType, ManagedBean.VETOED_ANNOTATION)) { + String msg = Messages.getMessage("InjectionPointInvalidVetoedClassBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidVetoedClassBean, + DiagnosticSeverity.Warning)); + } + + // Check if the type does not have a constructor with no parameters or the class declares a constructor that is not annotated @Inject. + if (!ManagedBean.containsValidConstructor(variableType)) { + String msg = Messages.getMessage("InjectionPointInvalidConstructorBean"); + diagnostics.add(context.createDiagnostic(uri, msg, range, Constants.DIAGNOSTIC_SOURCE, + ErrorCode.InjectionPointInvalidConstructorBean, + DiagnosticSeverity.Warning)); + } + } catch (JavaModelException jme) { + JakartaCorePlugin.logException("Cannot obtain injection point diagnostics for variable: " + variable + " in file: " + uri, jme); + } + } } diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/ErrorCode.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/ErrorCode.java index 9633210e..130289e6 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/ErrorCode.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/java/org/eclipse/lsp4jakarta/jdt/internal/di/ErrorCode.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2023 IBM Corporation and others. +* Copyright (c) 2023, 2024 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -23,7 +23,13 @@ public enum ErrorCode implements IJavaErrorCode { InvalidInjectAnnotationOnAbstractMethod, InvalidInjectAnnotationOnStaticMethod, InvalidInjectAnnotationOnGenericMethod, - InvalidInjectAnnotationOnMultipleConstructors; + InvalidInjectAnnotationOnMultipleConstructors, + InjectionPointInvalidPrimitiveBean, + InjectionPointInvalidInnerClassBean, + InjectionPointInvalidAbstractClassBean, + InjectionPointInvalidExtensionProviderBean, + InjectionPointInvalidVetoedClassBean, + InjectionPointInvalidConstructorBean; /** * {@inheritDoc} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/resources/org/eclipse/lsp4jakarta/jdt/core/messages/messages.properties b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/resources/org/eclipse/lsp4jakarta/jdt/core/messages/messages.properties index 788521fb..184c680b 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/resources/org/eclipse/lsp4jakarta/jdt/core/messages/messages.properties +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/src/main/resources/org/eclipse/lsp4jakarta/jdt/core/messages/messages.properties @@ -80,6 +80,12 @@ InjectNoAbstractMethod = The @Inject annotation must not define an abstract meth InjectNoStaticMethod = The @Inject annotation must not define a static method. InjectNoGenericMethod = The @Inject annotation must not define a generic method. InjectMoreThanOneConstructor = The @Inject annotation must not define more than one constructor. +InjectionPointInvalidPrimitiveBean = The parameter should not be a primitive type. +InjectionPointInvalidInnerClassBean = The parameter should not be an inner class. +InjectionPointInvalidAbstractClassBean = The parameter should not contain the abstract modifier. If it contains the abstract modifier, the class should be annotated with @Decorator. +InjectionPointInvalidExtensionProviderBean = The parameter should not implement the jakarta.enterprise.inject.spi.Extension interface either directly or through a superclass or through super interface. +InjectionPointInvalidVetoedClassBean = The parameter should not be annotated with @Vetoed either directly or through the package-info metadata. +InjectionPointInvalidConstructorBean = The parameter should define a constructor with no parameters or a constructor annotated with @Inject. # ClassConstructorDiagnosticsParticipant RootResourceClasses = Root resource classes are instantiated by the JAX-RS runtime and MUST have a public constructor. diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/.classpath b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/.classpath new file mode 100644 index 00000000..7bd3fdff --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/.classpath @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractDecoratorInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractDecoratorInjectionPointUser.java new file mode 100644 index 00000000..3373f7ad --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractDecoratorInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.AbstractDecoratorClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class AbstractDecoratorInjectionPointUser { + + @Inject + public AbstractDecoratorInjectionPointUser(AbstractDecoratorClass adc) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractInjectionPointUser.java new file mode 100644 index 00000000..7b0786a6 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/AbstractInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.AbstractClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class AbstractInjectionPointUser { + + @Inject + public AbstractInjectionPointUser(AbstractClass ac) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/ExtensionInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/ExtensionInjectionPointUser.java new file mode 100644 index 00000000..aa6338bd --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/ExtensionInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.ExtensionServiceClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class ExtensionInjectionPointUser { + + @Inject + public ExtensionInjectionPointUser(ExtensionServiceClass esc) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/Greeting.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/Greeting.java index 861ef04e..8e426658 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/Greeting.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/Greeting.java @@ -1,7 +1,18 @@ +/******************************************************************************* +* Copyright (c) 2012, 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ package io.openliberty.sample.jakarta.di; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Singleton; @ApplicationScoped public class Greeting { @@ -10,4 +21,13 @@ public String greet(String name) { return "Hello, " + name; } + public class Message { + public String title; + public String content; + + public Message() { + title = ""; + content = ""; + } + } } \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingNoDefaultConstructor.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingNoDefaultConstructor.java index be3f8187..0760f1b4 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingNoDefaultConstructor.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingNoDefaultConstructor.java @@ -1,3 +1,15 @@ +/******************************************************************************* +* Copyright (c) 2021, 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ package io.openliberty.sample.jakarta.di; public class GreetingNoDefaultConstructor { @@ -11,4 +23,4 @@ public GreetingNoDefaultConstructor(String greeting) { public String greet(String name) { return greeting + " " + name; } -} +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingServlet.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingServlet.java index d9a6d171..f60fdeed 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingServlet.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/GreetingServlet.java @@ -1,3 +1,15 @@ +/******************************************************************************* +* Copyright (c) 2021, 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ package io.openliberty.sample.jakarta.di; import jakarta.inject.Inject; @@ -9,7 +21,7 @@ public abstract class GreetingServlet { /** - * + * UID. */ private static final long serialVersionUID = 1L; @@ -22,10 +34,9 @@ public GreetingNoDefaultConstructor getInstance() { return new GreetingNoDefaultConstructor("Howdy"); } - // d2 + // d2: test code for @Inject methods cannot be final @Inject public final void injectFinal() { - // test code for @Inject methods cannot be final return; } @@ -42,8 +53,6 @@ public static void injectStatic() { // d5: test code for @Inject methods cannot be generic @Inject public List injectGeneric(T arg) { - // do nothing return new ArrayList(); }; - } diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InnerClassInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InnerClassInjectionPointUser.java new file mode 100644 index 00000000..8a7a4d8b --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InnerClassInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.Greeting.Message; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class InnerClassInjectionPointUser { + + @Inject + public InnerClassInjectionPointUser(Message message) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InvalidConstructorInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InvalidConstructorInjectionPointUser.java new file mode 100644 index 00000000..b5c26a80 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/InvalidConstructorInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.InvalidConstructorClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class InvalidConstructorInjectionPointUser { + + @Inject + public InvalidConstructorInjectionPointUser(InvalidConstructorClass icc) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/MultipleConstructorWithInject.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/MultipleConstructorWithInject.java index 9a64a12d..8fd14f92 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/MultipleConstructorWithInject.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/MultipleConstructorWithInject.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2021 IBM Corporation. +* Copyright (c) 2021, 2024 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 @@ -10,28 +10,27 @@ * Contributors: * Ananya Rao *******************************************************************************/ - package io.openliberty.sample.jakarta.di; import jakarta.inject.Inject; -public class MultipleConstructorWithInject{ +public class MultipleConstructorWithInject { private int productNum; private String productDesc; - + @Inject public MultipleConstructorWithInject(int productNum) { this.productNum = productNum; - } + } + @Inject public MultipleConstructorWithInject(String productDesc) { this.productDesc = productDesc; - } + } @Inject protected MultipleConstructorWithInject(int productNum, String productDesc) { this.productNum = productNum; this.productDesc = productDesc; - } + } } - diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/PrimitiveParamConstructorInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/PrimitiveParamConstructorInjectionPointUser.java new file mode 100644 index 00000000..1e580fd7 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/PrimitiveParamConstructorInjectionPointUser.java @@ -0,0 +1,23 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class PrimitiveParamConstructorInjectionPointUser { + + @Inject + public PrimitiveParamConstructorInjectionPointUser(Short s, int i, Long ol, float f, Double od, char c, Byte ob, boolean b) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperClassExtensionInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperClassExtensionInjectionPointUser.java new file mode 100644 index 00000000..3cda1e2f --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperClassExtensionInjectionPointUser.java @@ -0,0 +1,26 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.ExtensionServiceClassThroughParentExtensionClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class SuperClassExtensionInjectionPointUser { + + @Inject + public SuperClassExtensionInjectionPointUser(ExtensionServiceClassThroughParentExtensionClass esctpec) { + + } +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperInterfaceExtensionInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperInterfaceExtensionInjectionPointUser.java new file mode 100644 index 00000000..59c55a45 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/SuperInterfaceExtensionInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.ExtensionServiceClassUsingExtendedInterface; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class SuperInterfaceExtensionInjectionPointUser { + + @Inject + public SuperInterfaceExtensionInjectionPointUser(ExtensionServiceClassUsingExtendedInterface escuei) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedInjectionPointUser.java new file mode 100644 index 00000000..4be5a8f5 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.VetoedClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class VetoedInjectionPointUser { + + @Inject + public VetoedInjectionPointUser(VetoedClass vc) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedPackageInjectionPointUser.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedPackageInjectionPointUser.java new file mode 100644 index 00000000..0ff85127 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/VetoedPackageInjectionPointUser.java @@ -0,0 +1,24 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di; + +import io.openliberty.sample.jakarta.di.helpers.vetoed.PackageVetoedClass; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class VetoedPackageInjectionPointUser { + + @Inject + public VetoedPackageInjectionPointUser(PackageVetoedClass vbc) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractClass.java new file mode 100644 index 00000000..36faed86 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractClass.java @@ -0,0 +1,21 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public abstract class AbstractClass { + + public AbstractClass() {} +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractDecoratorClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractDecoratorClass.java new file mode 100644 index 00000000..ba0c013b --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/AbstractDecoratorClass.java @@ -0,0 +1,21 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.decorator.Decorator; + +@Decorator +public abstract class AbstractDecoratorClass { + + public AbstractDecoratorClass() {} +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClass.java new file mode 100644 index 00000000..0a500cdc --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClass.java @@ -0,0 +1,23 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.spi.Extension; + +@ApplicationScoped +public class ExtensionServiceClass implements Extension { + + public ExtensionServiceClass() {} + +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassThroughParentExtensionClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassThroughParentExtensionClass.java new file mode 100644 index 00000000..8ceb19a8 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassThroughParentExtensionClass.java @@ -0,0 +1,21 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ExtensionServiceClassThroughParentExtensionClass extends ExtensionServiceClass { + + public ExtensionServiceClassThroughParentExtensionClass() {} +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassUsingExtendedInterface.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassUsingExtendedInterface.java new file mode 100644 index 00000000..ff21111a --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ExtensionServiceClassUsingExtendedInterface.java @@ -0,0 +1,21 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ExtensionServiceClassUsingExtendedInterface implements ParentExtensionInterface { + + public ExtensionServiceClassUsingExtendedInterface() {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/InvalidConstructorClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/InvalidConstructorClass.java new file mode 100644 index 00000000..75d5d946 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/InvalidConstructorClass.java @@ -0,0 +1,22 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import io.openliberty.sample.jakarta.di.Greeting; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class InvalidConstructorClass { + + public InvalidConstructorClass(Greeting g) {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ParentExtensionInterface.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ParentExtensionInterface.java new file mode 100644 index 00000000..44ec7919 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/ParentExtensionInterface.java @@ -0,0 +1,19 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.inject.spi.Extension; + +public interface ParentExtensionInterface extends Extension { + +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/VetoedClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/VetoedClass.java new file mode 100644 index 00000000..7dfac7f9 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/VetoedClass.java @@ -0,0 +1,21 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.sample.jakarta.di.helpers; + +import jakarta.enterprise.inject.Vetoed; + +@Vetoed +public class VetoedClass { + + public VetoedClass() {} +} \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/PackageVetoedClass.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/PackageVetoedClass.java new file mode 100644 index 00000000..d5eddf75 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/PackageVetoedClass.java @@ -0,0 +1,9 @@ +package io.openliberty.sample.jakarta.di.helpers.vetoed; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class PackageVetoedClass { + + public PackageVetoedClass() {} +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/package-info.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/package-info.java new file mode 100644 index 00000000..047fc215 --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/projects/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/di/helpers/vetoed/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation and others. + * + * 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: + * IBM Corporation - initial implementation + *******************************************************************************/ + +@Vetoed +package io.openliberty.sample.jakarta.di.helpers.vetoed; + +import jakarta.enterprise.inject.Vetoed; \ No newline at end of file diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/DependencyInjectionTest.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/DependencyInjectionTest.java index 320def19..a62d0317 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/DependencyInjectionTest.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/DependencyInjectionTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2023 IBM Corporation and others. + * Copyright (c) 2021, 2024 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -49,23 +49,23 @@ public void DependencyInjectionDiagnostics() throws Exception { diagnosticsParams.setUris(Arrays.asList(uri)); // Create expected diagnostics. - Diagnostic d1 = d(17, 27, 35, "The @Inject annotation must not define a final field.", + Diagnostic d1 = d(29, 27, 35, "The @Inject annotation must not define a final field.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnFinalField"); // d1.setData(IType.FIELD); - Diagnostic d2 = d(33, 25, 39, "The @Inject annotation must not define an abstract method.", + Diagnostic d2 = d(44, 25, 39, "The @Inject annotation must not define an abstract method.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnAbstractMethod"); // d2.setData(IType.METHOD); - Diagnostic d3 = d(26, 22, 33, "The @Inject annotation must not define a final method.", + Diagnostic d3 = d(38, 22, 33, "The @Inject annotation must not define a final method.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnFinalMethod"); // d3.setData(IType.METHOD); - Diagnostic d4 = d(43, 23, 36, "The @Inject annotation must not define a generic method.", + Diagnostic d4 = d(54, 23, 36, "The @Inject annotation must not define a generic method.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnGenericMethod"); // d4.setData(IType.METHOD); - Diagnostic d5 = d(37, 23, 35, "The @Inject annotation must not define a static method.", + Diagnostic d5 = d(48, 23, 35, "The @Inject annotation must not define a static method.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnStaticMethod"); // d5.setData(IType.METHOD); @@ -73,35 +73,35 @@ public void DependencyInjectionDiagnostics() throws Exception { // Create expected quick fixes. JakartaJavaCodeActionParams codeActionParams = createCodeActionParams(uri, d1); - TextEdit te = te(16, 4, 17, 4, ""); + TextEdit te = te(28, 4, 29, 4, ""); CodeAction ca = ca(uri, "Remove @Inject", d1, te); - TextEdit te1 = te(17, 11, 17, 17, ""); + TextEdit te1 = te(29, 11, 29, 17, ""); CodeAction ca1 = ca(uri, "Remove the 'final' modifier", d1, te1); assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca, ca1); codeActionParams = createCodeActionParams(uri, d2); - te = te(32, 4, 33, 4, ""); + te = te(43, 4, 44, 4, ""); ca = ca(uri, "Remove @Inject", d2, te); - te1 = te(33, 10, 33, 19, ""); + te1 = te(44, 10, 44, 19, ""); ca1 = ca(uri, "Remove the 'abstract' modifier", d2, te1); assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca, ca1); codeActionParams = createCodeActionParams(uri, d3); - te = te(25, 4, 26, 4, ""); + te = te(37, 4, 38, 4, ""); ca = ca(uri, "Remove @Inject", d3, te); - te1 = te(26, 10, 26, 16, ""); + te1 = te(38, 10, 38, 16, ""); ca1 = ca(uri, "Remove the 'final' modifier", d3, te1); assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca, ca1); codeActionParams = createCodeActionParams(uri, d4); - te = te(42, 4, 43, 4, ""); + te = te(53, 4, 54, 4, ""); ca = ca(uri, "Remove @Inject", d4, te); assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca); codeActionParams = createCodeActionParams(uri, d5); - te = te(36, 4, 37, 4, ""); + te = te(47, 4, 48, 4, ""); ca = ca(uri, "Remove @Inject", d5, te); - te1 = te(37, 10, 37, 17, ""); + te1 = te(48, 10, 48, 17, ""); ca1 = ca(uri, "Remove the 'static' modifier", d5, te1); assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca, ca1); } diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/InjectionPointBeanValidationTests.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/InjectionPointBeanValidationTests.java new file mode 100644 index 00000000..437cecde --- /dev/null +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/InjectionPointBeanValidationTests.java @@ -0,0 +1,279 @@ +/******************************************************************************* +* Copyright (c) 2024 IBM Corporation and others. +* +* 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: +* IBM Corporation - initial implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.jdt.di; + +import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.assertJavaDiagnostics; +import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.d; + +import java.util.Arrays; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4jakarta.commons.JakartaJavaDiagnosticsParams; +import org.eclipse.lsp4jakarta.jdt.core.BaseJakartaTest; +import org.eclipse.lsp4jakarta.jdt.core.utils.IJDTUtils; +import org.eclipse.lsp4jakarta.jdt.internal.core.ls.JDTUtilsLSImpl; +import org.junit.Test; + +/** + * Tests injection point object diagnostics. + */ +public class InjectionPointBeanValidationTests extends BaseJakartaTest { + + /** + * JDT Utility class. + */ + protected static IJDTUtils IJDT_UTILS = JDTUtilsLSImpl.getInstance(); + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is an abstract object. + * + * @throws Exception + */ + @Test + public void abstractClassConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/AbstractInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 52, 54, + "The parameter should not contain the abstract modifier. If it contains the abstract modifier, the class should be annotated with @Decorator.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidAbstractClassBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests that no diagnostics are issued for an abstract class annotated with @Decorator. + * + * @throws Exception + */ + @Test + public void abstractClassDecoratorConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/AbstractDecoratorInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, new Diagnostic[] {}); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is an inner class. + * + * @throws Exception + */ + @Test + public void innerClassConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/InnerClassInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 48, 55, + "The parameter should not be an inner class.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidInnerClassBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is an extension service. + * + * @throws Exception + */ + @Test + public void extensionServiceConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/ExtensionInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 61, 64, + "The parameter should not implement the jakarta.enterprise.inject.spi.Extension interface either directly or through a superclass or through super interface.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidExtensionProviderBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is an extension service + * through a super class. + * + * @throws Exception + */ + @Test + public void superClassExtensionServiceConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/SuperClassExtensionInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 98, 105, + "The parameter should not implement the jakarta.enterprise.inject.spi.Extension interface either directly or through a superclass or through super interface.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidExtensionProviderBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is an extension service + * through a super interface. + * + * @throws Exception + */ + @Test + public void superInterfaceExtensionServiceConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/SuperInterfaceExtensionInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 97, 103, + "The parameter should not implement the jakarta.enterprise.inject.spi.Extension interface either directly or through a superclass or through super interface.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidExtensionProviderBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is a primitive. + * + * @throws Exception + */ + @Test + public void primitiveConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/PrimitiveParamConstructorInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(21, 61, 62, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d2 = d(21, 68, 69, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d3 = d(21, 76, 78, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d4 = d(21, 86, 87, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d5 = d(21, 96, 98, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d6 = d(21, 105, 106, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d7 = d(21, 113, 115, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + Diagnostic d8 = d(21, 125, 126, + "The parameter should not be a primitive type.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidPrimitiveBean"); + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1, d2, d3, d4, d5, d6, d7, d8); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is a vetoed bean. + * + * @throws Exception + */ + @Test + public void vetoedConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/VetoedInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 48, 50, + "The parameter should not be annotated with @Vetoed either directly or through the package-info metadata.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidVetoedClassBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that is a vetoed bean. + * + * @throws Exception + */ + @Test + public void vetoedPackageConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/VetoedPackageInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 62, 65, + "The parameter should not be annotated with @Vetoed either directly or through the package-info metadata.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidVetoedClassBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } + + /** + * Tests diagnostic issued for a bean constructor parameter injection point that does not define + * a class with a valid constructor. A valid constructor is one that has no parameters or one that + * is annotated with @Inject. + * + * @throws Exception + */ + @Test + public void invalidConstructorParam() throws Exception { + IJavaProject javaProject = loadJavaProject("jakarta-sample", ""); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/di/InvalidConstructorInjectionPointUser.java")); + String uri = javaFile.getLocation().toFile().toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // Test expected diagnostic + Diagnostic d1 = d(22, 72, 75, + "The parameter should define a constructor with no parameters or a constructor annotated with @Inject.", + DiagnosticSeverity.Warning, "jakarta-di", "InjectionPointInvalidConstructorBean"); + + assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1); + } +} diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/MultipleConstructorInjectTest.java b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/MultipleConstructorInjectTest.java index 7946a9e4..9add62ca 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/MultipleConstructorInjectTest.java +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.test/src/main/java/org/eclipse/lsp4jakarta/jdt/di/MultipleConstructorInjectTest.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2021 IBM Corporation. +* Copyright (c) 2021, 2024 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 @@ -50,7 +50,7 @@ public void multipleInject() throws Exception { diagnosticsParams.setUris(Arrays.asList(uri)); // test expected diagnostic - Diagnostic d1 = d(22, 11, 40, + Diagnostic d1 = d(21, 11, 40, "The @Inject annotation must not define more than one constructor.", DiagnosticSeverity.Error, "jakarta-di", "InvalidInjectAnnotationOnMultipleConstructors"); @@ -66,7 +66,7 @@ public void multipleInject() throws Exception { // test expected quick-fix JakartaJavaCodeActionParams codeActionParams1 = createCodeActionParams(uri, d1); - TextEdit te = te(21, 4, 22, 4, ""); + TextEdit te = te(20, 4, 21, 4, ""); CodeAction ca = ca(uri, "Remove @Inject", d1, te); assertJavaCodeAction(codeActionParams1, IJDT_UTILS, ca);