Advertisement
mbpaster

ReflectionUtils

Apr 30th, 2012
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.35 KB | None | 0 0
  1. /**
  2.  * ReflectionUtils.java
  3.  * Created on Apr 30, 2012
  4.  * Copyright 2012 mb
  5.  * <http://somethingididnotknow.wordpress.com>
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify it under
  8.  * the terms of the GNU General Public License as published by the Free Software
  9.  * Foundation; either version 2 of the License, or (at your option) any later
  10.  * version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful, but WITHOUT
  13.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  14.  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  15.  * details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License along with
  18.  * this program; if not, write to the Free Software Foundation, Inc., 51
  19.  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20.  */
  21.  
  22. import java.lang.reflect.Constructor;
  23. import java.lang.reflect.Field;
  24. import java.lang.reflect.InvocationTargetException;
  25. import java.lang.reflect.Method;
  26. import java.util.Arrays;
  27.  
  28. /**
  29.  * Some utility methods that can be used for unit tests to alter internal
  30.  * objects states by exploiting features from <tt>java.lang.reflect</tt>
  31.  * package.
  32.  *
  33.  * @author mb
  34.  */
  35. public class ReflectionUtils {
  36.  
  37.     /**
  38.      * Sets the value of the <tt>static</tt> field named <tt>fieldName</tt> in
  39.      * class <tt>clazz</tt> to <tt>newValue</tt> and returns <code>true</code>
  40.      * if the operation was successful.
  41.      *
  42.      * @param clazz
  43.      *            the class whose field is to be changed
  44.      * @param fieldName
  45.      *            the (case-sensitive) name of the field whose content is to be
  46.      *            changed
  47.      * @param newValue
  48.      *            the new value that the field should store
  49.      * @return <code>true</code> if the new value has been set,
  50.      *         <code>false</code> otherwise
  51.      */
  52.     public static boolean changeStaticField(Class<?> clazz, String fieldName,
  53.             Object newValue) {
  54.         if (clazz == null)
  55.             return false;
  56.         return change(clazz, null, fieldName, newValue);
  57.     }
  58.  
  59.     private static boolean change(Class<?> clazz, Object object,
  60.             String fieldName, Object newValue) {
  61.         boolean success = false;
  62.         try {
  63.             Field toChange = clazz.getDeclaredField(fieldName);
  64.             toChange.setAccessible(true);
  65.             toChange.set(object, newValue);
  66.             success = true;
  67.         } catch (NoSuchFieldException e) {
  68.             e.printStackTrace();
  69.         } catch (SecurityException e) {
  70.             e.printStackTrace();
  71.         } catch (IllegalArgumentException e) {
  72.             e.printStackTrace();
  73.         } catch (IllegalAccessException e) {
  74.             e.printStackTrace();
  75.         }
  76.         return success;
  77.     }
  78.  
  79.     private static Object call(Class<?> clazz, Object object,
  80.             String methodName, Object... args) throws IllegalArgumentException,
  81.             InvocationTargetException {
  82.         Method[] allMethods = clazz.getDeclaredMethods();
  83.         for (Method m : allMethods) {
  84.             // cycling through all methods, as we don't want users to specify
  85.             // the list of argument types, we rely on the compiler
  86.             if (m.getName().equals(methodName)) {
  87.                 m.setAccessible(true);
  88.                 try {
  89.                     Object result = m.invoke(object, args);
  90.                     return result;
  91.                 } catch (IllegalAccessException e) {
  92.                 } catch (IllegalArgumentException e) {
  93.                 }
  94.             }
  95.         }
  96.         throw new IllegalArgumentException(
  97.                 String.format(
  98.                         "No matching method has been found for method named %s and parameters %s",
  99.                         methodName, Arrays.toString(args)));
  100.     }
  101.  
  102.     /**
  103.      * Invokes the method called <tt>methodName</tt> on <tt>object</tt> passing
  104.      * the provided arguments to it, returning the result if the invocation was
  105.      * successful, throwing an {@link IllegalArgumentException} otherwise.
  106.      *
  107.      * @param object
  108.      *            the object onto which the method is to be invoked
  109.      * @param methodName
  110.      *            the (case-sensitive) name of the method to be called
  111.      * @param args
  112.      *            the arguments to be passed to the method
  113.      * @return the value returned by the method
  114.      * @throws IllegalArgumentException
  115.      *             in case a method called <tt>methodName</tt> accepting the
  116.      *             provided list of arguments is not found, or <tt>object</tt>
  117.      *             is <code>null</code>
  118.      * @throws InvocationTargetException
  119.      *             in case the method threw an exception (that can be retrieved
  120.      *             calling {@link InvocationTargetException#getCause()} on the
  121.      *             caught exception)
  122.      */
  123.     public static Object callMethod(Object object, String methodName,
  124.             Object... args) throws IllegalArgumentException,
  125.             InvocationTargetException {
  126.         if (object == null || methodName == null)
  127.             throw new IllegalArgumentException("null object or method name");
  128.         return call(object.getClass(), object, methodName, args);
  129.     }
  130.  
  131.     /**
  132.      * Invokes the method called <tt>methodName</tt> of class <tt>clazz</tt>
  133.      * passing the provided arguments to it, returning the result if the
  134.      * invocation was successful, throwing an {@link IllegalArgumentException}
  135.      * otherwise.
  136.      *
  137.      * @param clazz
  138.      *            the class whose method is to be invoked
  139.      * @param methodName
  140.      *            the (case-sensitive) name of the method to be called
  141.      * @param args
  142.      *            the arguments to be passed to the method
  143.      * @return the value returned by the method
  144.      * @throws IllegalArgumentException
  145.      *             in case a method called <tt>methodName</tt> accepting the
  146.      *             provided list of arguments is not found, or <tt>object</tt>
  147.      *             is <code>null</code>
  148.      * @throws InvocationTargetException
  149.      *             in case the method threw an exception (that can be retrieved
  150.      *             calling {@link InvocationTargetException#getCause()} on the
  151.      *             caught exception)
  152.      */
  153.     public static Object callStaticMethod(Class<?> clazz, String methodName,
  154.             Object... args) throws IllegalArgumentException,
  155.             InvocationTargetException {
  156.         if (clazz == null || methodName == null)
  157.             throw new IllegalArgumentException("null class or method name");
  158.         return call(clazz, null, methodName, args);
  159.     }
  160.  
  161.     /**
  162.      * Sets the value of the field named <tt>fieldName</tt> for object
  163.      * <tt>object</tt> to <tt>newValue</tt> and returns <code>true</code> if the
  164.      * operation was successful.
  165.      *
  166.      * @param object
  167.      *            the object whose field is to be changed
  168.      * @param fieldName
  169.      *            the (case-sensitive) name of the field whose content is to be
  170.      *            changed
  171.      * @param newValue
  172.      *            the new value that the field should store
  173.      * @return <code>true</code> if the new value has been set,
  174.      *         <code>false</code> otherwise
  175.      */
  176.     public static boolean changeField(Object object, String fieldName,
  177.             Object newValue) {
  178.         if (object == null)
  179.             return false;
  180.         return change(object.getClass(), object, fieldName, newValue);
  181.     }
  182.  
  183.     /**
  184.      * Creates a new object of type <tt>T</tt> by calling a constructor of class
  185.      * <tt>clazz</tt> accepting the provided list of <tt>args</tt>.
  186.      *
  187.      * @param <T>
  188.      *            the type of the object to be created
  189.      * @param clazz
  190.      *            the class of the object to be created (remember, it's
  191.      *            <tt>Class&lt;T&gt;</tt>)
  192.      * @param args
  193.      *            the arguments to feed the constructor with
  194.      * @return the created object or <code>null</code> if anything goes wrong
  195.      * @throws InvocationTargetException
  196.      *             in case the matching constructor throws an <tt>Exception</tt>
  197.      *             (that can be retrieved calling
  198.      *             {@link InvocationTargetException#getCause()} on the caught
  199.      *             exception) when called
  200.      */
  201.     public static <T> T createNew(Class<T> clazz, Object... args)
  202.             throws InvocationTargetException {
  203.         if (clazz == null)
  204.             return null;
  205.         Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
  206.         for (Constructor<?> c : allConstructors) {
  207.             // cycling through all constructors, as we don't want users to
  208.             // specify
  209.             // the list of argument types, we rely on the compiler
  210.             c.setAccessible(true);
  211.             try {
  212.                 Object result = c.newInstance(args);
  213.                 return clazz.cast(result);
  214.             } catch (IllegalAccessException e) {
  215.             } catch (IllegalArgumentException e) {
  216.             } catch (InstantiationException e) {
  217.                 e.printStackTrace();
  218.             }
  219.         }
  220.         throw new IllegalArgumentException(
  221.                 String.format(
  222.                         "No matching constructor has been found for class %s and parameters %s",
  223.                         clazz, Arrays.toString(args)));
  224.     }
  225. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement