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     */
013    package cpw.mods.fml.relauncher;
014    
015    import java.lang.reflect.Field;
016    import java.lang.reflect.Method;
017    /**
018     * Some reflection helper code.
019     *
020     * @author cpw
021     *
022     */
023    public 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    }