I am using Dropwizard with JDBI. I have a typical dao for user data:
public interface UserDao
{
@SqlQuery("select * from users where role = :id")
@Mapper(UserMapper.class)
String findNameById(@BindBean Role role);
}
The user itself has an attribute with a Role
type:
class User
{
private Role role;
/* the rest: other attributes, getters, setters, etc. */
}
Role is contained in another table called roles
. Now, I need to map Role
in the mapper, but I do not want to change the SELECT ...
statement to add the JOIN roles ...
part. We all know how joins affect queries and in the long run I'd like to avoid any joins if possible.
I know, that ResultSetMapper
interface has a map()
method, which gets a StatementContext
passed to it. That context has a getBinding()
method, which returns a Binding
class with all the data I need:
named = {HashMap$Node@1230} size = 3
0 = {HashMap$Node@1234} "id" -> "1"
1 = {HashMap$Node@1235} "name" -> "TestRole"
2 = {HashMap$Node@1236} "class" -> "class com.example.Role"
But that class com.example.Role
is not an instance of Role
, it's an instance of Argument
and I can't work with it.
So, is there a way to get that Role
argument and I just don't see it or do I have to instantiate it (again...) from the binding arguments (obviously they are there as debugger shows)?
I finally solved it by using a custom binder. First, I modified UserDao
to use @BindRole
instead of @BindBean
.
Next, I had to create the binder for the role. Here the role is bound manually on separate values:
@BindingAnnotation(BindRole.RoleBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindRole
{
public static class RoleBinderFactory implements BinderFactory
{
public Binder build(Annotation annotation)
{
return new Binder<BindRole, User>()
{
public void bind(SQLStatement q, BindRole bind, Role role)
{
q.bind("id", role.getId());
q.bind("name", role.getName());
q.define("role", role);
}
};
}
}
}
Notice the define()
method, it is responsible for setting attributes in StatementContext
, so don't overlook it.
Next, in the mapper I just have to get the Role
with getArgument()
:
Role role = new Role();
role.setId(1);
role.setName("TestRole");
Role r = (Role) statementContext.getAttribute("role");
boolean equals = e.equals(role);
In the debugger equals
is shown as true
, so problem solved. Woohoo.