Java tutorial
/* * Copyright (C) 2010-2015, Danilo Pianini and contributors * listed in the project's pom.xml file. * * This file is part of Alchemist, and is distributed under the terms of * the GNU General Public License, with a linking exception, as described * in the file LICENSE in the Alchemist distribution's top directory. */ package it.unibo.alchemist.language.protelis; import it.unibo.alchemist.language.protelis.datatype.Field; import it.unibo.alchemist.language.protelis.datatype.Fields; import it.unibo.alchemist.language.protelis.interfaces.AnnotatedTree; import it.unibo.alchemist.language.protelis.java7.functionals.BiFunction; import it.unibo.alchemist.language.protelis.java7.streams.Stream; import it.unibo.alchemist.language.protelis.util.ReflectionUtils; import it.unibo.alchemist.language.protelis.vm.ExecutionContext; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.apache.commons.lang3.ArrayUtils; /** * @author Danilo Pianini * */ public class MethodCall extends AbstractAnnotatedTree<Object> { private static final long serialVersionUID = -2299070628855971997L; private transient Method method; private final boolean fieldComposable; private final boolean ztatic; /** * @param m * the method to call * @param branch * the Protelis sub-programs * @param isStatic * if false, the first branch must contain the AnnotatedTree whose * annotation will contain the object on which the method will be * invoked */ public MethodCall(final Method m, final List<AnnotatedTree<?>> branch, final boolean isStatic) { super(branch); Objects.requireNonNull(m, "No compatible method found."); method = m; ztatic = isStatic; boolean found = false; for (Class<?> clazz : method.getParameterTypes()) { if (Field.class.isAssignableFrom(clazz)) { found = true; break; } } fieldComposable = !found; } @Override public void eval(final ExecutionContext context) { projectAndEval(context); // Obtain target and arguments final Object target = ztatic ? null : getBranch(0).getAnnotation(); final Stream<?> s = getBranchesAnnotationStream(); final Object[] args = ztatic ? s.toArray() : s.skip(1).toArray(); /* * Check if any of the parameters is a field */ if (fieldComposable) { final boolean fieldTarget = target == null ? false : Field.class.isAssignableFrom(target.getClass()); List<Integer> list = new ArrayList<>(); for (Object o : args) { if (Field.class.isAssignableFrom(o.getClass())) { list.add(ArrayUtils.indexOf(args, o)); } } final int[] fieldIndexes = new int[list.size()]; for (Integer i : list) { fieldIndexes[i] = list.get(i); } // End if (fieldTarget || fieldIndexes.length > 0) { setAnnotation(Fields.apply(new BiFunction<Object, Object[], Object>() { @Override public Object apply(Object actualT, Object[] actualA) { return ReflectionUtils.invokeMethod(method, actualT, actualA); } }, fieldTarget, fieldIndexes, target, args)); return; } } setAnnotation(ReflectionUtils.invokeMethod(method, target, args)); } /** * @return the method return type */ public Class<?> getReturnType() { return method.getReturnType(); } @Override public MethodCall copy() { return new MethodCall(method, deepCopyBranches(), ztatic); } @Override protected void asString(final StringBuilder sb, final int i) { sb.append(method.getName()); sb.append('/'); // TODO: Workaround for different Method API sb.append(method.getParameterTypes().length); sb.append(" ("); fillBranches(sb, i, ','); sb.append(')'); } private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeObject(method.getDeclaringClass()); out.writeUTF(method.getName()); out.writeObject(method.getParameterTypes()); } private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); final Class<?> declaringClass = (Class<?>) in.readObject(); final String methodName = in.readUTF(); final Class<?>[] parameterTypes = (Class<?>[]) in.readObject(); try { method = declaringClass.getMethod(methodName, parameterTypes); } catch (Exception e) { throw new IOException(String.format("Error occurred resolving deserialized method '%s.%s'", declaringClass.getSimpleName(), methodName), e); } } }