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>