Code Pretty Print Script

Friday, November 15, 2013

Reflections

Are you working with Java Reflection? Having trouble invoking your methods through reflection? Wish there was a simple way to call an arbitrary method on an object?
Swans Reflecting Elephants - Dali
Swans Reflecting Elephants (1937) - Dali
/*
 * Copyright © 2013 - Elliott Frisch
 * 
 * THIS SOFTWARE IS PROVIDED UNDER THE CREATIVE COMMONS
 * LICENSE 3.0 "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
 * A PARTICULAR PURPOSE.
 * 
 * To use this software you must agree to the complete
 * license terms available at:
 * http://creativecommons.org/licenses/by/3.0/us/deed.en_US
 * 
 * It is the intent of the author(s) that you may use or
 * modify this software for any purpose (including your own
 * commercial gain) provided that this notice remains in its
 * entirety.
 * 
 * Created by Elliott Frisch - www.frischcode.com
 */
package com.frischcode.util;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.math.BigDecimal;

/**
 * <b>Rationale:</b> Provide a mechanism to generically call
 * a method.
 * 
 * @author Elliott Frisch
 */
public class MethodUtil {
  /**
   * Returns the size (or length) of an array.
   * 
   * @param obj
   *          The Array to find the size of .
   * @return The length of the array (if object is an
   *         array), or 0.
   */
  private static int safeSize(Object obj) {
    if (obj != null) {
      return Array.getLength(obj);
    }
    return 0;
  }

  /**
   * If it exists, invoke methodName on receiver - passing
   * parameters (if they exist) as arguments. If
   * receiver.methodName(parameters) returns, return the
   * returned value.
   * 
   * @param receiver
   *          The receiver to invoke.
   * @param methodName
   *          The name of the method to call.
   * @param parameters
   *          The arguments to pass to the method.
   * @return The value returned from invoking methodName on
   *         receiver.
   * @throws Exception
   *           Any Exception thrown by invoking the method
   *           with the passed parameters.
   */
  public static Object callMethod(Object receiver,
      String methodName, Object... parameters)
      throws Exception {
    if (receiver == null || methodName == null) {
      return null;
    }
    methodName = methodName.trim();
    if (methodName.length() == 0) {
      return null;
    }
    Class<?> cls = receiver.getClass();
    Method toInvoke = null;
    outer: for (Method method : cls.getMethods()) {
      if (!methodName.equals(method.getName())) {
        continue;
      }
      Class<?>[] mTypes = method.getParameterTypes();
      if (parameters == null && mTypes == null) {
        toInvoke = method;
        break;
      } else if (safeSize(mTypes) == 0
          || safeSize(parameters) == 0) {
        continue;
      } else if (safeSize(mTypes) != safeSize(parameters)) {
        continue;
      }

      for (int i = 0; i < mTypes.length; ++i) {
        if (!mTypes[i].isAssignableFrom(parameters[i]
            .getClass())) {
          continue outer;
        }
      }
      toInvoke = method;
      break;
    }
    if (toInvoke != null) {
      try {
        return toInvoke.invoke(receiver, parameters);
      } catch (Exception t) {
        throw t;
      }
    }
    return null;
  }

  /**
   * A small sample program. Prints 100. Prints 200.
   * 
   * @param args
   */
  public static void main(String[] args) {
    try {
      BigDecimal a = new BigDecimal("99");
      a = (BigDecimal) callMethod(a, "add",
          new BigDecimal("1"));
      System.out.println(a);
      System.out.println(callMethod(a, "multiply",
          new BigDecimal("2")));
      System.out.flush();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}