YodaUtility.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2011,  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         if (c == null) {
059             return false;
060         }
061         return existsMethod(c, name, parameterTypes);
062     }
063 
064     /**
065      * Analyze if a class or one of its super classes contains a given method.
066      <p>
067      * Example: you can test with <code>YodaUtility.existsMethod(URLConnection.class,
068      * "setConnectTimeout", new Class[] {Integer.TYPE}</code> with JDK 1.4.2 and if you run it
069      * with a 1.5 JRE or higher then it will be successfully executed.
070      *
071      @param   clazz           Class to analyze.
072      @param   name            Method name.
073      @param   parameterTypes  Parameter types.
074      @return  Does the class (or one of its super classes) have such a method?
075      */
076     public static boolean existsMethod(final Class clazz, final String name,
077             final Class[] parameterTypes) {
078         Method method = null;
079         Class cl = clazz;
080         try {
081             while (!Object.class.equals(cl)) {
082                 try {
083                     method = cl.getDeclaredMethod(name, parameterTypes);
084                     break;
085                 catch (NoSuchMethodException ex) {
086                     cl = cl.getSuperclass();
087                 }
088             }
089             if (method == null) {
090                 return false;
091             }
092             return true;
093         catch (SecurityException e) {
094             throw new RuntimeException(e);
095         }
096     }
097 
098     /**
099      * This method executes a method on an object or one of its super instances (even if it is
100      * private).
101      <p>
102      * Example: you can compile <code>YodaUtility.executeMethod((URLConnection) httpConnection,
103      * "setConnectTimeout", new Class[] {Integer.TYPE}, new Object[] { new Integer(100)});</code>
104      * with JDK 1.4.2 and if you run it with a 1.5 JRE or higher then it will be successfully
105      * executed.
106      *
107      @param   obj             Object.
108      @param   name            Method name.
109      @param   parameterTypes  Parameter types.
110      @param   parameter       Parameter values.
111      @return  Execution result.
112      @throws  NoSuchMethodException       Method not found.
113      @throws  InvocationTargetException   Wrapped exception.
114      */
115     public static Object executeMethod(final Object obj, final String name,
116             final Class[] parameterTypes, final Object[] parameterthrows NoSuchMethodException,
117             InvocationTargetException {
118         Method method = null;
119         try {
120             Class cl = obj.getClass();
121             while (!Object.class.equals(cl)) {
122                 try {
123                     method = cl.getDeclaredMethod(name, parameterTypes);
124                     break;
125                 catch (NoSuchMethodException ex) {
126                     cl = cl.getSuperclass();
127                 }
128             }
129             if (method == null) {
130                 throw new NoSuchMethodException(name);
131             }
132             method.setAccessible(true);
133         catch (SecurityException e) {
134             throw new RuntimeException(e);
135         }
136         try {
137             return method.invoke(obj, parameter);
138         catch (IllegalArgumentException e) {
139             throw new RuntimeException(e);
140         catch (IllegalAccessException e) {
141             throw new RuntimeException(e);
142         }
143     }
144 
145     /**
146      * This method executes a static class method (even if it is private).
147      <p>
148      * Example: you can compile <code>YodaUtility.executeMethod(
149      * "java.util.concurrent.locks.LockSupport",
150      * "park", new Class[0], new Object[0]);</code>
151      * with JDK 1.4.2 and if you run it with a 1.5 JRE or higher then it will be successfully
152      * executed.
153      *
154      @param   clazzName       Name of class.
155      @param   name            Name of static method to execute.
156      @param   parameterTypes  Parameter types.
157      @param   parameter       Parameter values.
158      @return  Execution result.
159      @throws  NoSuchMethodException       Method not found.
160      @throws  InvocationTargetException   Wrapped exception.
161      */
162     public static Object executeMethod(final String clazzName, final String name,
163             final Class[] parameterTypes, final Object[] parameterthrows NoSuchMethodException,
164             InvocationTargetException {
165         Method method = null;
166         try {
167             Class cl = Class.forName(clazzName);
168             method = cl.getDeclaredMethod(name, parameterTypes);
169             if (method == null) {
170                 throw new NoSuchMethodException(name);
171             }
172             method.setAccessible(true);
173             return method.invoke(cl, parameter);
174         catch (SecurityException e) {
175             throw new RuntimeException(e);
176         catch (ClassNotFoundException e) {
177             throw new RuntimeException(e);
178         catch (IllegalAccessException e) {
179             throw new RuntimeException(e);
180         }
181     }
182 
183     /**
184      * This method returns the contents of an object variable .The class hierarchy is recursively
185      * searched to find such a field (even if it is private).
186      *
187      @param   obj     Object.
188      @param   name    Variable name.
189      @return  Contents of variable.
190      @throws  NoSuchFieldException    Variable of given name was not found.
191      */
192     public static Object getFieldValue(final Object obj, final String namethrows NoSuchFieldException {
193         final Field field = getField(obj, name);
194         try {
195             return field.get(obj);
196         catch (IllegalArgumentException e) {
197             throw new RuntimeException(e);
198         catch (IllegalAccessException e) {
199             throw new RuntimeException(e);
200         }
201     }
202 
203     /**
204      * This method sets the contents of an object variable. The class hierarchy is recursively
205      * searched to find such a field (even if it is private).
206      *
207      @param   obj     Object.
208      @param   name    Variable name.
209      @param   value   Value to set.
210      @throws  NoSuchFieldException    Variable of given name was not found.
211      */
212     public static void setFieldContent(final Object obj, final String name, final Object value)
213             throws NoSuchFieldException {
214         final Field field = getField(obj, name);
215         try {
216             field.set(obj, value);
217         catch (IllegalArgumentException e) {
218             throw new RuntimeException(e);
219         catch (IllegalAccessException e) {
220             throw new RuntimeException(e);
221         }
222     }
223 
224     /**
225      * Get field of given name in given object. The class hierarchy is recursively searched
226      * to find such a field (even if it is private).
227      *
228      @param   obj     Object to work on.
229      @param   name    Search this field.
230      @return  Found field.
231      @throws  NoSuchFieldException    Field with name <code>name</code> was not found.
232      */
233     public static Field getField(final Object obj, final String namethrows NoSuchFieldException {
234         Field field = null;
235         try {
236             Class cl = obj.getClass();
237             while (!Object.class.equals(cl)) {
238                 try {
239                     field = cl.getDeclaredField(name);
240                     break;
241                 catch (NoSuchFieldException ex) {
242                     cl = cl.getSuperclass();
243                 }
244             }
245             if (field == null) {
246                 throw (new NoSuchFieldException(name + " within " + obj.getClass()));
247             }
248             field.setAccessible(true);
249         catch (SecurityException e) {
250             throw new RuntimeException(e);
251         }
252         return field;
253     }
254 
255 }