I'm playing around with lambdas and got into my head that I wanted to try creating a simple db/object mapper as a part of the learning.
Yes, there are plenty of frameworks that already do this, but this is more about learning and the problem I've run into is technical.
First, I wanted to define all mapping logic in an enum.
It started out plain and simple with just a bunch of field names:
enum ThingColumn {
id, language;
}
That let me create the following method (implementation not relevant) which gives api user compile check on columns:
public Collection<Thing> findAll(ThingColumn... columns);
After that I wanted to define more rules in the enum, specifically how results are mapped from a java.sql.ResultSet to my Thing class.
Starting out simple I created a functional interface:
@FunctionalInterface
static interface ThingResultMapper {
void map(Thing to, ResultSet from, String column) ;
}
and added it to the enum:
enum ThingColumn {
id((t, rs, col) -> t.setId(rs.getLong(col))),
language((t, rs, col) ->t.setLanguage(rs.getString(col)));
ThingColumn(ThingResultMapper mapper){..}
}
I created a mapResultSetRow method which uses the lambdas from the enum to extract data from the ResultSet:
public Thing mapResultSetRow(ResultSet rs, ThingColumn... fields) {
Thing t = new Thing();
Stream.of(fields)
.forEach(f -> f.getMapper().map(t, rs, f.name()));
return t;
}
The above findAll could then use the mapResultSetRow to apply relevant mappers to the ResultSet. Nice and tidy.
Almost anyway. I think the enum is quite ugly and contains a lot of boiler plate with that lambda you have to put in for every mapping. Ideally I would like to do this instead:
enum ThingColumn {
id(ResultSet::getLong, Thing::setId),
language(ResultSet::getString, Thing::setLanguage);
}
However that does of course not compile and now I'm stuck, problems with non-static/static.. I'll break it down a little first by removing some noise:
enum ThingColumn {
id(ResultSet::getLong); // <<- compile error
ThingColumn(Function<String,?> resultSetExtractor) {..}
}
Compile error: Cannot make a static reference to the non-static method getLong(String) from the type ResultSet.
I suppose what I want is either not possible to do, or possible by changing the signature of the labmda in the enum's constructor.
I found a similar issue in this question: Limits of static method references in Java 8 where Dmitry Ginzburg's answer (scroll down, not accepted as correct answer) outlines some issues, however no solution.
Thank you for reading so far :)
Any thoughts?
ResultSet::getLongexpresses a single method interface that takes a ResultSet instance, likeObject f(ResultSet rs, String col). At the very least this wouldn't fit into aFunction<String,?>. I wouldn't have expected that compile error from it, though.