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