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

markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new 2b80587f9d Review "Avoid registering TLD listeners twice for a 
duplicate taglib..."
2b80587f9d is described below

commit 2b80587f9dbe1de5ff1248a2e32dcdfacd8a3a54
Author: Mark Thomas <[email protected]>
AuthorDate: Fri Nov 6 10:03:50 2026 +0000

    Review "Avoid registering TLD listeners twice for a duplicate taglib..."
    
    Refactor de-duplication to the same listener isn't added twice but
    duplicate tablib URIs that define different listeners register all
    listeners.
---
 java/org/apache/jasper/servlet/TldScanner.java     | 33 +++++-----
 test/org/apache/jasper/servlet/TestTldScanner.java | 70 ++++++++++++++++++++++
 2 files changed, 89 insertions(+), 14 deletions(-)

diff --git a/java/org/apache/jasper/servlet/TldScanner.java 
b/java/org/apache/jasper/servlet/TldScanner.java
index da2fb0ac0d..718786c167 100644
--- a/java/org/apache/jasper/servlet/TldScanner.java
+++ b/java/org/apache/jasper/servlet/TldScanner.java
@@ -194,9 +194,7 @@ public class TldScanner {
                 TaglibXml tld = tldParser.parse(tldResourcePath);
                 uriTldResourcePathMap.put(taglibURI, tldResourcePath);
                 tldResourcePathTaglibXmlMap.put(tldResourcePath, tld);
-                if (tld.getListeners() != null) {
-                    listeners.addAll(tld.getListeners());
-                }
+                addListeners(tld);
             } else {
                 log.warn(Localizer.getMessage(MSG + 
".webxmlFailPathDoesNotExist", resourcePath, taglibURI));
             }
@@ -309,14 +307,8 @@ public class TldScanner {
             tld = tldParser.parse(path);
         }
         String uri = tld.getUri();
-        // JSP.7.3.6.1: the first mapping for a taglib URI wins. A TLD with a
-        // previously seen URI found via a different resource path (for
-        // example, an unpacked JAR in WEB-INF/classes/META-INF or the same
-        // TLD shipped in two JARs) is a duplicate.
-        boolean duplicateUri = false;
         if (uri != null) {
-            duplicateUri = uriTldResourcePathMap.containsKey(uri);
-            if (!duplicateUri) {
+            if (!uriTldResourcePathMap.containsKey(uri)) {
                 uriTldResourcePathMap.put(uri, path);
             }
         }
@@ -327,10 +319,23 @@ public class TldScanner {
         }
 
         tldResourcePathTaglibXmlMap.put(path, tld);
-        if (tld.getListeners() != null && !duplicateUri) {
-            // The listeners of a duplicate tag library have already been
-            // registered when the tag library was first discovered.
-            listeners.addAll(tld.getListeners());
+        addListeners(tld);
+    }
+
+    /*
+     * Registers the listeners declared by the TLD, ignoring any listener 
class that has already been registered. The
+     * same TLD may be found via more than one resource path and under more 
than one URI (for example, a taglib-uri in
+     * web.xml that differs from the URI declared in the TLD itself) and a 
listener class must only be instantiated
+     * once.
+     */
+    private void addListeners(TaglibXml tld) {
+        if (tld.getListeners() == null) {
+            return;
+        }
+        for (String listener : tld.getListeners()) {
+            if (!listeners.contains(listener)) {
+                listeners.add(listener);
+            }
         }
     }
 
diff --git a/test/org/apache/jasper/servlet/TestTldScanner.java 
b/test/org/apache/jasper/servlet/TestTldScanner.java
index 152a94b37d..950a1ebdf1 100644
--- a/test/org/apache/jasper/servlet/TestTldScanner.java
+++ b/test/org/apache/jasper/servlet/TestTldScanner.java
@@ -29,6 +29,8 @@ import java.util.Map;
 import java.util.logging.Level;
 
 import jakarta.servlet.ServletContext;
+import jakarta.servlet.descriptor.JspConfigDescriptor;
+import jakarta.servlet.descriptor.TaglibDescriptor;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -180,6 +182,74 @@ public class TestTldScanner extends TomcatBaseTest {
     }
 
 
+    @Test
+    public void testListenersNotDuplicatedForDifferentTaglibUris() throws 
Exception {
+        // Two TLDs with different URIs that declare the same listener class
+        // must not cause that class to be registered, and therefore
+        // instantiated, twice.
+        ServletContext mockContext = EasyMock.createMock(ServletContext.class);
+        EasyMock.replay(mockContext);
+
+        TldScanner scanner = new TldScanner(mockContext, true, true, true);
+
+        File appDir = new File(getTemporaryDirectory(), 
"different-uri-listeners");
+        TldResourcePath first = createTld(appDir, "one",
+                "<uri>http://tomcat.apache.org/first</uri>\n" +
+                "  <listener>\n" +
+                "    
<listener-class>com.example.SharedListener</listener-class>\n" +
+                "  </listener>");
+        TldResourcePath second = createTld(appDir, "two",
+                "<uri>http://tomcat.apache.org/second</uri>\n" +
+                "  <listener>\n" +
+                "    
<listener-class>com.example.SharedListener</listener-class>\n" +
+                "  </listener>");
+
+        scanner.parseTld(first);
+        scanner.parseTld(second);
+
+        EasyMock.verify(mockContext);
+        Assert.assertEquals(2, scanner.getUriTldResourcePathMap().size());
+        Assert.assertEquals(1, scanner.getListeners().size());
+        Assert.assertEquals("com.example.SharedListener", 
scanner.getListeners().get(0));
+    }
+
+
+    @Test
+    public void testListenersNotDuplicatedForWebXmlTaglibUriMismatch() throws 
Exception {
+        // The taglib-uri in web.xml differs from the URI declared in the TLD
+        // itself. The same TLD found again by the scan has a URI that is not
+        // yet mapped, so the duplicate can only be detected by listener class.
+        File appDir = new File(getTemporaryDirectory(), 
"webxml-uri-mismatch-listeners");
+        TldResourcePath declared = createTld(appDir, "one",
+                "<uri>http://tomcat.apache.org/mismatch</uri>\n" +
+                "  <listener>\n" +
+                "    
<listener-class>com.example.MismatchListener</listener-class>\n" +
+                "  </listener>");
+        TldResourcePath found = createTld(appDir, "two",
+                "<uri>http://tomcat.apache.org/mismatch</uri>\n" +
+                "  <listener>\n" +
+                "    
<listener-class>com.example.MismatchListener</listener-class>\n" +
+                "  </listener>");
+
+        TaglibDescriptor taglib = EasyMock.createMock(TaglibDescriptor.class);
+        
EasyMock.expect(taglib.getTaglibURI()).andReturn("urn:mismatch").anyTimes();
+        
EasyMock.expect(taglib.getTaglibLocation()).andReturn("/one/example.tld").anyTimes();
+        JspConfigDescriptor jspConfig = 
EasyMock.createMock(JspConfigDescriptor.class);
+        
EasyMock.expect(jspConfig.getTaglibs()).andReturn(Collections.singleton(taglib)).anyTimes();
+        ServletContext mockContext = EasyMock.createMock(ServletContext.class);
+        
EasyMock.expect(mockContext.getJspConfigDescriptor()).andReturn(jspConfig).anyTimes();
+        
EasyMock.expect(mockContext.getResource("/one/example.tld")).andReturn(declared.getUrl()).anyTimes();
+        EasyMock.replay(taglib, jspConfig, mockContext);
+
+        TldScanner scanner = new TldScanner(mockContext, true, true, true);
+        scanner.scanJspConfig();
+        scanner.parseTld(found);
+
+        Assert.assertEquals(1, scanner.getListeners().size());
+        Assert.assertEquals("com.example.MismatchListener", 
scanner.getListeners().get(0));
+    }
+
+
     private static TldResourcePath createTld(File appDir, String name,
             String extraElements) throws Exception {
         File tld = new File(appDir, name + "/example.tld");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to