Skip to content

Commit

Permalink
Merge pull request #500 from mrglavas/jakarta-code-action-handler-poc
Browse files Browse the repository at this point in the history
Proof-of-concept for unifying the design for MicroProfile and Jakarta EE code actions.
  • Loading branch information
mrglavas authored Sep 20, 2023
2 parents abdfec6 + 3a2b517 commit d9364f3
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.ServletDiagnosticsCollector;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.websocket.WebSocketDiagnosticsCollector;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.core.java.codeaction.CodeActionHandler;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.core.ls.PsiUtilsLSImpl;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4jakarta.commons.*;
Expand All @@ -66,7 +67,7 @@ public static PropertiesManagerForJakarta getInstance() {
}

private List<DiagnosticsCollector> diagnosticsCollectors = new ArrayList<>();
private JakartaCodeActionHandler codeActionHandler = new JakartaCodeActionHandler();
private final CodeActionHandler codeActionHandler;

private PropertiesManagerForJakarta() {
diagnosticsCollectors.add(new ServletDiagnosticsCollector());
Expand All @@ -83,7 +84,7 @@ private PropertiesManagerForJakarta() {
diagnosticsCollectors.add(new DependencyInjectionDiagnosticsCollector());
diagnosticsCollectors.add(new JsonpDiagnosticCollector());
diagnosticsCollectors.add(new WebSocketDiagnosticsCollector());
codeActionHandler = new JakartaCodeActionHandler();
codeActionHandler = new CodeActionHandler("jakarta");
}

/**
Expand Down Expand Up @@ -405,7 +406,24 @@ private static PsiFile resolveTypeRoot(String uri, Project project) {

public List<CodeAction> getCodeAction(JakartaJavaCodeActionParams params, IPsiUtils utils) {
return ApplicationManager.getApplication().runReadAction((Computable<List<CodeAction>>) () -> {
return codeActionHandler.codeAction(params, utils);
final List<? extends CodeAction> unresolvedCodeActions = codeActionHandler.codeAction(adapt(params), utils);
if (unresolvedCodeActions != null) {
final List<CodeAction> resolvedCodeActions = new ArrayList<>(unresolvedCodeActions.size());
unresolvedCodeActions.forEach(unresolvedCodeAction -> {
if (unresolvedCodeAction != null) {
resolvedCodeActions.add(codeActionHandler.resolveCodeAction(unresolvedCodeAction, utils));
}
});
return resolvedCodeActions;
}
return null;
});
}

private MicroProfileJavaCodeActionParams adapt(JakartaJavaCodeActionParams params) {
MicroProfileJavaCodeActionParams mpParams = new MicroProfileJavaCodeActionParams(params.getTextDocument(), params.getRange(), params.getContext());
mpParams.setResourceOperationSupported(params.isResourceOperationSupported());
mpParams.setResolveSupported(true);
return mpParams;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@
import com.intellij.psi.util.PsiTreeUtil;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.Messages;
import io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.codeAction.proposal.ModifyModifiersProposal;
import io.openliberty.tools.intellij.lsp4mp4ij.psi.core.java.codeaction.ExtendedCodeAction;
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 org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.lsp4mp.commons.CodeActionResolveData;

import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Quick fix for ResourceMethodDiagnosticsCollector that uses
Expand All @@ -34,26 +41,57 @@
* @author Matthew Shocrylas
*
*/
public class NonPublicResourceMethodQuickFix {
public class NonPublicResourceMethodQuickFix implements IJavaCodeActionParticipant {

private static final Logger LOGGER = Logger.getLogger(NonPublicResourceMethodQuickFix.class.getName());

private final static String TITLE_MESSAGE = Messages.getMessage("MakeMethodPublic");

@Override
public String getParticipantId() {
return NonPublicResourceMethodQuickFix.class.getName();
}

public List<? extends CodeAction> getCodeActions(JavaCodeActionContext context, Diagnostic diagnostic) {

final PsiElement node = context.getCoveredNode();
final PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);
final PsiMethod parentMethod = PsiTreeUtil.getParentOfType(node, PsiMethod.class);

if (parentMethod != null) {
ChangeCorrectionProposal proposal = new ModifyModifiersProposal(TITLE_MESSAGE, context.getSource().getCompilationUnit(),
context.getASTRoot(), parentType, 0, parentMethod.getModifierList(), Collections.singletonList("public"));

// Convert the proposal to LSP4J CodeAction
CodeAction codeAction = context.convertToCodeAction(proposal, diagnostic);
codeAction.setTitle(TITLE_MESSAGE);
return Collections.singletonList(codeAction);
return Collections.singletonList(createCodeAction(context, diagnostic));
}
return Collections.emptyList();
}

@Override
public CodeAction resolveCodeAction(JavaCodeActionResolveContext context) {

final CodeAction toResolve = context.getUnresolved();
final PsiElement node = context.getCoveredNode();
final PsiClass parentType = PsiTreeUtil.getParentOfType(node, PsiClass.class);
final PsiMethod parentMethod = PsiTreeUtil.getParentOfType(node, PsiMethod.class);

assert parentMethod != null;
ChangeCorrectionProposal proposal = new ModifyModifiersProposal(TITLE_MESSAGE, context.getSource().getCompilationUnit(),
context.getASTRoot(), parentType, 0, parentMethod.getModifierList(), Collections.singletonList("public"));
try {
WorkspaceEdit we = context.convertToWorkspaceEdit(proposal);
toResolve.setEdit(we);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Unable to create workspace edit for code action to make method public", e);
}
return toResolve;
}

private CodeAction createCodeAction(JavaCodeActionContext context, Diagnostic diagnostic) {
ExtendedCodeAction codeAction = new ExtendedCodeAction(TITLE_MESSAGE);
codeAction.setRelevance(0);
codeAction.setDiagnostics(Collections.singletonList(diagnostic));
codeAction.setKind(CodeActionKind.QuickFix);
codeAction.setData(new CodeActionResolveData(context.getUri(), getParticipantId(),
context.getParams().getRange(), Collections.emptyMap(),
context.getParams().isResourceOperationSupported(),
context.getParams().isCommandConfigurationUpdateSupported()));
return codeAction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public static PropertiesManagerForJava getInstance() {
private final CodeActionHandler codeActionHandler;

private PropertiesManagerForJava() {
this.codeActionHandler = new CodeActionHandler();
this.codeActionHandler = new CodeActionHandler("mp");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
*/
public class CodeActionHandler {

private final String group;

public CodeActionHandler(String group) {
this.group = group;
}

/**
* Returns all the code actions applicable for the context given by the
* parameters.
Expand Down Expand Up @@ -98,6 +104,7 @@ public List<? extends CodeAction> codeAction(MicroProfileJavaCodeActionParams pa
// Get list of code action definition for the given kind
List<io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.core.java.codeaction.JavaCodeActionDefinition> codeActionDefinitions = io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.core.java.codeaction.JavaCodeActionDefinition.EP.extensions()
.filter(definition -> definition.isAdaptedForCodeAction(context))
.filter(definition -> group.equals(definition.getGroup()))
.filter(definition -> codeActionKind.equals(definition.getKind()))
.collect(Collectors.toList());
if (codeActionDefinitions != null) {
Expand Down Expand Up @@ -201,6 +208,7 @@ public CodeAction resolveCodeAction(CodeAction unresolved, IPsiUtils utils) {

IJavaCodeActionParticipant participant = JavaCodeActionDefinition.EP.extensions()
.filter(definition -> unresolved.getKind().startsWith(definition.getKind()))
.filter(definition -> group.equals(definition.getGroup()))
.filter(definition -> participantId.equals(definition.getParticipantId()))
.findFirst().orElse(null);
return participant.resolveCodeAction(context.copy());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,15 @@ public class JavaCodeActionDefinition extends BaseKeyedLazyInstance<IJavaCodeAct

private static final Logger LOGGER = Logger.getLogger(JavaCodeActionDefinition.class.getName());
private static final String KIND_ATTR = "kind";
private static final String GROUP_ATTR = "group";
private static final String TARGET_DIAGNOSTIC_ATTR = "targetDiagnostic";

@Attribute("kind")
@Attribute(KIND_ATTR)
private String kind;

@Attribute(GROUP_ATTR)
private String group;

@Attribute(TARGET_DIAGNOSTIC_ATTR)
@RequiredElement
private String targetDiagnostic;
Expand Down Expand Up @@ -94,6 +98,15 @@ public String getKind() {
return !StringUtils.isEmpty(kind) ? kind : CodeActionKind.QuickFix;
}

/**
* Returns the name of the group which this code action is
* a member or null.
*
* @return the name of the group which this code action is
* a member or null.
*/
public @Nullable String getGroup() { return group; }

/**
* Returns the target diagnostic and null otherwise.
*
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,35 +123,50 @@
implementation="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.restclient.java.MicroProfileRestClientCodeLensParticipant"/>

<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-config#NO_VALUE_ASSIGNED_TO_PROPERTY"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.config.java.NoValueAssignedToPropertyQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-config#NO_VALUE_ASSIGNED_TO_PROPERTY"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.config.java.InsertDefaultValueAnnotationAttributeQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-health#ImplementHealthCheck"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.health.java.ImplementHealthCheckQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-health#HealthAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.health.java.HealthAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-metrics#ApplicationScopedAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.metrics.java.ApplicationScopedAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-restclient#InjectAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.restclient.java.InjectAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-restclient#RestClientAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.restclient.java.RestClientAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-restclient#InjectAndRestClientAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.restclient.java.InjectAndRestClientAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="quickfix"
group="mp"
targetDiagnostic="microprofile-restclient#RegisterRestClientAnnotationMissing"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.restclient.java.RegisterRestClientAnnotationMissingQuickFix"/>
<javaCodeActionParticipant kind="source"
group="mp"
implementationClass="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.openapi.java.MicroProfileGenerateOpenAPIOperation"/>

<javaCodeActionParticipant kind="quickfix"
group="jakarta"
targetDiagnostic="jakarta-jax_rs#NonPublicResourceMethod"
implementationClass="io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.jax_rs.NonPublicResourceMethodQuickFix"/>

<configSourceProvider
implementation="io.openliberty.tools.intellij.lsp4mp4ij.psi.internal.core.providers.MicroProfileConfigSourceProvider"/>

Expand Down

0 comments on commit d9364f3

Please sign in to comment.