From f11f535f1699656639ae1a2eb694db6e47d3f846 Mon Sep 17 00:00:00 2001 From: michaeloffner Date: Wed, 4 Sep 2024 16:44:15 +0200 Subject: [PATCH] improve exception message when no method match --- .../commons/lang/PhysicalClassLoader.java | 9 +++- .../lucee/runtime/exp/FunctionException.java | 2 +- .../lucee/transformer/dynamic/meta/Clazz.java | 48 +++++++++++++++++-- loader/build.xml | 2 +- loader/pom.xml | 2 +- 5 files changed, 56 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java index 9b7c8dd8aa..b3b6c26b80 100644 --- a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java +++ b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java @@ -65,6 +65,7 @@ public final class PhysicalClassLoader extends URLClassLoader implements Extenda static { boolean res = registerAsParallelCapable(); } + private static RC rc = new RC(); private static Map classLoaders = new ConcurrentHashMap<>(); @@ -82,6 +83,8 @@ public final class PhysicalClassLoader extends URLClassLoader implements Extenda private boolean rpc; + private String birthplace; + private static long counter = 0L; private static long _start = 0L; private static String start = Long.toString(_start, Character.MAX_RADIX); @@ -163,7 +166,7 @@ private PhysicalClassLoader(Config c, List resources, Resource directo this.resources = resources; config = (ConfigPro) c; this.addionalClassLoader = addionalClassLoader; - + this.birthplace = ExceptionUtil.getStacktrace(new Throwable(), false); this.pageSourcePool = pageSourcePool; // ClassLoader resCL = parent!=null?parent:config.getResourceClassLoader(null); @@ -175,6 +178,10 @@ private PhysicalClassLoader(Config c, List resources, Resource directo this.rpc = rpc; } + public String getBirthplace() { + return birthplace; + } + public boolean isRPC() { return rpc; } diff --git a/core/src/main/java/lucee/runtime/exp/FunctionException.java b/core/src/main/java/lucee/runtime/exp/FunctionException.java index fe8a1a14e5..ce3ac957a5 100644 --- a/core/src/main/java/lucee/runtime/exp/FunctionException.java +++ b/core/src/main/java/lucee/runtime/exp/FunctionException.java @@ -65,7 +65,7 @@ public FunctionException(PageContext pc, String functionName, int badArgumentPos this(pc, functionName, toStringBadArgumentPosition(badArgumentPosition), badArgumentName, message, detail); } - private static String toStringBadArgumentPosition(int pos) { + public static String toStringBadArgumentPosition(int pos) { switch (pos) { case 1: return "first"; diff --git a/core/src/main/java/lucee/transformer/dynamic/meta/Clazz.java b/core/src/main/java/lucee/transformer/dynamic/meta/Clazz.java index cde87d2de9..549ad2baed 100644 --- a/core/src/main/java/lucee/transformer/dynamic/meta/Clazz.java +++ b/core/src/main/java/lucee/transformer/dynamic/meta/Clazz.java @@ -16,9 +16,11 @@ import lucee.commons.lang.ClassException; import lucee.commons.lang.ClassUtil; import lucee.commons.lang.Pair; +import lucee.commons.lang.PhysicalClassLoader; import lucee.commons.lang.types.RefInteger; import lucee.commons.lang.types.RefIntegerImpl; import lucee.runtime.config.Constants; +import lucee.runtime.exp.FunctionException; import lucee.runtime.exp.PageException; import lucee.runtime.java.JavaObject; import lucee.runtime.op.Caster; @@ -212,13 +214,53 @@ public static Method getMethodMatch(Clazz clazz, final Collection.Key methodName * (first,third,10th) and because this object have no constructor taking no arguments, Lucee cannot * instantiate them. you need first to instantiate this objects. */ + + Class[] trgArgs = Reflector.getClasses(args); + String strTrgArgs = Reflector.getDspMethods(trgArgs); StringBuilder msg = new StringBuilder(); - msg.append("No matching method for ").append(lucee.runtime.type.util.Type.getName(clazz.getDeclaringClass())).append(".").append(methodName).append("(") - .append(Reflector.getDspMethods(Reflector.getClasses(args))).append(") found. "); + msg.append("No matching method for ").append(lucee.runtime.type.util.Type.getName(clazz.getDeclaringClass())).append(".").append(methodName).append("(").append(strTrgArgs) + .append(") found. "); if (methods.size() > 0) { msg.append("there are similar methods with the same name, but diferent arguments:\n "); + Class[] srcArgs; + String strSrcArgs; for (Method m: methods) { - msg.append(methodName).append('(').append(Reflector.getDspMethods(m.getArgumentClasses())).append(");\n"); + srcArgs = m.getArgumentClasses(); + strSrcArgs = Reflector.getDspMethods(srcArgs); + if (strSrcArgs.equals(strTrgArgs)) { + ClassLoader srcClassLoader = null; + ClassLoader trgClassLoader = null; + int index = -1; + for (int i = 0; i < srcArgs.length; i++) { + if (srcArgs[i].getClassLoader() == trgArgs[i].getClassLoader()) continue; + index = i; + srcClassLoader = srcArgs[i].getClassLoader(); + trgClassLoader = trgArgs[i].getClassLoader(); + break; + } + String srcClassLoaderName = "Bootstrap ClassLoader"; + if (srcClassLoader instanceof PhysicalClassLoader) { + srcClassLoaderName = "PhysicalClassLoader loaded at " + ((PhysicalClassLoader) srcClassLoader).getBirthplace(); + } + else if (srcClassLoader != null) { + srcClassLoaderName = srcClassLoader.toString(); + } + String trgClassLoaderName = "Bootstrap ClassLoader"; + if (trgClassLoader instanceof PhysicalClassLoader) { + trgClassLoaderName = "PhysicalClassLoader loaded at " + ((PhysicalClassLoader) trgClassLoader).getBirthplace(); + } + else if (trgClassLoader != null) { + trgClassLoaderName = srcClassLoader.toString(); + } + + if (index != -1) throw new NoSuchMethodException("Found a matching method for [" + lucee.runtime.type.util.Type.getName(clazz.getDeclaringClass()) + "(" + + strSrcArgs + ")], but the classes were loaded by different class loaders. \n" + "The " + FunctionException.toStringBadArgumentPosition(index + 1) + + " argument [" + lucee.runtime.type.util.Type.getName(srcArgs[index]) + "] was loaded by the class loader [" + trgClassLoaderName + + "], but the provided argument is from the class loader [" + srcClassLoaderName + "]." + + " Ensure that both classes are loaded by the same class loader to avoid conflicts."); + + } + msg.append(methodName).append('(').append(strSrcArgs).append(");\n"); } } diff --git a/loader/build.xml b/loader/build.xml index 3ad3b29d22..b147c7d36c 100644 --- a/loader/build.xml +++ b/loader/build.xml @@ -2,7 +2,7 @@ - + diff --git a/loader/pom.xml b/loader/pom.xml index 102973120e..90534515f8 100644 --- a/loader/pom.xml +++ b/loader/pom.xml @@ -3,7 +3,7 @@ org.lucee lucee - 6.2.0.73-SNAPSHOT + 6.2.0.74-SNAPSHOT jar Lucee Loader Build