This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch fix/struts7-action-detection
in repository https://gitbox.apache.org/repos/asf/struts-intellij-plugin.git

commit 7b26500d15307d25a0749e3111cb0ccc7b527e32
Author: Lukasz Lenart <[email protected]>
AuthorDate: Thu Jul 2 16:28:12 2026 +0200

    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]>
---
 CHANGELOG.md                                       |  1 +
 .../java/com/intellij/struts2/StrutsConstants.java |  6 ++++
 .../struts2/inspection/StrutsActionClassUtil.java  | 16 +++++----
 .../StrutsParameterAnnotationInspectionTest.java   | 38 ++++++++++++++++++++++
 4 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a1a56b..773449d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,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/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
 
b/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
index ff6f0c5..dd5d9fb 100644
--- 
a/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
+++ 
b/src/test/java/com/intellij/struts2/inspection/StrutsParameterAnnotationInspectionTest.java
@@ -52,6 +52,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");
@@ -154,6 +180,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());

Reply via email to