int paramCount; if (paramTypes == null) {
paramCount = 0;
} else {
paramCount = paramTypes.length;
}
Method[] methods = base.getClass().getMethods();
Map<Method,MatchResult> candidates = new HashMap<>();
for (Method m : methods) { if (!m.getName().equals(methodName)) { // Method name doesn't match continue;
}
Class<?>[] mParamTypes = m.getParameterTypes(); int mParamCount = mParamTypes.length;
// Check the number of parameters // Multiple tests to improve readability if (!m.isVarArgs() && paramCount != mParamCount) { // Method has wrong number of parameters continue;
} if (m.isVarArgs() && paramCount < mParamCount -1) { // Method has wrong number of parameters continue;
} if (m.isVarArgs() && paramCount == mParamCount && paramValues != null &&
paramValues.length > paramCount && !paramTypes[mParamCount -1].isArray()) { // Method arguments don't match continue;
} if (m.isVarArgs() && paramCount > mParamCount && paramValues != null &&
paramValues.length != paramCount) { // Might match a different varargs method continue;
} if (!m.isVarArgs() && paramValues != null && paramCount != paramValues.length) { // Might match a different varargs method continue;
}
// Check the parameters match int exactMatch = 0; int assignableMatch = 0; int coercibleMatch = 0; int varArgsMatch = 0; boolean noMatch = false; for (int i = 0; i < mParamCount; i++) { // Can't be null if (m.isVarArgs() && i == (mParamCount - 1)) { if (i == paramCount || (paramValues != null && paramValues.length == i)) { // Var args defined but nothing is passed as varargs // Use MAX_VALUE so this matches only if nothing else does
varArgsMatch = Integer.MAX_VALUE; break;
} Class<?> varType = mParamTypes[i].getComponentType(); for (int j = i; j < paramCount; j++) { if (isAssignableFrom(paramTypes[j], varType)) {
assignableMatch++;
varArgsMatch++;
} else { if (paramValues == null) {
noMatch = true; break;
} else { if (isCoercibleFrom(ctx, paramValues[j], varType)) {
coercibleMatch++;
varArgsMatch++;
} else {
noMatch = true; break;
}
}
} // Don't treat a varArgs match as an exact match, it can // lead to a varArgs method matching when the result // should be ambiguous
}
} else { if (mParamTypes[i].equals(paramTypes[i])) {
exactMatch++;
} elseif (paramTypes[i] != null && isAssignableFrom(paramTypes[i], mParamTypes[i])) {
assignableMatch++;
} else { if (paramValues == null) {
noMatch = true; break;
} else { if (isCoercibleFrom(ctx, paramValues[i], mParamTypes[i])) {
coercibleMatch++;
} else {
noMatch = true; break;
}
}
}
}
} if (noMatch) { continue;
}
// If a method is found where every parameter matches exactly, // and no vars args are present, return it if (exactMatch == paramCount && varArgsMatch == 0) {
Method result = getMethod(base.getClass(), base, m); if (result == null) { thrownew MethodNotFoundException(MessageFactory.get( "error.method.notfound", base, property,
paramString(paramTypes)));
} return result;
}
candidates.put(m, new MatchResult(
m.isVarArgs(), exactMatch, assignableMatch, coercibleMatch, varArgsMatch, m.isBridge()));
}
// Look for the method that has the highest number of parameters where // the type matches exactly
MatchResult bestMatch = new MatchResult(true, 0, 0, 0, 0, true);
Method match = null; boolean multiple = false; for (Map.Entry<Method, MatchResult> entry : candidates.entrySet()) { int cmp = entry.getValue().compareTo(bestMatch); if (cmp > 0 || match == null) {
bestMatch = entry.getValue();
match = entry.getKey();
multiple = false;
} elseif (cmp == 0) {
multiple = true;
}
} if (multiple) { if (bestMatch.getExactCount() == paramCount - 1) { // Only one parameter is not an exact match - try using the // super class
match = resolveAmbiguousMethod(candidates.keySet(), paramTypes);
} else {
match = null;
}
if (match == null) { // If multiple methods have the same matching number of parameters // the match is ambiguous so throw an exception thrownew MethodNotFoundException(MessageFactory.get( "error.method.ambiguous", base, property,
paramString(paramTypes)));
}
}
// Handle case where no match at all was found if (match == null) { thrownew MethodNotFoundException(MessageFactory.get( "error.method.notfound", base, property,
paramString(paramTypes)));
}
/* *Thisclassduplicatescodeinjakarta.el.Util.Whenmakingchangeskeep *thecodeinsync.
*/ privatestatic Method resolveAmbiguousMethod(Set<Method> candidates, Class<?>[] paramTypes) { // Identify which parameter isn't an exact match
Method m = candidates.iterator().next();
int nonMatchIndex = 0; Class<?> nonMatchClass = null;
for (int i = 0; i < paramTypes.length; i++) { if (m.getParameterTypes()[i] != paramTypes[i]) {
nonMatchIndex = i;
nonMatchClass = paramTypes[i]; break;
}
}
if (nonMatchClass == null) { // Null will always be ambiguous returnnull;
}
for (Method c : candidates) { if (c.getParameterTypes()[nonMatchIndex] ==
paramTypes[nonMatchIndex]) { // Methods have different non-matching parameters // Result is ambiguous returnnull;
}
}
// Can't be null Class<?> superClass = nonMatchClass.getSuperclass(); while (superClass != null) { for (Method c : candidates) { if (c.getParameterTypes()[nonMatchIndex].equals(superClass)) { // Found a match return c;
}
}
superClass = superClass.getSuperclass();
}
// Treat instances of Number as a special case
Method match = null; if (Number.class.isAssignableFrom(nonMatchClass)) { for (Method c : candidates) { Class<?> candidateType = c.getParameterTypes()[nonMatchIndex]; if (Number.class.isAssignableFrom(candidateType) ||
candidateType.isPrimitive()) { if (match == null) {
match = c;
} else { // Match still ambiguous
match = null; break;
}
}
}
}
return match;
}
/* *Thisclassduplicatescodeinjakarta.el.Util.Whenmakingchangeskeep *thecodeinsync.
*/ privatestaticboolean isAssignableFrom(Class<?> src, Class<?> target) { // src will always be an object // Short-cut. null is always assignable to an object and in EL null // can always be coerced to a valid value for a primitive if (src == null) { returntrue;
}
@Override publicint compareTo(MatchResult o) { // Non-varArgs always beats varArgs int cmp = Boolean.compare(o.isVarArgs(), this.isVarArgs()); if (cmp == 0) {
cmp = Integer.compare(this.getExactCount(), o.getExactCount()); if (cmp == 0) {
cmp = Integer.compare(this.getAssignableCount(), o.getAssignableCount()); if (cmp == 0) {
cmp = Integer.compare(this.getCoercible(), o.getCoercible()); if (cmp == 0) { // Fewer var args matches are better
cmp = Integer.compare(o.getVarArgsCount(), this.getVarArgsCount()); if (cmp == 0) { // The nature of bridge methods is such that it actually // doesn't matter which one we pick as long as we pick // one. That said, pick the 'right' one (the non-bridge // one) anyway.
cmp = Boolean.compare(o.isBridge(), this.isBridge());
}
}
}
}
} return cmp;
}
@Override publicint hashCode() { finalint prime = 31; int result = 1;
result = prime * result + assignableCount;
result = prime * result + (bridge ? 1231 : 1237);
result = prime * result + coercibleCount;
result = prime * result + exactCount;
result = prime * result + (varArgs ? 1231 : 1237);
result = prime * result + varArgsCount; return result;
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.