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


The following commit(s) were added to refs/heads/main by this push:
     new 65f9784eb WW-5792 fix(config): warn instead of silently skipping 
non-public action classes
65f9784eb is described below

commit 65f9784eba12f308581b337ed8e589ec51f277a6
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Oct 24 10:23:53 2026 +0200

    WW-5792 fix(config): warn instead of silently skipping non-public action 
classes
    
    verifyAction threw "is not public" inside the try whose RuntimeException
    handler swallowed it, so a non-public action class only produced a
    misleading INFO line. It now logs a WARN naming the class and location
    and skips the constructor check, so startup behaves as before.
    Failing startup is tracked in WW-5809 for 8.0.0.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../providers/XmlDocConfigurationProvider.java     |  3 +-
 .../struts2/config/providers/NonPublicAction.java  | 29 +++++++++++++++++
 .../XmlConfigurationProviderActionsTest.java       | 36 ++++++++++++++++++++++
 .../providers/xwork-test-action-non-public.xml     | 32 +++++++++++++++++++
 4 files changed, 99 insertions(+), 1 deletion(-)

diff --git 
a/core/src/main/java/org/apache/struts2/config/providers/XmlDocConfigurationProvider.java
 
b/core/src/main/java/org/apache/struts2/config/providers/XmlDocConfigurationProvider.java
index e7e7d4066..0080d97f3 100644
--- 
a/core/src/main/java/org/apache/struts2/config/providers/XmlDocConfigurationProvider.java
+++ 
b/core/src/main/java/org/apache/struts2/config/providers/XmlDocConfigurationProvider.java
@@ -542,7 +542,8 @@ public abstract class XmlDocConfigurationProvider 
implements ConfigurationProvid
             Class<?> clazz = allowAndLoadClass(className);
             if (objectFactory.isNoArgConstructorRequired()) {
                 if (!Modifier.isPublic(clazz.getModifiers())) {
-                    throw new ConfigurationException("Action class [" + 
className + "] is not public", loc);
+                    LOG.warn("Action class [{}] is not public, this will fail 
at startup in Struts 8.0.0 - {}", className, loc);
+                    return;
                 }
                 clazz.getConstructor();
             }
diff --git 
a/core/src/test/java/org/apache/struts2/config/providers/NonPublicAction.java 
b/core/src/test/java/org/apache/struts2/config/providers/NonPublicAction.java
new file mode 100644
index 000000000..6a54551db
--- /dev/null
+++ 
b/core/src/test/java/org/apache/struts2/config/providers/NonPublicAction.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.config.providers;
+
+import org.apache.struts2.action.Action;
+
+class NonPublicAction implements Action {
+
+    public String execute() {
+        return SUCCESS;
+    }
+
+}
diff --git 
a/core/src/test/java/org/apache/struts2/config/providers/XmlConfigurationProviderActionsTest.java
 
b/core/src/test/java/org/apache/struts2/config/providers/XmlConfigurationProviderActionsTest.java
index 076fdaa6d..a7bda3a5e 100644
--- 
a/core/src/test/java/org/apache/struts2/config/providers/XmlConfigurationProviderActionsTest.java
+++ 
b/core/src/test/java/org/apache/struts2/config/providers/XmlConfigurationProviderActionsTest.java
@@ -18,6 +18,11 @@
  */
 package org.apache.struts2.config.providers;
 
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.struts2.ObjectFactory;
 import org.apache.struts2.SimpleAction;
 import org.apache.struts2.config.ConfigurationException;
@@ -161,6 +166,24 @@ public class XmlConfigurationProviderActionsTest extends 
ConfigurationTestBase {
         }
     }
 
+    public void testNonPublicActionWarnsAndLoads() {
+        final String filename = 
"org/apache/struts2/config/providers/xwork-test-action-non-public.xml";
+        LogCapture logCapture = new LogCapture();
+        Logger logger = (Logger) 
LogManager.getLogger(XmlConfigurationProvider.class);
+        logger.addAppender(logCapture);
+        logCapture.start();
+        try {
+            buildConfigurationProvider(filename);
+        } finally {
+            logCapture.stop();
+            logger.removeAppender(logCapture);
+        }
+
+        
assertNotNull(configuration.getPackageConfig("default").getActionConfigs().get("NonPublic"));
+        assertTrue(logCapture.events.stream().anyMatch(event -> 
event.getLevel() == Level.WARN
+                && event.getMessage().getFormattedMessage().contains("Action 
class [" + NonPublicAction.class.getName() + "] is not public")));
+    }
+
     public void testPackageDefaultClassRef() {
         final String filename = 
"org/apache/struts2/config/providers/xwork-test-actions-packagedefaultclassref.xml";
 
@@ -221,4 +244,17 @@ public class XmlConfigurationProviderActionsTest extends 
ConfigurationTestBase {
         exceptionMappings = new ArrayList<>();
         this.objectFactory = container.getInstance(ObjectFactory.class);
     }
+
+    private static class LogCapture extends AbstractAppender {
+        private final List<LogEvent> events = new ArrayList<>();
+
+        LogCapture() {
+            super("LogCapture", null, null, false, null);
+        }
+
+        @Override
+        public void append(LogEvent event) {
+            events.add(event.toImmutable());
+        }
+    }
 }
diff --git 
a/core/src/test/resources/org/apache/struts2/config/providers/xwork-test-action-non-public.xml
 
b/core/src/test/resources/org/apache/struts2/config/providers/xwork-test-action-non-public.xml
new file mode 100644
index 000000000..4a55fc209
--- /dev/null
+++ 
b/core/src/test/resources/org/apache/struts2/config/providers/xwork-test-action-non-public.xml
@@ -0,0 +1,32 @@
+<?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 6.0//EN"
+        "https://struts.apache.org/dtds/struts-6.0.dtd";>
+<struts>
+    <include file="xwork-test-beans.xml"/>
+    <package name="default">
+
+        <action name="NonPublic" 
class="org.apache.struts2.config.providers.NonPublicAction"/>
+
+    </package>
+</struts>

Reply via email to