This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit c5b1afb2923a0365c56b3de58b1b0e4e9c4fff30 Author: opencode <[email protected]> AuthorDate: Mon Oct 19 11:15:49 2026 +0200 Use the canonical enum name in the optimized string interpreter StringInterpreterEnum converts static (non-EL) tag attribute values into enum constant references in generated JSP Java source. It referenced the enum type by Class.getName(), which for a nested enum returns the binary name with '$' separators, e.g. com.example.Tags$Status, so a static attribute value for a setter taking a nested enum type made the generated JSP class fail to compile on first request. Use getCanonicalName() instead, matching the dot-separated name the DefaultStringInterpreter fallback already uses. Found by code review. --- .../optimizations/StringInterpreterEnum.java | 5 +++- .../optimizations/TestStringInterpreterEnum.java | 20 +++++++++++++++ .../TestStringInterpreterTagSetters.java | 6 +++++ test/webapp/bug6nnnn/bug64872b-nested-timeunit.jsp | 29 ++++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/java/org/apache/jasper/optimizations/StringInterpreterEnum.java b/java/org/apache/jasper/optimizations/StringInterpreterEnum.java index ff52b6b1ac..8c21ede54f 100644 --- a/java/org/apache/jasper/optimizations/StringInterpreterEnum.java +++ b/java/org/apache/jasper/optimizations/StringInterpreterEnum.java @@ -42,7 +42,10 @@ public class StringInterpreterEnum extends DefaultStringInterpreter { try { @SuppressWarnings({ "unchecked", "rawtypes" }) Enum<?> enumValue = Enum.valueOf((Class<? extends Enum>) c, s); - return c.getName() + "." + enumValue.name(); + // The canonical name (dot-separated) must be used here. The + // binary name returned by getName() contains '$' separators + // for nested types and is not valid Java source. + return c.getCanonicalName() + "." + enumValue.name(); } catch (IllegalArgumentException iae) { if (log.isDebugEnabled()) { log.debug(Localizer.getMessage("jsp.error.typeConversion", s, "Enum[" + c.getName() + "]"), iae); diff --git a/test/org/apache/jasper/optimizations/TestStringInterpreterEnum.java b/test/org/apache/jasper/optimizations/TestStringInterpreterEnum.java index b22cd36581..459e7c81fe 100644 --- a/test/org/apache/jasper/optimizations/TestStringInterpreterEnum.java +++ b/test/org/apache/jasper/optimizations/TestStringInterpreterEnum.java @@ -18,6 +18,7 @@ package org.apache.jasper.optimizations; import java.util.concurrent.TimeUnit; +import org.junit.Assert; import org.junit.Test; public class TestStringInterpreterEnum { @@ -30,6 +31,15 @@ public class TestStringInterpreterEnum { } + /* + * Enum nested in a class so the binary name differs from the canonical + * name by a '$' separator. + */ + public enum NestedEnum { + VALUE + } + + @Test public void testBadTerms() { String[] badTerms = new String[] { "", "mis format", "fudge", ";", ".", "\"", " " }; @@ -37,4 +47,14 @@ public class TestStringInterpreterEnum { new TestInterpreter().evaluate(TimeUnit.class, badTerm); } } + + + @Test + public void testNestedEnumUsesCanonicalName() { + // The generated code must reference the canonical name (dot + // separated). The binary name contains '$' and is not valid Java + // source. + String result = new TestInterpreter().evaluate(NestedEnum.class, "VALUE"); + Assert.assertEquals(NestedEnum.class.getCanonicalName() + ".VALUE", result); + } } \ No newline at end of file diff --git a/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java b/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java index ca6db5864e..fca4d3560f 100644 --- a/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java +++ b/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java @@ -73,6 +73,12 @@ public class TestStringInterpreterTagSetters extends TomcatBaseTest { String actual = bc.toString(); Assert.assertTrue(actual, actual.contains("01 The value of foo is [SECONDS]")); + + bc = getUrl("http://localhost:" + getPort() + "/test/bug6nnnn/bug64872b-nested-timeunit.jsp"); + + actual = bc.toString(); + + Assert.assertTrue(actual, actual.contains("01 The value of foo is [SECONDS]")); } diff --git a/test/webapp/bug6nnnn/bug64872b-nested-timeunit.jsp b/test/webapp/bug6nnnn/bug64872b-nested-timeunit.jsp new file mode 100644 index 0000000000..3f0bc21baf --- /dev/null +++ b/test/webapp/bug6nnnn/bug64872b-nested-timeunit.jsp @@ -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. +--%> +<%@ taglib uri="http://tomcat.apache.org/tag-setters" prefix="ts" %> +<html> + <head><title>Bug 64872b nested enum test case</title></head> + <body> + <% + for (int i=0; i < 5000; i++) { + %> + <p>01 The value of foo is [<ts:tagNestedTimeUnit foo="SECONDS" />]</p> + <% + } + %> + </body> +</html> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
