package calculator.interpreter.annotations; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import net.sf.etl.parsers.SourceLocation; import calculator.interpreter.AnnotationValue; import calculator.interpreter.Environment; import calculator.interpreter.EvalException; import calculator.interpreter.EvalUtils; import calculator.interpreter.Function; import calculator.interpreter.Variable; /** * The java method annotation */ public class JavaMethodAnnotation extends JavaReflectionProcessor { /** {@inheritDoc} */ public void process(AnnotationValue annotation, Environment env, Variable var) { if (annotation.arguments.size() < 2) { throw new EvalException(annotation.location, "Wrong number of the arguments for annotation expected at least 2 and found " + annotation.arguments); } Class<?> c = getClass(annotation, 0); String methodName = EvalUtils.expectString(annotation.location, "the field name (the argument " + 1 + ")", annotation.arguments.get(1)); Class<?>[] parameterTypes = new Class[annotation.arguments.size() - 2]; for (int i = 0; i < annotation.arguments.size() - 2; i++) { parameterTypes[i] = getClass(annotation, i + 2); } try { Method method = c.getMethod(methodName, parameterTypes); var.bind(annotation.location, new MethodFunction(method)); } catch (Exception e) { throw new EvalException(annotation.location, "The method " + methodName + " cannot be located: " + e); } } /** * The method based function */ private static class MethodFunction extends Function { /** the method to invoke */ private final Method method; /** the arity of the method */ private final int arity; /** the static modifier */ private final boolean isStatic; /** * The constructor * * @param method the wrapped method */ public MethodFunction(Method method) { this.method = method; isStatic = Modifier.isStatic(method.getModifiers()); arity = method.getParameterTypes().length + (isStatic ? 0 : 1); } @Override public Object apply(SourceLocation location, List<Object> args) { assert args.size() == arity; Object[] a = (isStatic ? args : args.subList(1, arity)).toArray(); Object t = isStatic ? null : args.get(0); try { return method.invoke(t, a); } catch (Exception e) { throw new EvalException(location, "The method " + method + " cannot be invoked: " + e); } } @Override public int arity() { return arity; } } }