| Class | Line # | Actions | |||
|---|---|---|---|---|---|
| PA | 67 | 32 | 24 |
| 1 | /* | |
| 2 | * Copyright 2004-2012 Sebastian Dietrich (Sebastian.Dietrich@e-movimento.com) | |
| 3 | * | |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 5 | * you may not use this file except in compliance with the License. | |
| 6 | * You may obtain a copy of the License at | |
| 7 | * | |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 | * | |
| 10 | * Unless required by applicable law or agreed to in writing, software | |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 13 | * See the License for the specific language governing permissions and | |
| 14 | * limitations under the License. | |
| 15 | */ | |
| 16 | package junit.extensions; | |
| 17 | ||
| 18 | import java.util.Collection; | |
| 19 | ||
| 20 | /** | |
| 21 | * This class is used to access a method or field of an object no matter what | |
| 22 | * the access modifier of the method or field. The syntax for accessing fields | |
| 23 | * and methods is out of the ordinary because this class uses reflection to peel | |
| 24 | * away protection. | |
| 25 | * <p> | |
| 26 | * a.k.a. The "ObjectMolester" | |
| 27 | * <p> | |
| 28 | * Here is an example of using this to access a private member: <br> | |
| 29 | * Given the following class <code>MyClass</code>: <br> | |
| 30 | * | |
| 31 | * <pre> | |
| 32 | * public class MyClass | |
| 33 | * { | |
| 34 | * private String name; // private attribute | |
| 35 | * | |
| 36 | * // private constructor | |
| 37 | * private MyClass() | |
| 38 | * { | |
| 39 | * super(); | |
| 40 | * } | |
| 41 | * | |
| 42 | * // private method | |
| 43 | * private void setName(String newName) | |
| 44 | * { | |
| 45 | * this.name = newName; | |
| 46 | * } | |
| 47 | * } | |
| 48 | * </pre> | |
| 49 | * | |
| 50 | * We now want to access the class: <br> | |
| 51 | * | |
| 52 | * <pre> | |
| 53 | * MyClass myObj = PA.instantiate(MyClass.class); | |
| 54 | * PA.invokeMethod(myObj, "setName(java.lang.String)", "myNewName"); | |
| 55 | * String name = PA.getValue(myObj, "name"); | |
| 56 | * </pre> | |
| 57 | * | |
| 58 | * This class extends {@link PrivilegedAccessor} by re-throwing checked | |
| 59 | * {@link Exception}s as {@link RuntimeException}s. | |
| 60 | * | |
| 61 | * | |
| 62 | * @see PrivilegedAccessor | |
| 63 | * | |
| 64 | * @author Sebastian Dietrich (sebastian.dietrich@e-movimento.com) | |
| 65 | * @author Lubos Bistak (lubos@bistak.sk) | |
| 66 | */ | |
| 67 | public class PA | |
| 68 | { | |
| 69 | private final Object instanceOrClass; | |
| 70 | ||
| 71 | /** | |
| 72 | * Private constructor to make it impossible to instantiate this class from | |
| 73 | * outside of PA. | |
| 74 | * | |
| 75 | * @param instanceOrClass | |
| 76 | */ | |
| 77 | 17 | private PA(Object instanceOrClass) |
| 78 | { | |
| 79 | 17 | this.instanceOrClass = instanceOrClass; |
| 80 | } | |
| 81 | ||
| 82 | /** | |
| 83 | * Returns a string representation of the given object. The string has the | |
| 84 | * following format: "<classname> {<attributes and values>}" whereas | |
| 85 | * <attributes and values> is a comma separated list with | |
| 86 | * <attributeName>=<attributeValue> <atributes and values> includes all | |
| 87 | * attributes of the objects class followed by the attributes of its | |
| 88 | * superclass (if any) and so on. | |
| 89 | * | |
| 90 | * @param instanceOrClass | |
| 91 | * the object or class to get a string representation of | |
| 92 | * @return a string representation of the given object | |
| 93 | * | |
| 94 | * @see PrivilegedAccessor#toString(Object) | |
| 95 | */ | |
| 96 | 0 | public static String toString(final Object instanceOrClass) |
| 97 | { | |
| 98 | 0 | return PrivilegedAccessor.toString(instanceOrClass); |
| 99 | } | |
| 100 | ||
| 101 | /** | |
| 102 | * Gets the name of all fields (public, private, protected, default) of the | |
| 103 | * given instance or class. This includes as well all fields (public, private, | |
| 104 | * protected, default) of all its super classes. | |
| 105 | * | |
| 106 | * @param instanceOrClass | |
| 107 | * the instance or class to get the fields of | |
| 108 | * @return the collection of field names of the given instance or class | |
| 109 | * | |
| 110 | * @see PrivilegedAccessor#getFieldNames(Object) | |
| 111 | */ | |
| 112 | 0 | public static Collection<String> getFieldNames( |
| 113 | final Object instanceOrClass) | |
| 114 | { | |
| 115 | 0 | return PrivilegedAccessor.getFieldNames(instanceOrClass); |
| 116 | } | |
| 117 | ||
| 118 | /** | |
| 119 | * Gets the signatures of all methods (public, private, protected, default) of | |
| 120 | * the given instance or class. This includes as well all methods (public, | |
| 121 | * private, protected, default) of all its super classes. This does not | |
| 122 | * include constructors. | |
| 123 | * | |
| 124 | * @param instanceOrClass | |
| 125 | * the instance or class to get the method signatures of | |
| 126 | * @return the collection of method signatures of the given instance or class | |
| 127 | * | |
| 128 | * @see PrivilegedAccessor#getMethodSignatures(Object) | |
| 129 | */ | |
| 130 | 0 | public static Collection<String> getMethodSignatures( |
| 131 | final Object instanceOrClass) | |
| 132 | { | |
| 133 | 0 | return PrivilegedAccessor.getMethodSignatures(instanceOrClass); |
| 134 | } | |
| 135 | ||
| 136 | /** | |
| 137 | * Gets the value of the named field and returns it as an object. If | |
| 138 | * instanceOrClass is a class then a static field is returned. | |
| 139 | * | |
| 140 | * @param instanceOrClass | |
| 141 | * the instance or class to get the field from | |
| 142 | * @param fieldName | |
| 143 | * the name of the field | |
| 144 | * @return an object representing the value of the field | |
| 145 | * @throws IllegalArgumentException | |
| 146 | * if the field does not exist | |
| 147 | * | |
| 148 | * @see PrivilegedAccessor#getValue(Object,String) | |
| 149 | */ | |
| 150 | 174 | public static Object getValue(final Object instanceOrClass, |
| 151 | final String fieldName) | |
| 152 | { | |
| 153 | 174 | try |
| 154 | { | |
| 155 | 174 | return PrivilegedAccessor.getValue(instanceOrClass, fieldName); |
| 156 | } catch (Exception e) | |
| 157 | { | |
| 158 | 0 | throw new IllegalArgumentException("Can't get value of " + fieldName |
| 159 | + " from " + instanceOrClass, e); | |
| 160 | } | |
| 161 | } | |
| 162 | ||
| 163 | /** | |
| 164 | * Gets the value of the named field and returns it as an object. | |
| 165 | * | |
| 166 | * @param fieldName | |
| 167 | * the name of the field | |
| 168 | * @return an object representing the value of the field | |
| 169 | * @throws IllegalArgumentException | |
| 170 | * if the field does not exist | |
| 171 | * | |
| 172 | * @see PA#getValue(Object,String) | |
| 173 | */ | |
| 174 | 0 | public Object getValue(final String fieldName) |
| 175 | { | |
| 176 | 0 | return PA.getValue(instanceOrClass, fieldName); |
| 177 | } | |
| 178 | ||
| 179 | /** | |
| 180 | * Instantiates an object of the given class with the given arguments and the | |
| 181 | * given argument types. If you want to instantiate a member class, you must | |
| 182 | * provide the object it is a member of as first argument. | |
| 183 | * | |
| 184 | * @param fromClass | |
| 185 | * the class to instantiate an object from | |
| 186 | * @param arguments | |
| 187 | * the arguments to pass to the constructor | |
| 188 | * @param argumentTypes | |
| 189 | * the fully qualified types of the arguments of the constructor | |
| 190 | * @return an object of the given type | |
| 191 | * @throws IllegalArgumentException | |
| 192 | * if the class can't be instantiated. This could be the case if the | |
| 193 | * number of actual and formal parameters differ; if an unwrapping | |
| 194 | * conversion for primitive arguments fails; if, after possible | |
| 195 | * unwrapping, a parameter value cannot be converted to the | |
| 196 | * corresponding formal parameter type by a method invocation | |
| 197 | * conversion; if this Constructor object enforces Java language | |
| 198 | * access control and the underlying constructor is inaccessible; if | |
| 199 | * the underlying constructor throws an exception; if the | |
| 200 | * constructor could not be found; or if the class that declares the | |
| 201 | * underlying constructor represents an abstract class. | |
| 202 | * | |
| 203 | * @see PrivilegedAccessor#instantiate(Class,Class[],Object[]) | |
| 204 | */ | |
| 205 | 0 | public static <T> T instantiate(final Class<? extends T> fromClass, |
| 206 | final Class<?>[] argumentTypes, final Object... arguments) | |
| 207 | { | |
| 208 | 0 | try |
| 209 | { | |
| 210 | 0 | return PrivilegedAccessor.instantiate(fromClass, argumentTypes, |
| 211 | correctVarargs(arguments)); | |
| 212 | } catch (Exception e) | |
| 213 | { | |
| 214 | 0 | throw new IllegalArgumentException("Can't instantiate class " |
| 215 | + fromClass + " with arguments " + arguments, e); | |
| 216 | } | |
| 217 | } | |
| 218 | ||
| 219 | /** | |
| 220 | * Instantiates an object of the given class with the given arguments. If you | |
| 221 | * want to instantiate a member class, you must provide the object it is a | |
| 222 | * member of as first argument. | |
| 223 | * | |
| 224 | * @param fromClass | |
| 225 | * the class to instantiate an object from | |
| 226 | * @param arguments | |
| 227 | * the arguments to pass to the constructor | |
| 228 | * @return an object of the given type | |
| 229 | * @throws IllegalArgumentException | |
| 230 | * if the class can't be instantiated. This could be the case if the | |
| 231 | * number of actual and formal parameters differ; if an unwrapping | |
| 232 | * conversion for primitive arguments fails; or if, after possible | |
| 233 | * unwrapping, a parameter value cannot be converted to the | |
| 234 | * corresponding formal parameter type by a method invocation | |
| 235 | * conversion; if this Constructor object enforces Java language | |
| 236 | * access control and the underlying constructor is inaccessible; if | |
| 237 | * the underlying constructor throws an exception; if the | |
| 238 | * constructor could not be found; or if the class that declares the | |
| 239 | * underlying constructor represents an abstract class. | |
| 240 | * | |
| 241 | * @see PrivilegedAccessor#instantiate(Class,Object[]) | |
| 242 | */ | |
| 243 | 0 | public static <T> T instantiate(final Class<? extends T> fromClass, |
| 244 | final Object... arguments) | |
| 245 | { | |
| 246 | 0 | try |
| 247 | { | |
| 248 | 0 | return PrivilegedAccessor.instantiate(fromClass, |
| 249 | correctVarargs(arguments)); | |
| 250 | } catch (Exception e) | |
| 251 | { | |
| 252 | 0 | throw new IllegalArgumentException("Can't instantiate class " |
| 253 | + fromClass + " with arguments " + arguments, e); | |
| 254 | } | |
| 255 | } | |
| 256 | ||
| 257 | /** | |
| 258 | * Calls a method on the given object instance with the given arguments. | |
| 259 | * Arguments can be object types or representations for primitives. | |
| 260 | * | |
| 261 | * @param instanceOrClass | |
| 262 | * the instance or class to invoke the method on | |
| 263 | * @param methodSignature | |
| 264 | * the name of the method and the parameters <br> | |
| 265 | * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)") | |
| 266 | * @param arguments | |
| 267 | * an array of objects to pass as arguments | |
| 268 | * @return the return value of this method or null if void | |
| 269 | * @throws IllegalArgumentException | |
| 270 | * if the method could not be invoked. This could be the case if the | |
| 271 | * method is inaccessible; if the underlying method throws an | |
| 272 | * exception; if no method with the given | |
| 273 | * <code>methodSignature</code> could be found; or if an argument | |
| 274 | * couldn't be converted to match the expected type | |
| 275 | * | |
| 276 | * @see PrivilegedAccessor#invokeMethod(Object,String,Object[]) | |
| 277 | */ | |
| 278 | 0 | public static Object invokeMethod(final Object instanceOrClass, |
| 279 | final String methodSignature, final Object... arguments) | |
| 280 | { | |
| 281 | 0 | try |
| 282 | { | |
| 283 | 0 | return PrivilegedAccessor.invokeMethod(instanceOrClass, |
| 284 | methodSignature, correctVarargs(arguments)); | |
| 285 | } catch (Exception e) | |
| 286 | { | |
| 287 | 0 | throw new IllegalArgumentException( |
| 288 | "Can't invoke method " + methodSignature + " on " | |
| 289 | + instanceOrClass + " with arguments " + arguments, | |
| 290 | e); | |
| 291 | } | |
| 292 | } | |
| 293 | ||
| 294 | /** | |
| 295 | * Calls a method with the given arguments. Arguments can be object types or | |
| 296 | * representations for primitives. | |
| 297 | * | |
| 298 | * @param methodSignature | |
| 299 | * the name of the method and the parameters <br> | |
| 300 | * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)") | |
| 301 | * @param arguments | |
| 302 | * an array of objects to pass as arguments | |
| 303 | * @return the return value of this method or null if void | |
| 304 | * @throws IllegalArgumentException | |
| 305 | * if the method could not be invoked. This could be the case if the | |
| 306 | * method is inaccessible; if the underlying method throws an | |
| 307 | * exception; if no method with the given | |
| 308 | * <code>methodSignature</code> could be found; or if an argument | |
| 309 | * couldn't be converted to match the expected type | |
| 310 | * @see PA#invokeMethod(Object, String, Object...) | |
| 311 | */ | |
| 312 | 0 | public Object invokeMethod(final String methodSignature, |
| 313 | final Object... arguments) | |
| 314 | { | |
| 315 | 0 | return PA.invokeMethod(instanceOrClass, methodSignature, arguments); |
| 316 | } | |
| 317 | ||
| 318 | /** | |
| 319 | * Corrects varargs to their initial form. If you call a method with an | |
| 320 | * object-array as last argument the Java varargs mechanism converts this | |
| 321 | * array in single arguments. This method returns an object array if the | |
| 322 | * arguments are all of the same type. | |
| 323 | * | |
| 324 | * @param arguments | |
| 325 | * the possibly converted arguments of a vararg method | |
| 326 | * @return arguments possibly converted | |
| 327 | */ | |
| 328 | 0 | private static Object[] correctVarargs(final Object... arguments) |
| 329 | { | |
| 330 | 0 | if ((arguments == null) || changedByVararg(arguments)) |
| 331 | 0 | return new Object[] { arguments }; |
| 332 | 0 | return arguments; |
| 333 | } | |
| 334 | ||
| 335 | /** | |
| 336 | * Tests if the arguments were changed by vararg. Arguments are changed by | |
| 337 | * vararg if they are of a non primitive array type. E.g. arguments[] = | |
| 338 | * Object[String[]] is converted to String[] while e.g. arguments[] = | |
| 339 | * Object[int[]] is not converted and stays Object[int[]] | |
| 340 | * | |
| 341 | * Unfortunately we can't detect the difference for arg = Object[primitive] | |
| 342 | * since arguments[] = Object[Object[primitive]] which is converted to | |
| 343 | * Object[primitive] and arguments[] = Object[primitive] which stays | |
| 344 | * Object[primitive] | |
| 345 | * | |
| 346 | * and we can't detect the difference for arg = Object[non primitive] since | |
| 347 | * arguments[] = Object[Object[non primitive]] is converted to Object[non | |
| 348 | * primitive] and arguments[] = Object[non primitive] stays Object[non | |
| 349 | * primitive] | |
| 350 | * | |
| 351 | * @param parameters | |
| 352 | * the parameters | |
| 353 | * @return true if parameters were changes by varargs, false otherwise | |
| 354 | */ | |
| 355 | 0 | private static boolean changedByVararg(final Object[] parameters) |
| 356 | { | |
| 357 | 0 | if ((parameters.length == 0) || (parameters[0] == null)) |
| 358 | 0 | return false; |
| 359 | ||
| 360 | 0 | if (parameters.getClass() == Object[].class) |
| 361 | 0 | return false; |
| 362 | ||
| 363 | 0 | return true; |
| 364 | } | |
| 365 | ||
| 366 | /** | |
| 367 | * Sets the value of the named field. If fieldName denotes a static field, | |
| 368 | * provide a class, otherwise provide an instance. If the fieldName denotes a | |
| 369 | * final field, this method could fail with an IllegalAccessException, since | |
| 370 | * setting the value of final fields at other times than instantiation can | |
| 371 | * have unpredictable effects.<br/> | |
| 372 | * <br/> | |
| 373 | * Example:<br/> | |
| 374 | * <br/> | |
| 375 | * <code> | |
| 376 | * String myString = "Test"; <br/> | |
| 377 | * <br/> | |
| 378 | * //setting the private field value<br/> | |
| 379 | * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/> | |
| 380 | * <br/> | |
| 381 | * //setting the static final field serialVersionUID - MIGHT FAIL<br/> | |
| 382 | * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/> | |
| 383 | * <br/> | |
| 384 | * </code> | |
| 385 | * | |
| 386 | * @param instanceOrClass | |
| 387 | * the instance or class to set the field | |
| 388 | * @param fieldName | |
| 389 | * the name of the field | |
| 390 | * @param value | |
| 391 | * the new value of the field | |
| 392 | * @throws IllegalArgumentException | |
| 393 | * if the value could not be set. This could be the case if no field | |
| 394 | * with the given <code>fieldName</code> can be found; or if the | |
| 395 | * field was final | |
| 396 | * | |
| 397 | * @see PrivilegedAccessor.setValue(Object,String,Object) | |
| 398 | */ | |
| 399 | 17 | public static PA setValue(final Object instanceOrClass, |
| 400 | final String fieldName, final Object value) | |
| 401 | { | |
| 402 | 17 | try |
| 403 | { | |
| 404 | 17 | PrivilegedAccessor.setValue(instanceOrClass, fieldName, value); |
| 405 | } catch (Exception e) | |
| 406 | { | |
| 407 | 0 | throw new IllegalArgumentException("Can't set value " + value + " at " |
| 408 | + fieldName + " in " + instanceOrClass, e); | |
| 409 | } | |
| 410 | 17 | return new PA(instanceOrClass); |
| 411 | } | |
| 412 | ||
| 413 | /** | |
| 414 | * Sets the value of the named field. If fieldName denotes a static field, | |
| 415 | * provide a class, otherwise provide an instance. If the fieldName denotes a | |
| 416 | * final field, this method could fail with an IllegalAccessException, since | |
| 417 | * setting the value of final fields at other times than instantiation can | |
| 418 | * have unpredictable effects.<br/> | |
| 419 | * <br/> | |
| 420 | * Example:<br/> | |
| 421 | * <br/> | |
| 422 | * <code> | |
| 423 | * String myString = "Test"; <br/> | |
| 424 | * <br/> | |
| 425 | * //setting the private field value<br/> | |
| 426 | * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/> | |
| 427 | * <br/> | |
| 428 | * //setting the static final field serialVersionUID - MIGHT FAIL<br/> | |
| 429 | * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/> | |
| 430 | * <br/> | |
| 431 | * </code> | |
| 432 | * | |
| 433 | * @param fieldName | |
| 434 | * the name of the field | |
| 435 | * @param value | |
| 436 | * the new value of the field | |
| 437 | * @throws IllegalArgumentException | |
| 438 | * if the value could not be set. This could be the case if no field | |
| 439 | * with the given <code>fieldName</code> can be found; or if the | |
| 440 | * field was final | |
| 441 | * | |
| 442 | * @see PA.setValue(Object,String,Object) | |
| 443 | */ | |
| 444 | 0 | public PA setValue(final String fieldName, final Object value) |
| 445 | { | |
| 446 | 0 | PA.setValue(instanceOrClass, fieldName, value); |
| 447 | 0 | return this; |
| 448 | } | |
| 449 | } |