|
22 | 22 | import java.beans.PropertyEditorSupport; |
23 | 23 | import java.io.File; |
24 | 24 | import java.io.IOException; |
| 25 | +import java.lang.reflect.Field; |
25 | 26 | import java.nio.charset.CodingErrorAction; |
| 27 | +import java.util.ArrayList; |
26 | 28 | import java.util.Date; |
| 29 | +import java.util.List; |
| 30 | +import java.util.Map; |
27 | 31 | import java.util.Scanner; |
28 | 32 |
|
| 33 | +import org.apache.jasper.compiler.JspRuntimeContext; |
| 34 | +import org.apache.jasper.servlet.JspServlet; |
| 35 | + |
29 | 36 | import jakarta.servlet.http.HttpServletResponse; |
30 | 37 | import jakarta.servlet.jsp.JspException; |
31 | 38 | import jakarta.servlet.jsp.PageContext; |
@@ -828,6 +835,44 @@ public void testInclude01() throws Exception { |
828 | 835 | doTestJsp("include-01.jsp"); |
829 | 836 | } |
830 | 837 |
|
| 838 | + /* |
| 839 | + * Verify that _jspx_dependants entries appear in the same order as the |
| 840 | + * <%@ include file="..." %> directives in the source JSP, ensuring |
| 841 | + * reproducible builds (LinkedHashMap preserves insertion order). |
| 842 | + */ |
| 843 | + @Test |
| 844 | + public void testDependantsOrder() throws Exception { |
| 845 | + Tomcat tomcat = getTomcatInstanceTestWebapp(false, true); |
| 846 | + |
| 847 | + ByteChunk body = new ByteChunk(); |
| 848 | + int rc = getUrl("http://localhost:" + getPort() + |
| 849 | + "/test/jsp/generator/dependants-order.jsp", body, null); |
| 850 | + Assert.assertEquals(body.toString(), HttpServletResponse.SC_OK, rc); |
| 851 | + |
| 852 | + // JSP classes are loaded by a per-JSP JasperLoader child classloader, |
| 853 | + // not by the webapp classloader. Retrieve the dependants map through |
| 854 | + // the JspServletWrapper, which calls getDependants() on the live |
| 855 | + // servlet instance via the JspSourceDependent interface. |
| 856 | + Context ctx = (Context) tomcat.getHost().findChild("/test"); |
| 857 | + Wrapper jspWrapper = (Wrapper) ctx.findChild("jsp"); |
| 858 | + JspServlet jspServlet = (JspServlet) jspWrapper.getServlet(); |
| 859 | + Field rctxtField = JspServlet.class.getDeclaredField("rctxt"); |
| 860 | + rctxtField.setAccessible(true); |
| 861 | + JspRuntimeContext rctxt = (JspRuntimeContext) rctxtField.get(jspServlet); |
| 862 | + Map<String,Long> dependants = rctxt.getWrapper( |
| 863 | + "/jsp/generator/dependants-order.jsp").getDependants(); |
| 864 | + |
| 865 | + // Expect exactly the three fragments, in directive order: a, b, c. |
| 866 | + List<String> keys = new ArrayList<>(dependants.keySet()); |
| 867 | + Assert.assertEquals(3, keys.size()); |
| 868 | + Assert.assertTrue("a.jspf should precede b.jspf in _jspx_dependants", |
| 869 | + keys.indexOf("/jsp/generator/dependants-order-a.jspf") < |
| 870 | + keys.indexOf("/jsp/generator/dependants-order-b.jspf")); |
| 871 | + Assert.assertTrue("b.jspf should precede c.jspf in _jspx_dependants", |
| 872 | + keys.indexOf("/jsp/generator/dependants-order-b.jspf") < |
| 873 | + keys.indexOf("/jsp/generator/dependants-order-c.jspf")); |
| 874 | + } |
| 875 | + |
831 | 876 | @Test |
832 | 877 | public void testSetProperty01() throws Exception { |
833 | 878 | doTestJsp("setproperty-01.jsp"); |
|
0 commit comments