Mercurial > hg > Members > tatsuki > functionaljava-master > core
comparison src/main/java/fj/test/reflect/Check.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fe80c1edf1be |
---|---|
1 package fj.test.reflect; | |
2 | |
3 import static fj.Bottom.error; | |
4 import fj.Class; | |
5 import static fj.Class.clas; | |
6 import fj.F; | |
7 import fj.Function; | |
8 import fj.P; | |
9 import static fj.P.p; | |
10 import fj.P2; | |
11 import fj.P3; | |
12 import fj.data.Array; | |
13 import static fj.data.Array.array; | |
14 import fj.data.List; | |
15 import static fj.data.List.join; | |
16 import static fj.data.List.list; | |
17 import fj.data.Option; | |
18 import static fj.data.Option.fromNull; | |
19 import static fj.data.Option.none; | |
20 import static fj.data.Option.some; | |
21 import static fj.data.Option.somes; | |
22 import fj.test.CheckResult; | |
23 import fj.test.Property; | |
24 import fj.test.Rand; | |
25 | |
26 import java.lang.reflect.AnnotatedElement; | |
27 import java.lang.reflect.Constructor; | |
28 import java.lang.reflect.Field; | |
29 import java.lang.reflect.Method; | |
30 import static java.lang.reflect.Modifier.isStatic; | |
31 | |
32 /** | |
33 * Functions for checking properties in a class that are found reflectively and according to various | |
34 * annotations. | |
35 * | |
36 * @version %build.number% | |
37 */ | |
38 public final class Check { | |
39 private Check() { | |
40 throw new UnsupportedOperationException(); | |
41 } | |
42 | |
43 /** | |
44 * Returns the results and names of checking the properties on the given classes using a | |
45 * {@link Rand#standard standard random generator}. | |
46 * | |
47 * @param c The classes to check the properties of. | |
48 * @param categories The categories of properties to return. If no categories are specified, all | |
49 * candidate properties are returned, otherwise, only those properties in the given categories are | |
50 * returned (properties in no category are omitted in this latter case). | |
51 * @return The results and names of checking the properties on the given classes using a | |
52 * {@link Rand#standard standard random generator}. | |
53 */ | |
54 public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final String... categories) { | |
55 return check(c, Rand.standard, categories); | |
56 } | |
57 | |
58 /** | |
59 * Returns the results and names of checking the properties on the given classes using a | |
60 * {@link Rand#standard standard random generator}. | |
61 * | |
62 * @param c The classes to check the properties of. | |
63 * @param categories The categories of properties to return. If no categories are specified, all | |
64 * candidate properties are returned, otherwise, only those properties in the given categories are | |
65 * returned (properties in no category are omitted in this latter case). | |
66 * @return The results and names of checking the properties on the given classes using a | |
67 * {@link Rand#standard standard random generator}. | |
68 */ | |
69 public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final List<String> categories) { | |
70 return check(c, Rand.standard, categories.toArray().array(String[].class)); | |
71 } | |
72 | |
73 /** | |
74 * Returns the results and names of checking the properties on the given classes. | |
75 * | |
76 * @param c The classes to check the properties of. | |
77 * @param r The random generator to use to check the properties on the given classes. | |
78 * @param categories The categories of properties to return. If no categories are specified, all | |
79 * candidate properties are returned, otherwise, only those properties in the given categories are | |
80 * returned (properties in no category are omitted in this latter case). | |
81 * @return The results and names of checking the properties on the given classes. | |
82 */ | |
83 public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final Rand r, final String... categories) { | |
84 return join(c.map(new F<java.lang.Class<T>, List<P2<String, CheckResult>>>() { | |
85 public List<P2<String, CheckResult>> f(final java.lang.Class<T> c) { | |
86 return check(c, r, categories); | |
87 } | |
88 })); | |
89 } | |
90 | |
91 /** | |
92 * Returns the results and names of checking the properties on the given classes. | |
93 * | |
94 * @param c The classes to check the properties of. | |
95 * @param r The random generator to use to check the properties on the given classes. | |
96 * @param categories The categories of properties to return. If no categories are specified, all | |
97 * candidate properties are returned, otherwise, only those properties in the given categories are | |
98 * returned (properties in no category are omitted in this latter case). | |
99 * @return The results and names of checking the properties on the given classes. | |
100 */ | |
101 public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final Rand r, final List<String> categories) { | |
102 return check(c, r, categories.toArray().array(String[].class)); | |
103 } | |
104 | |
105 /** | |
106 * Returns the results and names of checking the properties on the given class using a | |
107 * {@link Rand#standard standard random generator}. | |
108 * | |
109 * @param c The class to check the properties of. | |
110 * @param categories The categories of properties to return. If no categories are specified, all | |
111 * candidate properties are returned, otherwise, only those properties in the given categories are | |
112 * returned (properties in no category are omitted in this latter case). | |
113 * @return The results and names of checking the properties on the given class using a | |
114 * {@link Rand#standard standard random generator}. | |
115 */ | |
116 public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final String... categories) { | |
117 return check(c, Rand.standard, categories); | |
118 } | |
119 | |
120 /** | |
121 * Returns the results and names of checking the properties on the given class using a | |
122 * {@link Rand#standard standard random generator}. | |
123 * | |
124 * @param c The class to check the properties of. | |
125 * @param categories The categories of properties to return. If no categories are specified, all | |
126 * candidate properties are returned, otherwise, only those properties in the given categories are | |
127 * returned (properties in no category are omitted in this latter case). | |
128 * @return The results and names of checking the properties on the given class using a | |
129 * {@link Rand#standard standard random generator}. | |
130 */ | |
131 public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final List<String> categories) { | |
132 return check(c, Rand.standard, categories.toArray().array(String[].class)); | |
133 } | |
134 | |
135 /** | |
136 * Returns the results and names of checking the properties on the given class. | |
137 * | |
138 * @param c The class to check the properties of. | |
139 * @param r The random generator to use to check the properties on the given class. | |
140 * @param categories The categories of properties to return. If no categories are specified, all | |
141 * candidate properties are returned, otherwise, only those properties in the given categories are | |
142 * returned (properties in no category are omitted in this latter case). | |
143 * @return The results of checking the properties on the given class. | |
144 */ | |
145 public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final Rand r, final String... categories) { | |
146 return join(clas(c).inheritance().map(new F<Class<? super T>, List<P3<Property, String, Option<CheckParams>>>>() { | |
147 public List<P3<Property, String, Option<CheckParams>>> f(final Class<? super T> c) { | |
148 return properties(c.clas(), categories); | |
149 } | |
150 })).map(new F<P3<Property, String, Option<CheckParams>>, P2<String, CheckResult>>() { | |
151 public P2<String, CheckResult> f(final P3<Property, String, Option<CheckParams>> p) { | |
152 if(p._3().isSome()) { | |
153 final CheckParams ps = p._3().some(); | |
154 return p(p._2(), p._1().check(r, ps.minSuccessful(), ps.maxDiscarded(), ps.minSize(), ps.maxSize())); | |
155 } else | |
156 return p(p._2(), p._1().check(r)); | |
157 } | |
158 }); | |
159 } | |
160 | |
161 /** | |
162 * Returns the results and names of checking the properties on the given class. | |
163 * | |
164 * @param c The class to check the properties of. | |
165 * @param r The random generator to use to check the properties on the given class. | |
166 * @param categories The categories of properties to return. If no categories are specified, all | |
167 * candidate properties are returned, otherwise, only those properties in the given categories are | |
168 * returned (properties in no category are omitted in this latter case). | |
169 * @return The results of checking the properties on the given class. | |
170 */ | |
171 public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final Rand r, final List<String> categories) { | |
172 return check(c, r, categories.toArray().array(String[].class)); | |
173 } | |
174 | |
175 /** | |
176 * Returns all properties, their name and possible check parameters in a given class that are | |
177 * found reflectively and according to various annotations. For example, properties or their | |
178 * enclosing class that are annotated with {@link NoCheck} are not considered. The name of a | |
179 * property is specified by the {@link Name annotation} or if this annotation is not present, the | |
180 * name of the method or field that represents the property. | |
181 * | |
182 * @param c The class to look for properties on. | |
183 * @param categories The categories of properties to return. If no categories are specified, all | |
184 * candidate properties are returned, otherwise, only those properties in the given categories are | |
185 * returned (properties in no category are omitted in this latter case). | |
186 * @return All properties, their name and possible check parameters in a given class that are | |
187 * found reflectively and according to various annotations. | |
188 */ | |
189 public static <U, T extends U> List<P3<Property, String, Option<CheckParams>>> properties(final java.lang.Class<T> c, final String... categories) { | |
190 //noinspection ClassEscapesDefinedScope | |
191 final Array<P3<Property, String, Option<CheckParams>>> propFields = properties(array(c.getDeclaredFields()).map(new F<Field, PropertyMember>() { | |
192 public PropertyMember f(final Field f) { | |
193 return new PropertyMember() { | |
194 public java.lang.Class<?> type() { | |
195 return f.getType(); | |
196 } | |
197 | |
198 public AnnotatedElement element() { | |
199 return f; | |
200 } | |
201 | |
202 public String name() { | |
203 return f.getName(); | |
204 } | |
205 | |
206 public int modifiers() { | |
207 return f.getModifiers(); | |
208 } | |
209 | |
210 public <X> Property invoke(final X x) throws IllegalAccessException { | |
211 f.setAccessible(true); | |
212 return (Property)f.get(x); | |
213 } | |
214 | |
215 public boolean isProperty() { | |
216 return true; | |
217 } | |
218 }; | |
219 } | |
220 }), c, categories); | |
221 | |
222 //noinspection ClassEscapesDefinedScope | |
223 final Array<P3<Property, String, Option<CheckParams>>> propMethods = properties(array(c.getDeclaredMethods()).map(new F<Method, PropertyMember>() { | |
224 public PropertyMember f(final Method m) { | |
225 //noinspection ProhibitedExceptionDeclared | |
226 return new PropertyMember() { | |
227 public java.lang.Class<?> type() { | |
228 return m.getReturnType(); | |
229 } | |
230 | |
231 public AnnotatedElement element() { | |
232 return m; | |
233 } | |
234 | |
235 public String name() { | |
236 return m.getName(); | |
237 } | |
238 | |
239 public int modifiers() { | |
240 return m.getModifiers(); | |
241 } | |
242 | |
243 public <X> Property invoke(final X x) throws Exception { | |
244 m.setAccessible(true); | |
245 return (Property)m.invoke(x); | |
246 } | |
247 | |
248 public boolean isProperty() { | |
249 return m.getParameterTypes().length == 0; | |
250 } | |
251 }; | |
252 } | |
253 }), c, categories); | |
254 | |
255 return propFields.append(propMethods).toList(); | |
256 } | |
257 | |
258 private interface PropertyMember { | |
259 java.lang.Class<?> type(); | |
260 AnnotatedElement element(); | |
261 String name(); | |
262 int modifiers(); | |
263 @SuppressWarnings({"ProhibitedExceptionDeclared"}) | |
264 <X> Property invoke(X x) throws Exception; | |
265 boolean isProperty(); | |
266 } | |
267 | |
268 private static <T> Array<P3<Property, String, Option<CheckParams>>> properties(final Array<PropertyMember> ms, final java.lang.Class<T> declaringClass, final String... categories) { | |
269 final Option<T> t = emptyCtor(declaringClass).map(new F<Constructor<T>, T>() { | |
270 @SuppressWarnings({"OverlyBroadCatchBlock"}) | |
271 public T f(final Constructor<T> ctor) { | |
272 try { | |
273 ctor.setAccessible(true); | |
274 return ctor.newInstance(); | |
275 } catch(Exception e) { | |
276 throw error(e.toString()); | |
277 } | |
278 } | |
279 }); | |
280 | |
281 final F<AnnotatedElement, F<String, Boolean>> p = new F<AnnotatedElement, F<String, Boolean>>() { | |
282 public F<String, Boolean> f(final AnnotatedElement e) { | |
283 return new F<String, Boolean>() { | |
284 public Boolean f(final String s) { | |
285 final F<Category, Boolean> p = new F<Category, Boolean>() { | |
286 public Boolean f(final Category c) { | |
287 return array(c.value()).exists(new F<String, Boolean>() { | |
288 public Boolean f(final String cs) { | |
289 return cs.equals(s); | |
290 } | |
291 }); | |
292 } | |
293 }; | |
294 | |
295 @SuppressWarnings("unchecked") | |
296 final List<Boolean> bss = somes(list(fromNull(e.getAnnotation(Category.class)).map(p), | |
297 fromNull(declaringClass.getAnnotation(Category.class)).map(p))); | |
298 return bss.exists(Function.<Boolean>identity()); | |
299 } | |
300 }; | |
301 } | |
302 }; | |
303 | |
304 final F<Name, String> nameS = new F<Name, String>() { | |
305 public String f(final Name name) { | |
306 return name.value(); | |
307 } | |
308 }; | |
309 | |
310 return ms.filter(new F<PropertyMember, Boolean>() { | |
311 public Boolean f(final PropertyMember m) { | |
312 //noinspection ObjectEquality | |
313 return m.isProperty() && | |
314 m.type() == Property.class && | |
315 !m.element().isAnnotationPresent(NoCheck.class) && | |
316 !declaringClass.isAnnotationPresent(NoCheck.class) && | |
317 (categories.length == 0 || array(categories).exists(p.f(m.element()))) && | |
318 (t.isSome() || isStatic(m.modifiers())); | |
319 } | |
320 }).map(new F<PropertyMember, P3<Property, String, Option<CheckParams>>>() { | |
321 public P3<Property, String, Option<CheckParams>> f(final PropertyMember m) { | |
322 try { | |
323 final Option<CheckParams> params = fromNull(m.element().getAnnotation(CheckParams.class)).orElse(fromNull(declaringClass.getAnnotation(CheckParams.class))); | |
324 final String name = fromNull(m.element().getAnnotation(Name.class)).map(nameS).orSome(m.name()); | |
325 return p(m.invoke(t.orSome(P.<T>p(null))), name, params); | |
326 } catch(Exception e) { | |
327 throw error(e.toString()); | |
328 } | |
329 } | |
330 }); | |
331 } | |
332 | |
333 private static <T> Option<Constructor<T>> emptyCtor(final java.lang.Class<T> c) { | |
334 Option<Constructor<T>> ctor; | |
335 | |
336 //noinspection UnusedCatchParameter | |
337 try { | |
338 ctor = some(c.getDeclaredConstructor()); | |
339 } catch(NoSuchMethodException e) { | |
340 ctor = none(); | |
341 } | |
342 return ctor; | |
343 } | |
344 } |