I have a stanza of code that is repeatedly used. Here are two examples:
public java.sql.Struct createStruct(String typeName, Object[] attributes) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Struct ret = delegate().createStruct(name.toLowerCase(), attributes);
setSearchPath(searchPath);
return ret;
}
public java.sql.Array createArray(String typeName, Object[] elements) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Array ret = delegate().createArray(name.toLowerCase(), elements);
setSearchPath(searchPath);
return ret;
}
You can see that these two methods have the general form:
public <T> createXXX(String typeName, Object[] objects) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = delegate().createXXX(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
Where T
is the return type of some set of functions createXXX
that have a common signature but different return type.
I'm pretty sure how I would do this in Javascript, F#, C#, Scala or any number of other languages.
I just can't seem to wrap my head around how to do this in Java in a type-safe manner that allows me to call each createXXX
method so that the setup and tear-down can happen in one block of code, rather than sprinkled throughout each wrapper method.
I know I could use reflection, but am looking for a way to do this using lambdas, if possible, or whatever structure makes the most sense in Java.
Something like this, where the method to be called is passed as the third parameter (I know this code is completely malformed in Java):
public Struct createStruct(String typeName, Object[] attributes) {
return createTypeWithCorrectSearchPath<>(
typeName,
attributes,
delegate().createStruct
);
}
public Struct createArray(String typeName, Object[] elements) {
return createTypeWithCorrectSearchPath<>(
typeName,
elements,
delegate().createArray
);
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
[SOME-METHOD-HERE]) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = [SOME-METHOD-HERE](name, objects);
setSearchPath(searchPath);
return ret;
}
I've read the apparently duplicate questions:
- How do I pass a method as a parameter in Java 8?
- How do I pass method as a parameter in Java?
- Java Pass Method as Parameter
As well as some questions about method references with generics:
For whatever reason it's not gelling for me, so I'm risking asking a question that will immediately be marked as duplicate in the hopes that someone will take pity and help me out...
UPDATE 2015-02-06
While both Louis Wasserman and Neuron gave basically the same answer, it was Louis that more pedantically offered a pattern that worked best for me... with an explicit example of how to pass the method reference.
Here's what ended up working for me:
interface SearchPathCreator<T> {
T create(String typeName, Object[] objects) throws SQLException;
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
SearchPathCreator<?> creator) throws SQLException {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
//noinspection unchecked
T ret = (T) creator.create(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
Which is called just like Louis suggested:
public Struct createStruct(
String typeName,
Object[] attributes) throws SQLException {
return createTypeWithCorrectSearchPath(
typeName,
attributes,
delegate()::createStruct
);
}