This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-intellij-plugin.git
The following commit(s) were added to refs/heads/main by this push:
new acc0caa Struts 7 action detection + @StrutsParameter quick-fix (#110)
acc0caa is described below
commit acc0caa48b8664ef46497d28b1faa8229d87ae00
Author: Lukasz Lenart <[email protected]>
AuthorDate: Thu Jul 2 16:58:40 2026 +0200
Struts 7 action detection + @StrutsParameter quick-fix (#110)
* fix(inspection): detect Struts 7 actions via modern Action interface
Recognize actions implementing org.apache.struts2.action.Action (Struts 7+)
in addition to the legacy com.opensymphony.xwork2.Action, and check the
action interface independently of the Convention plugin. Only the *Action
naming convention remains gated behind Convention plugin presence.
This lets the @StrutsParameter inspection cover convention/interface-based
actions on Struts 7, where the legacy XWork Action interface no longer
exists.
Co-authored-by: Cursor <[email protected]>
* feat(inspection): add "Annotate with @StrutsParameter" quick-fix
Offer a one-click fix on the missing-annotation warning that inserts
@StrutsParameter on the flagged field or setter and shortens the import.
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
---
CHANGELOG.md | 2 +
.../java/com/intellij/struts2/StrutsConstants.java | 6 ++
.../struts2/inspection/StrutsActionClassUtil.java | 16 +++--
.../StrutsParameterAnnotationInspection.java | 33 ++++++++-
.../resources/messages/Struts2Bundle.properties | 1 +
.../StrutsParameterAnnotationInspectionTest.java | 80 ++++++++++++++++++++++
6 files changed, 131 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a1a56b..99ae7c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
### Added
- Add Java inspection for Struts action setters and public fields missing
`@StrutsParameter` when annotation-based parameter binding is required
+- Add "Annotate with `@StrutsParameter`" quick-fix for the missing-annotation
inspection
- Diagram tab auto-refreshes when `struts.xml` is edited (same file, active
tab) and on tab activation after Text edits
([#97](https://github.com/apache/struts-intellij-plugin/issues/97))
### Removed
@@ -15,6 +16,7 @@
### Fixed
+- Recognize Struts 7 actions implementing `org.apache.struts2.action.Action`
(and detect the action interface independently of the Convention plugin) so the
`@StrutsParameter` inspection also covers convention/interface-based actions
- Update Struts 7.2.1 metadata support: add current constants and completion
values for annotation-required parameters, chaining annotation checks,
`html5`/`css_xhtml` themes, `jakarta-stream` multipart parsing, and modern
web.xml Struts filters
- Fix false "Cannot resolve symbol" errors for namespace-relative JSP result
paths (e.g. `WEB-INF/upload.jsp` without leading slash)
- Fix path completion inside `<result>` tags by restoring correct
`FileReferenceSet` construction for IntelliJ 2026.1
diff --git a/src/main/java/com/intellij/struts2/StrutsConstants.java
b/src/main/java/com/intellij/struts2/StrutsConstants.java
index 26903c9..cb0c81d 100644
--- a/src/main/java/com/intellij/struts2/StrutsConstants.java
+++ b/src/main/java/com/intellij/struts2/StrutsConstants.java
@@ -40,6 +40,12 @@ public final class StrutsConstants {
@NonNls
public static final String XWORK_ACTION_CLASS =
"com.opensymphony.xwork2.Action";
+ /**
+ * Modern Struts action interface (Struts 7+), replacing the legacy {@link
#XWORK_ACTION_CLASS}.
+ */
+ @NonNls
+ public static final String STRUTS_ACTION_CLASS =
"org.apache.struts2.action.Action";
+
@NonNls
public static final String STRUTS_PARAMETER_ANNOTATION =
"org.apache.struts2.interceptor.parameter.StrutsParameter";
diff --git
a/src/main/java/com/intellij/struts2/inspection/StrutsActionClassUtil.java
b/src/main/java/com/intellij/struts2/inspection/StrutsActionClassUtil.java
index 2f2b2f2..3e1d46f 100644
--- a/src/main/java/com/intellij/struts2/inspection/StrutsActionClassUtil.java
+++ b/src/main/java/com/intellij/struts2/inspection/StrutsActionClassUtil.java
@@ -55,16 +55,20 @@ final class StrutsActionClassUtil {
return true;
}
- if (!isConventionPluginPresent(psiClass)) {
- return false;
+ // Implementing the Struts action interface marks it as an action,
regardless of the Convention plugin.
+ // Struts 7+ uses org.apache.struts2.action.Action; earlier versions use
com.opensymphony.xwork2.Action.
+ if (InheritanceUtil.isInheritor(psiClass,
StrutsConstants.STRUTS_ACTION_CLASS) ||
+ InheritanceUtil.isInheritor(psiClass,
StrutsConstants.XWORK_ACTION_CLASS)) {
+ return true;
}
- final String className = psiClass.getName();
- if (className != null && StringUtil.endsWith(className, "Action")) {
- return true;
+ // The *Action naming convention only applies when the Convention plugin
is present.
+ if (isConventionPluginPresent(psiClass)) {
+ final String className = psiClass.getName();
+ return className != null && StringUtil.endsWith(className, "Action");
}
- return InheritanceUtil.isInheritor(psiClass,
StrutsConstants.XWORK_ACTION_CLASS);
+ return false;
}
private static boolean isConcretePublicClass(@Nullable PsiClass psiClass) {
diff --git
a/src/main/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspection.java
b/src/main/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspection.java
index 7a113b5..010cd35 100644
---
a/src/main/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspection.java
+++
b/src/main/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspection.java
@@ -15,15 +15,24 @@
package com.intellij.struts2.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaElementVisitor;
+import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiIdentifier;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiModifierListOwner;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.StrutsConstants;
import com.intellij.struts2.facet.StrutsFacet;
import org.jetbrains.annotations.NotNull;
@@ -66,8 +75,30 @@ public final class StrutsParameterAnnotationInspection
extends LocalInspectionTo
}
holder.registerProblem(identifier,
-
StrutsBundle.message("inspections.struts.parameter.annotation.message"));
+
StrutsBundle.message("inspections.struts.parameter.annotation.message"),
+ new AddStrutsParameterAnnotationFix());
}
};
}
+
+ private static final class AddStrutsParameterAnnotationFix implements
LocalQuickFix {
+ @Override
+ public @NotNull String getFamilyName() {
+ return
StrutsBundle.message("inspections.struts.parameter.annotation.fix");
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor
descriptor) {
+ final PsiModifierListOwner owner =
+ PsiTreeUtil.getParentOfType(descriptor.getPsiElement(),
PsiModifierListOwner.class);
+ final PsiModifierList modifierList = owner != null ?
owner.getModifierList() : null;
+ if (modifierList == null ||
+
modifierList.hasAnnotation(StrutsConstants.STRUTS_PARAMETER_ANNOTATION)) {
+ return;
+ }
+
+ final PsiAnnotation annotation =
modifierList.addAnnotation(StrutsConstants.STRUTS_PARAMETER_ANNOTATION);
+
JavaCodeStyleManager.getInstance(project).shortenClassReferences(annotation);
+ }
+ }
}
diff --git a/src/main/resources/messages/Struts2Bundle.properties
b/src/main/resources/messages/Struts2Bundle.properties
index b9064e7..39b3afd 100644
--- a/src/main/resources/messages/Struts2Bundle.properties
+++ b/src/main/resources/messages/Struts2Bundle.properties
@@ -66,6 +66,7 @@ inspections.hardcoded.action.url.display.name=Hardcoded
action URL
inspections.struts.parameter.annotation.display.name=Missing StrutsParameter
annotation
inspections.struts.parameter.annotation.message=Parameter injection requires
@StrutsParameter when struts.parameters.requireAnnotations is enabled
+inspections.struts.parameter.annotation.fix=Annotate with @StrutsParameter
intentions.family.name=Struts 2
diff --git
a/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
b/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
index ff6f0c5..401bb1b 100644
---
a/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
+++
b/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
@@ -14,6 +14,7 @@
*/
package com.intellij.struts2.inspection;
+import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.psi.PsiFile;
import com.intellij.struts2.BasicLightHighlightingTestCase;
@@ -52,6 +53,32 @@ public class StrutsParameterAnnotationInspectionTest extends
BasicLightHighlight
myFixture.checkHighlighting();
}
+ public void testWarnsInActionImplementingModernActionInterface() {
+ configureStrutsParameterAnnotation();
+ configureModernActionInterface();
+ createStrutsFileSetFromFixture("struts.xml",
"struts-require-annotations.xml");
+
+ configureFileForHighlighting("test/ModernController.java", """
+ package test;
+
+ import org.apache.struts2.action.Action;
+
+ public class ModernController implements Action {
+ public String <warning descr="%s">username</warning>;
+
+ public void <warning descr="%s">setPassword</warning>(String password)
{
+ }
+
+ @Override
+ public String execute() {
+ return SUCCESS;
+ }
+ }
+ """.formatted(WARNING, WARNING));
+
+ myFixture.checkHighlighting();
+ }
+
public void testDoesNotWarnAboutAnnotatedMembers() {
configureStrutsParameterAnnotation();
createStrutsFileSetFromFixture("struts.xml",
"struts-require-annotations.xml");
@@ -144,6 +171,47 @@ public class StrutsParameterAnnotationInspectionTest
extends BasicLightHighlight
myFixture.checkHighlighting();
}
+ public void testQuickFixAnnotatesInjectableMember() {
+ configureStrutsParameterAnnotation();
+ configureModernActionInterface();
+ createStrutsFileSetFromFixture("struts.xml",
"struts-require-annotations.xml");
+
+ myFixture.configureByText("ModernController.java", """
+ package test;
+
+ import org.apache.struts2.action.Action;
+
+ public class ModernController implements Action {
+ public String user<caret>name;
+
+ @Override
+ public String execute() {
+ return SUCCESS;
+ }
+ }
+ """);
+
+ final IntentionAction fix = myFixture.findSingleIntention("Annotate with
@StrutsParameter");
+ myFixture.launchAction(fix);
+
+ myFixture.checkResult("""
+ package test;
+
+ import org.apache.struts2.action.Action;
+ import org.apache.struts2.interceptor.parameter.StrutsParameter;
+
+ public class ModernController implements Action {
+ @StrutsParameter
+ public String username;
+
+ @Override
+ public String execute() {
+ return SUCCESS;
+ }
+ }
+ """);
+ }
+
private void configureStrutsParameterAnnotation() {
myFixture.addFileToProject("org/apache/struts2/interceptor/parameter/StrutsParameter.java",
"""
package org.apache.struts2.interceptor.parameter;
@@ -154,6 +222,18 @@ public class StrutsParameterAnnotationInspectionTest
extends BasicLightHighlight
""");
}
+ private void configureModernActionInterface() {
+ myFixture.addFileToProject("org/apache/struts2/action/Action.java", """
+ package org.apache.struts2.action;
+
+ public interface Action {
+ String SUCCESS = "success";
+
+ String execute() throws Exception;
+ }
+ """);
+ }
+
private void configureFileForHighlighting(@NotNull String path, @NotNull
String text) {
final PsiFile psiFile = myFixture.addFileToProject(path, text);
myFixture.configureFromExistingVirtualFile(psiFile.getVirtualFile());