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.git
commit 706045e61d01971bd12736308f0e7bcbceac6852 Author: Lukasz Lenart <[email protected]> AuthorDate: Mon Nov 2 10:28:31 2026 +0100 WW-4164 fix(core): address Sonar findings on extension support Co-Authored-By: Claude Sonnet 5.5 <[email protected]> --- .../org/apache/struts2/config/impl/DefaultConfiguration.java | 6 +++--- core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java | 2 +- .../struts2/dispatcher/mapper/ActionExtensionResolver.java | 7 ++++--- .../org/apache/struts2/dispatcher/mapper/ActionExtensions.java | 4 ++-- .../apache/struts2/dispatcher/mapper/DefaultActionMapper.java | 9 +++++---- .../apache/struts2/dispatcher/ActionExtensionEndToEndTest.java | 4 +++- .../apache/struts2/dispatcher/mapper/ActionExtensionsTest.java | 4 ++-- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/config/impl/DefaultConfiguration.java b/core/src/main/java/org/apache/struts2/config/impl/DefaultConfiguration.java index a53170105..30dcb0968 100644 --- a/core/src/main/java/org/apache/struts2/config/impl/DefaultConfiguration.java +++ b/core/src/main/java/org/apache/struts2/config/impl/DefaultConfiguration.java @@ -563,9 +563,9 @@ public class DefaultConfiguration implements Configuration { warnIfHttpMethodNotEnforced(baseConfig, interceptors); - List<String> extensions = !baseConfig.getExtensions().isEmpty() - ? baseConfig.getExtensions() - : packageContext.getFullExtensions(); + List<String> extensions = baseConfig.getExtensions().isEmpty() + ? packageContext.getFullExtensions() + : baseConfig.getExtensions(); warnIfExtensionNotEnforced(baseConfig, extensions, interceptors); String methodRegex = container.getInstance(String.class, StrutsConstants.STRUTS_SMI_METHOD_REGEX); diff --git a/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java b/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java index 331648c1c..cee6fa5c5 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java @@ -756,7 +756,7 @@ public class Dispatcher { if (container.getInstance(ActionMapper.class).getClass() == DefaultActionMapper.class) { return; } - boolean declared = configurationManager.getConfiguration().getRuntimeConfiguration().getActionConfigs().values().stream() + boolean declared = container.getInstance(Configuration.class).getRuntimeConfiguration().getActionConfigs().values().stream() .flatMap(actions -> actions.values().stream()) .anyMatch(config -> !config.getExtensions().isEmpty()); if (declared) { diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensionResolver.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensionResolver.java index f322b10f0..bdbafac9f 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensionResolver.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensionResolver.java @@ -28,6 +28,7 @@ import org.apache.struts2.config.entities.ActionConfig; import org.apache.struts2.inject.Inject; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; /** * Chooses the extension of a generated action URL from the extensions the target action accepts, so links, @@ -40,7 +41,7 @@ public class ActionExtensionResolver { private Configuration configuration; private List<String> extensions; private boolean allowDynamicMethodCalls; - private volatile DeclarationState declarationState; + private final AtomicReference<DeclarationState> declarationState = new AtomicReference<>(); /** * @param configuration the configuration used to look up the target action @@ -113,14 +114,14 @@ public class ActionExtensionResolver { } private boolean anyActionDeclaresExtensions(RuntimeConfiguration runtimeConfiguration) { - DeclarationState cached = declarationState; + DeclarationState cached = declarationState.get(); if (cached != null && cached.runtimeConfiguration == runtimeConfiguration) { return cached.anyDeclared; } boolean anyDeclared = runtimeConfiguration.getActionConfigs().values().stream() .flatMap(actionConfigs -> actionConfigs.values().stream()) .anyMatch(actionConfig -> !actionConfig.getExtensions().isEmpty()); - declarationState = new DeclarationState(runtimeConfiguration, anyDeclared); + declarationState.set(new DeclarationState(runtimeConfiguration, anyDeclared)); return anyDeclared; } diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensions.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensions.java index ec90209fa..99a0f0614 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensions.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/ActionExtensions.java @@ -38,12 +38,12 @@ public final class ActionExtensions { * Parses a comma separated extension list; a trailing comma adds an empty entry. * * @param value the raw value, may be {@code null} - * @return an unmodifiable list in declared order, or {@code null} when {@code value} is {@code null} + * @return an unmodifiable list in declared order, or an empty list when {@code value} is {@code null} * @since 7.5.0 */ public static List<String> parse(String value) { if (value == null) { - return null; + return List.of(); } if (value.isEmpty()) { return List.of(""); diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java index c4ddf8575..c39bd8be4 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java @@ -40,6 +40,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import static org.apache.commons.lang3.StringUtils.normalizeSpace; @@ -137,7 +138,7 @@ public class DefaultActionMapper implements ActionMapper { protected List<String> extensions = List.of("action", ""); - private volatile DeclaredExtensions declaredExtensions; + private final AtomicReference<DeclaredExtensions> declaredExtensions = new AtomicReference<>(); protected Container container; @@ -253,7 +254,7 @@ public class DefaultActionMapper implements ActionMapper { } else { this.extensions = null; } - this.declaredExtensions = null; + this.declaredExtensions.set(null); } @Override @@ -529,7 +530,7 @@ public class DefaultActionMapper implements ActionMapper { } private DeclaredExtensions declaredExtensions(RuntimeConfiguration runtimeConfiguration) { - DeclaredExtensions cached = declaredExtensions; + DeclaredExtensions cached = declaredExtensions.get(); if (cached != null && cached.runtimeConfiguration == runtimeConfiguration) { return cached; } @@ -549,7 +550,7 @@ public class DefaultActionMapper implements ActionMapper { .sorted(Comparator.comparingInt(String::length).reversed().thenComparing(Comparator.naturalOrder())) .toList(); DeclaredExtensions computed = new DeclaredExtensions(runtimeConfiguration, declaredOnly, emptyDeclaredOnly); - declaredExtensions = computed; + declaredExtensions.set(computed); return computed; } diff --git a/core/src/test/java/org/apache/struts2/dispatcher/ActionExtensionEndToEndTest.java b/core/src/test/java/org/apache/struts2/dispatcher/ActionExtensionEndToEndTest.java index 0086defcc..d5c64479a 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/ActionExtensionEndToEndTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/ActionExtensionEndToEndTest.java @@ -27,6 +27,7 @@ import org.apache.struts2.action.Action; import org.apache.struts2.components.URL; import org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter; import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.util.StrutsTestCaseHelper; import org.apache.struts2.util.ValueStack; import org.apache.struts2.util.ValueStackFactory; import org.springframework.mock.web.MockFilterChain; @@ -60,7 +61,8 @@ public class ActionExtensionEndToEndTest extends StrutsInternalTestCase { @Override protected void setUp() throws Exception { - PrepareOperations.clearDevModeOverride(); + super.setUp(); + StrutsTestCaseHelper.tearDown(dispatcher); Map<String, String> params = new HashMap<>(); params.put("config", "struts-default.xml,org/apache/struts2/dispatcher/struts-extension-one-package.xml"); params.put(StrutsConstants.STRUTS_ACTION_EXTENSION, "action,,"); diff --git a/core/src/test/java/org/apache/struts2/dispatcher/mapper/ActionExtensionsTest.java b/core/src/test/java/org/apache/struts2/dispatcher/mapper/ActionExtensionsTest.java index 3a1f46fe1..b3ec0ee3b 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/mapper/ActionExtensionsTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/mapper/ActionExtensionsTest.java @@ -38,8 +38,8 @@ public class ActionExtensionsTest extends TestCase { assertThat(ActionExtensions.parse("")).isEqualTo(List.of("")); } - public void testParseNull() { - assertThat(ActionExtensions.parse(null)).isNull(); + public void testParseNullIsEmpty() { + assertThat(ActionExtensions.parse(null)).isEmpty(); } public void testAllowsNullAsEmpty() {
