This is an automated email from the ASF dual-hosted git repository.

kusal pushed a commit to branch WW-5440-convention
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 611933c60b06837938c6c4067db4b6c8a45ab9bb
Author: Kusal Kithul-Godage <g...@kusal.io>
AuthorDate: Sat Jul 13 23:08:46 2024 +1000

    WW-5440 Fix OGNL allowlist compat with Convention plugin
---
 apps/showcase/pom.xml                              |  6 ++
 .../apache/struts2/showcase/ConventionTest.java    | 70 ++++++++++++++++++++++
 .../xwork2/config/ConfigurationUtil.java           | 13 +++-
 .../providers/XmlDocConfigurationProvider.java     |  5 +-
 .../org/apache/struts2/ognl/ProviderAllowlist.java | 35 ++++++++---
 .../apache/struts2/ognl/ProviderAllowlistTest.java | 27 ++++-----
 .../convention/ClasspathConfigurationProvider.java | 11 +++-
 .../convention/ClasspathPackageProvider.java       | 11 ++--
 .../PackageBasedActionConfigBuilder.java           | 61 ++++++++++++-------
 9 files changed, 185 insertions(+), 54 deletions(-)

diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml
index 3ea6e3dc8..e1ad28097 100644
--- a/apps/showcase/pom.xml
+++ b/apps/showcase/pom.xml
@@ -143,6 +143,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <!-- BeanValidation Example -->
         <dependency>
             <groupId>org.hibernate.validator</groupId>
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..d42973bfb
--- /dev/null
+++ 
b/apps/showcase/src/test/java/it/org/apache/struts2/showcase/ConventionTest.java
@@ -0,0 +1,70 @@
+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<Class<?>> getAllClassTypes(Class<?> clazz) {
+        HashSet<Class<?>> 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<ConfigurationProvider, Set<Class<?>>> allowlistMap;
+    private final Map<Object, Set<Class<?>>> allowlistMap;
     private Set<Class<?>> allowlistClasses;
 
     public ProviderAllowlist() {
@@ -42,24 +43,40 @@ public class ProviderAllowlist {
         reconstructAllowlist();
     }
 
-    public synchronized void registerAllowlist(ConfigurationProvider 
configurationProvider, Set<Class<?>> allowlist) {
-        Set<Class<?>> existingAllowlist = 
allowlistMap.get(configurationProvider);
+    public synchronized void registerAllowlist(Object key, Set<Class<?>> 
allowlist) {
+        Set<Class<?>> existingAllowlist = allowlistMap.get(key);
         if (existingAllowlist != null) {
-            clearAllowlist(configurationProvider);
+            clearAllowlist(key);
         }
-        this.allowlistMap.put(configurationProvider, new HashSet<>(allowlist));
+        this.allowlistMap.put(key, new HashSet<>(allowlist));
         this.allowlistClasses.addAll(allowlist);
     }
 
-    public synchronized void clearAllowlist(ConfigurationProvider 
configurationProvider) {
-        Set<Class<?>> allowlist = allowlistMap.get(configurationProvider);
+    /**
+     * @deprecated since 6.6.0, use {@link #registerAllowlist(Object, Set)}
+     */
+    @Deprecated
+    public synchronized void registerAllowlist(ConfigurationProvider 
configurationProvider, Set<Class<?>> allowlist) {
+        registerAllowlist((Object) configurationProvider, allowlist);
+    }
+
+    public synchronized void clearAllowlist(Object key) {
+        Set<Class<?>> allowlist = allowlistMap.get(key);
         if (allowlist == null) {
             return;
         }
-        this.allowlistMap.remove(configurationProvider);
+        this.allowlistMap.remove(key);
         reconstructAllowlist();
     }
 
+    /**
+     * @deprecated since 6.6.0, use {@link #clearAllowlist(Object)}
+     */
+    @Deprecated
+    public synchronized void clearAllowlist(ConfigurationProvider 
configurationProvider) {
+        clearAllowlist((Object) configurationProvider);
+    }
+
     public Set<Class<?>> getProviderAllowlist() {
         return unmodifiableSet(allowlistClasses);
     }
diff --git 
a/core/src/test/java/org/apache/struts2/ognl/ProviderAllowlistTest.java 
b/core/src/test/java/org/apache/struts2/ognl/ProviderAllowlistTest.java
index baf91b9b5..2584d16f4 100644
--- a/core/src/test/java/org/apache/struts2/ognl/ProviderAllowlistTest.java
+++ b/core/src/test/java/org/apache/struts2/ognl/ProviderAllowlistTest.java
@@ -18,7 +18,6 @@
  */
 package org.apache.struts2.ognl;
 
-import com.opensymphony.xwork2.config.ConfigurationProvider;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -39,10 +38,10 @@ public class ProviderAllowlistTest {
     private ProviderAllowlist providerAllowlist;
 
     @Mock
-    private ConfigurationProvider provider1;
+    private Object key1;
 
     @Mock
-    private ConfigurationProvider provider2;
+    private Object key2;
 
     @Before
     public void setUp() throws Exception {
@@ -51,37 +50,37 @@ public class ProviderAllowlistTest {
 
     @Test
     public void registerAllowlist() {
-        providerAllowlist.registerAllowlist(provider1, new 
HashSet<>(asList(String.class, Integer.class)));
-        providerAllowlist.registerAllowlist(provider2, new 
HashSet<>(asList(Double.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key1, new 
HashSet<>(asList(String.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key2, new 
HashSet<>(asList(Double.class, Integer.class)));
 
         
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(String.class,
 Integer.class, Double.class);
     }
 
     @Test
     public void registerAllowlist_twice() {
-        providerAllowlist.registerAllowlist(provider1, new 
HashSet<>(asList(String.class, Integer.class)));
-        providerAllowlist.registerAllowlist(provider1, new 
HashSet<>(asList(Double.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key1, new 
HashSet<>(asList(String.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key1, new 
HashSet<>(asList(Double.class, Integer.class)));
 
         
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(Integer.class,
 Double.class);
     }
 
     @Test
     public void clearAllowlist() {
-        providerAllowlist.registerAllowlist(provider1, new 
HashSet<>(asList(String.class, Integer.class)));
-        providerAllowlist.registerAllowlist(provider2, new 
HashSet<>(asList(Double.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key1, new 
HashSet<>(asList(String.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key2, new 
HashSet<>(asList(Double.class, Integer.class)));
 
-        providerAllowlist.clearAllowlist(provider1);
+        providerAllowlist.clearAllowlist(key1);
 
         
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(Integer.class,
 Double.class);
     }
 
     @Test
     public void clearAllowlist_both() {
-        providerAllowlist.registerAllowlist(provider1, new 
HashSet<>(asList(String.class, Integer.class)));
-        providerAllowlist.registerAllowlist(provider2, new 
HashSet<>(asList(Double.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key1, new 
HashSet<>(asList(String.class, Integer.class)));
+        providerAllowlist.registerAllowlist(key2, new 
HashSet<>(asList(Double.class, Integer.class)));
 
-        providerAllowlist.clearAllowlist(provider1);
-        providerAllowlist.clearAllowlist(provider2);
+        providerAllowlist.clearAllowlist(key1);
+        providerAllowlist.clearAllowlist(key2);
 
         assertThat(providerAllowlist.getProviderAllowlist()).isEmpty();
     }
diff --git 
a/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathConfigurationProvider.java
 
b/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathConfigurationProvider.java
index f3d873322..71ac094cf 100644
--- 
a/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathConfigurationProvider.java
+++ 
b/plugins/convention/src/main/java/org/apache/struts2/convention/ClasspathConfigurationProvider.java
@@ -36,7 +36,7 @@ import org.apache.struts2.dispatcher.DispatcherListener;
  * </p>
  */
 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;
 
 /**
  * <p>
@@ -34,20 +34,23 @@ import com.opensymphony.xwork2.inject.Container;
  * </p>
  */
 public class ClasspathPackageProvider implements PackageProvider {
-     private ActionConfigBuilder actionConfigBuilder;
+    private final ActionConfigBuilder actionConfigBuilder;
 
     @Inject
     public ClasspathPackageProvider(Container container) {
         this.actionConfigBuilder = 
container.getInstance(ActionConfigBuilder.class, 
container.getInstance(String.class, 
ConventionConstants.CONVENTION_ACTION_CONFIG_BUILDER));
     }
 
+    @Override
     public void init(Configuration configuration) throws 
ConfigurationException {
     }
 
+    @Override
     public boolean needsReload() {
-        return actionConfigBuilder.needsReload(); 
+        return actionConfigBuilder.needsReload();
     }
 
+    @Override
     public void loadPackages() throws ConfigurationException {
         actionConfigBuilder.buildActionConfigs();
     }
diff --git 
a/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java
 
b/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java
index 460cab49e..71331d4ef 100644
--- 
a/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java
+++ 
b/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.FileManagerFactory;
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.config.Configuration;
 import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationUtil;
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
 import com.opensymphony.xwork2.config.entities.InterceptorMapping;
@@ -57,6 +58,7 @@ import 
org.apache.struts2.convention.annotation.ExceptionMappings;
 import org.apache.struts2.convention.annotation.Namespace;
 import org.apache.struts2.convention.annotation.Namespaces;
 import org.apache.struts2.convention.annotation.ParentPackage;
+import org.apache.struts2.ognl.ProviderAllowlist;
 
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -125,6 +127,9 @@ public class PackageBasedActionConfigBuilder implements 
ActionConfigBuilder {
     private FileManager fileManager;
     private ClassFinderFactory classFinderFactory;
 
+    private final Set<Class<?>> allowlistClasses = new HashSet<>();
+    private ProviderAllowlist providerAllowlist;
+
     /**
      * Constructs actions based on a list of packages.
      *
@@ -167,6 +172,11 @@ public class PackageBasedActionConfigBuilder implements 
ActionConfigBuilder {
         this.devMode = BooleanUtils.toBoolean(mode);
     }
 
+    @Inject
+    public void setProviderAllowlist(ProviderAllowlist providerAllowlist) {
+        this.providerAllowlist = providerAllowlist;
+    }
+
     /**
      * @param reload Reload configuration when classes change. Defaults to 
"false" and should not be used
      *               in production.
@@ -345,33 +355,38 @@ public class PackageBasedActionConfigBuilder implements 
ActionConfigBuilder {
      * annotation which is used to control the parent package for a specific 
action. Lastly, the
      * {@link ResultMapBuilder} is used to create ResultConfig instances of 
the action.
      */
+    @Override
     public void buildActionConfigs() {
+        allowlistClasses.clear();
+
         //setup reload class loader based on dev settings
         initReloadClassLoader();
 
-        if (!disableActionScanning) {
-            if (actionPackages == null && packageLocators == null) {
-                throw new ConfigurationException("At least a list of action 
packages or action package locators " +
-                        "must be given using one of the properties 
[struts.convention.action.packages] or " +
-                        "[struts.convention.package.locators]");
-            }
+        if (disableActionScanning) {
+            return;
+        }
 
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Loading action configurations");
-                if (actionPackages != null) {
-                    LOG.trace("Actions being loaded from action packages: {}", 
(Object[]) actionPackages);
-                }
-                if (packageLocators != null) {
-                    LOG.trace("Actions being loaded using package locator's: 
{}", (Object[]) packageLocators);
-                }
-                if (excludePackages != null) {
-                    LOG.trace("Excluding actions from packages: {}", 
(Object[]) excludePackages);
-                }
-            }
+        if (actionPackages == null && packageLocators == null) {
+            throw new ConfigurationException("At least a list of action 
packages or action package locators " +
+                    "must be given using one of the properties 
[struts.convention.action.packages] or " +
+                    "[struts.convention.package.locators]");
+        }
 
-            Set<Class<?>> classes = findActions();
-            buildConfiguration(classes);
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Loading action configurations");
+            if (actionPackages != null) {
+                LOG.trace("Actions being loaded from action packages: {}", 
(Object[]) actionPackages);
+            }
+            if (packageLocators != null) {
+                LOG.trace("Actions being loaded using package locator's: {}", 
(Object[]) packageLocators);
+            }
+            if (excludePackages != null) {
+                LOG.trace("Excluding actions from packages: {}", (Object[]) 
excludePackages);
+            }
         }
+
+        Set<Class<?>> classes = findActions();
+        buildConfiguration(classes);
     }
 
     protected ClassLoaderInterface getClassLoaderInterface() {
@@ -765,7 +780,10 @@ public class PackageBasedActionConfigBuilder implements 
ActionConfigBuilder {
                 } else if (actionAnnotation != null)
                     createActionConfig(defaultPackageConfig, actionClass, 
defaultActionName, methodName, actionAnnotation, allowedMethods);
             }
+
+            
allowlistClasses.addAll(ConfigurationUtil.getAllClassTypes(actionClass));
         }
+        providerAllowlist.registerAllowlist(this, allowlistClasses);
 
         buildIndexActions(packageConfigs);
 
@@ -1153,10 +1171,13 @@ public class PackageBasedActionConfigBuilder implements 
ActionConfigBuilder {
         }
     }
 
+    @Override
     public void destroy() {
         loadedFileUrls.clear();
+        providerAllowlist.clearAllowlist(this);
     }
 
+    @Override
     public boolean needsReload() {
         if (devMode && reload) {
             for (String url : loadedFileUrls) {

Reply via email to