On behalf of the SDK Team, it is my great pleasure to announce that the Java SDK version 2.2 is now GA!

This version is packed with enhancements and bugfixes. First and foremost it offers compatibility with all the new shiny things our new Couchbase Server 4.0 brings to the table.

Thanks to feedback and after quite a few iterations (there were not one but two Developer Previews for this release!), we now have a rich set of improvements to take advantage of when migrating from 2.0/2.1 to 2.2.

See the release notes for a complete list of changes, but here is a recap:


To get your hands on this release, simply update your pom.xml (or download the archive):

You can also peruse the javadocs and SDK documentation for this release.

New Features

N1QL & MDS Support

The SDK has been tuned to seamlessly work with Couchbase Server 4.0:

  • Explore a full DSL to work with N1QL and perform SELECT as well as work with indexes.

  • Let the SDK and the query service optimize queries you run often by using the adhoc(false) tuning of N1qlParams in you N1qlQuery.

  • Rely on the SDK to be aware of your MDS cluster (Multi Dimensional Scaling, the possibility for nodes to have different services enabled, allowing you to scale nodes up according to their need, eg. more RAM for data nodes, more CPU for query nodes).

About query optimization: this is a replacement of the initial prepare API in developer previews. No need to hold on to a PreparedPayload or QueryPlan. Marking a query for optimization using N1qlParams's adhoc(false) method will internally use prepared statement feature of the query engine, caching up to 5000 execution plans for faster execution.

Enhanced Durability

Another possibility introduced in Couchbase Server 4.0 is enhanced durability. The idea is that rather than using CAS to check correct persistence and replication of your data, a finer grained MutationToken can be emitted by the server with each mutation and used for durability observation.

It allows to ensure a specific mutation has been seen on a replica even if a newer mutation is made in the meantime (changing yet again the CAS on the master and replica). It also allows for more correct state detection if a hard failover has been triggered in the cluster.

To activate this feature on the CouchbaseEnvironment use the mutationTokensEnabled(true) method.

Note This implies that additional bytes are sent by the server on each mutation response, so it comes with a slight overhead and therefore is turned off by default.


What is going on inside the SDK? What is the health of my JVM? Are those latencies due to network round trips or are they occuring in the SDK?

All these questions and more find answers through the new Metrics feature!

Runtime and Latency metrics are collected all the time, and are regularly dumped to the EventBus (an Observable itself), by default every hour. Additionaly to changing the interval for the dump, one can easily configure a consumer for these metric events that logs them.

Have a look at the documentation to discover all the nitty gritty details of it 🙂

Simple ODM with Repository API

We are exploring ODM (Object-Document Mapping) in the form of a Repository interface that allows to store Entity classes directly, provided they are simple enough (eg. for now it needs an empty constructor) and annotated with @Document, @Id and @Field.

From Hot Observable to Cold Ones

This is a major change to the behavior of the async API. In RxJava, a hot Observable will emit data wether or not someone is listening/subscribing, and will always serve the same data to new subscribers.

This was the behavior of Couchbase SDK Observables previously. This meant that if you needed new subscriptions to trigger a new operation on the database (for example in the context of retry), you had to wrap your call in a Observable.defer().

Otherwise all retries would see the same first result, for example a TemporaryFailureException.

From 2.2 onwards, the default behavior is to have cold Observables, meaning that the wrapping in defer is now redundant. All SDK calls will seamlessly work with RxJava's retry semantics.

Unless you explicitely subscribe() to an Observable returned by the SDK, no db interaction is triggered. This is a lazier “do nothing until needed” approach that is also beneficial while declaring fallback streams (like with Observable#onErrorResumeNext()).

API Improvements

getFromReplica iteration

In the sync API, there is now an overload of getFromReplica that returns an Iterator, allowing for easy consumption of only part of the responses (eg. when only interested in the fastest response).

includeDocs in ViewQuery

Still in the sync API, if you want your ViewQuery to efficiently retrieve the whole content of the documents in the background, you can now use the includeDocs option.

Counter Semantics

Previously, counter method would initialize the counter document with the default value of 0 if no initialValue was provided in the overload.

This has been changed so that instead, a DocumentDoesNotExistException is thrown with these kind of overloads (like in the 1.4 SDK generation). To initialize with 0 instead of erroring, simply use one of the overloads that accept an initialValue.

Durability Requirement Support for counter, append and prepend

Previously no overload would allow to set a PersistTo and/or ReplicateTo durability requirement. This has now been implemented.

CASMismatchException instead of CouchbaseException for append and prepend

As the title implies, where both methods would just return a generic CouchbaseException

Design Document Options

You can now specify different options on a per design document basis when creating or replacing one.

CouchbaseEnvironment: Avoiding Confusion

The CouchbaseEnvironment.Builder doesn't implement the interface anymore, forcing you to call build() to obtain the actual environment (and thus avoiding confusing NullPointerException during usage).


Name Changes

Some classes related to N1QL have been renamed to avoid confusion and better align with other similar classes and/or other SDKs:

  • Most Query related classes have been prefixed with N1QL (eg. AsyncQueryResult becomes AsyncN1qlQueryResult). This is more consistent with the naming eg. for views (ViewQuery, N1qlQuery).

  • QueryParams becomes N1qlParams and QueryMetrics becomes N1qlMetrics.

  • The various instances of the word parametrized have been replaced with parameterized across documentation and the SDKs. For example in N1qlQuery.parameterized(Statement st, JsonObject paramValues) factory method…

Dependency Upgrades

The following external dependency had been updated:

  • RxJava from 1.0.4 to 1.0.14

Additionaly, internal dependencies have also been updated:

  • Netty from 4.0.25.Final to 4.0.30.Final
  • LMAX Disruptor 3.3.0 to 3.3.2
  • Jackson from 2.4.2 to 2.6.1
  • LatencyUtils new in version 2.0.2

We hope you enjoy this release, Happy Coding!

Posted by Simon Basle, Software Engineer, Pivotal

Simon Basl_ is a Paris-based Software Engineer working in the Spring team at Pivotal. Previously, he worked in the Couchbase Java SDK team. His interests span software design aspects (OOP, design patterns, software architecture), rich clients, what lies beyond code (continuous integration, (D)VCS, best practices), and reactive programming. He is also an editor for the French version of InfoQ.com.

Leave a reply