YodaUtility.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2013,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.base.utility;
017 
018 import java.lang.reflect.Field;
019 import java.lang.reflect.InvocationTargetException;
020 import java.lang.reflect.Method;
021 
022 
023 /**
024  * We learned so much from the great Jedi master. Using the force we can get and set private
025  * fields of arbitrary objects. We can even execute private methods...
026  *
027  @author  Michael Meyling
028  */
029 public abstract class YodaUtility {
030 
031     /**
032      * Constructor, should never be called.
033      */
034     private YodaUtility() {
035         // don't call me
036     }
037 
038     /**
039      * Analyze if a class or one of its super classes contains a given method.
040      <p>
041      * Example: you can test with <code>YodaUtility.existsMethod("java.net.URLConnection",
042      * "setConnectTimeout", new Class[] {Integer.TYPE}</code> with JDK 1.4.2 and if you run it
043      * with a 1.5 JRE or higher then it will be successfully executed.
044      *
045      @param   clazz           Class to analyze.
046      @param   name            Method name.
047      @param   parameterTypes  Parameter types.
048      @return  Does the class (or one of its super classes) have such a method?
049      */
050     public static boolean existsMethod(final String clazz, final String name,
051             final Class[] parameterTypes) {
052         Class c;
053         try {
054             c = Class.forName(clazz);
055         catch (ClassNotFoundException e) {
056             return false;
057         }
058         return existsMethod(c, name, parameterTypes);
059     }
060 
061     /**
062      * Analyze if a class or one of its super classes contains a given method.
063      <p>
064      * Example: you can test with <code>YodaUtility.existsMethod(URLConnection.class,
065      * "setConnectTimeout", new Class[] {Integer.TYPE}</code> with JDK 1.4.2 and if you run it
066      * with a 1.5 JRE or higher then it will be successfully executed.
067      *
068      @param   clazz           Class to analyze.
069      @param   name            Method name.
070      @param   parameterTypes  Parameter types.
071      @return  Does the class (or one of its super classes) have such a method?
072      */
073     public static boolean existsMethod(final Class clazz, final String name,
074             final Class[] parameterTypes) {
075         Method method = null;
076         Class cl = clazz;
077         try {
078             while (!Object.class.equals(cl)) {
079                 try {
080                     method = cl.getDeclaredMethod(name, parameterTypes);
081                     break;
082                 catch (NoSuchMethodException ex) {
083                     cl = cl.getSuperclass();
084                 }
085             }
086             if (method == null) {
087                 return false;
088             }
089             return true;
090         catch (SecurityException e) {
091             throw new RuntimeException(e);
092         }
093     }
094 
095     /**
096      * This method executes a method on an object or one of its super instances (even if it is
097      * private).
098      <p>
099      * Example: you can compile <code>YodaUtility.executeMethod((URLConnection) httpConnection,
100      * "setConnectTimeout", new Class[] {Integer.TYPE}, new Object[] { new Integer(100)});</code>
101      * with JDK 1.4.2 and if you run it with a 1.5 JRE or higher then it will be successfully
102      * executed.
103      *
104      @param   obj             Object.
105      @param   name            Method name.
106      @param   parameterTypes  Parameter types.
107      @param   parameter       Parameter values.
108      @return  Execution result.
109      @throws  NoSuchMethodException       Method not found.
110      @throws  InvocationTargetException   Wrapped exception.
111      */
112     public static Object executeMethod(final Object obj, final String name,
113             final Class[] parameterTypes, final Object[] parameterthrows NoSuchMethodException,
114             InvocationTargetException {
115         Method method = null;
116         try {
117             Class cl = obj.getClass();
118             while (!Object.class.equals(cl)) {
119                 try {
120                     method = cl.getDeclaredMethod(name, parameterTypes);
121                     break;
122                 catch (NoSuchMethodException ex) {
123                     cl = cl.getSuperclass();
124                 }
125             }
126             if (method == null) {
127                 throw new NoSuchMethodException(name);
128             }
129             method.setAccessible(true);
130         catch (SecurityException e) {
131             throw new RuntimeException(e);
132         }
133         try {
134             return method.invoke(obj, parameter);
135         catch (IllegalArgumentException e) {
136             throw new RuntimeException(e);
137         catch (IllegalAccessException e) {
138             throw new RuntimeException(e);
139         }
140     }
141 
142     /**
143      * This method executes a static class method (even if it is private).
144      <p>
145      * Example: you can compile <code>YodaUtility.executeMethod(
146      * "java.util.concurrent.locks.LockSupport",
147      * "park", new Class[0], new Object[0]);</code>
148      * with JDK 1.4.2 and if you run it with a 1.5 JRE or higher then it will be successfully
149      * executed.
150      *
151      @param   clazzName       Name of class.
152      @param   name            Name of static method to execute.
153      @param   parameterTypes  Parameter types.
154      @param   parameter       Parameter values.
155      @return  Execution result.
156      @throws  NoSuchMethodException       Method not found.
157      @throws  InvocationTargetException   Wrapped exception.
158      */
159     public static Object executeMethod(final String clazzName, final String name,
160             final Class[] parameterTypes, final Object[] parameterthrows NoSuchMethodException,
161             InvocationTargetException {
162         Method method = null;
163         try {
164             Class cl = Class.forName(clazzName);
165             method = cl.getDeclaredMethod(name, parameterTypes);
166             if (method == null) {
167                 throw new NoSuchMethodException(name);
168             }
169             method.setAccessible(true);
170             return method.invoke(cl, parameter);
171         catch (SecurityException e) {
172             throw new RuntimeException(e);
173         catch (ClassNotFoundException e) {
174             throw new RuntimeException(e);
175         catch (IllegalAccessException e) {
176             throw new RuntimeException(e);
177         }
178     }
179 
180     /**
181      * This method returns the contents of an object variable .The class hierarchy is recursively
182      * searched to find such a field (even if it is private).
183      *
184      @param   obj     Object.
185      @param   name    Variable name.
186      @return  Contents of variable.
187      @throws  NoSuchFieldException    Variable of given name was not found.
188      */
189     public static Object getFieldValue(final Object obj, final String namethrows NoSuchFieldException {
190         final Field field = getField(obj, name);
191         try {
192             return field.get(obj);
193         catch (IllegalArgumentException e) {
194             throw new RuntimeException(e);
195         catch (IllegalAccessException e) {
196             throw new RuntimeException(e);
197         }
198     }
199 
200     /**
201      * This method sets the contents of an object variable. The class hierarchy is recursively
202      * searched to find such a field (even if it is private).
203      *
204      @param   obj     Object.
205      @param   name    Variable name.
206      @param   value   Value to set.
207      @throws  NoSuchFieldException    Variable of given name was not found.
208      */
209     public static void setFieldContent(final Object obj, final String name, final Object value)
210             throws NoSuchFieldException {
211         final Field field = getField(obj, name);
212         try {
213             field.set(obj, value);
214         catch (IllegalArgumentException e) {
215             throw new RuntimeException(e);
216         catch (IllegalAccessException e) {
217             throw new RuntimeException(e);
218         }
219     }
220 
221     /**
222      * Get field of given name in given object. The class hierarchy is recursively searched
223      * to find such a field (even if it is private).
224      *
225      @param   obj     Object to work on.
226      @param   name    Search this field.
227      @return  Found field.
228      @throws  NoSuchFieldException    Field with name <code>name</code> was not found.
229      */
230     public static Field getField(final Object obj, final String namethrows NoSuchFieldException {
231         Field field = null;
232         try {
233             Class cl = obj.getClass();
234             while (!Object.class.equals(cl)) {
235                 try {
236                     field = cl.getDeclaredField(name);
237                     break;
238                 catch (NoSuchFieldException ex) {
239                     cl = cl.getSuperclass();
240                 }
241             }
242             if (field == null) {
243                 throw (new NoSuchFieldException(name + " within " + obj.getClass()));
244             }
245             field.setAccessible(true);
246         catch (SecurityException e) {
247             throw new RuntimeException(e);
248         }
249         return field;
250     }
251 
252 }