Skip to content

Instantly share code, notes, and snippets.

@sberan
Created December 13, 2012 15:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sberan/4277292 to your computer and use it in GitHub Desktop.
Save sberan/4277292 to your computer and use it in GitHub Desktop.
DB query with lambda concept
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
/* Just a fake DBHandle for example's sake */
class DBHandle {
public <T> QueryBuilder<T> query(String q) {
return new QueryBuilder<>();
}
}
class QueryBuilder<T> implements MetaFunction.MapResult<T, Stream<T>> {
final Map<String, Object> params = new HashMap<>();
public <U> QueryBuilder<T> setParameter(String name, Object value) {
params.put(name, value);
return this;
}
@Override
public Stream<T> mapResult(MetaFunction<T> handler) {
//TODO: actually create the stream here
return null;
}
}
public class DBExample {
static class Something {
public Something(Integer id, String name) {
}
}
public Set<Something> doSomeDBStuff(DBHandle db) {
//the parameter type should be inferred by the time jdk8 goes live, due to JEP 101.
//for now, we need to supply it:
return db.<Something>query("select id, name from something")
.mapResult((Integer id, String name) -> new Something(id, name))
.into(new HashSet<>());
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Yo dawg, I heard u like functions
*/
public interface MetaFunction<Result> {
//set of generic functions, with increasing arity.
//these should eventually be generated at compile time, to clean up the source and make it easier to modify
interface F<R> extends MetaFunction<R> { }
interface F0<R> extends F<R> { R apply(); }
interface F1<T1, R> extends F<R> { R apply(T1 p1); }
interface F2<T1, T2, R> extends F<R> { R apply(T1 p1, T2 p); }
interface F3<T1, T2, T3, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3); }
interface F4<T1, T2, T3, T4, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4); }
interface F5<T1, T2, T3, T4, T5, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5); }
interface F6<T1, T2, T3, T4, T5, T6, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc); }
interface F7<T1, T2, T3, T4, T5, T6, T7, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7); }
interface F8<T1, T2, T3, T4, T5, T6, T7, T8, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8); }
interface F9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8, T9 p9); }
interface F10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> extends F<R> { R apply(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 pc, T7 p7, T8 p8, T9 p9, T10 p10); }
/**
* Extend this to add a mapResult() method to your class which accepts function parameters with arity 0..10
*
* Eventually these could be generated for arbitrary method names via JSR-269
*/
interface MapResult<FunctionResultType, MethodResultType> {
MethodResultType mapResult(MetaFunction<FunctionResultType> handler);
default MethodResultType mapResult(F0<FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1> MethodResultType mapResult(F1<T1, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2> MethodResultType mapResult(F2<T1, T2, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3> MethodResultType mapResult(F3<T1, T2, T3, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4> MethodResultType mapResult(F4<T1, T2, T3, T4, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5> MethodResultType mapResult(F5<T1, T2, T3, T4, T5, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6> MethodResultType mapResult(F6<T1, T2, T3, T4, T5, T6, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7> MethodResultType mapResult(F7<T1, T2, T3, T4, T5, T6, T7, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8> MethodResultType mapResult(F8<T1, T2, T3, T4, T5, T6, T7, T8, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8, T9> MethodResultType mapResult(F9<T1, T2, T3, T4, T5, T6, T7, T8, T9, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
default <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> MethodResultType mapResult(F10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, FunctionResultType> handler) {
return mapResult((F<FunctionResultType>) handler);
}
}
/**
* Applies the function with a dynamic number of args. Shitty implementation, but hey it works.
*/
@SuppressWarnings("unchecked")
default final Result apply(Object... args) {
for(Method method : this.getClass().getDeclaredMethods()) {
if(method.getName().equals("apply") && !Arrays.deepEquals(method.getParameterTypes(), new Object[]{Object[].class})) {
try {
return (Result) method.invoke(this, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
throw new IllegalStateException("This function class does not have an application method!");
}
}
@brianm
Copy link

brianm commented Dec 13, 2012

I like it a lot, actually. The biggest problem I see is the interface for whatever is being passed to MapResult. It would need to be overloaded with (on the order of) (( * )! ) as far as I understand lambdas interactions with interfaces.

Do you hav a scheme in mind for how to implement this?

@sberan
Copy link
Author

sberan commented Dec 13, 2012

I've been toying around with this concept for a possible web library, and I've been able to get it working using type inference to infer the argument types. So it ends up being the order of () rather than (()!).

I have some code very much like this which is working, I can adapt it to this case and send it your way tonight.

@brianm
Copy link

brianm commented Dec 13, 2012

Please do, I'd love it!

@sberan
Copy link
Author

sberan commented Dec 14, 2012

Hey Brian, here it is! The MetaFunction stuff would hopefully be a library on its own, because I'm sure this will be a common need for library implementors. Looking forward to hearing your thoughts!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment