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.