To address your "arbitrary types" question, you can implement a BinderFactory
to bind to anything you want.
@BindingAnnotation(UserBinder.UserBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface UserBinder {
public static class UserBinderFactory implements BinderFactory {
@Override
public Binder build(Annotation annotation) {
return new Binder<UserBinder, User>() {
@Override
public void bind(SQLStatement<?> q, UserBinder bind, User arg) {
q.bind("userId", arg.getUserId());
q.bind("uuid", arg.getUuid());
q.bind("openId", arg.getOpenId());
q.bind("givenName", arg.getGivenName());
// etc.
}
};
}
}
}
This is most useful if you have complex types that you want stored in a particular way, e.g. binary data, or collections that you want turned into CSVs or only stored in separate mapping tables. Then you use your new fancy binder like so:
@SqlUpdate(
"INSERT INTO user (openId,givenName,uuid," +
// etc.
") VALUES (:openId,:givenName,:uuid" +
// etc.
")"
)
public abstract int createUser(
@UserBinder User user
);
You can also use an @BindBean
annotation, which will automatically look up fields on an object by the bind parameter name (e.g. it can map a query placeholder ":userId"
to the getUserId()
method).