What is new in RavenDB 3.0JVM Client API

time to read 6 min | 1175 words

RavenDB has always been accessible from other platforms. We have users using RavenDB from Python and Node.JS, we also have users using Ruby & PHP, although there isn’t a publicly available resource for that.

With RaenDB 3.0, we release an official Java Client API for RavenDB. Using it is pretty simple if you are familiar with the RavenDB API or the Hibernate API.

We start by creating the document store:

IDocumentStore store = new DocumentStore(ravenDbUrl, "todo-db");
store.initialize();
store.executeIndex(new TodoByTitleIndex());

Note that we have an compiled index as well here, which looks like this:

public class TodoByTitleIndex extends AbstractIndexCreationTask {

    public TodoByTitleIndex() {
        map = "from t in docs.todos select new { t.Title, t.CreationDate } ";
        QTodo t = QTodo.todo;
        index(t.title, FieldIndexing.ANALYZED);
    }
}

Since Java doesn’t have Linq, we use the Querydsl to handle that. The index syntax is still Linq on the server side, though.

That is enough about setup, let us see how we can actually work with this. Here is us doing a search:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    ServletContext context = request.getSession().getServletContext();
    IDocumentStore store = (IDocumentStore) context.getAttribute(ContextManager.DOCUMENT_STORE);

    String searchText = request.getParameter("search");

    try (IDocumentSession session = store.openSession()) {
        QTodo t = QTodo.todo;

        IRavenQueryable<Todo> query = session.query(Todo.class, TodoByTitleIndex.class)
            .orderBy(t.creationDate.asc());

        if (StringUtils.isNotBlank(searchText)) {
            query = query.where(t.title.eq(searchText));
        }

        List<Todo> todosList = query.toList();

        response.getWriter().write(RavenJArray.fromObject(todosList).toString());
        response.getWriter().close();

    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Basically, we get the store from the context, and then open a session. You can see the fluent query API, and how we work with sessions.

A more interesting example, albeit simpler, is how we write:

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
    IOException {
    ServletContext context = request.getSession().getServletContext();
    IDocumentStore store = (IDocumentStore) context.getAttribute(ContextManager.DOCUMENT_STORE);

    try (IDocumentSession session = store.openSession()) {
        Todo todo = new Todo(request.getParameter("title"));
        session.store(todo);
        session.saveChanges();

    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

This API should be instantly familiar for any RavenDB or Hibernate users. As for the actual entity definition, here it goes:

@QueryEntity
public class Todo {

    private Boolean completed;
    private Date creationDate;
    private Integer id;
    private String title;

    public Todo() {
        super();
    }

    public Todo(final String title) {
        super();
        this.title = title;
        this.creationDate = new Date(System.currentTimeMillis());
    }

    public Boolean getCompleted() {
        return completed;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public Integer getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setCompleted(Boolean completed) {
        this.completed = completed;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Todo [title=" + title + ", completed =" + completed + ", creationDate=" + creationDate + ", id=" + id
            + "]";
    }
}
Except for the @QueryEntity annotation, it is a plain old Java class.
 
And of course, I’m using the term Java Client API, but this is actually available for any JVM language. Including Groovy, Scala and Clojure*.
 
* There is actually a dedicated RavenDB client for Clojure, written by Mark Woodhall.

More posts in "What is new in RavenDB 3.0" series:

  1. (24 Sep 2014) Meta discussion
  2. (23 Sep 2014) Operations–Optimizations
  3. (22 Sep 2014) Operations–the nitty gritty details
  4. (22 Sep 2014) Operations–production view
  5. (19 Sep 2014) Operations–the pretty pictures tour
  6. (19 Sep 2014) SQL Replication
  7. (18 Sep 2014) Queries improvements
  8. (17 Sep 2014) Query diagnostics
  9. (17 Sep 2014) Indexing enhancements
  10. (16 Sep 2014) Indexing backend
  11. (15 Sep 2014) Simplicity
  12. (15 Sep 2014) JVM Client API
  13. (12 Sep 2014) Client side
  14. (11 Sep 2014) The studio
  15. (11 Sep 2014) RavenFS
  16. (10 Sep 2014) Voron