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 655260c  Add Struts 7.2.1 metadata support (#108)
655260c is described below

commit 655260c8aebdb2203501e4343829399acc678a63
Author: Lukasz Lenart <[email protected]>
AuthorDate: Thu Jul 2 13:07:53 2026 +0200

    Add Struts 7.2.1 metadata support (#108)
    
    * docs: add Struts 7.2.1 support design
    
    Capture the focused metadata compatibility scope for Struts 7.2.1
    before implementation planning.
    
    Co-authored-by: Cursor <[email protected]>
    
    * docs: add Struts 7.2.1 support implementation plan
    
    Break the approved metadata compatibility design into concrete TDD
    implementation tasks.
    
    Co-authored-by: Cursor <[email protected]>
    
    * test: cover Struts 7.2.1 constant metadata completions
    
    Co-authored-by: Cursor <[email protected]>
    
    * test: use subset assertion for Struts 7.2.1 constants
    
    Co-authored-by: Cursor <[email protected]>
    
    * feat: update Struts 7.2.1 constant metadata
    
    Add annotation-required parameter constants, jakarta-stream multipart
    parser, html5/css_xhtml theme values, and strikeout for deprecated ajax
    theme in constant completion.
    
    Co-authored-by: Cursor <[email protected]>
    
    * feat: update Struts theme completion variants
    
    Add css_xhtml and html5 themes and mark ajax as deprecated in JSP tag
    theme completion.
    
    Co-authored-by: Cursor <[email protected]>
    
    * feat: detect modern Struts filter class in web.xml
    
    Recognize org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
    for web.xml constant completion alongside legacy filter classes.
    
    Co-authored-by: Cursor <[email protected]>
    
    * docs: add changelog entry for Struts 7.2.1 metadata support
    
    Co-authored-by: Cursor <[email protected]>
    
    ---------
    
    Co-authored-by: Cursor <[email protected]>
---
 CHANGELOG.md                                       |   1 +
 .../plans/2026-07-02-struts-7-2-1-support.md       | 736 +++++++++++++++++++++
 .../2026-07-02-struts-7-2-1-support-design.md      | 140 ++++
 .../model/constant/StrutsConstantManagerImpl.java  |   3 +-
 .../contributor/StringValuesConverter.java         |  15 +
 .../contributor/StrutsConstantContributorBase.java |   7 +
 .../contributor/StrutsCoreConstantContributor.java |  11 +-
 .../reference/StrutsReferenceContributor.java      |   3 +-
 .../reference/jsp/ThemeReferenceProvider.java      |   8 +-
 .../struts2/dom/struts/StrutsCompletionTest.java   |  20 +
 .../contributor/StringValuesConverterTest.java     |  49 ++
 .../reference/jsp/ThemeReferenceProviderTest.java  |  47 ++
 .../struts2/reference/web/WebXmlConstantTest.java  |  14 +
 .../WEB-INF/web_name_completion_modern_filter.xml  |  37 ++
 .../WEB-INF/web_value_completion_modern_filter.xml |  37 ++
 .../filter/StrutsPrepareAndExecuteFilter.java      |  26 +
 ...uts-completionvariants-constant_theme_value.xml |  29 +
 ...s-completionvariants-multipart_parser_value.xml |  29 +
 18 files changed, 1206 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 416376d..9b7270a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@
 
 ### Fixed
 
+- 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
 - Assume default `dispatcher` result type when a package does not declare 
result types (typical `extends="struts-default"` setups)
diff --git a/docs/superpowers/plans/2026-07-02-struts-7-2-1-support.md 
b/docs/superpowers/plans/2026-07-02-struts-7-2-1-support.md
new file mode 100644
index 0000000..3708720
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-02-struts-7-2-1-support.md
@@ -0,0 +1,736 @@
+# Struts 7.2.1 Metadata Compatibility Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use 
superpowers:subagent-driven-development (recommended) or 
superpowers:executing-plans to implement this plan task-by-task. Steps use 
checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Update static Struts metadata so Struts 7.2.1 projects get current 
completion values and modern web.xml filter support.
+
+**Architecture:** Keep the change local to existing metadata providers and 
web.xml filter predicates. Extend the string-value converter to support 
deprecated completion presentation, then reuse it for `struts.ui.theme`; update 
JSP tag theme completion independently with the same visible values. Tests stay 
focused on completion variants, deprecated lookup presentation, and web.xml 
filter matching.
+
+**Tech Stack:** Java, IntelliJ Platform PSI/completion APIs, IntelliJ light 
fixture tests, Gradle test tasks.
+
+---
+
+## File Structure
+
+- Modify 
`src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java`
 to support deprecated lookup presentation for selected values.
+- Modify 
`src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java`
 to add a helper for string-valued constants with deprecated values.
+- Modify 
`src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java`
 to add Struts 7.2.1 constants and updated value variants.
+- Modify 
`src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java` 
to add `css_xhtml`, `html5`, and deprecated `ajax` tag theme completion.
+- Modify 
`src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java`
 to include `STRUTS_2_5_FILTER_CLASS` in web.xml filter detection.
+- Modify 
`src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java` 
to register web.xml param references for `STRUTS_2_5_FILTER_CLASS`.
+- Modify 
`src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java` to 
cover new constant names and value variants.
+- Create 
`src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java`
 to verify deprecated lookup presentation.
+- Modify 
`src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java` and 
add test fixtures for modern filter completion.
+- Add test data under `src/test/testData/strutsXml/completion/` and 
`src/test/testData/reference/web/constant/WEB-INF/`.
+
+---
+
+### Task 1: Add Completion Tests For Struts 7.2.1 Constant Metadata
+
+**Files:**
+- Modify: 
`src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java`
+- Create: 
`src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml`
+- Create: 
`src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml`
+
+- [ ] **Step 1: Add constant value completion fixtures**
+
+Create 
`src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml`:
+
+```xml
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd";>
+
+<struts>
+  <constant name="struts.ui.theme" value="<caret>"/>
+</struts>
+```
+
+Create 
`src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml`:
+
+```xml
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd";>
+
+<struts>
+  <constant name="struts.multipart.parser" value="<caret>"/>
+</struts>
+```
+
+- [ ] **Step 2: Add failing completion tests**
+
+In `StrutsCompletionTest`, add these methods after 
`testCompletionVariantsConstantName()`:
+
+```java
+  public void testCompletionVariantsStruts721ConstantNames() {
+    performCompletionVariantTest("struts-completionvariants-constant_name.xml",
+                                 "struts.parameters.requireAnnotations",
+                                 
"struts.parameters.requireAnnotations.transitionMode",
+                                 "struts.chaining.requireAnnotations");
+  }
+
+  public void testCompletionVariantsThemeConstantValue() {
+    
performCompletionVariantTest("struts-completionvariants-constant_theme_value.xml",
+                                 "ajax", "css_xhtml", "html5", "simple", 
"xhtml");
+  }
+
+  public void testCompletionVariantsMultipartParserConstantValue() {
+    
performCompletionVariantTest("struts-completionvariants-multipart_parser_value.xml",
+                                 "cos", "jakarta", "jakarta-stream", "pell");
+  }
+```
+
+- [ ] **Step 3: Run tests and verify failure**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "StrutsCompletionTest" --no-configuration-cache
+```
+
+Expected: `testCompletionVariantsStruts721ConstantNames`, 
`testCompletionVariantsThemeConstantValue`, and 
`testCompletionVariantsMultipartParserConstantValue` fail because the new 
constants/values are not yet present.
+
+- [ ] **Step 4: Commit failing tests**
+
+```bash
+git add 
src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java \
+  
src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml
 \
+  
src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml
+git commit -m "$(cat <<'EOF'
+test: cover Struts 7.2.1 constant metadata completions
+
+EOF
+)"
+```
+
+---
+
+### Task 2: Implement Struts 7.2.1 Constant Metadata
+
+**Files:**
+- Modify: 
`src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java`
+- Modify: 
`src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java`
+- Modify: 
`src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java`
+- Create: 
`src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java`
+
+- [ ] **Step 1: Add deprecated lookup presentation test**
+
+Create 
`src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java`:
+
+```java
+/*
+ * Copyright 2026 The authors
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.struts2.model.constant.contributor;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import junit.framework.TestCase;
+
+import java.util.Collections;
+
+public class StringValuesConverterTest extends TestCase {
+  public void testDeprecatedValueUsesStrikeoutLookupPresentation() {
+    StringValuesConverter converter = new StringValuesConverter(
+      new String[]{"ajax", "html5"},
+      Collections.singleton("ajax")
+    );
+
+    LookupElement lookupElement = converter.createLookupElement("ajax");
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    lookupElement.renderElement(presentation);
+
+    assertTrue(presentation.isStrikeout());
+  }
+
+  public void testRegularValueDoesNotUseStrikeoutLookupPresentation() {
+    StringValuesConverter converter = new StringValuesConverter(
+      new String[]{"ajax", "html5"},
+      Collections.singleton("ajax")
+    );
+
+    LookupElement lookupElement = converter.createLookupElement("html5");
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    lookupElement.renderElement(presentation);
+
+    assertFalse(presentation.isStrikeout());
+  }
+}
+```
+
+- [ ] **Step 2: Run test and verify failure**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "StringValuesConverterTest" 
--no-configuration-cache
+```
+
+Expected: compilation fails because `StringValuesConverter(String[], 
Collection<String>)` does not exist.
+
+- [ ] **Step 3: Implement deprecated string value support**
+
+Update `StringValuesConverter.java` to this full content:
+
+```java
+/*
+ * Copyright 2009 The authors
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.struts2.model.constant.contributor;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xml.ConvertContext;
+import com.intellij.util.xml.ResolvingConverter;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Resolves to list of given Strings.
+ */
+class StringValuesConverter extends ResolvingConverter.StringConverter {
+
+  private final String[] values;
+  private final Set<String> deprecatedValues;
+
+  StringValuesConverter(@NonNls final String... values) {
+    this(values, Set.of());
+  }
+
+  StringValuesConverter(@NonNls final String[] values, @NotNull final 
Collection<String> deprecatedValues) {
+    Arrays.sort(values);
+    this.values = values;
+    this.deprecatedValues = ContainerUtil.newHashSet(deprecatedValues);
+  }
+
+  @Override
+  public String fromString(final String s, final ConvertContext context) {
+    return Arrays.binarySearch(values, s) > -1 ? s : null;
+  }
+
+  @Override
+  public @NotNull LookupElement createLookupElement(String s) {
+    return 
LookupElementBuilder.create(s).withStrikeoutness(deprecatedValues.contains(s));
+  }
+
+  @Override
+  @NotNull
+  public Collection<String> getVariants(final ConvertContext context) {
+    return Arrays.asList(values);
+  }
+
+}
+```
+
+- [ ] **Step 4: Add base helper for deprecated string values**
+
+In `StrutsConstantContributorBase.java`, add `import java.util.Arrays;`.
+
+Then add this helper after `addStringValuesProperty(...)`:
+
+```java
+  protected static StrutsConstant 
addStringValuesPropertyWithDeprecatedValues(@NonNls final String propertyName,
+                                                                             
@NonNls final String[] values,
+                                                                             
@NonNls final String... deprecatedValues) {
+    return new StrutsConstant(propertyName, new StringValuesConverter(values, 
Arrays.asList(deprecatedValues)));
+  }
+```
+
+- [ ] **Step 5: Update core metadata**
+
+In `StrutsCoreConstantContributor.java`, replace:
+
+```java
+      addStringValuesProperty("struts.multipart.parser", "cos", "pell", 
"jakarta"),
+```
+
+with:
+
+```java
+      addStringValuesProperty("struts.multipart.parser", "cos", "pell", 
"jakarta", "jakarta-stream"),
+```
+
+Replace:
+
+```java
+      addStringValuesProperty("struts.ui.theme", "simple", "xhtml", "ajax"),
+```
+
+with:
+
+```java
+      addStringValuesPropertyWithDeprecatedValues("struts.ui.theme",
+                                                 new String[]{"simple", 
"xhtml", "css_xhtml", "html5", "ajax"},
+                                                 "ajax"),
+```
+
+Replace the final constant:
+
+```java
+      addBooleanProperty("struts.ognl.allowStaticMethodAccess")
+```
+
+with:
+
+```java
+      addBooleanProperty("struts.ognl.allowStaticMethodAccess"),
+      addBooleanProperty("struts.parameters.requireAnnotations"),
+      
addBooleanProperty("struts.parameters.requireAnnotations.transitionMode"),
+      addBooleanProperty("struts.chaining.requireAnnotations")
+```
+
+- [ ] **Step 6: Run constant tests**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "StringValuesConverterTest" --tests 
"StrutsCompletionTest" --no-configuration-cache
+```
+
+Expected: all tests in `StringValuesConverterTest` pass, and the new 
`StrutsCompletionTest` methods pass.
+
+- [ ] **Step 7: Commit constant metadata implementation**
+
+```bash
+git add 
src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
 \
+  
src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
 \
+  
src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
 \
+  
src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java
+git commit -m "$(cat <<'EOF'
+feat: update Struts 7.2.1 constant metadata
+
+EOF
+)"
+```
+
+---
+
+### Task 3: Update Tag Theme Completion
+
+**Files:**
+- Modify: 
`src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java`
+- Create: 
`src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java`
+
+- [ ] **Step 1: Add direct provider test for tag theme lookup values**
+
+Create 
`src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java`:
+
+```java
+/*
+ * Copyright 2026 The authors
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.struts2.reference.jsp;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ThemeReferenceProviderTest extends TestCase {
+  public void testDefaultThemeVariantsIncludeCurrentAndLegacyThemes() {
+    Object[] variants = ThemeReferenceProvider.getDefaultThemes();
+    Set<String> lookupStrings = Arrays.stream(variants)
+      .map(variant -> ((LookupElement) variant).getLookupString())
+      .collect(Collectors.toSet());
+
+    assertEquals(Set.of("simple", "xhtml", "css_xhtml", "html5", "ajax"), 
lookupStrings);
+  }
+
+  public void testAjaxThemeVariantIsDeprecated() {
+    LookupElement ajax = 
Arrays.stream(ThemeReferenceProvider.getDefaultThemes())
+      .map(variant -> (LookupElement) variant)
+      .filter(variant -> "ajax".equals(variant.getLookupString()))
+      .findFirst()
+      .orElseThrow();
+
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    ajax.renderElement(presentation);
+
+    assertTrue(presentation.isStrikeout());
+  }
+}
+```
+
+- [ ] **Step 2: Run provider test and verify failure**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "ThemeReferenceProviderTest" 
--no-configuration-cache
+```
+
+Expected: compilation fails because 
`ThemeReferenceProvider.getDefaultThemes()` does not exist.
+
+- [ ] **Step 3: Implement tag theme variants**
+
+In `ThemeReferenceProvider.java`, replace the existing `DEFAULT_THEMES` block 
with:
+
+```java
+  private static final Object[] DEFAULT_THEMES = new Object[]{
+    LookupElementBuilder.create("simple").withIcon(StrutsIcons.THEME),
+    LookupElementBuilder.create("xhtml").withIcon(StrutsIcons.THEME),
+    LookupElementBuilder.create("css_xhtml").withIcon(StrutsIcons.THEME),
+    LookupElementBuilder.create("html5").withIcon(StrutsIcons.THEME),
+    
LookupElementBuilder.create("ajax").withIcon(StrutsIcons.THEME).withStrikeoutness(true)
+  };
+
+  static Object[] getDefaultThemes() {
+    return DEFAULT_THEMES;
+  }
+```
+
+- [ ] **Step 4: Run tag theme tests**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "ThemeReferenceProviderTest" 
--no-configuration-cache
+```
+
+Expected: `ThemeReferenceProviderTest` passes.
+
+- [ ] **Step 5: Commit tag theme completion implementation**
+
+```bash
+git add 
src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java \
+  
src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java
+git commit -m "$(cat <<'EOF'
+feat: update Struts theme completion variants
+
+EOF
+)"
+```
+
+---
+
+### Task 4: Add Modern Struts Filter Detection For web.xml Constants
+
+**Files:**
+- Modify: 
`src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java`
+- Modify: 
`src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java`
+- Modify: 
`src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java`
+- Create: 
`src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml`
+- Create: 
`src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml`
+
+- [ ] **Step 1: Add web.xml fixtures for modern filter class**
+
+Create 
`src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml`:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";>
+
+  <filter>
+    <filter-name>struts2</filter-name>
+    
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
+
+    <init-param>
+      <param-name><caret></param-name>
+      <param-value></param-value>
+    </init-param>
+  </filter>
+
+</web-app>
+```
+
+Create 
`src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml`:
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";>
+
+  <filter>
+    <filter-name>struts2</filter-name>
+    
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
+
+    <init-param>
+      <param-name>struts.url.includeParams</param-name>
+      <param-value><caret></param-value>
+    </init-param>
+  </filter>
+
+</web-app>
+```
+
+- [ ] **Step 2: Add failing web.xml tests**
+
+In `WebXmlConstantTest`, add:
+
+```java
+  public void testNameCompletionWithModernFilterClass() {
+    final StrutsCoreConstantContributor coreConstantContributor = new 
StrutsCoreConstantContributor();
+    final List<StrutsConstant> constants = 
coreConstantContributor.getStrutsConstantDefinitions(getModule());
+    final String[] variants = ContainerUtil.map2Array(constants, String.class, 
strutsConstant -> strutsConstant.getName());
+    
myFixture.testCompletionVariants("/WEB-INF/web_name_completion_modern_filter.xml",
 variants);
+  }
+
+  public void testValueCompletionWithModernFilterClass() {
+    
myFixture.testCompletionVariants("/WEB-INF/web_value_completion_modern_filter.xml",
+                                     "none", "get", "all");
+  }
+```
+
+- [ ] **Step 3: Run tests and verify failure**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "WebXmlConstantTest" --no-configuration-cache
+```
+
+Expected: the new modern-filter completion tests fail because reference 
providers are not registered for `STRUTS_2_5_FILTER_CLASS`.
+
+- [ ] **Step 4: Update constant manager filter detection**
+
+In `StrutsConstantManagerImpl`, replace:
+
+```java
+    return InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS) ||
+           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS);
+```
+
+with:
+
+```java
+    return InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS) ||
+           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS) ||
+           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_5_FILTER_CLASS);
+```
+
+- [ ] **Step 5: Update web.xml reference contributor pattern**
+
+In `StrutsReferenceContributor`, replace:
+
+```java
+                                            or(psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS),
+                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS)
+                                            )
+```
+
+with:
+
+```java
+                                            or(psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS),
+                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS),
+                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_5_FILTER_CLASS)
+                                            )
+```
+
+- [ ] **Step 6: Run web.xml tests**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "WebXmlConstantTest" --no-configuration-cache
+```
+
+Expected: `WebXmlConstantTest` passes.
+
+- [ ] **Step 7: Commit web.xml filter detection implementation**
+
+```bash
+git add 
src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
 \
+  src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java 
\
+  src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java \
+  
src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml
 \
+  
src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml
+git commit -m "$(cat <<'EOF'
+fix: support modern Struts filter constants in web.xml
+
+EOF
+)"
+```
+
+---
+
+### Task 5: Final Verification And Changelog
+
+**Files:**
+- Modify: `CHANGELOG.md`
+
+- [ ] **Step 1: Add changelog entry**
+
+Under `CHANGELOG.md` → `[Unreleased]` → `### Fixed`, add:
+
+```markdown
+- 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
+```
+
+- [ ] **Step 2: Run focused verification**
+
+Run:
+
+```bash
+./gradlew test -x rat --tests "StringValuesConverterTest" --tests 
"ThemeReferenceProviderTest" --tests "StrutsCompletionTest" --tests 
"WebXmlConstantTest" --no-configuration-cache
+```
+
+Expected: all targeted tests pass.
+
+- [ ] **Step 3: Run broader test verification**
+
+Run:
+
+```bash
+./gradlew test -x rat --no-configuration-cache
+```
+
+Expected: test suite passes, excluding Apache RAT checks.
+
+- [ ] **Step 4: Check lints for edited files**
+
+Use Cursor's linter diagnostics for:
+
+```text
+src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
+src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
+src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
+src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java
+src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
+src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java
+```
+
+Expected: no new diagnostics from the implementation.
+
+- [ ] **Step 5: Commit changelog and final verification fixes**
+
+```bash
+git add CHANGELOG.md
+git commit -m "$(cat <<'EOF'
+docs: note Struts 7.2.1 metadata support
+
+EOF
+)"
+```
+
+If verification required code/test fixes, include those files in the same 
commit only when they are directly related to final cleanup.
+
diff --git a/docs/superpowers/specs/2026-07-02-struts-7-2-1-support-design.md 
b/docs/superpowers/specs/2026-07-02-struts-7-2-1-support-design.md
new file mode 100644
index 0000000..195a505
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-02-struts-7-2-1-support-design.md
@@ -0,0 +1,140 @@
+# Struts 7.2.1 Metadata Compatibility
+
+**Date:** 2026-07-02  
+**Status:** Approved for implementation planning
+
+## Problem
+
+Apache Struts 7.2.1 adds or emphasizes configuration values that the plugin 
does not currently suggest because several completion sources are maintained as 
static metadata. The plugin still works for typical Struts 7.2.1 projects that 
use the published `struts-6.0.dtd`, but completion and web.xml reference 
support lag behind current Struts metadata.
+
+The public Struts DTD catalog at <https://struts.apache.org/dtds/> does not 
publish `struts-6.5.dtd`, so this work should not add that DTD as part of 7.2.1 
support.
+
+## Goals
+
+1. Suggest Struts 7.2.1-relevant core constants in `<constant name="...">` and 
web.xml init-param contexts.
+2. Suggest current UI themes, including `html5` and `css_xhtml`.
+3. Keep the legacy `ajax` theme available for existing projects, but mark it 
as deprecated in completion.
+4. Suggest the `jakarta-stream` multipart parser value.
+5. Treat the modern Struts filter class as a Struts filter for web.xml 
constant references.
+6. Keep the implementation small, static, and easy to review for the upcoming 
plugin release.
+
+## Non-Goals
+
+- Implementing an `@StrutsParameter` inspection. That requires 
Java/property-flow analysis and should be a separate feature.
+- Adding `struts-6.5.dtd`, since it is not published in the public DTD catalog.
+- Dynamically loading all constants from the project's Struts JAR.
+- Broadly refreshing every historical Struts constant in one pass.
+
+## Decision
+
+Use a focused static metadata update.
+
+This approach keeps the release change narrow: update the existing hardcoded 
completion providers and filter detection logic instead of introducing a new 
dynamic metadata subsystem. It covers the visible Struts 7.2.1 gaps while 
avoiding a larger design for Java inspections or runtime JAR introspection.
+
+## Alternatives Considered
+
+### Minimal release hygiene
+
+Only add the three annotation-related constants and `html5` theme.
+
+Rejected because it leaves known stale completions (`css_xhtml`, 
`jakarta-stream`, and modern web.xml filter detection) that are cheap to fix in 
the same PR.
+
+### Full Struts 7.x metadata refresh
+
+Mirror a much larger set of constants from Struts 7.2.1's 
`org.apache.struts2.StrutsConstants`.
+
+Rejected for this release because it increases review noise and maintenance 
burden. A dynamic or generated metadata approach can be considered separately 
if the static list keeps drifting.
+
+## Components
+
+### `StrutsCoreConstantContributor`
+
+Update static core constant definitions:
+
+- Add boolean constants:
+  - `struts.parameters.requireAnnotations`
+  - `struts.parameters.requireAnnotations.transitionMode`
+  - `struts.chaining.requireAnnotations`
+- Update `struts.multipart.parser` values to include `jakarta-stream`.
+- Update `struts.ui.theme` values to include:
+  - `simple`
+  - `xhtml`
+  - `css_xhtml`
+  - `html5`
+  - `ajax` as deprecated
+
+If the existing helper methods cannot mark a single string value as 
deprecated, add a small local helper for lookup variants rather than changing 
unrelated contributor behavior.
+
+### `ThemeReferenceProvider`
+
+Update tag `theme` attribute completion to match the core theme list:
+
+- `simple`
+- `xhtml`
+- `css_xhtml`
+- `html5`
+- `ajax` as deprecated
+
+Use IntelliJ lookup presentation support to strike through or otherwise mark 
`ajax` deprecated while still offering it.
+
+### `StrutsConstantManagerImpl`
+
+Include `StrutsConstants.STRUTS_2_5_FILTER_CLASS` in web.xml Struts filter 
detection. This lets constants from filter init-params participate in the same 
precedence/resolution logic for modern Struts applications.
+
+### `StrutsReferenceContributor`
+
+Include `StrutsConstants.STRUTS_2_5_FILTER_CLASS` in the web.xml filter 
pattern so `<param-name>` and `<param-value>` references are registered for 
modern Struts filters.
+
+## Data Flow
+
+```text
+struts.xml <constant name="...">
+        |
+        v
+ConstantNameConverterImpl
+        |
+        v
+StrutsConstantManager.getConstants(module)
+        |
+        v
+StrutsCoreConstantContributor static metadata
+
+web.xml modern Struts filter
+        |
+        v
+filter-class matches STRUTS_2_5_FILTER_CLASS
+        |
+        v
+constant name/value reference providers register and resolve
+```
+
+## Error Handling
+
+No new runtime error handling is needed. These changes affect completion 
variants and reference registration only.
+
+If the deprecated `ajax` theme is present in existing code, it should not be 
flagged as invalid by this work. It should remain selectable/resolvable, with 
only the completion lookup indicating deprecation.
+
+## Testing
+
+Add or update focused tests:
+
+1. Constant name completion includes:
+   - `struts.parameters.requireAnnotations`
+   - `struts.parameters.requireAnnotations.transitionMode`
+   - `struts.chaining.requireAnnotations`
+2. `struts.ui.theme` value completion includes `html5`, `css_xhtml`, and 
deprecated-but-present `ajax`.
+3. `theme` tag attribute completion includes `html5`, `css_xhtml`, and 
deprecated-but-present `ajax`.
+4. `struts.multipart.parser` value completion includes `jakarta-stream`.
+5. web.xml reference tests cover 
`org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter`.
+
+Run targeted tests first, then the broader suite before completion:
+
+```bash
+./gradlew test -x rat --tests "StrutsCompletionTest"
+./gradlew test -x rat --tests "WebXmlConstantTest"
+./gradlew test -x rat
+```
+
+## Follow-Up
+
+Create a separate design for `@StrutsParameter` awareness. Struts 7.2.1 relies 
heavily on `struts.parameters.requireAnnotations=true`, but a useful inspection 
needs to understand action classes, setters/fields, OGNL/property paths, and 
configuration constants. That scope is larger than this metadata compatibility 
update.
diff --git 
a/src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
 
b/src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
index d01042b..7ad7690 100644
--- 
a/src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
+++ 
b/src/main/java/com/intellij/struts2/model/constant/StrutsConstantManagerImpl.java
@@ -69,7 +69,8 @@ public class StrutsConstantManagerImpl extends 
StrutsConstantManager {
   private static final Condition<Filter> WEB_XML_STRUTS_FILTER_CONDITION = 
filter -> {
     final PsiClass filterClass = filter.getFilterClass().getValue();
     return InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS) ||
-           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS);
+           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS) ||
+           InheritanceUtil.isInheritor(filterClass, 
StrutsConstants.STRUTS_2_5_FILTER_CLASS);
   };
 
 
diff --git 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
index 6f39642..e87a73e 100644
--- 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
+++ 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StringValuesConverter.java
@@ -15,6 +15,8 @@
 
 package com.intellij.struts2.model.constant.contributor;
 
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
 import com.intellij.util.xml.ConvertContext;
 import com.intellij.util.xml.ResolvingConverter;
 import org.jetbrains.annotations.NonNls;
@@ -22,6 +24,8 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Resolves to list of given Strings.
@@ -29,10 +33,16 @@ import java.util.Collection;
 class StringValuesConverter extends ResolvingConverter.StringConverter {
 
   private final String[] values;
+  private final Set<String> deprecatedValues;
 
   StringValuesConverter(@NonNls final String... values) {
+    this(values, Set.of());
+  }
+
+  StringValuesConverter(@NonNls final String[] values, @NotNull final 
Collection<String> deprecatedValues) {
     Arrays.sort(values);
     this.values = values;
+    this.deprecatedValues = new HashSet<>(deprecatedValues);
   }
 
   @Override
@@ -40,6 +50,11 @@ class StringValuesConverter extends 
ResolvingConverter.StringConverter {
     return Arrays.binarySearch(values, s) > -1 ? s : null;
   }
 
+  @Override
+  public @NotNull LookupElement createLookupElement(String s) {
+    return 
LookupElementBuilder.create(s).withStrikeoutness(deprecatedValues.contains(s));
+  }
+
   @Override
   @NotNull
   public Collection<String> getVariants(final ConvertContext context) {
diff --git 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
index 5dd5bc1..10f317e 100644
--- 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
+++ 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsConstantContributorBase.java
@@ -27,6 +27,7 @@ import 
com.intellij.util.xml.converters.values.NumberValueConverter;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -72,6 +73,12 @@ public abstract class StrutsConstantContributorBase 
implements StrutsConstantCon
     return new StrutsConstant(propertyName, new StringValuesConverter(values));
   }
 
+  protected static StrutsConstant 
addStringValuesPropertyWithDeprecatedValues(@NonNls final String propertyName,
+                                                                             
@NonNls final String[] values,
+                                                                             
@NonNls final String... deprecatedValues) {
+    return new StrutsConstant(propertyName, new StringValuesConverter(values, 
Arrays.asList(deprecatedValues)));
+  }
+
   protected static StrutsConstant addDelimitedStringValuesProperty(@NonNls 
final String propertyName) {
     return new StrutsConstant(propertyName, new 
DelimitedStringValuesConverter());
   }
diff --git 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
index bf0a370..5b5b8e2 100644
--- 
a/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
+++ 
b/src/main/java/com/intellij/struts2/model/constant/contributor/StrutsCoreConstantContributor.java
@@ -64,7 +64,7 @@ public final class StrutsCoreConstantContributor extends 
StrutsConstantContribut
                                    Pair.create("struts",
                                                
"com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer")),
 
-      addStringValuesProperty("struts.multipart.parser", "cos", "pell", 
"jakarta"),
+      addStringValuesProperty("struts.multipart.parser", "cos", "pell", 
"jakarta", "jakarta-stream"),
       addStringProperty("struts.multipart.saveDir"),
       addIntegerProperty("struts.multipart.maxSize"),
       addStringProperty("struts.custom.properties"),
@@ -77,7 +77,9 @@ public final class StrutsCoreConstantContributor extends 
StrutsConstantContribut
       addBooleanProperty("struts.tag.altSyntax"),
       addBooleanProperty("struts.devMode"),
       addBooleanProperty("struts.i18n.reload"),
-      addStringValuesProperty("struts.ui.theme", "simple", "xhtml", "ajax"),
+      addStringValuesPropertyWithDeprecatedValues("struts.ui.theme",
+                                                 new String[]{"simple", 
"xhtml", "css_xhtml", "html5", "ajax"},
+                                                 "ajax"),
       addStringProperty("struts.ui.templateDir"),
       addStringValuesProperty("struts.ui.templateSuffix", "ftl", "vm", "jsp", 
"java"),
       addBooleanProperty("struts.configuration.xml.reload"),
@@ -98,7 +100,10 @@ public final class StrutsCoreConstantContributor extends 
StrutsConstantContribut
       addBooleanProperty("struts.mapper.alwaysSelectFullNamespace"),
       addClassWithShortcutProperty("struts.unknownHandlerManager",
                                    
"com.opensymphony.xwork2.UnknownHandlerManager"),
-      addBooleanProperty("struts.ognl.allowStaticMethodAccess")
+      addBooleanProperty("struts.ognl.allowStaticMethodAccess"),
+      addBooleanProperty("struts.parameters.requireAnnotations"),
+      
addBooleanProperty("struts.parameters.requireAnnotations.transitionMode"),
+      addBooleanProperty("struts.chaining.requireAnnotations")
   );
 
   @NotNull
diff --git 
a/src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java 
b/src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java
index c8bd417..8c01942 100644
--- 
a/src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java
+++ 
b/src/main/java/com/intellij/struts2/reference/StrutsReferenceContributor.java
@@ -51,7 +51,8 @@ public class StrutsReferenceContributor extends 
PsiReferenceContributor {
                    withParent(domElement(Filter.class).
                                 withChild("filter-class", 
genericDomValue().withValue(
                                             or(psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_0_FILTER_CLASS),
-                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS)
+                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_1_FILTER_CLASS),
+                                               psiClass().inheritorOf(false, 
StrutsConstants.STRUTS_2_5_FILTER_CLASS)
                                             )
                                           )
                                 )
diff --git 
a/src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java 
b/src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java
index 64d453d..edd510f 100644
--- 
a/src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java
+++ 
b/src/main/java/com/intellij/struts2/reference/jsp/ThemeReferenceProvider.java
@@ -39,9 +39,15 @@ public class ThemeReferenceProvider extends 
PsiReferenceProvider {
   private static final Object[] DEFAULT_THEMES = new Object[]{
     LookupElementBuilder.create("simple").withIcon(StrutsIcons.THEME),
     LookupElementBuilder.create("xhtml").withIcon(StrutsIcons.THEME),
-    LookupElementBuilder.create("ajax").withIcon(StrutsIcons.THEME)
+    LookupElementBuilder.create("css_xhtml").withIcon(StrutsIcons.THEME),
+    LookupElementBuilder.create("html5").withIcon(StrutsIcons.THEME),
+    
LookupElementBuilder.create("ajax").withIcon(StrutsIcons.THEME).withStrikeoutness(true)
   };
 
+  static Object[] getDefaultThemes() {
+    return DEFAULT_THEMES;
+  }
+
   @Override
   public PsiReference @NotNull [] getReferencesByElement(@NotNull final 
PsiElement element, @NotNull final ProcessingContext context) {
     return new PsiReference[]{new 
PsiReferenceBase<>((XmlAttributeValue)element) {
diff --git 
a/src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java 
b/src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java
index 84ae03b..10fb76e 100644
--- a/src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java
+++ b/src/test/java/com/intellij/struts2/dom/struts/StrutsCompletionTest.java
@@ -91,4 +91,24 @@ public class StrutsCompletionTest extends 
StrutsLightHighlightingTestCase {
 
     
performCompletionVariantTest("struts-completionvariants-constant_name.xml", 
variants);
   }
+
+  public void testCompletionVariantsStruts721ConstantNames() {
+    createStrutsFileSet("struts-completionvariants-constant_name.xml");
+    myFixture.configureByFile("struts-completionvariants-constant_name.xml");
+    myFixture.completeBasic();
+    assertContainsElements(myFixture.getLookupElementStrings(),
+                           "struts.parameters.requireAnnotations",
+                           
"struts.parameters.requireAnnotations.transitionMode",
+                           "struts.chaining.requireAnnotations");
+  }
+
+  public void testCompletionVariantsThemeConstantValue() {
+    
performCompletionVariantTest("struts-completionvariants-constant_theme_value.xml",
+                                 "ajax", "css_xhtml", "html5", "simple", 
"xhtml");
+  }
+
+  public void testCompletionVariantsMultipartParserConstantValue() {
+    
performCompletionVariantTest("struts-completionvariants-multipart_parser_value.xml",
+                                 "cos", "jakarta", "jakarta-stream", "pell");
+  }
 }
\ No newline at end of file
diff --git 
a/src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java
 
b/src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java
new file mode 100644
index 0000000..e89d4a2
--- /dev/null
+++ 
b/src/test/java/com/intellij/struts2/model/constant/contributor/StringValuesConverterTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2026 The authors
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.struts2.model.constant.contributor;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import junit.framework.TestCase;
+
+import java.util.Collections;
+
+public class StringValuesConverterTest extends TestCase {
+  public void testDeprecatedValueUsesStrikeoutLookupPresentation() {
+    StringValuesConverter converter = new StringValuesConverter(
+      new String[]{"ajax", "html5"},
+      Collections.singleton("ajax")
+    );
+
+    LookupElement lookupElement = converter.createLookupElement("ajax");
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    lookupElement.renderElement(presentation);
+
+    assertTrue(presentation.isStrikeout());
+  }
+
+  public void testRegularValueDoesNotUseStrikeoutLookupPresentation() {
+    StringValuesConverter converter = new StringValuesConverter(
+      new String[]{"ajax", "html5"},
+      Collections.singleton("ajax")
+    );
+
+    LookupElement lookupElement = converter.createLookupElement("html5");
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    lookupElement.renderElement(presentation);
+
+    assertFalse(presentation.isStrikeout());
+  }
+}
diff --git 
a/src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java
 
b/src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java
new file mode 100644
index 0000000..50f0182
--- /dev/null
+++ 
b/src/test/java/com/intellij/struts2/reference/jsp/ThemeReferenceProviderTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2026 The authors
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.struts2.reference.jsp;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ThemeReferenceProviderTest extends TestCase {
+  public void testDefaultThemeVariantsIncludeCurrentAndLegacyThemes() {
+    Object[] variants = ThemeReferenceProvider.getDefaultThemes();
+    Set<String> lookupStrings = Arrays.stream(variants)
+      .map(variant -> ((LookupElement) variant).getLookupString())
+      .collect(Collectors.toSet());
+
+    assertEquals(Set.of("simple", "xhtml", "css_xhtml", "html5", "ajax"), 
lookupStrings);
+  }
+
+  public void testAjaxThemeVariantIsDeprecated() {
+    LookupElement ajax = 
Arrays.stream(ThemeReferenceProvider.getDefaultThemes())
+      .map(variant -> (LookupElement) variant)
+      .filter(variant -> "ajax".equals(variant.getLookupString()))
+      .findFirst()
+      .orElseThrow();
+
+    LookupElementPresentation presentation = new LookupElementPresentation();
+    ajax.renderElement(presentation);
+
+    assertTrue(presentation.isStrikeout());
+  }
+}
diff --git 
a/src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java 
b/src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java
index 5206b0f..cf198fb 100644
--- a/src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java
+++ b/src/test/java/com/intellij/struts2/reference/web/WebXmlConstantTest.java
@@ -83,4 +83,18 @@ public class WebXmlConstantTest extends 
BasicLightHighlightingTestCase {
                                      "spring",
                                      "struts");
   }
+
+  public void testNameCompletionWithModernFilterClass() {
+    
myFixture.copyFileToProject("org/apache/struts2/dispatcher/filter/StrutsPrepareAndExecuteFilter.java");
+    final StrutsCoreConstantContributor coreConstantContributor = new 
StrutsCoreConstantContributor();
+    final List<StrutsConstant> constants = 
coreConstantContributor.getStrutsConstantDefinitions(getModule());
+    final String[] variants = ContainerUtil.map2Array(constants, String.class, 
strutsConstant -> strutsConstant.getName());
+    
myFixture.testCompletionVariants("/WEB-INF/web_name_completion_modern_filter.xml",
 variants);
+  }
+
+  public void testValueCompletionWithModernFilterClass() {
+    
myFixture.copyFileToProject("org/apache/struts2/dispatcher/filter/StrutsPrepareAndExecuteFilter.java");
+    
myFixture.testCompletionVariants("/WEB-INF/web_value_completion_modern_filter.xml",
+                                     "none", "get", "all");
+  }
 }
diff --git 
a/src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml
 
b/src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml
new file mode 100644
index 0000000..5de31bb
--- /dev/null
+++ 
b/src/test/testData/reference/web/constant/WEB-INF/web_name_completion_modern_filter.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";>
+
+  <filter>
+    <filter-name>struts2</filter-name>
+    
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
+
+    <init-param>
+      <param-name><caret></param-name>
+      <param-value></param-value>
+    </init-param>
+  </filter>
+
+</web-app>
diff --git 
a/src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml
 
b/src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml
new file mode 100644
index 0000000..1de56ce
--- /dev/null
+++ 
b/src/test/testData/reference/web/constant/WEB-INF/web_value_completion_modern_filter.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";>
+
+  <filter>
+    <filter-name>struts2</filter-name>
+    
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
+
+    <init-param>
+      <param-name>struts.url.includeParams</param-name>
+      <param-value><caret></param-value>
+    </init-param>
+  </filter>
+
+</web-app>
diff --git 
a/src/test/testData/reference/web/constant/org/apache/struts2/dispatcher/filter/StrutsPrepareAndExecuteFilter.java
 
b/src/test/testData/reference/web/constant/org/apache/struts2/dispatcher/filter/StrutsPrepareAndExecuteFilter.java
new file mode 100644
index 0000000..289066e
--- /dev/null
+++ 
b/src/test/testData/reference/web/constant/org/apache/struts2/dispatcher/filter/StrutsPrepareAndExecuteFilter.java
@@ -0,0 +1,26 @@
+package org.apache.struts2.dispatcher.filter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Test stub for Struts 2.5+ filter class (not present in struts2-core 2.3.1 
test dependency).
+ */
+public class StrutsPrepareAndExecuteFilter {
+}
diff --git 
a/src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml
 
b/src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml
new file mode 100644
index 0000000..9374dc4
--- /dev/null
+++ 
b/src/test/testData/strutsXml/completion/struts-completionvariants-constant_theme_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd";>
+
+<struts>
+  <constant name="struts.ui.theme" value="<caret>"/>
+</struts>
diff --git 
a/src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml
 
b/src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml
new file mode 100644
index 0000000..cb10d10
--- /dev/null
+++ 
b/src/test/testData/strutsXml/completion/struts-completionvariants-multipart_parser_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd";>
+
+<struts>
+  <constant name="struts.multipart.parser" value="<caret>"/>
+</struts>

Reply via email to