Index: java/javax/el/ImportHandler.java =================================================================== --- java/javax/el/ImportHandler.java (revision 1833823) +++ java/javax/el/ImportHandler.java (working copy) @@ -19,9 +19,11 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -29,7 +31,241 @@ */ public class ImportHandler { - private List packageNames = new ArrayList<>(); + private static final Map> standardPackages = new HashMap<>(); + + static { + // Servlet 4.0 + Set servletClassNames = new HashSet<>(); + // Interfaces + servletClassNames.add("AsyncContext"); + servletClassNames.add("AsyncEvent"); + servletClassNames.add("Filter"); + servletClassNames.add("FilterChain"); + servletClassNames.add("FilterConfig"); + servletClassNames.add("FilterRegistration"); + servletClassNames.add("FilterRegistration.Dynamic"); + servletClassNames.add("ReadListener"); + servletClassNames.add("Registration"); + servletClassNames.add("Registration.Dynamic"); + servletClassNames.add("RequestDispatcher"); + servletClassNames.add("Servlet"); + servletClassNames.add("ServletConfig"); + servletClassNames.add("ServletContainerInitializer"); + servletClassNames.add("ServletContext"); + servletClassNames.add("ServletContextAttributeListener"); + servletClassNames.add("ServletContextListener"); + servletClassNames.add("ServletRegistration"); + servletClassNames.add("ServletRegistration.Dynamic"); + servletClassNames.add("ServletRequest"); + servletClassNames.add("ServletRequestAttributeListener"); + servletClassNames.add("ServletRequestListener"); + servletClassNames.add("ServletResponse"); + servletClassNames.add("SessionCookieConfig"); + servletClassNames.add("SingleThreadModel"); + servletClassNames.add("WriteListener"); + // Classes + servletClassNames.add("AsyncEvent"); + servletClassNames.add("GenericFilter"); + servletClassNames.add("GenericServlet"); + servletClassNames.add("HttpConstraintElement"); + servletClassNames.add("HttpMethodConstraintElement"); + servletClassNames.add("MultipartConfigElement"); + servletClassNames.add("ServletContextAttributeEvent"); + servletClassNames.add("ServletContextEvent"); + servletClassNames.add("ServletInputStream"); + servletClassNames.add("ServletOutputStream"); + servletClassNames.add("ServletRequestAttributeEvent"); + servletClassNames.add("ServletRequestEvent"); + servletClassNames.add("ServletRequestWrapper"); + servletClassNames.add("ServletResponseWrapper"); + servletClassNames.add("ServletSecurityElement"); + // Enums + servletClassNames.add("DispatcherType"); + servletClassNames.add("SessionTrackingMode"); + // Exceptions + servletClassNames.add("ServletException"); + servletClassNames.add("UnavailableException"); + standardPackages.put("javax.servlet", servletClassNames); + + // Servlet 4.0 + Set servletHttpClassNames = new HashSet<>(); + // Interfaces + servletHttpClassNames.add("HttpServletMapping"); + servletHttpClassNames.add("HttpServletRequest"); + servletHttpClassNames.add("HttpServletResponse"); + servletHttpClassNames.add("HttpSession"); + servletHttpClassNames.add("HttpSessionActivationListener"); + servletHttpClassNames.add("HttpSessionAttributeListener"); + servletHttpClassNames.add("HttpSessionBindingListener"); + servletHttpClassNames.add("HttpSessionContext"); + servletHttpClassNames.add("HttpSessionIdListener"); + servletHttpClassNames.add("HttpSessionListener"); + servletHttpClassNames.add("HttpUpgradeHandler"); + servletHttpClassNames.add("Part"); + servletHttpClassNames.add("PushBuilder"); + servletHttpClassNames.add("WebConnection"); + // Classes + servletHttpClassNames.add("Cookie"); + servletHttpClassNames.add("HttpFilter"); + servletHttpClassNames.add("HttpServlet"); + servletHttpClassNames.add("HttpServletRequestWrapper"); + servletHttpClassNames.add("HttpServletResponseWrapper"); + servletHttpClassNames.add("HttpSessionBindingEvent"); + servletHttpClassNames.add("HttpSessionEvent"); + servletHttpClassNames.add("HttpUtils"); + // Enums + servletHttpClassNames.add("MappingMatch"); + standardPackages.put("javax.servlet.http", servletHttpClassNames); + + // JSP 2.3 + Set servletJspClassNames = new HashSet<>(); + //Interfaces + servletJspClassNames.add("HttpJspPage"); + servletJspClassNames.add("JspApplicationContext"); + servletJspClassNames.add("JspPage"); + // Classes + servletJspClassNames.add("ErrorData"); + servletJspClassNames.add("JspContext"); + servletJspClassNames.add("JspEngineInfo"); + servletJspClassNames.add("JspFactory"); + servletJspClassNames.add("JspWriter"); + servletJspClassNames.add("PageContext"); + servletJspClassNames.add("Exceptions"); + servletJspClassNames.add("JspException"); + servletJspClassNames.add("JspTagException"); + servletJspClassNames.add("SkipPageException"); + standardPackages.put("javax.jsp.servlet", servletJspClassNames); + + Set javaLangClassNames = new HashSet<>(); + // Taken from Java 11 EA18 Javadoc + // Interfaces + javaLangClassNames.add("Appendable"); + javaLangClassNames.add("AutoCloseable"); + javaLangClassNames.add("CharSequence"); + javaLangClassNames.add("Cloneable"); + javaLangClassNames.add("Comparable"); + javaLangClassNames.add("Iterable"); + javaLangClassNames.add("ProcessHandle"); + javaLangClassNames.add("ProcessHandle.Info"); + javaLangClassNames.add("Readable"); + javaLangClassNames.add("Runnable"); + javaLangClassNames.add("StackWalker.StackFrame"); + javaLangClassNames.add("System.Logger"); + javaLangClassNames.add("Thread.UncaughtExceptionHandler"); + //Classes + javaLangClassNames.add("Boolean"); + javaLangClassNames.add("Byte"); + javaLangClassNames.add("Character"); + javaLangClassNames.add("Character.Subset"); + javaLangClassNames.add("Character.UnicodeBlock"); + javaLangClassNames.add("Class"); + javaLangClassNames.add("ClassLoader"); + javaLangClassNames.add("ClassValue"); + javaLangClassNames.add("Compiler"); + javaLangClassNames.add("Double"); + javaLangClassNames.add("Enum"); + javaLangClassNames.add("Float"); + javaLangClassNames.add("InheritableThreadLocal"); + javaLangClassNames.add("Integer"); + javaLangClassNames.add("Long"); + javaLangClassNames.add("Math"); + javaLangClassNames.add("Module"); + javaLangClassNames.add("ModuleLayer"); + javaLangClassNames.add("ModuleLayer.Controller"); + javaLangClassNames.add("Number"); + javaLangClassNames.add("Object"); + javaLangClassNames.add("Package"); + javaLangClassNames.add("Process"); + javaLangClassNames.add("ProcessBuilder"); + javaLangClassNames.add("ProcessBuilder.Redirect"); + javaLangClassNames.add("Runtime"); + javaLangClassNames.add("RuntimePermission"); + javaLangClassNames.add("SecurityManager"); + javaLangClassNames.add("Short"); + javaLangClassNames.add("StackTraceElement"); + javaLangClassNames.add("StackWalker"); + javaLangClassNames.add("StrictMath"); + javaLangClassNames.add("String"); + javaLangClassNames.add("StringBuffer"); + javaLangClassNames.add("StringBuilder"); + javaLangClassNames.add("System"); + javaLangClassNames.add("System.LoggerFinder"); + javaLangClassNames.add("Thread"); + javaLangClassNames.add("ThreadGroup"); + javaLangClassNames.add("ThreadLocal"); + javaLangClassNames.add("Throwable"); + javaLangClassNames.add("Void"); + //Enums + javaLangClassNames.add("Character.UnicodeScript"); + javaLangClassNames.add("ProcessBuilder.Redirect.Type"); + javaLangClassNames.add("StackWalker.Option"); + javaLangClassNames.add("System.Logger.Level"); + javaLangClassNames.add("Thread.State"); + //Exceptions + javaLangClassNames.add("ArithmeticException"); + javaLangClassNames.add("ArrayIndexOutOfBoundsException"); + javaLangClassNames.add("ArrayStoreException"); + javaLangClassNames.add("ClassCastException"); + javaLangClassNames.add("ClassNotFoundException"); + javaLangClassNames.add("CloneNotSupportedException"); + javaLangClassNames.add("EnumConstantNotPresentException"); + javaLangClassNames.add("Exception"); + javaLangClassNames.add("IllegalAccessException"); + javaLangClassNames.add("IllegalArgumentException"); + javaLangClassNames.add("IllegalCallerException"); + javaLangClassNames.add("IllegalMonitorStateException"); + javaLangClassNames.add("IllegalStateException"); + javaLangClassNames.add("IllegalThreadStateException"); + javaLangClassNames.add("IndexOutOfBoundsException"); + javaLangClassNames.add("InstantiationException"); + javaLangClassNames.add("InterruptedException"); + javaLangClassNames.add("LayerInstantiationException"); + javaLangClassNames.add("NegativeArraySizeException"); + javaLangClassNames.add("NoSuchFieldException"); + javaLangClassNames.add("NoSuchMethodException"); + javaLangClassNames.add("NullPointerException"); + javaLangClassNames.add("NumberFormatException"); + javaLangClassNames.add("ReflectiveOperationException"); + javaLangClassNames.add("RuntimeException"); + javaLangClassNames.add("SecurityException"); + javaLangClassNames.add("StringIndexOutOfBoundsException"); + javaLangClassNames.add("TypeNotPresentException"); + javaLangClassNames.add("UnsupportedOperationException"); + //Errors + javaLangClassNames.add("AbstractMethodError"); + javaLangClassNames.add("AssertionError"); + javaLangClassNames.add("BootstrapMethodError"); + javaLangClassNames.add("ClassCircularityError"); + javaLangClassNames.add("ClassFormatError"); + javaLangClassNames.add("Error"); + javaLangClassNames.add("ExceptionInInitializerError"); + javaLangClassNames.add("IllegalAccessError"); + javaLangClassNames.add("IncompatibleClassChangeError"); + javaLangClassNames.add("InstantiationError"); + javaLangClassNames.add("InternalError"); + javaLangClassNames.add("LinkageError"); + javaLangClassNames.add("NoClassDefFoundError"); + javaLangClassNames.add("NoSuchFieldError"); + javaLangClassNames.add("NoSuchMethodError"); + javaLangClassNames.add("OutOfMemoryError"); + javaLangClassNames.add("StackOverflowError"); + javaLangClassNames.add("ThreadDeath"); + javaLangClassNames.add("UnknownError"); + javaLangClassNames.add("UnsatisfiedLinkError"); + javaLangClassNames.add("UnsupportedClassVersionError"); + javaLangClassNames.add("VerifyError"); + javaLangClassNames.add("VirtualMachineError"); + //Annotation Types + javaLangClassNames.add("Deprecated"); + javaLangClassNames.add("FunctionalInterface"); + javaLangClassNames.add("Override"); + javaLangClassNames.add("SafeVarargs"); + javaLangClassNames.add("SuppressWarnings"); + standardPackages.put("java.lang", javaLangClassNames); + + } + + private Map> packageNames = new ConcurrentHashMap<>(); private Map classNames = new ConcurrentHashMap<>(); private Map> clazzes = new ConcurrentHashMap<>(); private Map> statics = new ConcurrentHashMap<>(); @@ -127,7 +363,12 @@ // a) for sake of performance when used in JSPs (BZ 57142), // b) java.lang.Package.getPackage(name) is not reliable (BZ 57574), // c) such check is not required by specification. - packageNames.add(name); + Set preloaded = standardPackages.get(name); + if (preloaded == null) { + packageNames.put(name, Collections.emptySet()); + } else { + packageNames.put(name, preloaded); + } } @@ -159,8 +400,17 @@ // Search the package imports - note there may be multiple matches // (which correctly triggers an error) - for (String p : packageNames) { - className = p + '.' + name; + for (Map.Entry> entry : packageNames.entrySet()) { + if (!entry.getValue().isEmpty()) { + // Standard package where we know all the class names + if (!entry.getValue().contains(name)) { + // Requested name isn't in the list so it isn't in this + // package so move on to next package. This allows the + // class loader look-up to be skipped. + continue; + } + } + className = entry.getKey() + '.' + name; Class clazz = findClass(className, false); if (clazz != null) { if (result != null) { Index: test/javax/el/TestImportHandlerPerformance.java =================================================================== --- test/javax/el/TestImportHandlerPerformance.java (nonexistent) +++ test/javax/el/TestImportHandlerPerformance.java (working copy) @@ -0,0 +1,49 @@ +/* + * 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 javax.el; + +import org.junit.Test; + +public class TestImportHandlerPerformance { + + /* + * This test is looking at the cost of looking up a class when the standard + * JSP package imports are present: + * - java.lang + * - javax.servlet + * - javax.servlet.http + * - javax.servlet.jsp + * + * Before optimisation, this test took ~4.6s on markt's desktop + * After optimisation, this test took ~1.5s on markt's desktop + */ + @Test + public void testBug62453() throws Exception { + long totalTime = 0; + for (int i = 0; i < 100000; i++) { + ImportHandler ih = new ImportHandler(); + ih.importPackage("javax.servlet"); + ih.importPackage("javax.servlet.http"); + ih.importPackage("javax.servlet.jsp"); + long start = System.nanoTime(); + ih.resolveClass("unknown"); + long end = System.nanoTime(); + totalTime += (end -start); + } + System.out.println("Time taken: " + totalTime + "ns"); + } +} Property changes on: test/javax/el/TestImportHandlerPerformance.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: test/javax/servlet/jsp/el/TestScopedAttributeELResolver.java =================================================================== --- test/javax/servlet/jsp/el/TestScopedAttributeELResolver.java (nonexistent) +++ test/javax/servlet/jsp/el/TestScopedAttributeELResolver.java (working copy) @@ -0,0 +1,37 @@ +/* + * 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 javax.servlet.jsp.el; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +public class TestScopedAttributeELResolver extends TomcatBaseTest { + + @Test + public void testBug49196() throws Exception { + getTomcatInstanceTestWebapp(true, true); + + ByteChunk res = getUrl("http://localhost:" + getPort() + + "/test/bug6nnnn/bug62453.jsp"); + + String result = res.toString(); + Assert.assertTrue(result, result.contains("OK")); + } +} Property changes on: test/javax/servlet/jsp/el/TestScopedAttributeELResolver.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: test/webapp/WEB-INF/tags/bug62453.tag =================================================================== --- test/webapp/WEB-INF/tags/bug62453.tag (nonexistent) +++ test/webapp/WEB-INF/tags/bug62453.tag (working copy) @@ -0,0 +1,26 @@ +<%-- + 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 prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ attribute name="foo" required="true" %> +<%@ attribute name="bar" %> +<%@ attribute name="baz" %> + +
+
foo: ${foo.toString()}
+
bar: ${bar.toString()}
+
baz: ${baz.toString()}
+
\ No newline at end of file Index: test/webapp/bug6nnnn/bug62453.jsp =================================================================== --- test/webapp/bug6nnnn/bug62453.jsp (nonexistent) +++ test/webapp/bug6nnnn/bug62453.jsp (working copy) @@ -0,0 +1,24 @@ +<%-- + 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 prefix="tags" tagdir="/WEB-INF/tags" %> + + + +

Example of Uninitialized Tag Attributes

+ + + \ No newline at end of file Property changes on: test/webapp/bug6nnnn/bug62453.jsp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property