SQL Object Argument Binding

Arguments passed to properly annotated methods on sql object instances will be bound to the statements being executed. There are two binding annotations included with JDBI, @Bind and @BindBean. In addition to these binding annotations, there is a facility for defining your own.

The @Bind annotation binds a single named argument. If no value is specified for the annotation it will bind the argument to the name it. For example:

public static interface BindExamples
{
  @SqlUpdate("insert into something (id, name) values (:id, :name)")
  void insert(@Bind("id") int id, @Bind("name") String name);

  @SqlUpdate("delete from something where name = :it")
  void deleteByName(@Bind String name);
}

The @BindBean annotation binds JavaBeans™ properties by name. If no value is given to the annotation the bean properties will be bound directly to their property names. If a value is given, the properties will be prefixed by the value given and a period. Take the Something bean, which has the properties id and name in the following example:

public static interface BindBeanExample
{
  @SqlUpdate("insert into something (id, name) values (:id, :name)")
  void insert(@BindBean Something s);

  @SqlUpdate("update something set name = :s.name where id = :s.id")
  void update(@BindBean("s") Something something);
}

Finally, we can define our own binding annotations. To do this we create an annotation type annotated with the @BindingAnnotation annotation. This annotation requires a value, which is a Class implementing BinderFactory. The BinderFactory is parameterized with the annotation type and the type of argument expected. When your custom binding annotation is used, a binder factory will be created and used to create Binder instances which actually bind the values. Let’s look at a trivial example.

// our binding annotation
@BindingAnnotation(BindSomething.SomethingBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindSomething 
{ 

  public static class SomethingBinderFactory implements BinderFactory
  {
    public Binder build(Annotation annotation)
    {
      return new Binder<BindSomething, Something>()
      {
        public void bind(SQLStatement q, BindSomething bind, Something arg)
        {
          q.bind("ident", arg.getId());
          q.bind("nom", arg.getName());
        }
      };
    }
  }
}

This binding annotation, @BindSomething is used to bind the properties of a something instance to the names ident and nom. The binding annotation is declared to be a binding annotation, using the static inner class SomethingBinderFactory. It is also declared to only apply to methods, and that it should be retained at runtime (the @Retention(RetentionPolicy.RUNTIME) annotation is really important, don’t forget it).

The SomethingBinderFactory produces a Binder instance which will receive the sql statement, the annotation which lead to it being used, and the argument which it is to bind. In this case it binds values statically, but you could have any values on the annotation you like to influence how it is bound.