User Guide

CRUD operations

If you want to use CRUD operations defined in net.sf.autodao.Dao interface, you need:

  1. Make you entity implement net.sf.autodao.PersistentEntity interface:
      @Entity
      public class Book implements PersistentEntity<Long> {
    
        ...
    
        public Long getPrimaryKey() {
          return this.id;
        }
      }
  2. Inherit your dao from net.sf.autodao.Dao interface:
    public interface BookDao extends Dao<Book, Long> {
      ...
    }
  3. Now you can use CRUD operations for you persistent object:

    Book b = new Book();
    b.setTitle("The Master and Margarita");
    
    dao.create(b); // new book was persisted
    
    Long id = ...;
    Book b2 = dao.get(id); // get by primary key
    dao.delete(b2); // book was deleted

Note that CRUD is absolutely optional, your DAO interfaces don't have to inherit from anything if you don't want to.

Named parameters

By default, finder method parameters are passed as indexed parameters. You can modify this behavior on per-method basis and use named parameters if you want:

public interface BookDao {

  @Finder(query="from Book where title = :title")
  Book getByTitle(@Named("title") String title);
}

It is a error to mix named and indexed parameters (AutoDAO will produce a error during startup).

Advice: use named parameters when you need to use same parameter more than once in query or if there are too many parameters.

Spring configuration

In order to configure AutoDAO, you first need to tell Spring about AutoDAO custom tags namespace by adding following attributes on beans root tag in Spring context file:

<beans xmlns:dao="http://autodao.sourceforge.net/schemas/autodao-0.12"
       xsi:schemaLocation="http://autodao.sourceforge.net/schemas/autodao-0.12
                           http://autodao.sourceforge.net/schemas/autodao-0.12.xsd">
  ...
</beans>

Explicit

To explicitly define your DAO in Spring context, you need to use dao:hibernate/dao:jpa tag. Its only required attribute is interface - interface this DAO will implement.

By default, AutoDAO searches Hibernate SessionFactory under sessionFactory bean name and JPA EntityManagerFactory under entityManagerFactory. If you use another bean name, then you need to tell AutoDAO about it by specifying its name in session-factory/entity-manager-factory attribute respectively.

If you want to assign specific bean name to your DAO, use id attribute (by default, Spring-assigned generated names are used).

In very rare conditions, you might want to explicitly specify persistent entity class for DAO. Use entity attribute for that.

Autodiscovery

There is alternative, much easier way to configure AutoDAO (idea borrowed from context:component-scan).

You may tell AutoDAO to automagically search classpath for DAO interfaces and define them as beans in Spring context.

Just put @AutoDAO annotation on interfaces that you want to be autodiscovered and add following to Spring context file:

Hibernate:

<dao:hibernateScan base-package="..." />

JPA:

<dao:jpaScan base-package="..." />

Where base-package attribute specifies package that'll be (recursively) searched for DAO interfaces with @AutoDAO annotation.

Same as with dao:hibernate/dao:jpa tag, you may provide alternative Hibernate SessionFactory bean name by specifying it in session-factory attribute and alternative EntityManagerFactory with entity-manager-factory attribute.

Transactions

AutoDAO doesn't begin/commit transactions itself. Instead, it participates in existing Spring-managed transactions. So it's your responsibility to properly setup transaction management. Read Transaction management Spring documentation.

By default, AutoDAO uses transactionManager bean name for PlatformTransactionManager. If you want to keep transaction manager under different name, tell AutoDAO to use it by specifying transaction-manager attribute on AutoDAO tags.

Single (unique) result

If you have a query that is guaranteed to return only one record, you can avoid List boilerplate in finder method return value and specify record type directly (you already saw this trick in quickstart):

public interface BookDao {

  @Finder(query="from Book where title = :title")
  Book getByTitle(@Named("title") String title);

  @Finder(query="select count(*) from Book")
  long countBooks();
}

You'll get exception from Hibernate if your query happens to return more than one result or ClassCastException if query result cannot be cast to finder method return value type.

Return value doesn't have to be persistent object, it can be any type that query will return.

Paging results

If you query needs result paging (also known as "maxResults"/"firstResult" or limit/offset), just use @Limit/@Offset annotations:

public interface BookDao {

  @Finder(query="from Book order by popularity")
  List<Book> getPopular(@Offset int pageNum, @Limit int pageSize);
}

Arguments with either @Limit or @Offset annotations won't be passed as query parameters but instead will be used to invoke appropriate methods of Hibernate query.

Custom result collections

In some situations you want finder method return value to be more specific than just java.util.List. For example, you know that all elements are unique and want to store them as java.util.Set. Or you want to perform some filtering on return value or any other case that involves non-list return value. Nothing complex, just specify desired collection type in return value and returnAs parameter of @Finder annotation:

public interface BookDao {

  @Finder(query="from Book where popularity > 20", returnAs=TreeSet.class)
  SortedSet<Book> getTopPopular();
}

You can use any collection implementation in returnAs argument so long as is has a no-arg constructor.

Collection/array arguments

If using named query parameters, you can declare finder methods with collection or array arguments:

public interface BookDao {

  @Finder(query="from Book where id in :ids")
  List<Book> getByIds(@Named("ids") long[] ids);

  @Finder(query="from Book where author in :authors")
  List<Book> findAllByAuthors(@Named("authors") Set<Author> authors);
}

Joda-time support

You can pass Joda-time ReadableInstant subclasses (most popular are DateTime and DateMidnight) and they'll be converted into java.util.Calendar instances that can be understood by Hibernate.

public interface BookDao {

  @Finder(query="from Book where date between ? and ?")
  List<Book> findBetween(DateMidnight since, DateMidnight until);
}

Named queries

If you have a legacy codebase with lots of named queries and don't want to move them into @Finder annotations, you can happily use existing named queries as is:

public interface BookDao {

  @Finder(queryName="Book.getByTitle")
  Book getByTitle(String title);
}

Using named native query is possible too:

public interface BookDao {

  @Finder(sqlQueryName="Book.sqlQuery")
  List<Object[]> findBySqlQuery(...);
}

Advice: use @Finder(query="...") instead of named queries. That way your queries are as close as possible to arguments that are passed to them.

Native SQL queries

Although ORM library such as Hibernate provides you with convenient query language, sometimes you want to use native SQL query. Nothing complex:

public interface BookDao {

  @Finder(sqlQuery = "select * from Book where title = :title")
  List<Object[]> getBookByTitle(@Named("title") String title);
}

Custom query argument transformation

In case you want to support custom query argument types, you can use query transformer API by writing classes that implements net.sf.autodao.QueryArgumentTransformer and declaring a map under autodaoQueryArgumentTransformers name in your application context.

Each key represents type that'll be converted and value points to converter instance that'll perform conversion.