/* * Copyright (C) 2014-2015 CS SI * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.snap.utils; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * a.k.a. The "ObjectMolester" * <p> * This class is used to access a method or field of an object no matter what * the access modifier of the method or field. The syntax for accessing fields * and methods is out of the ordinary because this class uses reflection to peel * away protection. * <p> * Here is an example of using this to access a private member. * <code>resolveName</code> is a private method of <code>Class</code>. * * <pre> * Class c = Class.class; * System.out.println(PrivilegedAccessor.invokeMethod(c, "resolveName","/ise/library/PrivilegedAccessor")); * </pre> * * @author Charlie Hubbard (chubbard@iss.net) * @author Prashant Dhokte (pdhokte@iss.net) * @author Dale Anson (danson@germane-software.com) */ public class PrivilegedAccessor { /** * Gets the value of the named field and returns it as an object. * * @param instance the object instance * @param fieldName the name of the field * @return an object representing the value of the field */ public static Object getValue(Object instance, String fieldName) throws IllegalAccessException, NoSuchFieldException { Field field = getField(instance.getClass(), fieldName); field.setAccessible(true); return field.get(instance); } public static void setValue(Object instance, String fieldName, Object value) throws IllegalAccessException, NoSuchFieldException { Field field = getField(instance.getClass(), fieldName); field.setAccessible(true); field.set(instance, value); } /** * Gets the value of the named static field and returns it as an object. * * @param c the class containing the static field * @param fieldName the name of the field * @return an object representing the value of the field */ public static Object getStaticValue(Class c, String fieldName) throws IllegalAccessException, NoSuchFieldException { Field field = getField(c, fieldName); field.setAccessible(true); return field.get(null); } /** * Calls a method on the given object instance with the given argument. * * @param instance the object instance * @param methodName the name of the method to invoke * @param arg the argument to pass to the method * @see PrivilegedAccessor#invokeMethod(Object,String,Object[]) */ public static Object invokeMethod(Object instance, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object[] args = new Object[1]; args[0] = arg; return invokeMethod(instance, methodName, args); } /** * Calls a method on the given object instance with the given arguments. * * @param instance the object instance * @param methodName the name of the method to invoke * @param args an array of objects to pass as arguments * @see PrivilegedAccessor#invokeMethod(Object,String,Object) */ public static Object invokeMethod(Object instance, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (args == null) args = new Object[] {}; Class[] classTypes = getClassArray(args); Method[] methods = instance.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; Class[] paramTypes = method.getParameterTypes(); if (method.getName().equals(methodName) && compare(paramTypes, args)) { return method.invoke(instance, args); } } StringBuffer sb = new StringBuffer(); sb.append("No method named ").append(methodName).append(" found in ") .append(instance.getClass().getName()).append(" with parameters ("); for (int x = 0; x < classTypes.length; x++) { sb.append(classTypes[x].getName()); if (x < classTypes.length - 1) { sb.append(", "); } } sb.append(")"); throw new NoSuchMethodException(sb.toString()); } /** * Converts the object array to an array of Classes. * * @param args the object array to convert * @return a Class array */ private static Class[] getClassArray(Object[] args) { Class[] classTypes = null; if (args != null) { classTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { if (args[i] != null) classTypes[i] = args[i].getClass(); } } return classTypes; } /** * Gets the named method with a method signature matching classTypes from the given insance * and returns it as an object. * @param instance the object instance * @param methodName the method name * @param classTypes the method argument types */ public static Method getMethod(Object instance, String methodName, Class[] classTypes) throws NoSuchMethodException { Method accessMethod = getMethod(instance.getClass(), methodName, classTypes); accessMethod.setAccessible(true); return accessMethod; } /** * Return the named field from the given class. * @param thisClass The class * @param fieldName The field name */ public static Field getField(Class thisClass, String fieldName) throws NoSuchFieldException { if (thisClass == null) throw new NoSuchFieldException("Invalid field : " + fieldName); try { return thisClass.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { return getField(thisClass.getSuperclass(), fieldName); } } /** * Return the named method with a method signature matching classTypes from the given class. * @param thisClass the class containing the method * @param methodName the name of the method * @param classTypes the method argument types */ public static Method getMethod(Class thisClass, String methodName, Class[] classTypes) throws NoSuchMethodException { if (thisClass == null) throw new NoSuchMethodException("Invalid method : " + methodName); try { return thisClass.getDeclaredMethod(methodName, classTypes); } catch (NoSuchMethodException e) { return getMethod(thisClass.getSuperclass(), methodName, classTypes); } } private static boolean compare(Class[] c, Object[] args) { if (c.length != args.length) { return false; } for (int i = 0; i < c.length; i++) { if (!c[i].isInstance(args[i])) { return false; } } return true; } /** * Creates a new instance of the named class initialized with the given arguments. * * @param classname the name of the class to instantiate. * @param args the arguments to pass as parameters to the constructor of the class. * @return the instantiated object */ public static Object getNewInstance(String classname, Object[] args) throws ClassNotFoundException, InstantiationException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (classname == null) throw new ClassNotFoundException(); if (args == null) args = new Object[] {}; Class[] classTypes = getClassArray(args); Class c = Class.forName(classname); Constructor[] constructors = c.getConstructors(); for (int i = 0; i < constructors.length; i++) { Constructor constructor = constructors[i]; Class[] paramTypes = constructor.getParameterTypes(); if (compare(paramTypes, args)) { return constructor.newInstance(args); } } StringBuffer sb = new StringBuffer(); sb.append("No constructor found for ").append(classname).append(" with parameters ("); for (int x = 0; x < classTypes.length; x++) { sb.append(classTypes[x].getName()); if (x < classTypes.length - 1) sb.append(", "); } sb.append(")"); throw new NoSuchMethodException(sb.toString()); } }