Mercurial > hg > Members > tatsuki > functionaljava-master > core
view 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 |
line wrap: on
line source
package fj.test.reflect; import static fj.Bottom.error; import fj.Class; import static fj.Class.clas; import fj.F; import fj.Function; import fj.P; import static fj.P.p; import fj.P2; import fj.P3; import fj.data.Array; import static fj.data.Array.array; import fj.data.List; import static fj.data.List.join; import static fj.data.List.list; import fj.data.Option; import static fj.data.Option.fromNull; import static fj.data.Option.none; import static fj.data.Option.some; import static fj.data.Option.somes; import fj.test.CheckResult; import fj.test.Property; import fj.test.Rand; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import static java.lang.reflect.Modifier.isStatic; /** * Functions for checking properties in a class that are found reflectively and according to various * annotations. * * @version %build.number% */ public final class Check { private Check() { throw new UnsupportedOperationException(); } /** * Returns the results and names of checking the properties on the given classes using a * {@link Rand#standard standard random generator}. * * @param c The classes to check the properties of. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given classes using a * {@link Rand#standard standard random generator}. */ public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final String... categories) { return check(c, Rand.standard, categories); } /** * Returns the results and names of checking the properties on the given classes using a * {@link Rand#standard standard random generator}. * * @param c The classes to check the properties of. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given classes using a * {@link Rand#standard standard random generator}. */ public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final List<String> categories) { return check(c, Rand.standard, categories.toArray().array(String[].class)); } /** * Returns the results and names of checking the properties on the given classes. * * @param c The classes to check the properties of. * @param r The random generator to use to check the properties on the given classes. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given classes. */ public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final Rand r, final String... categories) { return join(c.map(new F<java.lang.Class<T>, List<P2<String, CheckResult>>>() { public List<P2<String, CheckResult>> f(final java.lang.Class<T> c) { return check(c, r, categories); } })); } /** * Returns the results and names of checking the properties on the given classes. * * @param c The classes to check the properties of. * @param r The random generator to use to check the properties on the given classes. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given classes. */ public static <T> List<P2<String, CheckResult>> check(final List<java.lang.Class<T>> c, final Rand r, final List<String> categories) { return check(c, r, categories.toArray().array(String[].class)); } /** * Returns the results and names of checking the properties on the given class using a * {@link Rand#standard standard random generator}. * * @param c The class to check the properties of. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given class using a * {@link Rand#standard standard random generator}. */ public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final String... categories) { return check(c, Rand.standard, categories); } /** * Returns the results and names of checking the properties on the given class using a * {@link Rand#standard standard random generator}. * * @param c The class to check the properties of. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results and names of checking the properties on the given class using a * {@link Rand#standard standard random generator}. */ public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final List<String> categories) { return check(c, Rand.standard, categories.toArray().array(String[].class)); } /** * Returns the results and names of checking the properties on the given class. * * @param c The class to check the properties of. * @param r The random generator to use to check the properties on the given class. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results of checking the properties on the given class. */ public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final Rand r, final String... categories) { return join(clas(c).inheritance().map(new F<Class<? super T>, List<P3<Property, String, Option<CheckParams>>>>() { public List<P3<Property, String, Option<CheckParams>>> f(final Class<? super T> c) { return properties(c.clas(), categories); } })).map(new F<P3<Property, String, Option<CheckParams>>, P2<String, CheckResult>>() { public P2<String, CheckResult> f(final P3<Property, String, Option<CheckParams>> p) { if(p._3().isSome()) { final CheckParams ps = p._3().some(); return p(p._2(), p._1().check(r, ps.minSuccessful(), ps.maxDiscarded(), ps.minSize(), ps.maxSize())); } else return p(p._2(), p._1().check(r)); } }); } /** * Returns the results and names of checking the properties on the given class. * * @param c The class to check the properties of. * @param r The random generator to use to check the properties on the given class. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return The results of checking the properties on the given class. */ public static <T> List<P2<String, CheckResult>> check(final java.lang.Class<T> c, final Rand r, final List<String> categories) { return check(c, r, categories.toArray().array(String[].class)); } /** * Returns all properties, their name and possible check parameters in a given class that are * found reflectively and according to various annotations. For example, properties or their * enclosing class that are annotated with {@link NoCheck} are not considered. The name of a * property is specified by the {@link Name annotation} or if this annotation is not present, the * name of the method or field that represents the property. * * @param c The class to look for properties on. * @param categories The categories of properties to return. If no categories are specified, all * candidate properties are returned, otherwise, only those properties in the given categories are * returned (properties in no category are omitted in this latter case). * @return All properties, their name and possible check parameters in a given class that are * found reflectively and according to various annotations. */ public static <U, T extends U> List<P3<Property, String, Option<CheckParams>>> properties(final java.lang.Class<T> c, final String... categories) { //noinspection ClassEscapesDefinedScope final Array<P3<Property, String, Option<CheckParams>>> propFields = properties(array(c.getDeclaredFields()).map(new F<Field, PropertyMember>() { public PropertyMember f(final Field f) { return new PropertyMember() { public java.lang.Class<?> type() { return f.getType(); } public AnnotatedElement element() { return f; } public String name() { return f.getName(); } public int modifiers() { return f.getModifiers(); } public <X> Property invoke(final X x) throws IllegalAccessException { f.setAccessible(true); return (Property)f.get(x); } public boolean isProperty() { return true; } }; } }), c, categories); //noinspection ClassEscapesDefinedScope final Array<P3<Property, String, Option<CheckParams>>> propMethods = properties(array(c.getDeclaredMethods()).map(new F<Method, PropertyMember>() { public PropertyMember f(final Method m) { //noinspection ProhibitedExceptionDeclared return new PropertyMember() { public java.lang.Class<?> type() { return m.getReturnType(); } public AnnotatedElement element() { return m; } public String name() { return m.getName(); } public int modifiers() { return m.getModifiers(); } public <X> Property invoke(final X x) throws Exception { m.setAccessible(true); return (Property)m.invoke(x); } public boolean isProperty() { return m.getParameterTypes().length == 0; } }; } }), c, categories); return propFields.append(propMethods).toList(); } private interface PropertyMember { java.lang.Class<?> type(); AnnotatedElement element(); String name(); int modifiers(); @SuppressWarnings({"ProhibitedExceptionDeclared"}) <X> Property invoke(X x) throws Exception; boolean isProperty(); } private static <T> Array<P3<Property, String, Option<CheckParams>>> properties(final Array<PropertyMember> ms, final java.lang.Class<T> declaringClass, final String... categories) { final Option<T> t = emptyCtor(declaringClass).map(new F<Constructor<T>, T>() { @SuppressWarnings({"OverlyBroadCatchBlock"}) public T f(final Constructor<T> ctor) { try { ctor.setAccessible(true); return ctor.newInstance(); } catch(Exception e) { throw error(e.toString()); } } }); final F<AnnotatedElement, F<String, Boolean>> p = new F<AnnotatedElement, F<String, Boolean>>() { public F<String, Boolean> f(final AnnotatedElement e) { return new F<String, Boolean>() { public Boolean f(final String s) { final F<Category, Boolean> p = new F<Category, Boolean>() { public Boolean f(final Category c) { return array(c.value()).exists(new F<String, Boolean>() { public Boolean f(final String cs) { return cs.equals(s); } }); } }; @SuppressWarnings("unchecked") final List<Boolean> bss = somes(list(fromNull(e.getAnnotation(Category.class)).map(p), fromNull(declaringClass.getAnnotation(Category.class)).map(p))); return bss.exists(Function.<Boolean>identity()); } }; } }; final F<Name, String> nameS = new F<Name, String>() { public String f(final Name name) { return name.value(); } }; return ms.filter(new F<PropertyMember, Boolean>() { public Boolean f(final PropertyMember m) { //noinspection ObjectEquality return m.isProperty() && m.type() == Property.class && !m.element().isAnnotationPresent(NoCheck.class) && !declaringClass.isAnnotationPresent(NoCheck.class) && (categories.length == 0 || array(categories).exists(p.f(m.element()))) && (t.isSome() || isStatic(m.modifiers())); } }).map(new F<PropertyMember, P3<Property, String, Option<CheckParams>>>() { public P3<Property, String, Option<CheckParams>> f(final PropertyMember m) { try { final Option<CheckParams> params = fromNull(m.element().getAnnotation(CheckParams.class)).orElse(fromNull(declaringClass.getAnnotation(CheckParams.class))); final String name = fromNull(m.element().getAnnotation(Name.class)).map(nameS).orSome(m.name()); return p(m.invoke(t.orSome(P.<T>p(null))), name, params); } catch(Exception e) { throw error(e.toString()); } } }); } private static <T> Option<Constructor<T>> emptyCtor(final java.lang.Class<T> c) { Option<Constructor<T>> ctor; //noinspection UnusedCatchParameter try { ctor = some(c.getDeclaredConstructor()); } catch(NoSuchMethodException e) { ctor = none(); } return ctor; } }