1 package org.djutils.reflection;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.lang.annotation.Annotation;
6 import java.lang.reflect.Array;
7 import java.lang.reflect.Constructor;
8 import java.lang.reflect.Field;
9 import java.lang.reflect.Method;
10 import java.lang.reflect.Modifier;
11 import java.net.MalformedURLException;
12 import java.net.URISyntaxException;
13 import java.net.URL;
14 import java.nio.file.Files;
15 import java.nio.file.Path;
16 import java.nio.file.Paths;
17 import java.nio.file.attribute.BasicFileAttributes;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26 import java.util.Set;
27 import java.util.jar.JarEntry;
28 import java.util.jar.JarFile;
29 import java.util.zip.ZipEntry;
30
31 import org.djutils.io.ResourceResolver;
32 import org.djutils.primitives.Primitive;
33
34
35
36
37
38
39
40
41
42
43
44 public final class ClassUtil
45 {
46
47 private static final Map<String, Object> CACHE = Collections.synchronizedMap(new LinkedHashMap<String, Object>());
48
49
50
51
52 private ClassUtil()
53 {
54
55 }
56
57
58
59
60
61
62
63
64
65
66
67 @SuppressWarnings("unchecked")
68 public static <T> Constructor<T>[] getAllConstructors(final Class<T> clazz)
69 {
70 return (Constructor<T>[]) clazz.getDeclaredConstructors();
71 }
72
73
74
75
76
77
78
79
80
81
82 @SuppressWarnings("unchecked")
83 private static <T> Constructor<T> resolveConstructorCache(final Class<T> clazz, final Class<?>[] parameterTypes)
84 throws NoSuchMethodException
85 {
86 String key = "CONSTRUCTOR:" + clazz + "@" + FieldSignature.toDescriptor(parameterTypes);
87 if (CACHE.containsKey(key))
88 {
89 return (Constructor<T>) CACHE.get(key);
90 }
91 Constructor<T> constructor = clazz.getDeclaredConstructor(parameterTypes);
92 CACHE.put(key, constructor);
93 return constructor;
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public static <T> Constructor<T> resolveConstructor(final Class<T> clazz, final Class<?> callerClass,
110 final Class<?>[] parameterTypes) throws NoSuchMethodException, IllegalAccessException
111 {
112 Constructor<T> constructor = ClassUtil.resolveConstructor(clazz, parameterTypes);
113 if (ClassUtil.isVisible(constructor, callerClass.getClass()))
114 {
115 return constructor;
116 }
117 throw new IllegalAccessException("constructor resolved but not visible");
118 }
119
120
121
122
123
124
125
126
127
128 @SuppressWarnings("unchecked")
129 public static <T> Constructor<T> resolveConstructor(final Class<T> clazz, final Class<?>[] parameterTypes)
130 throws NoSuchMethodException
131 {
132 try
133 {
134 return resolveConstructorCache(clazz, (Class<?>[]) ClassUtil.checkInput(parameterTypes, Class.class));
135 }
136 catch (Exception exception)
137 {
138 String className = clazz.getName();
139 if (className.indexOf("$") >= 0)
140 {
141 Class<?> parentClass = null;
142 try
143 {
144 parentClass = Class.forName(className.substring(0, className.lastIndexOf("$")));
145 }
146 catch (Exception e2)
147 {
148 throw new NoSuchMethodException("class " + parentClass + " not found to resolve constructor");
149 }
150 return (Constructor<T>) ClassUtil.resolveConstructor(parentClass,
151 (Class<?>[]) ClassUtil.checkInput(parameterTypes, Class.class));
152 }
153 throw new NoSuchMethodException("class " + clazz + " does not contain constructor");
154 }
155 }
156
157
158
159
160
161
162
163
164
165 @SuppressWarnings("unchecked")
166 public static <T> Constructor<T> resolveConstructor(final Class<T> clazz, final Object[] arguments)
167 throws NoSuchMethodException
168 {
169 Class<?>[] parameterTypes = ClassUtil.getClass(arguments);
170 String key = "CONSTRUCTOR:" + clazz + "@" + FieldSignature.toDescriptor(parameterTypes);
171 if (CACHE.containsKey(key))
172 {
173 return (Constructor<T>) CACHE.get(key);
174 }
175 try
176 {
177 return ClassUtil.resolveConstructor(clazz, parameterTypes);
178 }
179 catch (NoSuchMethodException noSuchMethodException)
180 {
181
182 Constructor<T>[] constructors = ClassUtil.getAllConstructors(clazz);
183
184 constructors = ClassUtil.matchSignature(constructors, parameterTypes);
185
186 Constructor<T> result = (Constructor<T>) ClassUtil.getSpecificConstructor(constructors);
187 CACHE.put(key, result);
188 return result;
189 }
190 }
191
192
193
194
195
196
197
198 public static boolean matchSignature(final Constructor<?> constructor, final Class<?>[] argTypes)
199 {
200 if (constructor.getParameterTypes().length != argTypes.length)
201 {
202 return false;
203 }
204 Class<?>[] types = constructor.getParameterTypes();
205 for (int i = 0; i < constructor.getParameterTypes().length; i++)
206 {
207 if (!(types[i].isAssignableFrom(argTypes[i]) || types[i].equals(Primitive.getPrimitive(argTypes[i]))))
208 {
209 return false;
210 }
211 }
212 return true;
213 }
214
215
216
217
218
219
220
221
222
223 @SuppressWarnings("unchecked")
224 public static <T> Constructor<T>[] matchSignature(final Constructor<T>[] constructors, final Class<?>[] argTypes)
225 {
226 List<Constructor<T>> results = new ArrayList<Constructor<T>>();
227 for (int i = 0; i < constructors.length; i++)
228 {
229 if (ClassUtil.matchSignature(constructors[i], argTypes))
230 {
231 results.add(constructors[i]);
232 }
233 }
234 return results.toArray(new Constructor[results.size()]);
235 }
236
237
238
239
240
241
242
243
244
245 public static Set<Field> getAllFields(final Class<?> clazz, final Set<Field> result)
246 {
247 Field[] fields = clazz.getDeclaredFields();
248 for (int i = 0; i < fields.length; i++)
249 {
250 result.add(fields[i]);
251 }
252 if (clazz.getSuperclass() != null)
253 {
254 return ClassUtil.getAllFields(clazz.getSuperclass(), result);
255 }
256 return result;
257 }
258
259
260
261
262
263
264 public static Set<Field> getAllFields(final Class<?> clazz)
265 {
266 Set<Field> fieldSet = new LinkedHashSet<Field>();
267 return ClassUtil.getAllFields(clazz, fieldSet);
268 }
269
270
271
272
273
274
275
276
277
278 public static Field resolveField(final Class<?> clazz, final String fieldName) throws NoSuchFieldException
279 {
280 try
281 {
282 return resolveFieldSuper(clazz, fieldName);
283 }
284 catch (NoSuchFieldException noSuchFieldException)
285 {
286 String className = clazz.getName();
287 if (className.indexOf("$") >= 0)
288 {
289 Class<?> clazz2 = null;
290 try
291 {
292 clazz2 = Class.forName(className.substring(0, className.lastIndexOf("$")));
293 }
294 catch (ClassNotFoundException classNotFoundException)
295 {
296 throw new NoSuchFieldException("class " + clazz + " not found to resolve field " + fieldName);
297 }
298 return ClassUtil.resolveField(clazz2, fieldName);
299 }
300 throw new NoSuchFieldException("class " + clazz + " does not contain field " + fieldName);
301 }
302 }
303
304
305
306
307
308
309
310
311
312 public static Field resolveField(final Class<?> clazz, final Class<?> callerClass, final String name)
313 throws NoSuchFieldException
314 {
315 Field field = ClassUtil.resolveField(clazz, name);
316 if (ClassUtil.isVisible(field, callerClass.getClass()))
317 {
318 return field;
319 }
320 throw new NoSuchFieldException("field resolved but not visible");
321 }
322
323
324
325
326
327
328
329
330 public static Field resolveField(final Object object, final String fieldName) throws NoSuchFieldException
331 {
332 if (object == null)
333 {
334 throw new NoSuchFieldException("resolveField: object is null for field " + fieldName);
335 }
336 return resolveField(object.getClass(), fieldName);
337 }
338
339
340
341
342
343
344
345
346
347 public static List<Method> getAllMethods(final Class<?> clazz, final List<Method> result)
348 {
349 Method[] methods = clazz.getDeclaredMethods();
350 for (int i = 0; i < methods.length; i++)
351 {
352 result.add(methods[i]);
353 }
354 if (clazz.getSuperclass() != null)
355 {
356 return ClassUtil.getAllMethods(clazz.getSuperclass(), result);
357 }
358 return result;
359 }
360
361
362
363
364
365
366 public static List<Method> getAllMethods(final Class<?> clazz)
367 {
368 List<Method> methodSet = new ArrayList<Method>();
369 return ClassUtil.getAllMethods(clazz, methodSet);
370 }
371
372
373
374
375
376
377
378
379
380 public static List<Method> getAllMethods(final Class<?> clazz, final String name, final List<Method> result)
381 {
382 Method[] methods = clazz.getDeclaredMethods();
383 for (int i = 0; i < methods.length; i++)
384 {
385 if (methods[i].getName().equals(name))
386 {
387 result.add(methods[i]);
388 }
389 }
390 if (clazz.getSuperclass() != null)
391 {
392 return ClassUtil.getAllMethods(clazz.getSuperclass(), name, result);
393 }
394 return result;
395 }
396
397
398
399
400
401
402
403 public static List<Method> getAllMethods(final Class<?> clazz, final String name)
404 {
405 List<Method> methodSet = new ArrayList<Method>();
406 return ClassUtil.getAllMethods(clazz, name, methodSet);
407 }
408
409
410
411
412
413
414
415
416
417
418 public static Method resolveMethod(final Class<?> clazz, final Class<?> callerClass, final String name,
419 final Class<?>[] parameterTypes) throws NoSuchMethodException
420 {
421 Method method = ClassUtil.resolveMethod(clazz, name, parameterTypes);
422 if (ClassUtil.isVisible(method, callerClass))
423 {
424 return method;
425 }
426 throw new NoSuchMethodException("method found but not visible");
427 }
428
429
430
431
432
433
434
435
436
437 public static Method resolveMethod(final Class<?> clazz, final String name, final Class<?>[] parameterTypes)
438 throws NoSuchMethodException
439 {
440 try
441 {
442 return resolveMethodSuper(clazz, name, (Class<?>[]) ClassUtil.checkInput(parameterTypes, Class.class));
443 }
444 catch (Exception exception)
445 {
446 String className = clazz.getName();
447 if (className.indexOf("$") >= 0)
448 {
449 Class<?> parentClass = null;
450 try
451 {
452 parentClass = Class.forName(className.substring(0, className.lastIndexOf("$")));
453 }
454 catch (Exception e2)
455 {
456 throw new NoSuchMethodException("class " + parentClass + " not found to resolve method " + name);
457 }
458 return ClassUtil.resolveMethod(parentClass, name,
459 (Class<?>[]) ClassUtil.checkInput(parameterTypes, Class.class));
460 }
461 throw new NoSuchMethodException("class " + clazz + " does not contain method " + name);
462 }
463 }
464
465
466
467
468
469
470
471
472
473 public static Method resolveMethod(final Object object, final String name, final Class<?>[] parameterTypes)
474 throws NoSuchMethodException
475 {
476 if (object == null)
477 {
478 throw new NoSuchMethodException("resolveField: object is null for method " + name);
479 }
480 return resolveMethod(object.getClass(), name, parameterTypes);
481 }
482
483
484
485
486
487
488
489
490
491 public static Method resolveMethod(final Object object, final String name, final Object[] arguments)
492 throws NoSuchMethodException
493 {
494 Class<?>[] parameterTypes = ClassUtil.getClass(arguments);
495 String key = "METHOD:" + object.getClass() + "@" + name + "@" + FieldSignature.toDescriptor(parameterTypes);
496 if (CACHE.containsKey(key))
497 {
498 return (Method) CACHE.get(key);
499 }
500 try
501 {
502 return ClassUtil.resolveMethod(object, name, parameterTypes);
503 }
504 catch (NoSuchMethodException noSuchMethodException)
505 {
506
507 List<Method> methods = ClassUtil.getAllMethods(object.getClass(), name);
508 if (methods.size() == 0)
509 {
510 throw new NoSuchMethodException("No such method: " + name + " for object " + object);
511 }
512
513 methods = ClassUtil.matchSignature(methods, name, parameterTypes);
514 if (methods.size() == 0)
515 {
516 throw new NoSuchMethodException("No method with right signature: " + name + " for object " + object);
517 }
518
519 Method result = ClassUtil.getSpecificMethod(methods);
520 CACHE.put(key, result);
521 return result;
522 }
523 }
524
525
526
527
528
529
530
531
532
533 public static Set<Annotation> getAllAnnotations(final Class<?> clazz, final Set<Annotation> result)
534 {
535 Annotation[] annotations = clazz.getDeclaredAnnotations();
536 for (int i = 0; i < annotations.length; i++)
537 {
538 result.add(annotations[i]);
539 }
540 if (clazz.getSuperclass() != null)
541 {
542 return ClassUtil.getAllAnnotations(clazz.getSuperclass(), result);
543 }
544 return result;
545 }
546
547
548
549
550
551
552 public static Set<Annotation> getAllAnnotations(final Class<?> clazz)
553 {
554 Set<Annotation> annotationSet = new LinkedHashSet<Annotation>();
555 return ClassUtil.getAllAnnotations(clazz, annotationSet);
556 }
557
558
559
560
561
562
563
564
565
566 public static Annotation resolveAnnotation(final Class<?> clazz, final Class<? extends Annotation> annotationClass)
567 throws NoSuchElementException
568 {
569 try
570 {
571 return resolveAnnotationSuper(clazz, annotationClass);
572 }
573 catch (NoSuchElementException noSuchAnnotationException)
574 {
575 String className = clazz.getName();
576 if (className.indexOf("$") >= 0)
577 {
578 Class<?> clazz2 = null;
579 try
580 {
581 clazz2 = Class.forName(className.substring(0, className.lastIndexOf("$")));
582 }
583 catch (ClassNotFoundException classNotFoundException)
584 {
585 throw new NoSuchElementException("class " + clazz + " not found to resolve annotation " + annotationClass);
586 }
587 return ClassUtil.resolveAnnotation(clazz2, annotationClass);
588 }
589 throw new NoSuchElementException("class " + clazz + " does not contain annotation " + annotationClass);
590 }
591 }
592
593
594
595
596
597
598
599
600
601
602 public static boolean isVisible(final int modifiers, final Class<?> declaringClass, final Class<?> caller)
603 {
604 if (Modifier.isPublic(modifiers))
605 {
606 return true;
607 }
608 if (Modifier.isProtected(modifiers))
609 {
610 if (declaringClass.isAssignableFrom(caller))
611 {
612 return true;
613 }
614 if (declaringClass.getPackage().equals(caller.getPackage()))
615 {
616 return true;
617 }
618 return false;
619 }
620 if (declaringClass.equals(caller))
621 {
622 return true;
623 }
624 return false;
625 }
626
627
628
629
630
631
632
633
634
635 public static boolean isMoreSpecific(final Class<?>[] a, final Class<?>[] b)
636 {
637 if (a.length != b.length)
638 {
639 return false;
640 }
641 int i = 0;
642 while (i < a.length)
643 {
644 if (!b[i].isAssignableFrom(a[i]))
645 {
646 return false;
647 }
648 i++;
649 }
650 return true;
651 }
652
653
654
655
656
657
658
659
660
661 public static boolean isMoreSpecific(final Constructor<?> a, final Constructor<?> b)
662 {
663 if (Arrays.equals(a.getParameterTypes(), b.getParameterTypes()))
664 {
665 if (b.getDeclaringClass().isAssignableFrom(a.getDeclaringClass()))
666 {
667 return true;
668 }
669 }
670 return ClassUtil.isMoreSpecific(a.getParameterTypes(), b.getParameterTypes());
671 }
672
673
674
675
676
677
678
679
680
681 public static boolean isMoreSpecific(final Method a, final Method b)
682 {
683 if (!a.getName().equals(b.getName()))
684 {
685 return false;
686 }
687 return ClassUtil.isMoreSpecific(a.getParameterTypes(), b.getParameterTypes());
688 }
689
690
691
692
693
694
695
696 public static boolean isVisible(final Field field, final Class<?> caller)
697 {
698 return ClassUtil.isVisible(field.getModifiers(), field.getDeclaringClass(), caller);
699 }
700
701
702
703
704
705
706
707 public static boolean isVisible(final Constructor<?> constructor, final Class<?> caller)
708 {
709 return ClassUtil.isVisible(constructor.getModifiers(), constructor.getDeclaringClass(), caller);
710 }
711
712
713
714
715
716
717
718 public static boolean isVisible(final Method method, final Class<?> caller)
719 {
720 return ClassUtil.isVisible(method.getModifiers(), method.getDeclaringClass(), caller);
721 }
722
723
724
725
726
727
728
729
730
731 public static List<Method> matchSignature(final List<Method> methods, final String name, final Class<?>[] argTypes)
732 {
733 List<Method> results = new ArrayList<Method>();
734 for (int i = 0; i < methods.size(); i++)
735 {
736 if (ClassUtil.matchSignature(methods.get(i), name, argTypes))
737 {
738 results.add(methods.get(i));
739 }
740 }
741 return results;
742 }
743
744
745
746
747
748
749
750
751 public static boolean matchSignature(final Method method, final String name, final Class<?>[] argTypes)
752 {
753 if (!method.getName().equals(name))
754 {
755 return false;
756 }
757 if (method.getParameterTypes().length != argTypes.length)
758 {
759 return false;
760 }
761 Class<?>[] types = method.getParameterTypes();
762 for (int i = 0; i < method.getParameterTypes().length; i++)
763 {
764 if (!(types[i].isAssignableFrom(argTypes[i]) || types[i].equals(Primitive.getPrimitive(argTypes[i]))))
765 {
766 return false;
767 }
768 }
769 return true;
770 }
771
772
773
774
775
776
777
778
779 public static Class<?>[] getClass(final Object[] array)
780 {
781 if (array == null)
782 {
783 return new Class[0];
784 }
785 Class<?>[] result = new Class[array.length];
786 for (int i = 0; i < result.length; i++)
787 {
788 if (array[i] == null)
789 {
790 result[i] = null;
791 }
792 else
793 {
794 result[i] = array[i].getClass();
795 }
796 }
797 return result;
798 }
799
800
801
802
803
804
805
806
807
808 private static Object checkInput(final Object[] array, final Class<?> myClass)
809 {
810 if (array != null)
811 {
812 return array;
813 }
814 return Array.newInstance(myClass, 0);
815 }
816
817
818
819
820
821
822
823
824
825 private static Constructor<?> getSpecificConstructor(final Constructor<?>[] methods) throws NoSuchMethodException
826 {
827 if (methods.length == 0)
828 {
829 throw new NoSuchMethodException();
830 }
831 if (methods.length == 1)
832 {
833 return methods[0];
834 }
835
836 int resultID = 0;
837 while (resultID < methods.length)
838 {
839
840 boolean success = true;
841 for (int i = 0; i < methods.length; i++)
842 {
843 if (resultID == i)
844 {
845 continue;
846 }
847 if (!isMoreSpecific(methods[resultID], methods[i]))
848 {
849 success = false;
850 }
851 }
852
853 if (success)
854 {
855 return methods[resultID];
856 }
857 resultID++;
858 }
859
860 throw new NoSuchMethodException();
861 }
862
863
864
865
866
867
868
869
870
871 private static Method getSpecificMethod(final List<Method> methods) throws NoSuchMethodException
872 {
873
874 if (methods.size() == 0)
875 {
876 throw new NoSuchMethodException();
877 }
878 if (methods.size() == 1)
879 {
880 return methods.get(0);
881 }
882
883 int resultID = 0;
884 while (resultID < methods.size())
885 {
886
887 boolean success = true;
888 for (int i = 0; i < methods.size(); i++)
889 {
890 if (resultID == i)
891 {
892 continue;
893 }
894 if (!isMoreSpecific(methods.get(resultID), methods.get(i)))
895 {
896 success = false;
897 }
898 }
899
900 if (success)
901 {
902 return methods.get(resultID);
903 }
904 resultID++;
905 }
906
907 throw new NoSuchMethodException();
908 }
909
910
911
912
913
914
915
916
917
918 private static Method resolveMethodSuper(final Class<?> clazz, final String name, final Class<?>[] parameterTypes)
919 throws NoSuchMethodException
920 {
921 String key = "METHOD:" + clazz + "@" + name + "@" + FieldSignature.toDescriptor(parameterTypes);
922 try
923 {
924 if (CACHE.containsKey(key))
925 {
926 return (Method) CACHE.get(key);
927 }
928 Method method = clazz.getDeclaredMethod(name, parameterTypes);
929 CACHE.put(key, method);
930 return method;
931 }
932 catch (Exception exception)
933 {
934 if (clazz.getSuperclass() != null)
935 {
936 Method method = ClassUtil.resolveMethodSuper(clazz.getSuperclass(), name, parameterTypes);
937 CACHE.put(key, method);
938 return method;
939 }
940 throw new NoSuchMethodException(exception.getMessage());
941 }
942 }
943
944
945
946
947
948
949
950
951 private static Field resolveFieldSuper(final Class<?> clazz, final String fieldName) throws NoSuchFieldException
952 {
953 String key = "FIELD:" + clazz + "@" + fieldName;
954 try
955 {
956 if (CACHE.containsKey(key))
957 {
958 return (Field) CACHE.get(key);
959 }
960 Field result = clazz.getDeclaredField(fieldName);
961 CACHE.put(key, result);
962 return result;
963 }
964 catch (Exception exception)
965 {
966 if (clazz.getSuperclass() != null)
967 {
968 Field result = ClassUtil.resolveFieldSuper(clazz.getSuperclass(), fieldName);
969 CACHE.put(key, result);
970 return result;
971 }
972 throw new NoSuchFieldException(exception.getMessage());
973 }
974 }
975
976
977
978
979
980
981
982
983 private static Annotation resolveAnnotationSuper(final Class<?> clazz, final Class<? extends Annotation> annotationClass)
984 throws NoSuchElementException
985 {
986 String key = "ANNOTATION:" + clazz + "@" + annotationClass;
987 try
988 {
989 if (CACHE.containsKey(key))
990 {
991 return (Annotation) CACHE.get(key);
992 }
993 Annotation[] annotations = clazz.getDeclaredAnnotations();
994 Annotation result = null;
995 for (Annotation annotation : annotations)
996 {
997 if (annotation.annotationType().equals(annotationClass))
998 {
999 result = annotation;
1000 break;
1001 }
1002 }
1003 if (result == null)
1004 {
1005 throw new NoSuchElementException("Annotation " + annotationClass + " not found in class " + clazz.getName());
1006 }
1007 CACHE.put(key, result);
1008 return result;
1009 }
1010 catch (Exception exception)
1011 {
1012 if (clazz.getSuperclass() != null)
1013 {
1014 Annotation result = ClassUtil.resolveAnnotationSuper(clazz.getSuperclass(), annotationClass);
1015 CACHE.put(key, result);
1016 return result;
1017 }
1018 throw new NoSuchElementException(exception.getMessage());
1019 }
1020 }
1021
1022
1023
1024
1025
1026
1027 public static ClassFileDescriptor classFileDescriptorForObject(final Object object)
1028 {
1029 return classFileDescriptorForClass(object.getClass());
1030 }
1031
1032
1033
1034
1035
1036
1037 public static ClassFileDescriptor classFileDescriptorForClass(final Class<?> clazz)
1038 {
1039 Path classPath = ResourceResolver.resolve("/" + clazz.getName().replaceAll("\\.", "/") + ".class").asPath();
1040 return classFileDescriptorForPath(classPath);
1041 }
1042
1043
1044
1045
1046
1047
1048 public static ClassFileDescriptor classFileDescriptorForPath(final Path classPath)
1049 {
1050 try
1051 {
1052 URL clazzUrl = classPath.toUri().toURL();
1053 if (clazzUrl.toString().startsWith("jar:file:") && clazzUrl.toString().contains("!"))
1054 {
1055 String[] parts = clazzUrl.toString().split("\\!");
1056 String jarFileName = parts[0].replace("jar:file:", "");
1057 try
1058 {
1059 URL jarURL = new URL("file:" + jarFileName);
1060 File jarUrlFile = new File(jarURL.toURI());
1061 try (JarFile jarFile = new JarFile(jarUrlFile))
1062 {
1063 if (parts[1].startsWith("/"))
1064 {
1065 parts[1] = parts[1].substring(1);
1066 }
1067 JarEntry jarEntry = jarFile.getJarEntry(parts[1]);
1068 return new ClassFileDescriptor(jarEntry, jarFileName + "!" + parts[1]);
1069 }
1070 catch (Exception exception)
1071 {
1072 URL jarURL2 = new URL("file:" + jarFileName);
1073 return new ClassFileDescriptor(new File(jarURL2.toURI()));
1074 }
1075 }
1076 catch (URISyntaxException | MalformedURLException exception)
1077 {
1078 return new ClassFileDescriptor(new File(jarFileName));
1079 }
1080 }
1081 try
1082 {
1083 return new ClassFileDescriptor(new File(clazzUrl.toURI()));
1084 }
1085 catch (URISyntaxException exception)
1086 {
1087 return new ClassFileDescriptor(new File(clazzUrl.getPath()));
1088 }
1089 }
1090 catch (MalformedURLException exception)
1091 {
1092 return new ClassFileDescriptor(new File(classPath.toString()));
1093 }
1094
1095 }
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106 public static class ClassFileDescriptor
1107 {
1108
1109 private final String name;
1110
1111
1112 private final String path;
1113
1114
1115 private final boolean jar;
1116
1117
1118 private long lastChangedDate;
1119
1120
1121
1122
1123
1124 public ClassFileDescriptor(final File classFile)
1125 {
1126 this.name = classFile.getName();
1127 this.path = classFile.getPath();
1128 this.jar = false;
1129 long lastModified = classFile.lastModified();
1130 if (lastModified == 0L)
1131 {
1132 BasicFileAttributes attributes;
1133 try
1134 {
1135 attributes = Files.readAttributes(Paths.get(this.path), BasicFileAttributes.class);
1136 lastModified = attributes.lastModifiedTime().toMillis();
1137 }
1138 catch (IOException exception)
1139 {
1140
1141 }
1142 }
1143 this.lastChangedDate = lastModified;
1144 }
1145
1146
1147
1148
1149
1150
1151 public ClassFileDescriptor(final JarEntry jarEntry, final String path)
1152 {
1153 this.name = jarEntry.getName();
1154 this.path = path;
1155 this.jar = true;
1156 this.lastChangedDate = jarEntry.getLastModifiedTime().toMillis();
1157 }
1158
1159
1160
1161
1162
1163
1164 public ClassFileDescriptor(final ZipEntry zipEntry, final String path)
1165 {
1166 this.name = zipEntry.getName();
1167 this.path = path;
1168 this.jar = true;
1169 this.lastChangedDate = zipEntry.getLastModifiedTime().toMillis();
1170 }
1171
1172
1173
1174
1175 public String getName()
1176 {
1177 return this.name;
1178 }
1179
1180
1181
1182
1183 public String getPath()
1184 {
1185 return this.path;
1186 }
1187
1188
1189
1190
1191 public boolean isJar()
1192 {
1193 return this.jar;
1194 }
1195
1196
1197
1198
1199 public long getLastChangedDate()
1200 {
1201 return this.lastChangedDate;
1202 }
1203
1204 @Override
1205 public String toString()
1206 {
1207 return "ClassFileDescriptor [name=" + this.name + ", path=" + this.path + ", jar=" + this.jar + ", lastChangedDate="
1208 + this.lastChangedDate + "]";
1209 }
1210 }
1211 }