de.odysseus.el.tree.impl.ast.AstFunction Maven / Gradle / Ivy
/*
* Copyright 2006-2009 Odysseus Software GmbH
*
* Licensed 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 de.odysseus.el.tree.impl.ast;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.el.ELContext;
import javax.el.ELException;
import de.odysseus.el.misc.LocalMessages;
import de.odysseus.el.tree.Bindings;
import de.odysseus.el.tree.FunctionNode;
public class AstFunction extends AstRightValue implements FunctionNode {
private final int index;
private final String name;
private final AstParameters params;
private final boolean varargs;
public AstFunction(String name, int index, AstParameters params) {
this(name, index, params, false);
}
public AstFunction(String name, int index, AstParameters params, boolean varargs) {
this.name = name;
this.index = index;
this.params = params;
this.varargs = varargs;
}
/**
* Invoke method.
* @param bindings
* @param context
* @param base
* @param method
* @return method result
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected Object invoke(Bindings bindings, ELContext context, Object base, Method method)
throws InvocationTargetException, IllegalAccessException {
Class>[] types = method.getParameterTypes();
Object[] params = null;
if (types.length > 0) {
params = new Object[types.length];
if (varargs && method.isVarArgs()) {
for (int i = 0; i < params.length - 1; i++) {
Object param = getParam(i).eval(bindings, context);
if (param != null || types[i].isPrimitive()) {
params[i] = bindings.convert(param, types[i]);
}
}
int varargIndex = types.length - 1;
Class> varargType = types[varargIndex].getComponentType();
int length = getParamCount() - varargIndex;
Object array = null;
if (length == 1) { // special: eventually use argument as is
Object param = getParam(varargIndex).eval(bindings, context);
if (param != null && param.getClass().isArray()) {
if (types[varargIndex].isInstance(param)) {
array = param;
} else { // coerce array elements
length = Array.getLength(param);
array = Array.newInstance(varargType, length);
for (int i = 0; i < length; i++) {
Object elem = Array.get(param, i);
if (elem != null || varargType.isPrimitive()) {
Array.set(array, i, bindings.convert(elem, varargType));
}
}
}
} else { // single element array
array = Array.newInstance(varargType, 1);
if (param != null || varargType.isPrimitive()) {
Array.set(array, 0, bindings.convert(param, varargType));
}
}
} else {
array = Array.newInstance(varargType, length);
for (int i = 0; i < length; i++) {
Object param = getParam(varargIndex + i).eval(bindings, context);
if (param != null || varargType.isPrimitive()) {
Array.set(array, i, bindings.convert(param, varargType));
}
}
}
params[varargIndex] = array;
} else {
for (int i = 0; i < params.length; i++) {
Object param = getParam(i).eval(bindings, context);
if (param != null || types[i].isPrimitive()) {
params[i] = bindings.convert(param, types[i]);
}
}
}
}
return method.invoke(base, params);
}
@Override
public Object eval(Bindings bindings, ELContext context) {
Method method = bindings.getFunction(index);
try {
return invoke(bindings, context, null, method);
} catch (IllegalAccessException e) {
throw new ELException(LocalMessages.get("error.function.access", name), e);
} catch (InvocationTargetException e) {
throw new ELException(LocalMessages.get("error.function.invocation", name), e.getCause());
}
}
@Override
public String toString() {
return name;
}
@Override
public void appendStructure(StringBuilder b, Bindings bindings) {
b.append(bindings != null && bindings.isFunctionBound(index) ? "" : name);
params.appendStructure(b, bindings);
}
public int getIndex() {
return index;
}
public String getName() {
return name;
}
public boolean isVarArgs() {
return varargs;
}
public int getParamCount() {
return params.getCardinality();
}
protected AstNode getParam(int i) {
return params.getChild(i);
}
public int getCardinality() {
return 1;
}
public AstNode getChild(int i) {
return i == 0 ? params : null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy