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}