Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 154x 4x 150x 76x 74x 25x 49x 31x 18x 18x 18x 11x 11x 11x 2x 7x | import type { EvaluationContext } from './evaluation-context.js';
import { TypedValue } from '../typed-value.js';
import type { MethodResolver } from './method-resolver.js';
import { SpelEvaluationException } from '../error/spel-evaluation-exception.js';
import { SpelMessage } from '../error/spel-message.js';
import { invokeStringMethod } from './java-string-methods.js';
import { isTypeDescriptor } from '../type/type-descriptor.js';
import { invokeNumberMethod } from './java-number-methods.js';
export class ReflectiveMethodResolver implements MethodResolver {
public resolve(
_context: EvaluationContext,
target: unknown,
name: string,
args: unknown[],
): TypedValue | null {
if (target === null || target === undefined) {
return null;
}
// A string is resolved against java.lang.String only. JavaScript's string
// methods are deliberately not consulted, because several share a name with
// a Java method but not its semantics: `replaceAll` takes a regular
// expression in Java and a literal in JavaScript, so the JavaScript
// implementation silently returned the input unchanged.
if (typeof target === 'string') {
return invokeStringMethod(target, name, args);
}
// A resolved type handle resolves only against its own static members. Its
// JavaScript prototype members must not win the lookup: `valueOf` exists on
// Object.prototype, so `T(String).valueOf(42)` would otherwise return the
// handle itself instead of calling String.valueOf. This is the same shadowing
// problem the string branch above addresses, in a third place.
if (isTypeDescriptor(target)) {
return new TypedValue(target.callStaticMethod(name, ...args));
}
// A number is resolved against the Java wrapper classes only, for the same
// reason a string is resolved against java.lang.String only: JavaScript's
// Number offers a different set under different names, and `toFixed` and
// `toExponential` were callable purely because JavaScript provides them while
// no Java type does.
if (typeof target === 'number' || typeof target === 'bigint') {
return invokeNumberMethod(target, name, args);
}
// Objects, arrays and maps fall back to their own methods.
const targetObj = target as Record<string, unknown>;
const fn = targetObj[name];
if (typeof fn === 'function') {
try {
const result = (fn as (...args: unknown[]) => unknown).apply(target, args);
return new TypedValue(result);
} catch (e) {
throw new SpelEvaluationException(
-1,
SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
name,
(e as Error).message,
);
}
}
// Not found — return null so the accessor chain or another resolver can try.
return null;
}
}
|