diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml
index 3ea6e3dc8..5b5f0e590 100644
--- a/apps/showcase/pom.xml
+++ b/apps/showcase/pom.xml
@@ -137,6 +137,12 @@
test
+
+ org.assertj
+ assertj-core
+ test
+
+
net.sourceforge.htmlunithtmlunit
diff --git a/apps/showcase/src/test/java/it/org/apache/struts2/showcase/ConventionTest.java b/apps/showcase/src/test/java/it/org/apache/struts2/showcase/ConventionTest.java
new file mode 100644
index 000000000..76fd0e840
--- /dev/null
+++ b/apps/showcase/src/test/java/it/org/apache/struts2/showcase/ConventionTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 it.org.apache.struts2.showcase;
+
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlForm;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConventionTest {
+
+ private WebClient webClient;
+
+ @Before
+ public void setUp() throws Exception {
+ webClient = new WebClient();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ webClient.close();
+ }
+
+ @Test
+ public void listPeople() throws Exception {
+ HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/person/list-people.action");
+
+ assertThat(page.asNormalizedText()).contains(
+ "3\tAlexandru\tPapesco\n" +
+ "4\tJay\tBoss\n" +
+ "5\tRainer\tHermanos\n"
+ );
+ }
+
+ @Test
+ public void editPeople() throws Exception {
+ HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/person/edit-person.action");
+ HtmlForm form = page.getForms().get(0);
+
+ form.getInputByName("persons(1).name").setValue("Lukasz");
+ form.getInputByName("persons(1).lastName").setValue("Lenart");
+ form.getInputByName("persons(2).name").setValue("Kusal");
+ form.getInputByName("persons(2).lastName").setValue("Kithul-Godage");
+
+ HtmlSubmitInput button = form.getInputByValue("Save all persons");
+ page = button.click();
+
+ assertThat(page.asNormalizedText()).contains(
+ "1\tLukasz\tLenart\n" +
+ "2\tKusal\tKithul-Godage\n"
+ );
+ }
+
+ @Test
+ public void createPerson() throws Exception {
+ HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/person/new-person!input.action");
+ HtmlForm form = page.getForms().get(0);
+
+ form.getInputByName("person.name").type("Lukasz");
+ form.getInputByName("person.lastName").type("Lenart");
+
+ HtmlSubmitInput button = form.getInputByValue("Create person");
+ page = button.click();
+
+ assertThat(page.asNormalizedText()).contains("6\tLukasz\tLenart\n");
+ }
+}
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
index b85042688..06381c5b0 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
@@ -19,18 +19,21 @@
package com.opensymphony.xwork2.config;
import com.opensymphony.xwork2.config.entities.PackageConfig;
+import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.StringTokenizer;
/**
* ConfigurationUtil
- *
+ *
* @author Jason Carreira Created May 23, 2003 11:22:49 PM
*/
public class ConfigurationUtil {
@@ -83,4 +86,12 @@ public class ConfigurationUtil {
return parents;
}
+
+ public static Set> getAllClassTypes(Class> clazz) {
+ HashSet> classes = new HashSet<>();
+ classes.add(clazz);
+ classes.addAll(ClassUtils.getAllSuperclasses(clazz));
+ classes.addAll(ClassUtils.getAllInterfaces(clazz));
+ return classes;
+ }
}
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlDocConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlDocConfigurationProvider.java
index 6de202460..d874f850f 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlDocConfigurationProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlDocConfigurationProvider.java
@@ -45,7 +45,6 @@ import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.location.Location;
import com.opensymphony.xwork2.util.location.LocationUtils;
import org.apache.commons.lang3.BooleanUtils;
-import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -149,9 +148,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
protected Class> allowAndLoadClass(String className) throws ClassNotFoundException {
Class> clazz = loadClass(className);
- allowlistClasses.add(clazz);
- allowlistClasses.addAll(ClassUtils.getAllSuperclasses(clazz));
- allowlistClasses.addAll(ClassUtils.getAllInterfaces(clazz));
+ allowlistClasses.addAll(ConfigurationUtil.getAllClassTypes(clazz));
return clazz;
}
diff --git a/core/src/main/java/org/apache/struts2/ognl/ProviderAllowlist.java b/core/src/main/java/org/apache/struts2/ognl/ProviderAllowlist.java
index d10372885..93f7506b7 100644
--- a/core/src/main/java/org/apache/struts2/ognl/ProviderAllowlist.java
+++ b/core/src/main/java/org/apache/struts2/ognl/ProviderAllowlist.java
@@ -28,13 +28,14 @@ import java.util.Set;
import static java.util.Collections.unmodifiableSet;
/**
- * Allows {@link ConfigurationProvider}s to register classes that should be allowed to be used in OGNL expressions.
+ * Allows registration of classes that should be allowed to be used in OGNL expressions, using a key to identify the
+ * source of the allowlist.
*
* @since 6.4.0
*/
public class ProviderAllowlist {
- private final Map>> allowlistMap;
+ private final Map
*/
public class ClasspathConfigurationProvider implements ConfigurationProvider, DispatcherListener {
- private ActionConfigBuilder actionConfigBuilder;
+ private final ActionConfigBuilder actionConfigBuilder;
private boolean devMode;
private boolean reload;
private boolean listeningToDispatcher;
@@ -59,6 +59,7 @@ public class ClasspathConfigurationProvider implements ConfigurationProvider, Di
/**
* Not used.
*/
+ @Override
public void destroy() {
if (this.listeningToDispatcher) {
Dispatcher.removeDispatcherListener(this);
@@ -71,6 +72,7 @@ public class ClasspathConfigurationProvider implements ConfigurationProvider, Di
*
* @param configuration configuration
*/
+ @Override
public void init(Configuration configuration) {
if (devMode && reload && !listeningToDispatcher) {
//this is the only way I found to be able to get added to to ConfigurationProvider list
@@ -88,6 +90,7 @@ public class ClasspathConfigurationProvider implements ConfigurationProvider, Di
*
* @throws ConfigurationException in case of configuration errors
*/
+ @Override
public void register(ContainerBuilder containerBuilder, LocatableProperties locatableProperties)
throws ConfigurationException {
}
@@ -97,20 +100,24 @@ public class ClasspathConfigurationProvider implements ConfigurationProvider, Di
*
* @throws ConfigurationException in case of configuration errors
*/
+ @Override
public void loadPackages() throws ConfigurationException {
}
/**
* @return true if devMode, reload and actionConfigBuilder.needsReload()
*/
+ @Override
public boolean needsReload() {
return devMode && reload && actionConfigBuilder.needsReload();
}
+ @Override
public void dispatcherInitialized(Dispatcher du) {
du.getConfigurationManager().addContainerProvider(this);
}
+ @Override
public void dispatcherDestroyed(Dispatcher du) {
}
-}
\ No newline at end of file
+}
diff --git a/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathPackageProvider.java b/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathPackageProvider.java
index 7b314c05b..3ffec8488 100644
--- a/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathPackageProvider.java
+++ b/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathPackageProvider.java
@@ -18,11 +18,11 @@
*/
package org.apache.struts2.convention;
-import com.opensymphony.xwork2.config.PackageProvider;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
-import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.config.PackageProvider;
import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
/**
*