From eb7854ce69c8ed54e48a58e4d6f59c6369a6cc93 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Wed, 4 Feb 2026 10:06:31 +0530 Subject: [PATCH 01/11] Validate-@Resource-type-compatibility - initial commit --- .../annotations/AnnotationConstants.java | 1 + .../AnnotationDiagnosticsCollector.java | 90 ++++++++++++++----- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationConstants.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationConstants.java index 77133068f..591fd38ba 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationConstants.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationConstants.java @@ -41,6 +41,7 @@ public class AnnotationConstants { public static final String DIAGNOSTIC_CODE_ANNOTATION_START_WITH_SET = "ResourceNameMustStartWithSet"; public static final String DIAGNOSTIC_CODE_MUST_DECLARE_EXACTLY_ONE_PARAM = "ResourceMustDeclareExactlyOneParam"; public static final String DIAGNOSTIC_CODE_RETURN_TYPE_MUST_BE_VOID = "ResourceReturnTypeMustBeVoid"; + public static final String DIAGNOSTIC_CODE_RETURN_TYPE_MISMATCH = "ResourceTypeMismatch"; public static final String DIAGNOSTIC_CODE_POSTCONSTRUCT_PARAMS = "PostConstructParams"; public static final String DIAGNOSTIC_CODE_POSTCONSTRUCT_RETURN_TYPE = "PostConstructReturnType"; public static final String DIAGNOSTIC_CODE_POSTCONSTRUCT_EXCEPTION = "PostConstructException"; diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java index da2dedd30..fd2882f28 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java @@ -16,6 +16,7 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.AbstractDiagnosticsCollector; import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.DiagnosticsUtils; import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.Messages; @@ -27,6 +28,7 @@ import java.util.List; import java.util.regex.Pattern; +import static io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.DiagnosticsUtils.*; import static io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.annotations.AnnotationConstants.EXCEPTION; import static io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.annotations.AnnotationConstants.RUNTIME_EXCEPTION; @@ -150,6 +152,8 @@ public void collectDiagnostics(PsiJavaFile unit, List diagnostics) { } } else if (element instanceof PsiMethod) { validateResourceMethods(unit, diagnostics, (PsiMethod) element, annotation); + } else if (element instanceof PsiField) { + validateResourceFields(unit, diagnostics, (PsiField) element, annotation); } } if (isMatchedAnnotation(annotation, AnnotationConstants.POST_CONSTRUCT_FQ_NAME)) { @@ -213,6 +217,18 @@ public void collectDiagnostics(PsiJavaFile unit, List diagnostics) { } } + /** + * validateResourceFields + * This method is responsible for finding diagnostics in fields annotated with @Resource. + * @param unit + * @param diagnostics + * @param element + * @param annotation + */ + private void validateResourceFields(PsiJavaFile unit, List diagnostics, PsiField element, PsiAnnotation annotation) { + checkTypeCompatibility(unit, diagnostics, annotation, element.getType(), "field"); + } + /** * validateResourceMethods * This method is responsible for finding diagnostics in methods annotated with @Resource. @@ -223,31 +239,63 @@ public void collectDiagnostics(PsiJavaFile unit, List diagnostics) { */ private void validateResourceMethods(PsiJavaFile unit, List diagnostics, PsiMethod element, PsiAnnotation annotation) { String methodName = element.getName(); - PsiType returnType = element.getReturnType(); String diagnosticMessage; - if(!methodName.startsWith("set")){ - diagnosticMessage = Messages.getMessage("AnnotationNameMustStartWithSet", - "@Resource", methodName); - diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, - AnnotationConstants.DIAGNOSTIC_CODE_ANNOTATION_START_WITH_SET, null, - DiagnosticSeverity.Error)); - } - if(!(returnType == null || returnType.equals(PsiTypes.voidType()))){ - diagnosticMessage = Messages.getMessage("AnnotationReturnTypeMustBeVoid", - "@Resource", methodName); - diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, - AnnotationConstants.DIAGNOSTIC_CODE_RETURN_TYPE_MUST_BE_VOID, null, - DiagnosticSeverity.Error)); - } - if(element.getParameterList().getParametersCount() != 1){ - diagnosticMessage = Messages.getMessage("AnnotationMustDeclareExactlyOneParam", - "@Resource", methodName); - diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, - AnnotationConstants.DIAGNOSTIC_CODE_MUST_DECLARE_EXACTLY_ONE_PARAM, null, - DiagnosticSeverity.Error)); + String errorCode = validateSetterMethod(element); + switch (errorCode) { + case NAME_MUST_START_WITH_SET -> { + diagnosticMessage = Messages.getMessage("AnnotationNameMustStartWithSet", + "@Resource", methodName); + diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, + AnnotationConstants.DIAGNOSTIC_CODE_ANNOTATION_START_WITH_SET, null, + DiagnosticSeverity.Error)); + } + case RETURN_TYPE_MUST_BE_VOID -> { + diagnosticMessage = Messages.getMessage("AnnotationReturnTypeMustBeVoid", + "@Resource", methodName); + diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, + AnnotationConstants.DIAGNOSTIC_CODE_RETURN_TYPE_MUST_BE_VOID, null, + DiagnosticSeverity.Error)); + } + case MUST_DECLARE_EXACTLY_ONE_PARAM -> { + diagnosticMessage = Messages.getMessage("AnnotationMustDeclareExactlyOneParam", + "@Resource", methodName); + diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, + AnnotationConstants.DIAGNOSTIC_CODE_MUST_DECLARE_EXACTLY_ONE_PARAM, null, + DiagnosticSeverity.Error)); + } + case null, default -> { + PsiParameter param = element.getParameterList().getParameter(0); + checkTypeCompatibility(unit, diagnostics, annotation, param.getType(), "parameter"); + } } } + /** + * checkTypeCompatibility + * Create diagnostics if the type specified by a particular annotation is incompatible with + * the type of the corresponding field or method parameter. + * + * @param unit + * @param diagnostics + * @param annotation + * @param type + * @param typeString + */ + private void checkTypeCompatibility(PsiJavaFile unit, List diagnostics, PsiAnnotation annotation, PsiType type, String typeString) { + PsiAnnotationMemberValue typeValue = annotation.findDeclaredAttributeValue("type"); + if (typeValue instanceof PsiClassObjectAccessExpression) { + PsiType psiResourceType = ((PsiClassObjectAccessExpression) typeValue).getOperand().getType(); + PsiClass psiTypeClass = PsiUtil.resolveClassInType(type); + PsiClass psiResourceClass = PsiUtil.resolveClassInType(psiResourceType); + if (!inheritsFrom(psiResourceClass, psiTypeClass)){ + String diagnosticMessage = Messages.getMessage("ResourceTypeMismatch", + typeString); + diagnostics.add(createDiagnostic(annotation, unit, diagnosticMessage, + AnnotationConstants.DIAGNOSTIC_CODE_RETURN_TYPE_MISMATCH, null, + DiagnosticSeverity.Error)); + } + } + } private void processAnnotations(PsiJvmModifiersOwner psiModifierOwner, ArrayList> annotatables, From 50c8704f0f8aa31e6dd34d34ade87fccae8b37b3 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Wed, 4 Feb 2026 10:06:46 +0530 Subject: [PATCH 02/11] Validate-@Resource-type-compatibility - added utility methods --- .../lsp4jakarta/lsp4ij/DiagnosticsUtils.java | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java index f9dbbd031..d0ef1e99c 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2025 IBM Corporation + * Copyright (c) 2025, 2026 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 @@ -22,9 +22,12 @@ */ public class DiagnosticsUtils { + public static final String NAME_MUST_START_WITH_SET = "NameMustStartWithSet"; + public static final String MUST_DECLARE_EXACTLY_ONE_PARAM = "MustDeclareExactlyOneParam"; + public static final String RETURN_TYPE_MUST_BE_VOID = "ReturnTypeMustBeVoid"; /** * inheritsFrom - * Check if specified superType is present or not in the type hierarchy + * find super class and Check if it is present or not in the type hierarchy * * @param clazz * @param fqSuperType @@ -34,7 +37,42 @@ public static boolean inheritsFrom(PsiClass clazz, String fqSuperType) { Project project = clazz.getProject(); PsiClass superClass = JavaPsiFacade.getInstance(project) .findClass(fqSuperType, GlobalSearchScope.allScope(project)); - return superClass != null && - (clazz.isEquivalentTo(superClass) || clazz.isInheritor(superClass, true)); + return inheritsFrom(clazz, superClass); + } + + /** + * inheritsFrom + * Check if specified superClass is present or not in the type hierarchy + * + * @param clazz + * @param superClass + * @return + */ + public static boolean inheritsFrom(PsiClass clazz, PsiClass superClass) { + if (clazz == null || superClass == null) { + return false; + } + return clazz.isEquivalentTo(superClass) || clazz.isInheritor(superClass, true); + } + + + /** + * validateSetterMethod + * This is to check whether a method is a valid setter. + * + * @param element + * @return + */ + public static String validateSetterMethod(PsiMethod element) { + String methodName = element.getName(); + PsiType returnType = element.getReturnType(); + if(!methodName.startsWith("set")){ + return NAME_MUST_START_WITH_SET; + } else if(!(returnType == null || returnType.equals(PsiTypes.voidType()))){ + return RETURN_TYPE_MUST_BE_VOID; + } else if(element.getParameterList().getParametersCount() != 1){ + return MUST_DECLARE_EXACTLY_ONE_PARAM; + } + return null; } } From d17415c982f42fb79a0e68018557fffdde57de94 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Wed, 4 Feb 2026 10:06:57 +0530 Subject: [PATCH 03/11] Validate-@Resource-type-compatibility - added test cases --- .../annotations/ResourceAnnotationTest.java | 35 ++++++++++++ .../ResourceAnnotationTypeMismatch.java | 54 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/test/resources/projects/maven/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/annotations/ResourceAnnotationTypeMismatch.java diff --git a/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java b/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java index a0622aebe..d8a34b79f 100644 --- a/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java +++ b/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java @@ -100,4 +100,39 @@ public void ResourceAnnotation() throws Exception { CodeAction ca1 = ca(uri, "Add name to jakarta.annotation.Resource", d2, te1); assertJavaCodeAction(codeActionParams1, utils, ca1); } + + @Test + public void ResourceAnnotationTypeMismatch() throws Exception { + Module module = createMavenModule(new File("src/test/resources/projects/maven/jakarta-sample")); + IPsiUtils utils = PsiUtilsLSImpl.getInstance(getProject()); + + VirtualFile javaFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(ModuleUtilCore.getModuleDirPath(module) + + "/src/main/java/io/openliberty/sample/jakarta/annotations/ResourceAnnotationTypeMismatch.java"); + String uri = VfsUtilCore.virtualToIoFile(javaFile).toURI().toString(); + + JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams(); + diagnosticsParams.setUris(Arrays.asList(uri)); + + // expected annotations + Diagnostic d1 = d(8, 1, 51, "Type of the field MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + Diagnostic d2 = d(17, 1, 33, "Type of the field MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + Diagnostic d3 = d(23, 1, 33, "Type of the field MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + Diagnostic d4 = d(26, 1, 32, "Type of the field MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + Diagnostic d5 = d(44, 1, 31, "Type of the parameter MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + Diagnostic d6 = d(49, 1, 32, "Type of the parameter MUST be compatible with the type element of the Resource annotation, if specified.", + DiagnosticSeverity.Error, "jakarta-annotations", "ResourceTypeMismatch"); + + assertJavaDiagnostics(diagnosticsParams, utils, d1, d2, d3, d4, d5, d6); + + } } diff --git a/src/test/resources/projects/maven/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/annotations/ResourceAnnotationTypeMismatch.java b/src/test/resources/projects/maven/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/annotations/ResourceAnnotationTypeMismatch.java new file mode 100644 index 000000000..05eee2a95 --- /dev/null +++ b/src/test/resources/projects/maven/jakarta-sample/src/main/java/io/openliberty/sample/jakarta/annotations/ResourceAnnotationTypeMismatch.java @@ -0,0 +1,54 @@ +package io.openliberty.sample.jakarta.annotations; + +import io.openliberty.sample.jakarta.di.Greeting; +import jakarta.annotation.Resource; + +@Resource(type = Object.class, name = "") +class ResourceAnnotationTypeMismatch { + + @Resource(type = Object.class, name = "studentId") + private Integer studentId; + + @Resource(type = Integer.class) + private Integer mathsStudentId; + + @Resource(type = Integer.class) + private Object itStudentId; + + @Resource(type = Greeting.class) + private Integer bioStudentId; + + @Resource(name = "studentId") + private Integer mechStudentId; + + @Resource(type = Greeting.class) + private int englishStudentId; + + @Resource(type = Boolean.class) + private boolean frenchhStudentId; + + @Resource + public void setStudentId(Integer studentId) { + this.studentId = studentId; + } + + @Resource(type = Integer.class) + public void setMatchsStudentId(Integer studentId) { + this.studentId = studentId; + } + + @Resource(type = Integer.class) + public void setItStudentId(Object itStudentId) { + this.itStudentId = itStudentId; + } + + @Resource(type = Object.class) + public void setMechStudentId(Integer mechStudentId) { + this.mechStudentId = mechStudentId; + } + + @Resource(type = Boolean.class) + public void setChemStudentId(boolean frenchhStudentId) { + this.frenchhStudentId = frenchhStudentId; + } +} From b87b8107f5ce98aeeaf103ab277a017911ecc49d Mon Sep 17 00:00:00 2001 From: Rejoy Date: Wed, 4 Feb 2026 10:07:13 +0530 Subject: [PATCH 04/11] Validate-@Resource-type-compatibility - added diagnostics messages --- .../tools/intellij/lsp4jakarta/messages/messages.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties b/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties index 7f9aa5bca..42952a894 100644 --- a/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties +++ b/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties @@ -17,6 +17,7 @@ AnnotationMustDefineAttributeFollowing8601 = The {0} annotation must define the MethodMustNotHaveParameters = A method with the {0} annotation must not have any parameters. MethodMustBeVoid = A method with the {0} annotation must be void. MethodMustNotBeStatic = A method with the {0} annotation must not be static. +ResourceTypeMismatch = Type of the {0} MUST be compatible with the type element of the Resource annotation, if specified. MethodMustNotThrow = A method with the {0} annotation must not throw checked exceptions. RemoveCheckedExceptions = Remove all checked exceptions. AnnotationNameMustStartWithSet = {0} method ''{1}'' is invalid: method name must start with 'set'. From c47d5e98f8ed0f88e701f7ec38a1ac66441cdbb0 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Wed, 4 Feb 2026 15:40:55 +0530 Subject: [PATCH 05/11] feature/Validate-@Resource-type-compatibility - null, default work only in java 21 --- .../tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java | 3 ++- .../lsp4ij/annotations/AnnotationDiagnosticsCollector.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java index d0ef1e99c..672758a6e 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/DiagnosticsUtils.java @@ -25,6 +25,7 @@ public class DiagnosticsUtils { public static final String NAME_MUST_START_WITH_SET = "NameMustStartWithSet"; public static final String MUST_DECLARE_EXACTLY_ONE_PARAM = "MustDeclareExactlyOneParam"; public static final String RETURN_TYPE_MUST_BE_VOID = "ReturnTypeMustBeVoid"; + public static final String VALID_SETTER_METHOD = "ValidSetterMethod"; /** * inheritsFrom * find super class and Check if it is present or not in the type hierarchy @@ -73,6 +74,6 @@ public static String validateSetterMethod(PsiMethod element) { } else if(element.getParameterList().getParametersCount() != 1){ return MUST_DECLARE_EXACTLY_ONE_PARAM; } - return null; + return VALID_SETTER_METHOD; } } diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java index fd2882f28..eed0006eb 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/AnnotationDiagnosticsCollector.java @@ -263,10 +263,11 @@ private void validateResourceMethods(PsiJavaFile unit, List diagnost AnnotationConstants.DIAGNOSTIC_CODE_MUST_DECLARE_EXACTLY_ONE_PARAM, null, DiagnosticSeverity.Error)); } - case null, default -> { + case VALID_SETTER_METHOD -> { PsiParameter param = element.getParameterList().getParameter(0); checkTypeCompatibility(unit, diagnostics, annotation, param.getType(), "parameter"); } + default -> System.out.println("Unexpected value"); } } From b9e648357fbdce808e3536579093a64f766ce097 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Fri, 6 Feb 2026 17:29:13 +0530 Subject: [PATCH 06/11] added quick fixes --- src/main/resources/META-INF/plugin.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 2bb591fe3..4b313c8a5 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -290,6 +290,14 @@ group="jakarta" targetDiagnostic="jakarta-annotations#PreDestroyException" implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.annotations.RemoveCheckedExceptionsInThrowsQuickFix"/> + + Date: Fri, 6 Feb 2026 17:29:34 +0530 Subject: [PATCH 07/11] created 2 new quick fixes --- ...veResourceAnnotationAttributeQuickFix.java | 39 +++++++++++++++++++ .../RemoveResourceAnnotationQuickFix.java | 37 ++++++++++++++++++ .../lsp4jakarta/messages/messages.properties | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java create mode 100644 src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationQuickFix.java diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java new file mode 100644 index 000000000..c0e37648e --- /dev/null +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java @@ -0,0 +1,39 @@ +/******************************************************************************* +* Copyright (c) 2026 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.tools.intellij.lsp4jakarta.lsp4ij.annotations; + + +import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.quickfix.RemoveAnnotationAttributesQuickFix; + +import org.eclipse.lsp4jakarta.jdt.internal.Messages; + +/** + * Removes the @Resource annotation from the declaring element. + */ +public class RemoveResourceAnnotationAttributeQuickFix extends RemoveAnnotationAttributesQuickFix { + + public RemoveResourceAnnotationAttributeQuickFix() { + super("jakarta.annotation.Resource","type"); + } + + @Override + public String getLabel() { + return "df"; + } + + @Override + public String getParticipantId() { + return RemoveResourceAnnotationAttributeQuickFix.class.getName(); + } +} diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationQuickFix.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationQuickFix.java new file mode 100644 index 000000000..dd3c27e3e --- /dev/null +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationQuickFix.java @@ -0,0 +1,37 @@ +/******************************************************************************* +* Copyright (c) 2026 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.tools.intellij.lsp4jakarta.lsp4ij.annotations; + +import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.quickfix.RemoveAnnotationConflictQuickFix; + +/** + * Removes the @Resource annotation from the declaring element. + */ +public class RemoveResourceAnnotationQuickFix extends RemoveAnnotationConflictQuickFix { + + /** + * Constructor. + */ + public RemoveResourceAnnotationQuickFix() { + super(false, "jakarta.annotation.Resource"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getParticipantId() { + return RemoveResourceAnnotationQuickFix.class.getName(); + } +} diff --git a/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties b/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties index 42952a894..718dfb4bc 100644 --- a/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties +++ b/src/main/resources/io/openliberty/tools/intellij/lsp4jakarta/messages/messages.properties @@ -40,7 +40,7 @@ InsertModifierToNestedClass = Add ''{0}'' modifier to the nested class # RemoveAnnotationConflictQuickFix RemoveItem = Remove {0} - +RemoveAttribute = Remove {0} attribute from {1} # RemoveParamAnnotationQuickFix RemoveTheModifierFromParameter = Remove the {0} modifier from parameter {1} From 434774e8b169e2bf3df0cf43407a1b2663ab9e0e Mon Sep 17 00:00:00 2001 From: Rejoy Date: Fri, 6 Feb 2026 17:29:53 +0530 Subject: [PATCH 08/11] remove annotation attribute quickfix --- .../RemoveAnnotationAttributesQuickFix.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java new file mode 100644 index 000000000..ed671051e --- /dev/null +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * 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 API and implementation + * Lidia Ataupillco Ramos + *******************************************************************************/ +package io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.quickfix; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.JDTUtils; +import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.ModifyAnnotationProposal; +import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.IJavaCodeActionParticipant; +import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionContext; +import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.JavaCodeActionResolveContext; +import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.corrections.proposal.ChangeCorrectionProposal; +import io.openliberty.tools.intellij.util.ExceptionUtil; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.Diagnostic; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +/** + * Quickfix for removing annotations attributes + */ +public abstract class RemoveAnnotationAttributesQuickFix implements IJavaCodeActionParticipant { + + private final String[] attributes; + + private final String annotation; + + private static final Logger LOGGER = Logger.getLogger(RemoveAnnotationAttributesQuickFix.class.getName()); + + + public RemoveAnnotationAttributesQuickFix(String annotation, + String... attributes) { + this.annotation = annotation; + this.attributes = attributes; + } + + @Override + public List getCodeActions(JavaCodeActionContext context, Diagnostic diagnostic) { + return List.of(JDTUtils.createCodeAction(context, diagnostic, getLabel(), getParticipantId())); + } + + @Override + public CodeAction resolveCodeAction(JavaCodeActionResolveContext context) { + final CodeAction toResolve = context.getUnresolved(); + final PsiElement node = context.getCoveredNode(); + PsiModifierListOwner binding = getBinding(node); + // annotationNode is null when adding an annotation and non-null when adding attributes. + PsiAnnotation annotationNode = getAnnotation(node); + + assert binding != null; + String label = getLabel(); + ChangeCorrectionProposal proposal = new ModifyAnnotationProposal(label, context.getSource().getCompilationUnit(), + context.getASTRoot(), binding, annotationNode, 0, this.annotation, new ArrayList<>(), Arrays.asList(attributes)); + + ExceptionUtil.executeWithWorkspaceEditHandling(context, proposal, toResolve, LOGGER, "Unable to create workspace edit for code action " + label); + return toResolve; + } + + + private static PsiAnnotation getAnnotation(PsiElement e) { + if (e instanceof PsiAnnotation) { + return (PsiAnnotation) e; + } + return PsiTreeUtil.getParentOfType(e, PsiAnnotation.class); + } + protected static PsiModifierListOwner getBinding(PsiElement node) { + PsiModifierListOwner binding = PsiTreeUtil.getParentOfType(node, PsiVariable.class); + if (binding != null) { + return binding; + } + binding = PsiTreeUtil.getParentOfType(node, PsiMethod.class); + if (binding != null) { + return binding; + } + return PsiTreeUtil.getParentOfType(node, PsiClass.class); + } + protected abstract String getLabel(); + +} From bb6631f0be318009ffafa683f328e76b0ba3978c Mon Sep 17 00:00:00 2001 From: Rejoy Date: Fri, 6 Feb 2026 21:57:41 +0530 Subject: [PATCH 09/11] Update RemoveAnnotationAttributesQuickFix.java --- .../RemoveAnnotationAttributesQuickFix.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java index ed671051e..2e72f9c92 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/codeAction/proposal/quickfix/RemoveAnnotationAttributesQuickFix.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2024 IBM Corporation and others. + * Copyright (c) 2026 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 @@ -9,7 +9,6 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Lidia Ataupillco Ramos *******************************************************************************/ package io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.quickfix; @@ -27,7 +26,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.logging.Logger; @@ -59,25 +57,15 @@ public CodeAction resolveCodeAction(JavaCodeActionResolveContext context) { final CodeAction toResolve = context.getUnresolved(); final PsiElement node = context.getCoveredNode(); PsiModifierListOwner binding = getBinding(node); - // annotationNode is null when adding an annotation and non-null when adding attributes. - PsiAnnotation annotationNode = getAnnotation(node); - + PsiAnnotation annotationNode = PsiTreeUtil.getParentOfType(node, PsiAnnotation.class); assert binding != null; String label = getLabel(); ChangeCorrectionProposal proposal = new ModifyAnnotationProposal(label, context.getSource().getCompilationUnit(), context.getASTRoot(), binding, annotationNode, 0, this.annotation, new ArrayList<>(), Arrays.asList(attributes)); - ExceptionUtil.executeWithWorkspaceEditHandling(context, proposal, toResolve, LOGGER, "Unable to create workspace edit for code action " + label); return toResolve; } - - private static PsiAnnotation getAnnotation(PsiElement e) { - if (e instanceof PsiAnnotation) { - return (PsiAnnotation) e; - } - return PsiTreeUtil.getParentOfType(e, PsiAnnotation.class); - } protected static PsiModifierListOwner getBinding(PsiElement node) { PsiModifierListOwner binding = PsiTreeUtil.getParentOfType(node, PsiVariable.class); if (binding != null) { @@ -89,6 +77,7 @@ protected static PsiModifierListOwner getBinding(PsiElement node) { } return PsiTreeUtil.getParentOfType(node, PsiClass.class); } + protected abstract String getLabel(); } From 21184fc0418245715d79ae849551f6b86ea826cf Mon Sep 17 00:00:00 2001 From: Rejoy Date: Fri, 6 Feb 2026 22:08:46 +0530 Subject: [PATCH 10/11] Update RemoveResourceAnnotationAttributeQuickFix.java --- .../RemoveResourceAnnotationAttributeQuickFix.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java index c0e37648e..3677165ae 100644 --- a/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java +++ b/src/main/java/io/openliberty/tools/intellij/lsp4jakarta/lsp4ij/annotations/RemoveResourceAnnotationAttributeQuickFix.java @@ -14,12 +14,11 @@ package io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.annotations; +import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.Messages; import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.quickfix.RemoveAnnotationAttributesQuickFix; -import org.eclipse.lsp4jakarta.jdt.internal.Messages; - /** - * Removes the @Resource annotation from the declaring element. + * Removes the @Resource annotation attribute */ public class RemoveResourceAnnotationAttributeQuickFix extends RemoveAnnotationAttributesQuickFix { @@ -29,7 +28,7 @@ public RemoveResourceAnnotationAttributeQuickFix() { @Override public String getLabel() { - return "df"; + return Messages.getMessage("RemoveAttribute", "type", "@Resource"); } @Override From 80c02d9e2501233c54ab997e72a5bfd174895fe6 Mon Sep 17 00:00:00 2001 From: Rejoy Date: Fri, 6 Feb 2026 22:38:36 +0530 Subject: [PATCH 11/11] test cases --- .../annotations/ResourceAnnotationTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java b/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java index d8a34b79f..92f2370f2 100644 --- a/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java +++ b/src/test/java/io/openliberty/tools/intellij/lsp4jakarta/it/annotations/ResourceAnnotationTest.java @@ -134,5 +134,69 @@ public void ResourceAnnotationTypeMismatch() throws Exception { assertJavaDiagnostics(diagnosticsParams, utils, d1, d2, d3, d4, d5, d6); + JakartaJavaCodeActionParams codeActionParams = createCodeActionParams(uri, d1); + String newText11 = "package io.openliberty.sample.jakarta.annotations;\n\nimport io.openliberty.sample.jakarta.di.Greeting;\n" + + "import jakarta.annotation.Resource;\n\n@Resource(type = Object.class, name = \"\")\n" + + "class ResourceAnnotationTypeMismatch {\n\n\tprivate Integer studentId;\n\n\t@Resource(type = Integer.class)\n\t" + + "private Integer mathsStudentId;\n\n\t@Resource(type = Integer.class)\n\tprivate Object itStudentId;\n\n\t" + + "@Resource(type = Greeting.class)\n\tprivate Integer bioStudentId;\n\n\t@Resource(name = \"studentId\")\n\t" + + "private Integer mechStudentId;\n\n\t@Resource(type = Greeting.class)\n\tprivate int englishStudentId;\n\n\t" + + "@Resource(type = Boolean.class)\n\tprivate boolean frenchhStudentId;\n\n\t@Resource\n\t" + + "public void setStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setMatchsStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setItStudentId(Object itStudentId) {\n\t\tthis.itStudentId = itStudentId;\n\t}\n\n\t" + + "@Resource(type = Object.class)\n\tpublic void setMechStudentId(Integer mechStudentId) {\n\t\tthis.mechStudentId = mechStudentId;\n\t}\n\n\t" + + "@Resource(type = Boolean.class)\n\tpublic void setChemStudentId(boolean frenchhStudentId) {\n\t\tthis.frenchhStudentId = frenchhStudentId;\n\t}\n}\n"; + TextEdit te11 = te(0, 0, 54, 0, newText11); + CodeAction ca11 = ca(uri, "Remove @Resource", d1, te11); + String newText12 = "package io.openliberty.sample.jakarta.annotations;\n\nimport io.openliberty.sample.jakarta.di.Greeting;\n" + + "import jakarta.annotation.Resource;\n\n@Resource(type = Object.class, name = \"\")\nclass ResourceAnnotationTypeMismatch {\n\n\t" + + "@Resource( name = \"studentId\")\n\tprivate Integer studentId;\n\n\t@Resource(type = Integer.class)\n\tprivate Integer mathsStudentId;\n\n\t" + + "@Resource(type = Integer.class)\n\tprivate Object itStudentId;\n\n\t@Resource(type = Greeting.class)\n\tprivate Integer bioStudentId;\n\n\t" + + "@Resource(name = \"studentId\")\n\tprivate Integer mechStudentId;\n\n\t@Resource(type = Greeting.class)\n\tprivate int englishStudentId;\n\n\t" + + "@Resource(type = Boolean.class)\n\tprivate boolean frenchhStudentId;\n\n\t" + + "@Resource\n\tpublic void setStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setMatchsStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setItStudentId(Object itStudentId) {\n\t\tthis.itStudentId = itStudentId;\n\t}\n\n\t" + + "@Resource(type = Object.class)\n\tpublic void setMechStudentId(Integer mechStudentId) {\n\t\tthis.mechStudentId = mechStudentId;\n\t}\n\n\t" + + "@Resource(type = Boolean.class)\n\tpublic void setChemStudentId(boolean frenchhStudentId) {\n\t\tthis.frenchhStudentId = frenchhStudentId;\n\t}\n}\n"; + TextEdit te12 = te(0, 0, 54, 0, newText12); + CodeAction ca12 = ca(uri, "Remove type attribute from @Resource", d1, te12); + assertJavaCodeAction(codeActionParams, utils, ca11, ca12); + + JakartaJavaCodeActionParams codeActionParams2 = createCodeActionParams(uri, d6); + String newText21 = "package io.openliberty.sample.jakarta.annotations;\n\nimport io.openliberty.sample.jakarta.di.Greeting;\n" + + "import jakarta.annotation.Resource;\n\n@Resource(type = Object.class, name = \"\")\nclass ResourceAnnotationTypeMismatch {\n\n\t" + + "@Resource(type = Object.class, name = \"studentId\")\n\tprivate Integer studentId;\n\n\t" + + "@Resource(type = Integer.class)\n\tprivate Integer mathsStudentId;\n\n\t" + + "@Resource(type = Integer.class)\n\tprivate Object itStudentId;\n\n\t" + + "@Resource(type = Greeting.class)\n\tprivate Integer bioStudentId;\n\n\t" + + "@Resource(name = \"studentId\")\n\tprivate Integer mechStudentId;\n\n\t" + + "@Resource(type = Greeting.class)\n\tprivate int englishStudentId;\n\n\t" + + "@Resource(type = Boolean.class)\n\tprivate boolean frenchhStudentId;\n\n\t" + + "@Resource\n\tpublic void setStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setMatchsStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setItStudentId(Object itStudentId) {\n\t\tthis.itStudentId = itStudentId;\n\t}\n\n\t" + + "@Resource(type = Object.class)\n\tpublic void setMechStudentId(Integer mechStudentId) {\n\t\tthis.mechStudentId = mechStudentId;\n\t}\n\n\t" + + "public void setChemStudentId(boolean frenchhStudentId) {\n\t\tthis.frenchhStudentId = frenchhStudentId;\n\t}\n}\n"; + TextEdit te21 = te(0, 0, 54, 0, newText21); + CodeAction ca21 = ca(uri, "Remove @Resource", d6, te21); + String newText22 = "package io.openliberty.sample.jakarta.annotations;\n\nimport io.openliberty.sample.jakarta.di.Greeting;\n" + + "import jakarta.annotation.Resource;\n\n@Resource(type = Object.class, name = \"\")\nclass ResourceAnnotationTypeMismatch {\n\n\t" + + "@Resource(type = Object.class, name = \"studentId\")\n\tprivate Integer studentId;\n\n\t@Resource(type = Integer.class)\n\t" + + "private Integer mathsStudentId;\n\n\t@Resource(type = Integer.class)\n\tprivate Object itStudentId;\n\n\t" + + "@Resource(type = Greeting.class)\n\tprivate Integer bioStudentId;\n\n\t@Resource(name = \"studentId\")\n\t" + + "private Integer mechStudentId;\n\n\t@Resource(type = Greeting.class)\n\tprivate int englishStudentId;\n\n\t" + + "@Resource(type = Boolean.class)\n\tprivate boolean frenchhStudentId;\n\n\t@Resource\n\t" + + "public void setStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setMatchsStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\t" + + "@Resource(type = Integer.class)\n\tpublic void setItStudentId(Object itStudentId) {\n\t\tthis.itStudentId = itStudentId;\n\t}\n\n\t" + + "@Resource(type = Object.class)\n\tpublic void setMechStudentId(Integer mechStudentId) {\n\t\tthis.mechStudentId = mechStudentId;\n\t}\n\n\t" + + "@Resource()\n\tpublic void setChemStudentId(boolean frenchhStudentId) {\n\t\tthis.frenchhStudentId = frenchhStudentId;\n\t}\n}\n"; + TextEdit te22 = te(0, 0, 54, 0, newText22); + CodeAction ca22 = ca(uri, "Remove type attribute from @Resource", d6, te22); + assertJavaCodeAction(codeActionParams2, utils, ca21, ca22); + + } }