in src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java [815:920]
protected Object resolveNamespace(final String prefix, final JexlNode node) {
Object namespace;
// check whether this namespace is a functor
synchronized (this) {
if (functors != null) {
namespace = functors.get(prefix);
if (namespace != null) {
return namespace;
}
}
}
// check if namespace is a resolver
namespace = ns.resolveNamespace(prefix);
if (namespace == null) {
namespace = functions.get(prefix);
if (namespace == null) {
namespace = jexl.getNamespace(prefix);
}
if (prefix != null && namespace == null) {
throw new JexlException(node, "no such function namespace " + prefix, null);
}
}
Object functor = null;
// class or string (*1)
if (namespace instanceof Class<?> || namespace instanceof String) {
// the namespace(d) identifier
final ASTIdentifier nsNode = (ASTIdentifier) node.jjtGetChild(0);
final boolean cacheable = cache && prefix != null;
final Object cached = cacheable ? nsNode.jjtGetValue() : null;
// we know the class is used as namespace of static methods, no functor
if (cached instanceof Class<?>) {
return cached;
}
// attempt to reuse last cached constructor
if (cached instanceof JexlContext.NamespaceFunctor) {
final Object eval = ((JexlContext.NamespaceFunctor) cached).createFunctor(context);
if (JexlEngine.TRY_FAILED != eval) {
functor = eval;
namespace = cached;
}
}
if (functor == null) {
// find a constructor with that context as argument or without
for (int tried = 0; tried < 2; ++tried) {
final boolean withContext = tried == 0;
final JexlMethod ctor = withContext
? uberspect.getConstructor(namespace, context)
: uberspect.getConstructor(namespace);
if (ctor != null) {
try {
functor = withContext
? ctor.invoke(namespace, context)
: ctor.invoke(namespace);
// defensive
if (functor != null) {
// wrap the namespace in a NamespaceFunctor to shield us from the actual
// number of arguments to call it with.
final Object nsFinal = namespace;
// make it a class (not a lambda!) so instanceof (see *2) will catch it
namespace = (NamespaceFunctor) context -> withContext
? ctor.tryInvoke(null, nsFinal, context)
: ctor.tryInvoke(null, nsFinal);
if (cacheable && ctor.isCacheable()) {
nsNode.jjtSetValue(namespace);
}
break; // we found a constructor that did create a functor
}
} catch (final Exception xinst) {
throw new JexlException(node, "unable to instantiate namespace " + prefix, xinst);
}
}
}
// did not, will not create a functor instance; use a class, namespace of static methods
if (functor == null) {
try {
// try to find a class with that name
if (namespace instanceof String) {
namespace = uberspect.getClassLoader().loadClass((String) namespace);
}
// we know it's a class in all cases (see *1)
if (cacheable) {
nsNode.jjtSetValue(namespace);
}
} catch (final ClassNotFoundException e) {
// not a class
throw new JexlException(node, "no such class namespace " + prefix, e);
}
}
}
}
// if a namespace functor, instantiate the functor (if not done already) and store it (*2)
if (functor == null && namespace instanceof JexlContext.NamespaceFunctor) {
functor = ((JexlContext.NamespaceFunctor) namespace).createFunctor(context);
}
// got a functor, store it and return it
if (functor != null) {
synchronized (this) {
if (functors == null) {
functors = new HashMap<>();
}
functors.put(prefix, functor);
}
return functor;
}
return namespace;
}