Skip to content

Commit

Permalink
Merge pull request #513 from ajm01/issue-190
Browse files Browse the repository at this point in the history
add quickfix fn to handle composite annotations
  • Loading branch information
ajm01 committed Feb 27, 2024
2 parents e4c793f + 7c8865e commit 2ca7a71
Show file tree
Hide file tree
Showing 12 changed files with 469 additions and 90 deletions.
5 changes: 4 additions & 1 deletion jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<!-- Annotations -->
<extension point="org.eclipse.lsp4jakarta.jdt.core.javaFeatureParticipants">
<diagnostics class="org.eclipse.lsp4jakarta.jdt.internal.annotations.AnnotationDiagnosticsParticipant" />
<codeAction kind="quickfix"
targetDiagnostic="jakarta-annotations#MissingResourceAnnotation"
class="org.eclipse.lsp4jakarta.jdt.internal.annotations.InsertDefaultResourceAnnotationToResourcesAnnotation" />
<codeAction kind="quickfix"
targetDiagnostic="jakarta-annotations#MissingResourceNameAttribute"
class="org.eclipse.lsp4jakarta.jdt.internal.annotations.InsertNameAttributeToResourceAnnotationQuickFix" />
Expand All @@ -84,7 +87,7 @@
class="org.eclipse.lsp4jakarta.jdt.internal.annotations.RemovePreDestroyAnnotationQuickFix" />
<codeAction kind="quickfix"
targetDiagnostic="jakarta-annotations#PreDestroyParams"
class="org.eclipse.lsp4jakarta.jdt.internal.annotations.RemoveAllMethodParametersQuickFix" />
class="org.eclipse.lsp4jakarta.jdt.internal.annotations.RemoveAllMethodParametersQuickFix" />
</extension>

<!-- Bean Validation -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
* Copyright (c) 2023, 2024 Red Hat Inc. 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
Expand Down Expand Up @@ -28,6 +28,7 @@ public enum JakartaCodeActionId implements ICodeActionId {
ChangeReturnTypeToVoid,
InsertResourceAnnotationTypeAttribute,
InsertResourceAnnotationNameAttribute,
InsertDefaultResourceAnnotationToResourcesAnnotation,
RemoveAllParameters,
RemoveAnnotationPreDestroy,
RemoveAnnotationPostConstruct,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2023 IBM Corporation and others.
* Copyright (c) 2021, 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
Expand Down Expand Up @@ -65,7 +65,8 @@ public List<Diagnostic> collectDiagnostics(JavaDiagnosticsContext context, IProg
ArrayList<Tuple.Two<IAnnotation, IAnnotatable>> annotatables = new ArrayList<Two<IAnnotation, IAnnotatable>>();
String[] validAnnotations = { Constants.GENERATED_FQ_NAME };
String[] validTypeAnnotations = { Constants.GENERATED_FQ_NAME,
Constants.RESOURCE_FQ_NAME };
Constants.RESOURCE_FQ_NAME,
Constants.RESOURCES_FQ_NAME };
String[] validMethodAnnotations = { Constants.GENERATED_FQ_NAME,
Constants.POST_CONSTRUCT_FQ_NAME, Constants.PRE_DESTROY_FQ_NAME,
Constants.RESOURCE_FQ_NAME };
Expand Down Expand Up @@ -120,6 +121,7 @@ public List<Diagnostic> collectDiagnostics(JavaDiagnosticsContext context, IProg
IAnnotation annotation = annotatable.getFirst();
IAnnotatable element = annotatable.getSecond();

// process Types? (class declarations)
if (DiagnosticUtils.isMatchedAnnotation(unit, annotation, Constants.GENERATED_FQ_NAME)) {
for (IMemberValuePair pair : annotation.getMemberValuePairs()) {
// If date element exists and is non-empty, it must follow ISO 8601 format.
Expand Down Expand Up @@ -178,7 +180,74 @@ public List<Diagnostic> collectDiagnostics(JavaDiagnosticsContext context, IProg
}
}
}
} else if (DiagnosticUtils.isMatchedAnnotation(unit, annotation, Constants.RESOURCES_FQ_NAME)) {
if (element instanceof IType) {
for (IMemberValuePair internalAnnotation : annotation.getMemberValuePairs()) {
Object[] valuePairs = (Object[]) internalAnnotation.getValue();
String diagnosticMessage;
Range annotationRange = null;
if (valuePairs.length == 0) {
annotationRange = PositionUtils.toNameRange(annotation, context.getUtils());
diagnosticMessage = Messages.getMessage("ResourcesAnnotationMustDefineResourceAnnotation",
"@Resources", "@Resource");
diagnostics.add(context.createDiagnostic(uri, diagnosticMessage, annotationRange,
Constants.DIAGNOSTIC_SOURCE,
ErrorCode.MissingResourceAnnotation,
DiagnosticSeverity.Error));
}
int objKind = internalAnnotation.getValueKind();
for (Object childAnnotationObj : valuePairs) {
if (objKind == IMemberValuePair.K_ANNOTATION) {
IAnnotation childAnnotation = (IAnnotation) childAnnotationObj;
if (DiagnosticUtils.isMatchedAnnotation(unit, childAnnotation,
Constants.RESOURCE_FQ_NAME)) {
if (element instanceof IType) {
IType type = (IType) element;
if (type.getElementType() == IJavaElement.TYPE
&& ((IType) type).isClass()) {
annotationRange = PositionUtils.toNameRange(childAnnotation,
context.getUtils());
Boolean nameEmpty = true;
Boolean typeEmpty = true;
for (IMemberValuePair pair : childAnnotation.getMemberValuePairs()) {
if (pair.getMemberName().equals("name")) {
nameEmpty = false;
}
if (pair.getMemberName().equals("type")) {
typeEmpty = false;
}
}
if (nameEmpty) {
diagnosticMessage = Messages.getMessage(
"AnnotationMustDefineAttribute",
"@Resource", "name");
diagnostics.add(context.createDiagnostic(uri, diagnosticMessage,
annotationRange,
Constants.DIAGNOSTIC_SOURCE,
ErrorCode.MissingResourceNameAttribute,
DiagnosticSeverity.Error));
}

if (typeEmpty) {
diagnosticMessage = Messages.getMessage(
"AnnotationMustDefineAttribute",
"@Resource", "type");
diagnostics.add(context.createDiagnostic(uri, diagnosticMessage,
annotationRange,
Constants.DIAGNOSTIC_SOURCE,
ErrorCode.MissingResourceTypeAttribute,
DiagnosticSeverity.Error));
}
}
}
}
}
}
}
}
}

// process methods now?
if (DiagnosticUtils.isMatchedAnnotation(unit, annotation, Constants.POST_CONSTRUCT_FQ_NAME)) {
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2023 IBM Corporation and others.
* Copyright (c) 2021, 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
Expand Down Expand Up @@ -30,6 +30,10 @@ public class Constants {
public static final String RESOURCE = "Resource";
public static final String RESOURCE_FQ_NAME = "jakarta.annotation.Resource";

/* @Resources */
public static final String RESOURCES = "Resources";
public static final String RESOURCES_FQ_NAME = "jakarta.annotation.Resources";

/* @PostConstruct */
public static final String POST_CONSTRUCT = "PostConstruct";
public static final String POST_CONSTRUCT_FQ_NAME = "jakarta.annotation.PostConstruct";
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,6 +19,7 @@
*/
public enum ErrorCode implements IJavaErrorCode {
InvalidDateFormat,
MissingResourceAnnotation,
MissingResourceNameAttribute,
MissingResourceTypeAttribute,
PostConstructParams,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*******************************************************************************
* 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 API and implementation
*******************************************************************************/
package org.eclipse.lsp4jakarta.jdt.internal.annotations;

import org.eclipse.lsp4jakarta.commons.codeaction.ICodeActionId;
import org.eclipse.lsp4jakarta.commons.codeaction.JakartaCodeActionId;
import org.eclipse.lsp4jakarta.jdt.core.java.codeaction.InsertAnnotationAttributesQuickFix;

/**
* Inserts the name attribute to the @Resource annotation to the active element.
*/
public class InsertDefaultResourceAnnotationToResourcesAnnotation extends InsertAnnotationAttributesQuickFix {

/**
* Constructor.
*/
public InsertDefaultResourceAnnotationToResourcesAnnotation() {
super("jakarta.annotation.Resource", "name", "type");
}

/**
* {@inheritDoc}
*/
@Override
public String getParticipantId() {
return InsertDefaultResourceAnnotationToResourcesAnnotation.class.getName();
}

/**
* {@inheritDoc}
*/
@Override
protected ICodeActionId getCodeActionId() {
return JakartaCodeActionId.InsertDefaultResourceAnnotationToResourcesAnnotation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ MethodMustNotHaveParameters = A method with the {0} annotation must not have any
MethodMustBeVoid = A method with the {0} annotation must be void.
MethodMustNotBeStatic = A method with the {0} annotation must not be static.
MethodMustNotThrow = A method with the {0} annotation must not throw checked exceptions.
ResourcesAnnotationMustDefineResourceAnnotation = The {0} annotation must define at least one sub-annotation ''{1}''.

# HttpServletQuickFix
LetClassExtend = Let ''{0}'' extend ''{1}''
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package io.openliberty.sample.jakarta.annotations;

import jakarta.annotation.Resource;
import jakarta.annotation.Resources;

@Resource(type = Object.class, name = "aa")
public class ResourceAnnotation {

private Integer studentId;


@Resource(shareable = true)
private boolean isHappy;

@Resource(name = "test")
private boolean isSad;


private String emailAddress;





}

@Resource(name = "aa")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* 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 API and implementation
*******************************************************************************/
package io.openliberty.sample.jakarta.annotations;

import jakarta.annotation.Resource;
import jakarta.annotation.Resources;

@Resources ({ @Resource(name = "aaa"), @Resource(type = Object.class) })
public class ResourcesAnnotation {
}

@Resources ({})
class ResourcesAnnotationEmpty {
}

@Resource(name = "aa", type = Object.class)
class DoctoralStudent {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2022 IBM Corporation and others.
* Copyright (c) 2021, 2022, 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
Expand Down Expand Up @@ -63,10 +63,10 @@ public void GeneratedAnnotation() throws Exception {
assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca);

JakartaJavaCodeActionParams codeActionParams1 = createCodeActionParams(uri, d2);
TextEdit te1 = te(39, 0, 39, 30, "@Resource(type = \"\", name = \"\")");
TextEdit te1 = te(39, 0, 39, 30, "@Resource(type = Object.class, name = \"\")");
CodeAction ca1 = ca(uri, "Insert 'name' attribute to @Resource", d2, te1);
assertJavaCodeAction(codeActionParams1, IJDT_UTILS, ca1);

}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*******************************************************************************
* 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 API and implementation
*******************************************************************************/
package org.eclipse.lsp4jakarta.jdt.annotations;

import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.assertJavaCodeAction;
import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.assertJavaDiagnostics;
import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.ca;
import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.createCodeActionParams;
import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.d;
import static org.eclipse.lsp4jakarta.jdt.core.JakartaForJavaAssert.te;

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.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4jakarta.commons.JakartaJavaCodeActionParams;
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;

public class ResourcesAnnotationTest extends BaseJakartaTest {

protected static IJDTUtils IJDT_UTILS = JDTUtilsLSImpl.getInstance();

@Test
public void GeneratedAnnotation() throws Exception {
IJavaProject javaProject = loadJavaProject("jakarta-sample", "");
IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/io/openliberty/sample/jakarta/annotations/ResourcesAnnotation.java"));
String uri = javaFile.getLocation().toFile().toURI().toString();

JakartaJavaDiagnosticsParams diagnosticsParams = new JakartaJavaDiagnosticsParams();
diagnosticsParams.setUris(Arrays.asList(uri));

// expected annotations
Diagnostic d1 = d(17, 14, 37, "The @Resource annotation must define the attribute 'type'.",
DiagnosticSeverity.Error, "jakarta-annotations", "MissingResourceTypeAttribute");

Diagnostic d2 = d(17, 39, 69, "The @Resource annotation must define the attribute 'name'.",
DiagnosticSeverity.Error, "jakarta-annotations", "MissingResourceNameAttribute");

Diagnostic d3 = d(21, 0, 15, "The @Resources annotation must define at least one sub-annotation '@Resource'.",
DiagnosticSeverity.Error, "jakarta-annotations", "MissingResourceAnnotation");

assertJavaDiagnostics(diagnosticsParams, IJDT_UTILS, d1, d2, d3);

JakartaJavaCodeActionParams codeActionParams = createCodeActionParams(uri, d1);
TextEdit te1 = te(17, 0, 18, 0, "@Resources({ @Resource(name = \"aaa\", type = \"\"), @Resource(type = Object.class) })\n");
CodeAction ca1 = ca(uri, "Insert 'type' attribute to @Resource", d1, te1);
assertJavaCodeAction(codeActionParams, IJDT_UTILS, ca1);

JakartaJavaCodeActionParams codeActionParams1 = createCodeActionParams(uri, d2);
TextEdit te2 = te(17, 0, 18, 0, "@Resources({ @Resource(name = \"aaa\"), @Resource(type = Object.class, name = \"\") })\n");
CodeAction ca2 = ca(uri, "Insert 'name' attribute to @Resource", d2, te2);
assertJavaCodeAction(codeActionParams1, IJDT_UTILS, ca2);

JakartaJavaCodeActionParams codeActionParams2 = createCodeActionParams(uri, d3);
TextEdit te3 = te(21, 0, 21, 15, "@Resources({ @Resource(name = \"\", type = \"\") })");
CodeAction ca3 = ca(uri, "Insert 'name,type' attributes to @Resource", d3, te3);
assertJavaCodeAction(codeActionParams2, IJDT_UTILS, ca3);
}
}

0 comments on commit 2ca7a71

Please sign in to comment.