This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new ee79bd778e Fix BZ 55470 - Add class path logging to help debug CNFE ee79bd778e is described below commit ee79bd778e82bc3e4e4b17c955160ad0f428a7b7 Author: Mark Thomas <ma...@apache.org> AuthorDate: Wed Nov 6 10:07:15 2024 +0000 Fix BZ 55470 - Add class path logging to help debug CNFE https://bz.apache.org/bugzilla/show_bug.cgi?id=55470 Based on a patch by Ralf Hauser --- .../catalina/loader/WebappClassLoaderBase.java | 4 + .../apache/tomcat/util/buf/LocalStrings.properties | 5 + java/org/apache/tomcat/util/buf/ToStringUtil.java | 101 +++++++++++++++++++++ java/org/apache/tomcat/util/digester/Digester.java | 7 ++ 4 files changed, 117 insertions(+) diff --git a/java/org/apache/catalina/loader/WebappClassLoaderBase.java b/java/org/apache/catalina/loader/WebappClassLoaderBase.java index 51548b71b7..d224e473f8 100644 --- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java +++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java @@ -67,6 +67,7 @@ import org.apache.juli.logging.LogFactory; import org.apache.tomcat.InstrumentableClassLoader; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.buf.ToStringUtil; import org.apache.tomcat.util.collections.ConcurrentLruCache; import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.res.StringManager; @@ -1160,6 +1161,9 @@ public abstract class WebappClassLoaderBase extends URLClassLoader } } + if (log.isDebugEnabled()) { + log.debug(ToStringUtil.classPathForCNFE(this)); + } throw new ClassNotFoundException(name); } diff --git a/java/org/apache/tomcat/util/buf/LocalStrings.properties b/java/org/apache/tomcat/util/buf/LocalStrings.properties index 63e2eb38a2..ce64e0df22 100644 --- a/java/org/apache/tomcat/util/buf/LocalStrings.properties +++ b/java/org/apache/tomcat/util/buf/LocalStrings.properties @@ -33,6 +33,11 @@ hexUtils.fromHex.oddDigits=The input must consist of an even number of hex digit stringCache.byteTime=ByteCache generation time: {0}ms stringCache.charTime=CharCache generation time: {0}ms +toStringUtil.classpath.classloader=ClassLoader [{0}] loading classes from: +toStringUtil.classpath.header=Logging class path for each class loader in hierarchy to aid debugging of ClassNotFoundException +toStringUtil.classpath.platform=JRE provided classes +toStringUtil.classpath.unknown=Unknown - not an instance of URLClassLoader + uDecoder.eof=End of file (EOF) uDecoder.isHexDigit=The hexadecimal encoding is invalid uDecoder.noSlash=The encoded slash character is not allowed diff --git a/java/org/apache/tomcat/util/buf/ToStringUtil.java b/java/org/apache/tomcat/util/buf/ToStringUtil.java new file mode 100644 index 0000000000..1d562d6f6d --- /dev/null +++ b/java/org/apache/tomcat/util/buf/ToStringUtil.java @@ -0,0 +1,101 @@ +/* + * 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 org.apache.tomcat.util.buf; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +import org.apache.tomcat.util.res.StringManager; + +/** + * Utility class used to provide String representations of objects. It is typically used in debug logging. + */ +public class ToStringUtil { + + private static final StringManager sm = StringManager.getManager(ToStringUtil.class); + + private static final String INDENT = " "; + + + private ToStringUtil() { + // Utility class. Hide default constructor. + } + + + /** + * Generate a String representation of the class path for the given class loader and any parent class loaders to aid + * debugging of {@link ClassNotFoundException}. + * + * @param classLoader The class loader to analyse + * + * @return A String representation of the class path. The format is undefined and may change in future point + * releases. The output includes new lines. + */ + public static String classPathForCNFE(ClassLoader classLoader) { + // The result is expected to be fairly large + StringBuilder result = new StringBuilder(4096); + result.append(sm.getString("toStringUtil.classpath.header")); + result.append("\n"); + while (classLoader != null) { + classPathForCNFE(classLoader, result); + classLoader = classLoader.getParent(); + } + return result.toString(); + } + + + private static void classPathForCNFE(ClassLoader classLoader, StringBuilder result) { + result.append(INDENT); + result.append(sm.getString("toStringUtil.classpath.classloader", classLoader)); + result.append("\n"); + if (classLoader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) classLoader).getURLs(); + for (URL url : urls) { + result.append(INDENT); + result.append(INDENT); + result.append(url); + result.append("\n"); + } + } else if (classLoader == ClassLoader.getSystemClassLoader()) { + // From Java 9 the internal class loaders no longer extend + // URLCLassLoader + String cp = System.getProperty("java.class.path"); + if (cp != null && cp.length() > 0) { + String[] paths = cp.split(File.pathSeparator); + for (String path : paths) { + result.append(INDENT); + result.append(INDENT); + result.append(path); + result.append("\n"); + } + } + } else if (classLoader == ClassLoader.getPlatformClassLoader()) { + // From Java 9 the internal class loaders no longer extend + // URLCLassLoader + result.append(INDENT); + result.append(INDENT); + result.append(sm.getString("toStringUtil.classpath.platform")); + result.append("\n"); + } else { + result.append(INDENT); + result.append(INDENT); + result.append(sm.getString("toStringUtil.classpath.unknown")); + result.append("\n"); + } + } +} diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java index e7615ac7f0..ca64050436 100644 --- a/java/org/apache/tomcat/util/digester/Digester.java +++ b/java/org/apache/tomcat/util/digester/Digester.java @@ -44,6 +44,7 @@ import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.IntrospectionUtils.PropertySource; import org.apache.tomcat.util.buf.B2CConverter; +import org.apache.tomcat.util.buf.ToStringUtil; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; @@ -1262,6 +1263,12 @@ public class Digester extends DefaultHandler2 { log.trace(" Fire begin() for " + rule); } rule.begin(namespaceURI, name, list); + } catch (ClassNotFoundException cnfe) { + log.error(sm.getString("digester.error.begin"), cnfe); + if (log.isDebugEnabled()) { + log.debug(ToStringUtil.classPathForCNFE(getClassLoader())); + } + throw createSAXException(cnfe); } catch (Exception e) { log.error(sm.getString("digester.error.begin"), e); throw createSAXException(e); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org