1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.giraph.utils;
20
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.lang.annotation.Annotation;
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.NoSuchElementException;
29 import java.util.jar.JarEntry;
30 import java.util.jar.JarInputStream;
31
32
33
34
35 public class AnnotationUtils {
36
37 private AnnotationUtils() {
38 }
39
40
41
42
43
44
45
46
47
48
49 public static <T extends Annotation> List<Class<?>> getAnnotatedClasses(
50 Class<T> annotation, String packageName) {
51 ArrayList<Class<?>> ret = new ArrayList<Class<?>>();
52 for (Iterator<Class<?>> it = getClassesIterator(packageName);
53 it.hasNext();) {
54 Class<?> clazz = it.next();
55 if (clazz.getAnnotation(annotation) != null) {
56 ret.add(clazz);
57 }
58 }
59 return ret;
60 }
61
62
63
64
65
66
67
68 public static Iterator<Class<?>> getClassesIterator(String packageName) {
69 if (isExecutedFromJar()) {
70 try {
71 return new JarClassesIterator(packageName);
72 } catch (IOException e) {
73 throw new RuntimeException(e);
74 }
75 } else {
76 return new GeneralClassesIterator(packageName);
77 }
78 }
79
80
81
82
83 private static boolean isExecutedFromJar() {
84 return AnnotationUtils.class.getResource("AnnotationUtils.class")
85 .getProtocol().equals("jar");
86 }
87
88
89
90
91
92
93
94
95 private static String getCurrentJar() {
96 return AnnotationUtils.class.getProtectionDomain().getCodeSource()
97 .getLocation().getFile();
98 }
99
100
101
102
103
104
105 private static class JarClassesIterator implements Iterator<Class<?>> {
106
107 private final JarInputStream jarIn;
108
109 private boolean entryLoaded;
110
111 private JarEntry currentEntry;
112
113 private final String path;
114
115
116
117
118
119 public JarClassesIterator(String packageName) throws IOException {
120 jarIn = new JarInputStream(new FileInputStream(new File(
121 getCurrentJar())));
122 entryLoaded = false;
123 currentEntry = null;
124 path = packageName.replace(".", File.separator);
125 }
126
127 @Override
128 public boolean hasNext() {
129 loadNextEntry();
130 return currentEntry != null;
131 }
132
133 @Override
134 public Class<?> next() {
135 loadNextEntry();
136 if (currentEntry == null) {
137 throw new NoSuchElementException();
138 }
139 entryLoaded = false;
140
141 String className = currentEntry.getName().replace(".class",
142 "").replace(File.separator, ".");
143 return loadClass(className);
144 }
145
146
147
148
149 private void loadNextEntry() {
150 while (!entryLoaded) {
151 try {
152 currentEntry = jarIn.getNextJarEntry();
153 if (currentEntry == null || (currentEntry.getName().endsWith(
154 ".class") && (currentEntry.getName().startsWith(path)))) {
155 entryLoaded = true;
156 } else {
157 currentEntry = null;
158 }
159 } catch (IOException e) {
160 throw new RuntimeException(e);
161 }
162 }
163 if (currentEntry == null) {
164 try {
165 jarIn.close();
166 } catch (IOException e) {
167 throw new RuntimeException(e);
168 }
169 }
170 }
171
172 @Override
173 public void remove() {
174 throw new UnsupportedOperationException(
175 "Can't remove from classes iterator");
176 }
177 }
178
179
180
181
182
183
184 private static class GeneralClassesIterator implements Iterator<Class<?>> {
185
186 private final int stringPosition;
187
188 private final Iterator<File> iterator;
189
190
191
192
193 public GeneralClassesIterator(String packageName) {
194 String mainPath = AnnotationUtils.class.getProtectionDomain()
195 .getCodeSource().getLocation().getFile();
196 String subPath = packageName.replace(".", File.separator);
197 File directory = new File(mainPath + subPath);
198 stringPosition = directory.getPath().length() - packageName.length();
199 List<File> files = new ArrayList<File>();
200 addAllClassFiles(directory, files);
201 iterator = files.iterator();
202 }
203
204
205
206
207
208
209
210 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
211 "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
212 private void addAllClassFiles(File directory, List<File> files) {
213 for (File file : directory.listFiles()) {
214 if (file.isDirectory()) {
215 addAllClassFiles(file, files);
216 } else if (file.getName().endsWith(".class")) {
217 files.add(file);
218 }
219 }
220 }
221
222 @Override
223 public boolean hasNext() {
224 return iterator.hasNext();
225 }
226
227 @Override
228 public Class<?> next() {
229 String className = iterator.next().getPath().substring(stringPosition)
230 .replace(".class", "").replace(File.separator, ".");
231 return loadClass(className);
232 }
233
234 @Override
235 public void remove() {
236 throw new UnsupportedOperationException(
237 "Can't remove from classes iterator");
238 }
239 }
240
241
242
243
244
245
246
247 private static Class<?> loadClass(String className) {
248 try {
249 return Class.forName(className);
250 } catch (ClassNotFoundException e) {
251 throw new RuntimeException("Error loading class " + className, e);
252 } catch (NoClassDefFoundError e) {
253 throw new RuntimeException("Error loading class " + className, e);
254 }
255 }
256 }