Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can @Bind be used with enums and other arbitrary types using JDBI?

Does JDBI support binding of enum types via annotation?

For example, assuming a DAO that included a method:

@SqlQuery("select count(*) from answer a where a.foo = :foo")
Long someSqlQuery(@Bind("foo") Foo foo);

And, foo equal to Foo.BAR, could I expect a query:

select count(*) from answer a where a.foo = 'BAR'

If so, is toString() utilized to determine what is substituted?

Further, Does JDBI allow for using @Bind with any type that extends Object? And again, if so, is toString() used?

like image 809
vpiTriumph Avatar asked Apr 29 '15 19:04

vpiTriumph


People also ask

Is JDBI an ORM?

Jdbi is not an ORM. There is no session cache, change tracking, "open session in view", or cajoling the library to understand your schema. Instead, Jdbi provides straightforward mapping between SQL and simple tabular data structures.

How does JDBI work?

JDBI is a SQL convenience library for Java. It attempts to expose relational database access in idiomatic Java, using collections, beans, and so on, while maintaining the same level of detail as JDBC. It exposes two different style APIs, a fluent style and a sql object style.

What is a JDBI handle?

It is a wrapper around a JDBC Connection object. Handle provides essential methods for transaction management, statement creation, and other operations tied to the database session.


2 Answers

According to the source code Enum.name() is used, not toString()

If an object is bound, jdbi uses setObject(Object object) of the jdbc driver you're using. In my experience with PostgreSQL for example, it successfully binds Maps to hstore and arrays to postgreSQL arrays because that's what PostgreSQL's jdbc driver does.

If you want to handle a specific kind of objects in a specific way, you can implement ArgumentFactorys (for which there seems to be no documentation but an example here in Stack Overflow) or BinderFactorys (which I've just discovered now.)

like image 93
Natan Avatar answered Oct 21 '22 13:10

Natan


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).

like image 25
Patrick M Avatar answered Oct 21 '22 13:10

Patrick M