org.javimmutable.collections.util.ReflectionFunctions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javimmutable-collections Show documentation
Show all versions of javimmutable-collections Show documentation
Library providing immutable/persistent collection classes for
Java. While collections are immutable they provide methods for
adding and removing values by creating new modified copies of
themselves. Each copy shares almost all of its structure with
other copies to minimize memory consumption.
///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
//
// Copyright (c) 2017, Burton Computer Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// Neither the name of the Burton Computer Corporation nor the names
// of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.javimmutable.collections.util;
import org.javimmutable.collections.Func0;
import org.javimmutable.collections.Func1;
import org.javimmutable.collections.Func2;
import org.javimmutable.collections.Func3;
import org.javimmutable.collections.Func4;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Contains static constructors for creating FuncN objects that call methods using reflection.
*/
@SuppressWarnings("unchecked")
public final class ReflectionFunctions
{
private ReflectionFunctions()
{
}
/**
* Encapsulates the various checked exceptions that can be thrown by the java reflection methods.
*/
public static class ReflectionException
extends RuntimeException
{
public ReflectionException(Throwable throwable)
{
super(throwable);
}
}
/**
* Exception thrown if caller requests a static class but reflection finds a non-static class (or vice versa).
*/
public static class StaticMismatchException
extends RuntimeException
{
public StaticMismatchException()
{
super("static modifier on method does not match expected value");
}
}
/**
* Returns a Func0 instance that calls the specified non-static method on the specified java object.
*
* @param obj the object whose method should be invoked
* @param name the name of the method to invoke
* @param the return type of the function
*/
public static Func0 method(final Object obj,
String name)
{
return new ReflectionFunc0<>(findMethod(obj.getClass(), name, false), obj);
}
/**
* Returns a Func1 instance that calls the specified non-static method on the specified java object.
*
* @param obj the object whose method should be invoked
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param parameter 1 type
* @param the return type of the function
*/
public static Func1 method(final Object obj,
String name,
Class arg1Class)
{
return new ReflectionFunc1<>(findMethod(obj.getClass(), name, false, arg1Class), obj);
}
/**
* Returns a Func2 instance that calls the specified non-static method on the specified java object.
*
* @param obj the object whose method should be invoked
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param parameter 1 type
* @param parameter 2 type
*/
public static Func2 method(final Object obj,
String name,
Class arg1Class,
Class arg2Class)
{
return new ReflectionFunc2<>(findMethod(obj.getClass(), name, false, arg1Class, arg2Class), obj);
}
/**
* Returns a Func3 instance that calls the specified non-static method on the specified java object.
*
* @param obj the object whose method should be invoked
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param arg3Class Class of parameter 3 of the method
* @param parameter 1 type
* @param parameter 2 type
* @param parameter 3 type
* @param the return type of the function
*/
public static Func3 method(final Object obj,
String name,
Class arg1Class,
Class arg2Class,
Class arg3Class)
{
return new ReflectionFunc3<>(findMethod(obj.getClass(), name, false, arg1Class, arg2Class, arg3Class), obj);
}
/**
* Returns a Func4 instance that calls the specified non-static method on the specified java object.
*
* @param obj the object whose method should be invoked
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param arg3Class Class of parameter 3 of the method
* @param arg4Class Class of parameter 4 of the method
* @param parameter 1 type
* @param parameter 2 type
* @param parameter 3 type
* @param parameter 4 type
* @param the return type of the function
*/
public static Func4 method(final Object obj,
String name,
Class arg1Class,
Class arg2Class,
Class arg3Class,
Class arg4Class)
{
return new ReflectionFunc4<>(findMethod(obj.getClass(), name, false, arg1Class, arg2Class, arg3Class, arg4Class), obj);
}
/**
* Returns a Func1 instance that calls the specified non-static method on a java object
* passed as the parameter of the function. These functions are useful for invoking
* the same method on all objects returned by a Cursor.
*
* @param name name of the method to invoke
* @param klass class of the instance object parameter
*/
public static Func1 method(String name,
Class klass)
{
return new ParamReflectionFunc1<>(findMethod(klass, name, false));
}
/**
* Returns a Func2 instance that calls the specified non-static method on a java object
* passed as the last parameter of the Func2. These functions are useful for invoking
* the same method with the same arguments on all objects returned by a Cursor. The instance
* object is the last parameter to facilitate the use of Curry.of().
*
* @param name name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param klass class of the instance object parameter
*/
public static Func2 method(String name,
Class arg1Class,
Class klass)
{
return new ParamReflectionFunc2<>(findMethod(klass, name, false, arg1Class));
}
/**
* Returns a Func3 instance that calls the specified non-static method on a java object
* passed as the last parameter of the Func3. These functions are useful for invoking
* the same method with the same arguments on all objects returned by a Cursor. The instance
* object is the last parameter to facilitate the use of Curry.of().
*
* @param name name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param klass class of the instance object parameter
*/
public static Func3 method(String name,
Class arg1Class,
Class arg2Class,
Class klass)
{
return new ParamReflectionFunc3<>(findMethod(klass, name, false, arg1Class, arg2Class));
}
/**
* Returns a Func4 instance that calls the specified non-static method on a java object
* passed as the last parameter of the Func4. These functions are useful for invoking
* the same method with the same arguments on all objects returned by a Cursor. The instance
* object is the last parameter to facilitate the use of Curry.of().
*
* @param name name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param arg3Class Class of parameter 3 of the method
* @param klass class of the instance object parameter
*/
public static Func4 method(String name,
Class arg1Class,
Class arg2Class,
Class arg3Class,
Class klass)
{
return new ParamReflectionFunc4<>(findMethod(klass, name, false, arg1Class, arg2Class, arg3Class));
}
/**
* Returns a Func0 instance that calls the specified static method on the specified java object.
*
* @param name the name of the method to invoke
* @param the return type of the function
*/
public static Func0 staticMethod(final Class klass,
String name)
{
return new ReflectionFunc0<>(findMethod(klass, name, true), null);
}
/**
* Returns a Func3 instance that calls the specified static method on the specified java object.
*
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param parameter 1 type
* @param the return type of the function
*/
public static Func1 staticMethod(final Class klass,
String name,
Class arg1Class)
{
return new ReflectionFunc1<>(findMethod(klass, name, true, arg1Class), null);
}
/**
* Returns a Func2 instance that calls the specified static method on the specified java object.
*
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param parameter 1 type
* @param parameter 2 type
* @param the return type of the function
*/
public static Func2 staticMethod(final Class klass,
String name,
Class arg1Class,
Class arg2Class)
{
return new ReflectionFunc2<>(findMethod(klass, name, true, arg1Class, arg2Class), null);
}
/**
* Returns a Func3 instance that calls the specified static method on the specified java object.
*
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param arg3Class Class of parameter 3 of the method
* @param parameter 1 type
* @param parameter 2 type
* @param parameter 3 type
* @param the return type of the function
*/
public static Func3 staticMethod(final Class klass,
String name,
Class arg1Class,
Class arg2Class,
Class arg3Class)
{
return new ReflectionFunc3<>(findMethod(klass, name, true, arg1Class, arg2Class, arg3Class), null);
}
/**
* Returns a Func4 instance that calls the specified static method on the specified java object.
*
* @param name the name of the method to invoke
* @param arg1Class Class of parameter 1 of the method
* @param arg2Class Class of parameter 2 of the method
* @param arg3Class Class of parameter 3 of the method
* @param arg4Class Class of parameter 4 of the method
* @param parameter 1 type
* @param parameter 2 type
* @param parameter 3 type
* @param parameter 4 type
* @param the return type of the function
*/
public static Func4 staticMethod(final Class klass,
String name,
Class arg1Class,
Class arg2Class,
Class arg3Class,
Class arg4Class)
{
return new ReflectionFunc4<>(findMethod(klass, name, true, arg1Class, arg2Class, arg3Class, arg4Class), null);
}
private static class NoInstanceReflectionBase
{
protected final Method method;
private NoInstanceReflectionBase(Method method)
{
this.method = method;
}
}
private static class ReflectionBase
extends NoInstanceReflectionBase
{
protected final Object obj;
private ReflectionBase(Method method,
Object obj)
{
super(method);
this.obj = obj;
}
}
private static class ReflectionFunc0
extends ReflectionBase
implements Func0
{
private ReflectionFunc0(Method method,
Object obj)
{
super(method, obj);
}
@Override
public R apply()
{
return (R)callMethod(method, obj);
}
}
private static class ReflectionFunc1
extends ReflectionBase
implements Func1
{
private ReflectionFunc1(Method method,
Object obj)
{
super(method, obj);
}
@Override
public R apply(P1 param1)
{
return (R)callMethod(method, obj, param1);
}
}
private static class ReflectionFunc2
extends ReflectionBase
implements Func2
{
private ReflectionFunc2(Method method,
Object obj)
{
super(method, obj);
}
@Override
public R apply(P1 param1,
P2 param2)
{
return (R)callMethod(method, obj, param1, param2);
}
}
private static class ReflectionFunc3
extends ReflectionBase
implements Func3
{
private ReflectionFunc3(Method method,
Object obj)
{
super(method, obj);
}
@Override
public R apply(P1 param1,
P2 param2,
P3 param3)
{
return (R)callMethod(method, obj, param1, param2, param3);
}
}
private static class ReflectionFunc4
extends ReflectionBase
implements Func4
{
private ReflectionFunc4(Method method,
Object obj)
{
super(method, obj);
}
@Override
public R apply(P1 param1,
P2 param2,
P3 param3,
P4 param4)
{
return (R)callMethod(method, obj, param1, param2, param3, param4);
}
}
private static class ParamReflectionFunc1
extends NoInstanceReflectionBase
implements Func1
{
private ParamReflectionFunc1(Method method)
{
super(method);
}
@Override
public R apply(OT obj)
{
return (R)callMethod(method, obj);
}
}
private static class ParamReflectionFunc2
extends NoInstanceReflectionBase
implements Func2
{
private ParamReflectionFunc2(Method method)
{
super(method);
}
@Override
public R apply(P1 param1,
OT obj)
{
return (R)callMethod(method, obj, param1);
}
}
private static class ParamReflectionFunc3
extends NoInstanceReflectionBase
implements Func3
{
private ParamReflectionFunc3(Method method)
{
super(method);
}
@Override
public R apply(P1 param1,
P2 param2,
OT obj)
{
return (R)callMethod(method, obj, param1, param2);
}
}
private static class ParamReflectionFunc4
extends NoInstanceReflectionBase
implements Func4
{
private ParamReflectionFunc4(Method method)
{
super(method);
}
@Override
public R apply(P1 param1,
P2 param2,
P3 param3,
OT obj)
{
return (R)callMethod(method, obj, param1, param2, param3);
}
}
private static Object callMethod(Method method,
Object obj,
Object... params)
{
try {
return method.invoke(obj, params);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new ReflectionException(e);
}
}
private static Method findMethod(Class klass,
String name,
boolean expectStatic,
Class... args)
{
try {
Method method = klass.getMethod(name, args);
boolean isStatic = (method.getModifiers() & Modifier.STATIC) != 0;
if (isStatic != expectStatic) {
throw new StaticMismatchException();
}
return method;
} catch (NoSuchMethodException e) {
throw new ReflectionException(e);
}
}
}