    001/*
    002 * The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
    003 *
    004 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
    005 * Software Foundation; either version 2.1 of the License, or any later version.
    006 *
    007 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    008 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
    009 *
    010 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
    011 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    012 */
    013package cpw.mods.fml.relauncher;
    014
    015import java.lang.reflect.Field;
    016import java.lang.reflect.Method;
    017/**
    018 * Some reflection helper code.
    019 *
    020 * @author cpw
    021 *
    022 */
    023public class ReflectionHelper
    024{
    025    public static class UnableToFindMethodException extends RuntimeException
    026    {
    027        private String[] methodNames;
    028
    029        public UnableToFindMethodException(String[] methodNames, Exception failed)
    030        {
    031            super(failed);
    032            this.methodNames = methodNames;
    033        }
    034
    035    }
    036
    037    public static class UnableToFindClassException extends RuntimeException
    038    {
    039        private String[] classNames;
    040
    041        public UnableToFindClassException(String[] classNames, Exception err)
    042        {
    043            super(err);
    044            this.classNames = classNames;
    045        }
    046
    047    }
    048
    049    public static class UnableToAccessFieldException extends RuntimeException
    050    {
    051
    052        private String[] fieldNameList;
    053
    054        public UnableToAccessFieldException(String[] fieldNames, Exception e)
    055        {
    056            super(e);
    057            this.fieldNameList = fieldNames;
    058        }
    059    }
    060
    061    public static class UnableToFindFieldException extends RuntimeException
    062    {
    063        private String[] fieldNameList;
    064        public UnableToFindFieldException(String[] fieldNameList, Exception e)
    065        {
    066            super(e);
    067            this.fieldNameList = fieldNameList;
    068        }
    069    }
    070
    071    public static Field findField(Class<?> clazz, String... fieldNames)
    072    {
    073        Exception failed = null;
    074        for (String fieldName : fieldNames)
    075        {
    076            try
    077            {
    078                Field f = clazz.getDeclaredField(fieldName);
    079                f.setAccessible(true);
    080                return f;
    081            }
    082            catch (Exception e)
    083            {
    084                failed = e;
    085            }
    086        }
    087        throw new UnableToFindFieldException(fieldNames, failed);
    088    }
    089
    090    @SuppressWarnings("unchecked")
    091    public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, int fieldIndex)
    092    {
    093        try
    094        {
    095            Field f = classToAccess.getDeclaredFields()[fieldIndex];
    096            f.setAccessible(true);
    097            return (T) f.get(instance);
    098        }
    099        catch (Exception e)
    100        {
    101            throw new UnableToAccessFieldException(new String[0], e);
    102        }
    103    }
    104
    105    @SuppressWarnings("unchecked")
    106    public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, String... fieldNames)
    107    {
    108        try
    109        {
    110            return (T) findField(classToAccess, fieldNames).get(instance);
    111        }
    112        catch (Exception e)
    113        {
    114            throw new UnableToAccessFieldException(fieldNames, e);
    115        }
    116    }
    117
    118    public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, int fieldIndex)
    119    {
    120        try
    121        {
    122            Field f = classToAccess.getDeclaredFields()[fieldIndex];
    123            f.setAccessible(true);
    124            f.set(instance, value);
    125        }
    126        catch (Exception e)
    127        {
    128            throw new UnableToAccessFieldException(new String[0] , e);
    129        }
    130    }
    131
    132    public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, String... fieldNames)
    133    {
    134        try
    135        {
    136            findField(classToAccess, fieldNames).set(instance, value);
    137        }
    138        catch (Exception e)
    139        {
    140            throw new UnableToAccessFieldException(fieldNames, e);
    141        }
    142    }
    143
    144    public static Class<? super Object> getClass(ClassLoader loader, String... classNames)
    145    {
    146        Exception err = null;
    147        for (String className : classNames)
    148        {
    149            try
    150            {
    151                return (Class<? super Object>) Class.forName(className, false, loader);
    152            }
    153            catch (Exception e)
    154            {
    155                err = e;
    156            }
    157        }
    158
    159        throw new UnableToFindClassException(classNames, err);
    160    }
    161
    162
    163    public static <E> Method findMethod(Class<? super E> clazz, E instance, String[] methodNames, Class<?>... methodTypes)
    164    {
    165        Exception failed = null;
    166        for (String methodName : methodNames)
    167        {
    168            try
    169            {
    170                Method m = clazz.getDeclaredMethod(methodName, methodTypes);
    171                m.setAccessible(true);
    172                return m;
    173            }
    174            catch (Exception e)
    175            {
    176                failed = e;
    177            }
    178        }
    179        throw new UnableToFindMethodException(methodNames, failed);
    180    }
    181}