001package arcommon; 002 003import java.io.File; 004import java.lang.reflect.Constructor; 005import java.lang.reflect.Field; 006import java.lang.reflect.InvocationTargetException; 007import java.lang.reflect.Method; 008import java.lang.reflect.Modifier; 009import java.net.URL; 010import java.util.Arrays; 011import java.util.HashMap; 012import java.util.HashSet; 013import java.util.List; 014import java.util.Map; 015 016import sun.reflect.ReflectionFactory; 017 018public class ReflectionUtil { 019 public static Class<?> loadClass(String className) { 020 return loadClass(className, true); 021 } 022 023 public static Class<?> loadClass(String className, boolean throwOnFail) { 024 try { 025 return Class.forName(className); 026 } catch (ClassNotFoundException e) { 027 if (throwOnFail) { 028 throw new RuntimeException(e); 029 } 030 return null; 031 } catch (NoClassDefFoundError e) { 032 if (throwOnFail) { 033 throw new RuntimeException(e); 034 } 035 return null; 036 } 037 } 038 039 private static Class<?>[] parametersToClasses(Object[] parameterValues) { 040 if (parameterValues == null) { 041 return new Class[0]; 042 } 043 Class<?>[] parameters = new Class[parameterValues.length]; 044 for (int i = 0; i < parameters.length; i++) { 045 if (parameterValues[i] == null) { 046 continue; 047 } 048 parameters[i] = parameterValues[i].getClass(); 049 } 050 return parameters; 051 } 052 053 private static Class<?>[] parametersToClassesPrimitiveModified(Class<?>[] parameters) { 054 Class<?>[] result = new Class[parameters.length]; 055 Class<?>[] search = new Class[] {Long.class, Integer.class, Short.class, Character.class, Byte.class, Boolean.class, Double.class, Float.class}; 056 Class<?>[] replace = new Class[] {long.class, int.class , short.class, char.class , byte.class, boolean.class, double.class, float.class}; 057 for (int i = 0; i < parameters.length; i++) { 058 for (int j = 0; j < search.length; j++) { 059 if (parameters[i] == search[j]) { 060 result[i] = replace[j]; 061 break; 062 } 063 } 064 if (result[i] == null) { 065 result[i] = parameters[i]; 066 } 067 } 068 return result; 069 } 070 071 public static void setStaticFieldValue(Class<?> onClass, String fieldName, Object value) { 072 setFieldValue(null, onClass, fieldName, value); 073 } 074 075 public static Field findField(Class<?> onClass, String fieldName) { 076 return findField(onClass, fieldName, true); 077 } 078 079 public static Field findField(Class<?> onClass, String fieldName, boolean throwOnFail) { 080 Field field = null; 081 do { 082 try { 083 field = onClass.getDeclaredField(fieldName); 084 } catch (NoSuchFieldException e) { 085 if (onClass.getSuperclass() != null) { 086 onClass = onClass.getSuperclass(); 087 } else { 088 if (throwOnFail) { 089 throw new RuntimeException(e); 090 } 091 return null; 092 } 093 } 094 } while (field == null); 095 return field; 096 } 097 098 public static Field setFieldValue(Object onObject, Class<?> onClass, String fieldName, Object value) { 099 Field field = findField(onClass, fieldName); 100 setFieldValue(onObject, field, value); 101 return field; 102 } 103 104 public static void setFieldValue(Object onObject, Field field, Object value) { 105 try { 106 field.setAccessible(true); 107 field.set(onObject, value); 108 } catch (IllegalArgumentException e) { 109 throw new RuntimeException(e); 110 } catch (IllegalAccessException e) { 111 throw new RuntimeException(e); 112 } catch (SecurityException e) { 113 throw new RuntimeException(e); 114 } 115 } 116 117 public static Object getStaticFieldValue(Class<?> onClass, String fieldName) { 118 return getStaticFieldValue(onClass, fieldName, true); 119 } 120 121 public static Object getStaticFieldValue(Class<?> onClass, String fieldName, boolean throwOnFieldMissing) { 122 return getFieldValue(null, onClass, fieldName, throwOnFieldMissing); 123 } 124 125 public static Object getFieldValue(Object onObject, String fieldName) { 126 return getFieldValue(onObject, onObject.getClass(), fieldName); 127 } 128 129 public static Object getFieldValue(Object onObject, Class<?> onClass, String fieldName) { 130 return getFieldValue(onObject, onClass, fieldName, true); 131 } 132 133 public static Object getFieldValue(Object onObject, Class<?> onClass, String fieldName, boolean throwOnFieldMissing) { 134 Field field = null; 135 if (onObject == null) { // static 136 try { 137 field = onClass.getDeclaredField(fieldName); 138 } catch (SecurityException e) { 139 throw new RuntimeException(e); 140 } catch (NoSuchFieldException e) { 141 if (throwOnFieldMissing) { 142 throw new RuntimeException(e); 143 } 144 return null; 145 } 146 } else { 147 try { 148 field = onClass.getField(fieldName); 149 } catch (SecurityException e1) { 150 throw new RuntimeException(e1); 151 } catch (NoSuchFieldException e1) { 152 try { 153 field = onClass.getDeclaredField(fieldName); 154 } catch (SecurityException e) { 155 throw new RuntimeException(e1); 156 } catch (NoSuchFieldException e) { 157 if (onClass != Object.class) { 158 return getFieldValue(onObject, onClass.getSuperclass(), fieldName, throwOnFieldMissing); 159 } 160 if (throwOnFieldMissing) { 161 throw new RuntimeException(e1); 162 } 163 return null; 164 } 165 } 166 } 167 168 try { 169 field.setAccessible(true); 170 return field.get(onObject); 171 } catch (IllegalArgumentException e) { 172 throw new RuntimeException(e); 173 } catch (IllegalAccessException e) { 174 throw new RuntimeException(e); 175 } catch (SecurityException e) { 176 throw new RuntimeException(e); 177 } 178 } 179 180 public static boolean hasMethod(Class<?> onClass, String methodName, Class<?>[] parameters) { 181 return findMethod(onClass, methodName, parameters, true, false) != null; 182 } 183 184 public static Method findMethod(Class<?> onClass, String methodName, Class<?>[] parameters) { 185 return findMethod(onClass, methodName, parameters, true, true); 186 } 187 188 public static Method findStaticMethod(Class<?> onClass, String methodName, Class<?>[] parameters) { 189 return findMethod(onClass, methodName, parameters, false, true); 190 } 191 192 public static Method findMethod(Class<?> onClass, String methodName, Class<?>[] parameters, boolean nonStatic, boolean throwOnMissing) { 193 Exception exception = null; 194 if (nonStatic) { 195 try { 196 Method method = onClass.getMethod(methodName, parameters); 197 return method; 198 } catch (NoSuchMethodException e) { 199 Class<?>[] parametersPrimitive = parametersToClassesPrimitiveModified(parameters); 200 try { 201 Method method = onClass.getMethod(methodName, parametersPrimitive); 202 return method; 203 } catch (NoSuchMethodException e2) { 204 exception = e2; 205 } 206 } 207 } 208 209 try { 210 Method method = onClass.getDeclaredMethod(methodName, parameters); 211 return method; 212 } catch (NoSuchMethodException e) { 213 Class<?>[] parametersPrimitive = parametersToClassesPrimitiveModified(parameters); 214 try { 215 Method method = onClass.getDeclaredMethod(methodName, parametersPrimitive); 216 return method; 217 } catch (NoSuchMethodException e2) { 218 exception = e2; 219 } 220 } 221 222 Method method = null; 223 Method[] methods = onClass.getMethods(); 224 for (Method m : methods) { 225 if (m.getName().equals(methodName)) { 226 if (method == null) { 227 method = m; 228 } else { 229 throw new RuntimeException("Method \"" + methodName + "\" is not unique, and the parameters doesn't match one of them.\n" 230 + "Parameters: " + parameters + "\n" 231 + "Method1: " + m + "\n" 232 + "Method2: " + method); 233 } 234 } 235 } 236 237 if (method != null) { 238 return method; 239 } 240 241 if (throwOnMissing && exception != null) { 242 throw new RuntimeException(exception); 243 } 244 245 return method; 246 } 247 248 public static Object invokeStaticMethod(Class<?> onClass, String methodName, Object ... parameterValues) { 249 Class<?>[] parameters = parametersToClasses(parameterValues); 250 return invokeMethod(onClass, null, methodName, parameters, parameterValues); 251 } 252 253 public static Object invokeStaticMethod(Class<?> onClass, String methodName, Class<?>[] parameters, Object[] parameterValues) { 254 return invokeMethod(onClass, null, methodName, parameters, parameterValues); 255 } 256 257 public static Object invokeMethod(Object onObject, String methodName, Object ... parameterValues) { 258 Class<?>[] parameters = parametersToClasses(parameterValues); 259 return invokeMethod(onObject, methodName, parameters, parameterValues); 260 } 261 262 public static Object invokeMethod(Object onObject, String methodName, Class<?>[] parameters, Object[] parameterValues) { 263 return invokeMethod(onObject.getClass(), onObject, methodName, parameters, parameterValues); 264 } 265 266 private static Object invokeMethod(Class<?> onClass, Object onObject, String methodName, Class<?>[] parameters, Object[] parameterValues) { 267 Method method = findMethod(onClass, methodName, parameters, onObject != null, true); 268 return invokeMethod(onObject, method, parameterValues); 269 } 270 271 public static Object invokeMethod(Object onObject, Method method, Object[] parameterValues) { 272 try { 273 method.setAccessible(true); 274 Object returnObject = method.invoke(onObject, parameterValues); 275 return returnObject; 276 } catch (SecurityException e) { 277 throw new RuntimeException(e); 278 } catch (IllegalArgumentException e) { 279 throw new RuntimeException(e); 280 } catch (IllegalAccessException e) { 281 throw new RuntimeException(e); 282 } catch (InvocationTargetException e) { 283 throw new RuntimeException(e); 284 } 285 } 286 287 public static <T> T createInstanceDefaultConstructor(Class<T> clazz) { 288 return createInstanceUsingConstructor(clazz, new Class<?>[0], new Object[0]); 289 } 290 291 public static <T> T createInstanceUsingConstructor(Class<T> clazz, Object ... parameterValues) { 292 Class<?>[] parameters = parametersToClasses(parameterValues); 293 return createInstanceUsingConstructor(clazz, parameters, parameterValues); 294 } 295 296 public static <T> T createInstanceUsingConstructor(Class<T> clazz, Class<?>[] parameters, Object[] parameterValues) { 297 try { 298 Constructor<?> constructor = clazz.getConstructor(parameters); 299 Object returnObject = constructor.newInstance(parameterValues); 300 return clazz.cast(returnObject); 301 } catch (SecurityException e) { 302 throw new RuntimeException(e); 303 } catch (IllegalArgumentException e) { 304 throw new RuntimeException(e); 305 } catch (IllegalAccessException e) { 306 throw new RuntimeException(e); 307 } catch (NoSuchMethodException e) { 308 throw new RuntimeException(e); 309 } catch (InvocationTargetException e) { 310 throw new RuntimeException(e); 311 } catch (InstantiationException e) { 312 throw new RuntimeException(e); 313 } 314 } 315 316 /** 317 * Creates an object using default private constructor. 318 * <br> 319 * Note: Can create an object, even though the class only has a private constructor. 320 */ 321 public static <T> T createInstanceDefaultPrivateConstructor(Class<T> clazz) { 322 Constructor<?> constructor; 323 try { 324 constructor = clazz.getDeclaredConstructor(); 325 constructor.setAccessible(true); 326 return clazz.cast(constructor.newInstance()); 327 } catch (SecurityException e) { 328 throw new RuntimeException(e); 329 } catch (NoSuchMethodException e) { 330 throw new RuntimeException(e); 331 } catch (IllegalArgumentException e) { 332 throw new RuntimeException(e); 333 } catch (InstantiationException e) { 334 throw new RuntimeException(e); 335 } catch (IllegalAccessException e) { 336 throw new RuntimeException(e); 337 } catch (InvocationTargetException e) { 338 throw new RuntimeException(e); 339 } 340 } 341 342 /** 343 * Create an instance of clazz without calling any constructors. 344 * <br> 345 * Code copied from <a href="http://www.javaspecialists.eu/archive/Issue175.html">http://www.javaspecialists.eu/archive/Issue175.html</a><br> 346 * and modified 347 */ 348 public static <T> T createInstanceNoConstructorCall(Class<T> clazz) { 349 return createInstanceUsingParentConstructorOnly(clazz, Object.class); 350 } 351 352 /** 353 * Create an instance of clazz calling only the class parent's constructor(s). 354 */ 355 @SuppressWarnings("unchecked") 356 public static <T> T createInstanceUsingParentConstructorOnly(Class<T> clazz, Class<? super T> parent) { 357 return (T)createInstanceUsingParentConstructorOnlyUnsafe(clazz, parent); 358 } 359 360 private static Map<Class<?>, Map<Constructor<?>, Constructor<?>>> newConstructorForSerializationMap; 361 362 /** 363 * @see #createInstanceNoConstructorCall(Class) see createInstanceNoConstructorCall(Class) for details 364 */ 365 public static Object createInstanceUsingParentConstructorOnlyUnsafe(Class<?> clazz, Class<?> parent) { 366 try { 367 if (newConstructorForSerializationMap == null) { 368 newConstructorForSerializationMap = new HashMap<Class<?>, Map<Constructor<?>, Constructor<?>>>(); 369 } 370 371 Map<Constructor<?>, Constructor<?>> classMap = newConstructorForSerializationMap.get(clazz); 372 if (classMap == null) { 373 classMap = new HashMap<Constructor<?>, Constructor<?>>(); 374 newConstructorForSerializationMap.put(clazz, classMap); 375 } 376 377 ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory(); 378 Constructor<?> declaredConstructor = parent.getDeclaredConstructor(); 379 Constructor<?> constructor = classMap.get(declaredConstructor); 380 if (constructor == null) { 381 if (clazz.isArray()) { 382 throw new RuntimeException("clazz.isArray() => Use Array.newInstance(clazz.getComponentType(), length)"); 383 } 384 constructor = reflectionFactory.newConstructorForSerialization(clazz, declaredConstructor); // This call seems to be very show => Result is cached. 385 classMap.put(declaredConstructor, constructor); 386 } 387 388 return clazz.cast(constructor.newInstance()); 389 } catch (RuntimeException e) { 390 throw e; 391 } catch (Exception e) { 392 throw new IllegalStateException("Cannot create object", e); 393 } 394 } 395 396 public static <T> T createInstanceImplementingInterface(String className, Class<T> interfaceToImplement) { 397 Class<?> clazz = loadClass(className); 398 return createInstanceImplementingInterface(clazz, interfaceToImplement); 399 } 400 401 @SuppressWarnings("unchecked") 402 public static <T> T createInstanceImplementingInterface(Class<?> clazz, Class<T> interfaceToImplement) { 403 boolean ok = false; 404 Class<?> currentClass = clazz; 405 do { 406 for (int i = 0; i < currentClass.getInterfaces().length; i++) { 407 Class<?> interfaceClass = currentClass.getInterfaces()[i]; 408 if (interfaceClass.equals(interfaceToImplement)) { 409 ok = true; 410 break; 411 } 412 } 413 currentClass = currentClass.getSuperclass(); 414 } while (currentClass != null && !ok); 415 if (!ok) { 416 throw new RuntimeException("The class " + clazz.getName() + " doesn't implement the " + interfaceToImplement.getName() + " interface"); 417 } 418 419 Object instance = createInstanceDefaultConstructor(clazz); 420 421 return (T)instance; 422 } 423 424 public static boolean isClassEnum(Class<?> clazz) { 425 // See Enum.getDeclaringClass() for a reason for this code 426 if (clazz.isEnum()) { 427 return true; 428 } 429 Class<?> superclass = clazz.getSuperclass(); 430 if (superclass == null) { 431 return false; 432 } 433 return superclass.isEnum(); 434 } 435 436 @SuppressWarnings("rawtypes") 437 public static String enumToStringUnsafe(Object object) { 438 return enumToString((Enum)object); 439 } 440 441 public static String enumToString(Enum<?> object) { 442 Enum<?> o = object; 443 return o.name(); 444 } 445 446 public static Enum<?> stringToEnum(Class<?> clazz, String value) { 447 if (!clazz.isEnum()) { // This occurs for enum constants with constant-specific class bodies. 448 // See Enum.getDeclaringClass() for a reason for this code 449 clazz = clazz.getSuperclass(); 450 } 451 @SuppressWarnings({"unchecked", "rawtypes"}) 452 Enum result = Enum.valueOf((Class<Enum>)clazz, value); 453 return result; 454 } 455 456 public static void copyFields(Object fromObject, Object toObject) { 457 if (!fromObject.getClass().equals(toObject.getClass())) { 458 throw new RuntimeException("The classes are not identical: " + fromObject.getClass() + " <-> " + toObject.getClass()); 459 } 460 Field[] fromDeclaredFields = fromObject.getClass().getDeclaredFields(); 461 Field[] toDeclaredFields = toObject.getClass().getDeclaredFields(); 462 Field.setAccessible(fromDeclaredFields, true); 463 Field.setAccessible(toDeclaredFields, true); 464 for (int i = 0; i < fromDeclaredFields.length; i++) { 465 String name = fromDeclaredFields[i].getName(); 466 if ((fromDeclaredFields[i].getModifiers() & Modifier.STATIC) == Modifier.STATIC) { 467 continue; 468 } 469 470 boolean found = false; 471 for (int j = 0; j < toDeclaredFields.length; j++) { 472 if (toDeclaredFields[j].getName().equals(name)) { 473 Object valueObject; 474 try { 475 valueObject = fromDeclaredFields[i].get(fromObject); 476 toDeclaredFields[j].set(toObject, valueObject); 477 } catch (IllegalArgumentException e) { 478 throw new RuntimeException(e); 479 } catch (IllegalAccessException e) { 480 throw new RuntimeException(e); 481 } 482 found = true; 483 break; 484 } 485 } 486 if (!found) { 487 throw new RuntimeException("Internal error: Field " + name + " was not found"); 488 } 489 } 490 } 491 492 public static void printClassTree(Object object) { 493 HashSet<Object> printed = new HashSet<Object>(); 494 try { 495 Util.printMessageWithSourceLine("printClassTree()..."); 496 printClassTree(1, printed, object); 497 Util.printMessageWithSourceLine("..printClassTree()"); 498 } catch (Exception e) { 499 throw new RuntimeException(e); 500 } 501 } 502 503 private static final List<Class<?>> SKIP_CLASSES = Arrays.asList(new Class <?>[] {String.class}); 504 505 private static void printClassTree(int level, HashSet<Object> printed, Object object) throws IllegalArgumentException, IllegalAccessException { 506 printed.add(object); 507 Field[] fields = object.getClass().getDeclaredFields(); 508 String indent = StringUtil.stringWithNumberOfChar(level * 3, ' '); 509 boolean fieldsFound = false; 510 for (int i = 0; i < fields.length; i++) { 511 Field field = fields[i]; 512 int modifiers = field.getModifiers(); 513 if ((modifiers & Modifier.STATIC) == Modifier.STATIC) { 514 continue; 515 } 516 fieldsFound = true; 517 String fieldName = field.getName(); 518 Class<?> type = field.getType(); 519 String className = type.getName(); 520 field.setAccessible(true); 521 Object value = field.get(object); 522 boolean arrayPrimitive = false; 523 Object[] objectArrayValue = null; 524 if (type.isArray() && value != null) { 525 Class<?> componentType = type.getComponentType(); 526 boolean found = false; 527 if (componentType == int.class) { 528 int[] arrayValue = (int[])value; 529 className = "int [" + arrayValue.length + "]"; 530 value = Arrays.toString(arrayValue); 531 arrayPrimitive = true; 532 found = true; 533 } 534 if (componentType == char.class) { 535 char[] arrayValue = (char[])value; 536 className = "char [" + arrayValue.length + "]"; 537 value = new String(arrayValue); 538 arrayPrimitive = true; 539 found = true; 540 } 541 if (!found) { 542 try { 543 objectArrayValue = (Object[])value; 544 } catch (Exception e) { 545 throw new RuntimeException(e); 546 } 547 className = componentType.getName() + " [" + objectArrayValue.length + "]"; 548 value = Arrays.toString(objectArrayValue); 549 } 550 } 551 System.out.print(indent + fieldName + " (" + className + ") = " + value); 552 if (value == null || type.isPrimitive() || SKIP_CLASSES.contains(type) || arrayPrimitive) { 553 System.out.println(); 554 continue; 555 } 556 if (printed.contains(value)) { 557 System.out.println(" - Recursively"); 558 } else { 559 System.out.println(); 560 if (objectArrayValue != null) { 561 for (int j = 0; j < objectArrayValue.length; j++) { 562 if (objectArrayValue[j] == null || SKIP_CLASSES.contains(objectArrayValue[j].getClass())) { 563 continue; 564 } 565 System.out.println(indent + " [" + j + "] " + objectArrayValue[j].getClass().getCanonicalName()); 566 printClassTree(level + 2, printed, objectArrayValue[j]); 567 } 568 } else { 569 printClassTree(level + 1, printed, value); 570 } 571 } 572 } 573 574 if (!fieldsFound) { 575 System.out.println(indent + "- No fields found -"); 576 } 577 } 578 579 public static String classToClassNameInJavaSyntax(Class<?> clazz) { 580 return classToClassNameInJavaSyntax(clazz, true); 581 } 582 583 public static String classToClassNameInJavaSyntax(Class<?> clazz, boolean includePackage) { 584 String result; 585 if (clazz.isArray()) { 586 Class<?> componentType = clazz.getComponentType(); 587 result = classToClassNameInJavaSyntax(componentType, includePackage); 588 result += "[]"; 589 } else { 590 if (includePackage) { 591 result = clazz.getName(); 592 } else { 593 result = clazz.getSimpleName(); 594 } 595 } 596 return result; 597 } 598 599 public static Class<?> classNameInJavaSyntaxToClass(String className) { 600 return classNameInJavaSyntaxToClass(className, true); 601 } 602 603 public static Class<?> classNameInJavaSyntaxToClass(String classNameOriginal, boolean throwOnFail) { 604 String className = classNameOriginal; 605 if (className.endsWith("[]")) { 606 int dimensions = 0; 607 while (className.endsWith("[]")) { 608 className = className.substring(0, className.length() - 2); 609 dimensions++; 610 } 611 String dimensionsString = StringUtil.stringWithNumberOfChar(dimensions, '['); 612 if (className.endsWith(" ")) { 613 className = className.substring(0, className.length() - 1); 614 } 615 616 if (className.contains(" ")) { 617 throw new RuntimeException("Class name \"" + className + "\" contains space (\"" + classNameOriginal + "\")"); 618 } 619 620 String primitiveName = null; 621 if (className.equals("long")) { 622 primitiveName = "J"; 623 } else if (className.equals("int")) { 624 primitiveName = "I"; 625 } else if (className.equals("short")) { 626 primitiveName = "S"; 627 } else if (className.equals("byte")) { 628 primitiveName = "B"; 629 } else if (className.equals("char")) { 630 primitiveName = "C"; 631 } else if (className.equals("boolean")) { 632 primitiveName = "Z"; 633 } else if (className.equals("double")) { 634 primitiveName = "D"; 635 } else if (className.equals("float")) { 636 primitiveName = "F"; 637 } 638 639 String arrayClassName; 640 if (primitiveName != null) { 641 arrayClassName = dimensionsString + primitiveName; 642 } else { 643 arrayClassName = dimensionsString + "L" + className + ";"; 644 } 645 646 return loadClass(arrayClassName, throwOnFail); 647 } 648 649 if (className.equals("long")) { 650 return long.class; 651 } 652 if (className.equals("int")) { 653 return int.class; 654 } 655 if (className.equals("short")) { 656 return short.class; 657 } 658 if (className.equals("byte")) { 659 return byte.class; 660 } 661 if (className.equals("char")) { 662 return char.class; 663 } 664 if (className.equals("boolean")) { 665 return boolean.class; 666 } 667 if (className.equals("double")) { 668 return double.class; 669 } 670 if (className.equals("float")) { 671 return float.class; 672 } 673 674 if (className.contains(" ")) { 675 throw new RuntimeException("Class name \"" + className + "\" contains space"); 676 } 677 678 return loadClass(className, throwOnFail); 679 } 680 681 public static String classToEmptyImplementationSourceCode(Class<?> clazz) { 682 StringBuilder stringBuilder = new StringBuilder(); 683 Method[] methods = clazz.getMethods(); 684 for (int i = 0; i < methods.length; i++) { 685 Method method = methods[i]; 686 if ((method.getModifiers() & Modifier.NATIVE) == Modifier.NATIVE) { 687 continue; 688 } 689 if ((method.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { 690 continue; 691 } 692 693 // Copied from Method.toString() and modified 694 int mod = method.getModifiers() & Modifier.PUBLIC; 695 if (mod != 0) { 696 stringBuilder.append(Modifier.toString(mod) + " "); 697 } 698 stringBuilder.append(classToClassNameInJavaSyntax(method.getReturnType(), false)); 699 stringBuilder.append(" "); 700 stringBuilder.append(method.getName() + "("); 701 Class<?>[] parameters = method.getParameterTypes(); 702 for (int j = 0; j < parameters.length; j++) { 703 stringBuilder.append(classToClassNameInJavaSyntax(parameters[j], false)); 704 stringBuilder.append(" p" + j); 705 if (j < (parameters.length - 1)) { 706 stringBuilder.append(", "); 707 } 708 } 709 stringBuilder.append(")"); 710 Class<?>[] exceptions = method.getExceptionTypes(); 711 if (exceptions.length > 0) { 712 stringBuilder.append(" throws "); 713 for (int k = 0; k < exceptions.length; k++) { 714 stringBuilder.append(exceptions[k].getSimpleName()); 715 if (k < (exceptions.length - 1)) { 716 stringBuilder.append(", "); 717 } 718 } 719 } 720 stringBuilder.append(" {\n"); 721// stringBuilder.append(" // TODO Auto-generated method stub\n"); 722 stringBuilder.append(" throw new RuntimeException(\"Not implemented\");\n"); 723 stringBuilder.append("}\n"); 724 stringBuilder.append("\n"); 725 } 726 727 return stringBuilder.toString(); 728 } 729 730 private static final String JAR_FILE_NAME_PREFIX = "jar:file:"; 731 732 public static boolean loadedFromJarFile(Class<?> clazz) { 733 URL location = clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class"); 734 String locationString = location.toString(); 735 return locationString.startsWith(JAR_FILE_NAME_PREFIX); 736 } 737 738 public static String calculateJarFileName(Class<?> clazz) { 739 URL location = clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class"); 740 System.out.println("location.getPath(): " + location.getPath()); 741 String locationString = location.toString(); 742 743 if (!locationString.startsWith(JAR_FILE_NAME_PREFIX)) { 744 throw new RuntimeException("!locationString.startsWith(JAR_FILE_NAME_PREFIX): " + JAR_FILE_NAME_PREFIX + " " + locationString); 745 } 746 locationString = locationString.substring(JAR_FILE_NAME_PREFIX.length()); 747 int indexOf = locationString.indexOf("!"); 748 if (indexOf == -1) { 749 throw new RuntimeException("indexOf == -1: " + locationString); 750 } 751 locationString = locationString.substring(0, indexOf); 752 753 locationString = locationString.replace('/', File.separatorChar); 754 locationString = locationString.replace("%20", " "); 755 756 return locationString; 757 } 758 759 // NOTE: This method has not been tested a lot. 760 public static String calculateClassPath(Class<?> clazz) { 761 String classNameModfied = '/' + clazz.getName().replace('.', '/') + ".class"; 762 URL location = clazz.getResource(classNameModfied); 763 String path = location.getPath(); 764 if (path.endsWith(classNameModfied)) { 765 path = path.substring(0, path.length() - classNameModfied.length() + 1); 766 } else { 767 throw new RuntimeException("!path.endsWith(classNameModfied) " + path + " " + classNameModfied); 768 } 769 path = path.replace('/', File.separatorChar); 770 path = path.replace("%20", " "); 771 return path; 772 } 773 774 /** 775 * Use this method to avoid the following warning. 776 * <br> 777 * WARNING: An illegal reflective access operation has occurred<br> 778 * WARNING: Illegal reflective access by <packageName>.<className> (file:<path>) to field <packageName>.<className>.<fieldName><br> 779 * WARNING: Please consider reporting this to the maintainers of arcommon.ReflectionUtil<br> 780 * WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations<br> 781 * WARNING: All illegal access operations will be denied in a future release<br> 782 */ 783 public static void openPackageForModuleAccess(Class<?> classInPackage, Class<?> classInModule) { 784// openPackageForModuleAccess(classInPackage, classInModule.getModule()); 785 if (Util.getJavaVersion() < Util.JAVA_MODULE_SYSTEM_VERSION || Util.getJavaVersion() >= Util.JAVA_MODULE_SYSTEM_STRICT_VERSION) { // Util.getJavaVersion() == 16 => "java.lang.IllegalCallerException: sun.awt.X11 is not open to unnamed module @5a6d67c3" 786 return ; 787 } 788 // java.lang.Module is a java 9 class => Use reflection to make it compile on Java 8. 789 Object module = invokeMethod(classInModule, "getModule"); 790/* } 791 792 public static void openPackageForModuleAccess(Class<?> classInPackage, Module module) { 793 if (module.isNamed()) { 794 return ; 795 }*/ 796 Boolean isNamed = (Boolean)invokeMethod(module, "isNamed"); 797 if (isNamed.booleanValue()) { 798 return ; 799 } 800 801 // Code copied from https://stackoverflow.com/questions/46454995/how-to-hide-warning-illegal-reflective-access-in-java-9-without-jvm-argument 802 // and modified 803// classInPackage.getModule().addOpens(classInPackage.getPackageName(), module); 804 Object classInPackageModule = invokeMethod(classInPackage, "getModule"); 805 Object packageName = invokeMethod(classInPackage, "getPackageName"); 806 invokeMethod(classInPackageModule, "addOpens", packageName, module); 807 } 808}