Example: Java App Engine Application

This example is an App Engine application, written in Java, that provides two interfaces:

  1. A simple REST interface that can read and write arbitrary data to a Cloud Bigtable table.
  2. A web interface that uses Cloud Bigtable to track the number of visits from your Google account.

There are two different versions of this code sample:

Overview of the code sample

The code sample includes the following classes, which are identical in both versions of the sample:

  • BigtableHelper, which provides a connection to Cloud Bigtable.
  • HelloServlet, which tracks the number of times that your Google account has visited the site.
  • JsonServlet, which provides a limited REST API for Cloud Bigtable.


BigtableHelper provides a method to create a connection to Cloud Bigtable. It also caches the connection and provides a method that will retrieve the cached connection if it exists. This is because creating the connection is a relatively expensive operation.

public static void connect() throws IOException {
  Configuration c = HBaseConfiguration.create();

      org.apache.hadoop.hbase.client.Connection.class);   // Required for Cloud Bigtable

  if (PROJECT_ID == null || INSTANCE_ID == null ) {
    sc.log("environment variables BIGTABLE_PROJECT, and BIGTABLE_INSTANCE need to be defined.");
  c.set("google.bigtable.project.id", PROJECT_ID);
  c.set("google.bigtable.instance.id", INSTANCE_ID);

  connection = ConnectionFactory.createConnection(c);

public static Connection getConnection() {
  if(connection == null) {
    try {
    } catch (IOException e) {
      sc.log("connect ", e);
  if(connection == null) sc.log("BigtableHelper-No Connection");
  return connection;


HelloServlet handles HTTP GET requests to the root path of the server. For each request, the server gets the user ID for your Google account. It then gets a Cloud Bigtable connection from BigtableHelper; uses the connection to get a Table object, which enables you to read and write values; and uses the Table object to increment a counter for your user ID:

  public String getAndUpdateVisit(String id) throws IOException {
    long result;

// IMPORTANT - this try() is a java7 try w/ resources, which will call close() when done.
    try (Table t = BigtableHelper.getConnection().getTable( TABLE )) {

      // incrementColumnValue(row, family, column qualifier, amount)
      result = t.incrementColumnValue(Bytes.toBytes(id), Bytes.toBytes("visits"),
              Bytes.toBytes("visits"), 1);
    } catch (IOException e) {
      log("getAndUpdateVisit", e);
      return "0 error "+e.toString();
    return String.valueOf(result);


JsonServlet handles HTTP GET, POST, and DELETE requests to the path /json. It provides a limited REST API that can read, write, and delete values that are stored in a table named from-json.

By default, JsonServlet assumes that all values are stored in a column family named cf1. If a field name in the request includes a colon (:), JsonServlet treats the string as a column family, followed by a colon, followed by a column qualifier. For example, cf2:myField would store the column qualifier myField in the column family cf2.

JsonServlet also recognizes several data types and uses the appropriate Java classes when reading and writing values that use these types. For example, the boolean value true in a JSON request will be converted to a Java boolean and written to Cloud Bigtable as a single byte, 1.

The following excerpt from JsonServlet shows how it handles JSON POST requests. After getting a Cloud Bigtable connection from BigtableHelper, it uses the connection to get a Table object, which enables you to read and write values. For each key in the request, it determines the column family and column qualifier to use; it then identifies the type of each value in the JSON request and converts the value to bytes as appropriate. Finally, it writes the values to Cloud Bigtable:

  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
    String path = req.getPathInfo();

    if (path.length() < 5) {
      log("doPost-bad length-"+path.length());

// IMPORTANT - This try() is a java7 try w/ resources which will close() the table at the end.
    try(Table t = BigtableHelper.getConnection().getTable( TABLE )) {
      JSONObject json = new JSONObject(new JSONTokener(req.getReader()));
      String[] names = JSONObject.getNames(json);

      Put p = new Put(Bytes.toBytes(path.substring(1)));
      for(String key : names) {
        byte[] col = CF1;
        String[] k = key.split(":");    // Some other column family?
        if(k.length > 1) {
          col = Bytes.toBytes(k[0]);
          key = k[1];
        Object o = json.opt(key);
        if (o == null) {
          continue;       // skip null's for Bigtable / hbase
        switch (o.getClass().getSimpleName()) {
        case "Boolean":
         p.addColumn( col, Bytes.toBytes(key), Bytes.toBytes((boolean) o));

        case "String":
          p.addColumn( col, Bytes.toBytes(key), Bytes.toBytes((String) o));

        case "Double":  // Store as Strings
          p.addColumn( col, Bytes.toBytes(key), Bytes.toBytes(o.toString()));

        case "Long":
          p.addColumn( col, Bytes.toBytes(key), Bytes.toBytes((long) o));
        case "Integer":
          long x = ((Integer) o);
          p.addColumn( col, Bytes.toBytes(key), Bytes.toBytes(x));
    } catch (Exception io) {
      log("Json", io);
    resp.addHeader("Access-Control-Allow-Origin", "*");

Send feedback about...

Cloud Bigtable Documentation