Yes, that's what I'm doing currently and it's working great. But it gets complicated when I'm joining against multiple tables, although even that I built a generic RowMapper that can do that. I just figured it was such a common use case there had to be something easier, and @Nested was it. I'm a dope for not seeing that earlier :) Now I just need to figure out how to get the prefix stuff working nicely with my existing code (see below) and with @Nested. It's turning out to be a little weird, but I probably am doing something wrong.
If anyone is curious, here is my monstrosity. You use it like so:
List<Book> books = query.reduceRows(new FlexJoinRowMapper<>(Book.class,
new FlexJoinRowMapper.Joint<>("a_id", Long.class, Author.class, Book::setAuthor),
new FlexJoinRowMapper.Joint<>("c_id", Long.class, Category.class, Book::setCategory)))
.collect(Collectors.toList());
...
public class FlexJoinRowMapper<Source> implements RowReducer<FlexJoinRowMapper.Container<Source>, Source> {
private Class<Source> sourceClass;
private Joint<Source, ?, ?>[] joints;
@SafeVarargs
public FlexJoinRowMapper(Class<Source> sourceClass, Joint<Source, ?, ?>... joints) {
this.sourceClass = sourceClass;
this.joints = joints;
}
@Override
public Container<Source> container() {
Container<Source> container = new Container<>();
for (Joint<Source, ?, ?> joint : joints) {
container.linkMap.put(joint.keyColumn, new HashMap());
}
return container;
}
@Override
public void accumulate(Container<Source> container, RowView rowView) {
Source source = rowView.getRow(sourceClass);
container.results.add(source);
for (Joint<Source, ?, ?> joint : joints) {
Map links = container.linkMap.get(joint.keyColumn);
Object key = rowView.getColumn(joint.keyColumn, joint.key);
if (key != null) {
Object ref = links.computeIfAbsent(key, item -> rowView.getRow(joint.ref));
joint.linker.link(source, ref);
}
}
}
@Override
public Stream<Source> stream(Container<Source> container) {
return container.results.stream();
}
static class Container<Source> {
Collection<Source> results = new ArrayList<>();
Map<String, Map> linkMap = new HashMap<>();
}
public static class Joint<Source, Ref, Key> {
private Class<Ref> ref;
private Class<Key> key;
private ObjectLinker linker;
private String keyColumn;
public Joint(String keyColumn, Class<Key> key, Class<Ref> ref, ObjectLinker<Source, Ref> linker) {
this.keyColumn = keyColumn;
this.ref = ref;
this.key = key;
this.linker = linker;
}
}
}
public interface ObjectLinker<Source, Ref> {
void link(Source source, Ref ref);
}