AbstractDelegate.java

package autumn.lang.internals;

import autumn.lang.Delegate;
import com.google.common.base.Objects;
import com.mackenziehigh.autumn.resources.Finished;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
 * This class provides a partial implementation of the Delegate interface.
 *
 * @author Mackenzie High
 */
@Finished("2014/07/12")
public abstract class AbstractDelegate
        extends AbstractTypedFunctor
        implements Delegate
{
    private Method cache;

    /**
     * {@inheritDoc}
     */
    @Override
    public Method method()
    {
        // This result of this method is memoized in order in order to improve performance.
        if (cache != null)
        {
            return cache;
        }

        /**
         * Delegates always refer to public static methods.
         * Simply find a static method with a matching name and parameter list.
         */
        for (Method m : owner().getMethods())
        {
            if (isMatchingMethod(m))
            {
                return cache = m;
            }
        }

        throw new RuntimeException("This should never happen.");
    }

    /**
     * This method determines whether this delegate's name and parameters match those of a method.
     *
     * @param method is the possibly matching method.
     * @return true, iff this delegate matches the method.
     */
    private boolean isMatchingMethod(final Method method)
    {
        // Does the name match?
        if (!Objects.equal(method.getName(), this.name()))
        {
            return false;
        }

        // Does the parameter-list match?
        if (!Objects.equal(this.parameterTypes(), Arrays.asList(method.getParameterTypes())))
        {
            return false;
        }

        // The name and the parameter-list both match.
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString()
    {
        final Method m = this.method(); // TODO: should this be needed?

        final StringBuilder result = new StringBuilder();

        result.append("delegate ");

        result.append(owner().getSimpleName());

        result.append(Modifier.isStatic(m.getModifiers()) ? "::" : "."); // TODO: does this need changed?

        result.append(name());

        result.append('(');

        int i = 0;

        for (Class param : parameterTypes())
        {
            result.append(param.getSimpleName());

            result.append(i++ < parameterTypes().size() - 1 ? ", " : "");
        }

        result.append(')');

        return result.toString();
    }
}