Build a Java web application using Azure Cosmos DB and the SQL API

This Java web application tutorial shows you how to use the Microsoft Azure Cosmos DB service to store and access data from a Java application hosted on Azure App Service Web Apps. In this article, you will learn:

  • How to build a basic JavaServer Pages (JSP) application in Eclipse.
  • How to work with the Azure Cosmos DB service using the Azure Cosmos DB Java SDK.

This Java application tutorial shows you how to create a web-based task-management application that enables you to create, retrieve, and mark tasks as complete, as shown in the following image. Each of the tasks in the ToDo list is stored as JSON documents in Azure Cosmos DB.

My ToDo List Java application


This application development tutorial assumes that you have prior experience using Java. If you are new to Java or the prerequisite tools, we recommend downloading the complete todo project from GitHub and building it using the instructions at the end of this article. Once you have it built, you can review the article to gain insight on the code in the context of the project.

Prerequisites for this Java web application tutorial

Before you begin this application development tutorial, you must have the following:

If you're installing these tools for the first time, provides a walk-through of the installation process in the Quick Start section of their Tutorial: Installing TomCat7 and Using it with Eclipse article.

Step 1: Create an Azure Cosmos DB account

Let's start by creating an Azure Cosmos DB account. If you already have an account or if you are using the Azure Cosmos DB Emulator for this tutorial, you can skip to Step 2: Create the Java JSP application.

  1. Sign in to the Azure portal.

  2. Select Create a resource > Databases > Azure Cosmos DB.

    The Azure portal Databases pane

  3. On the Create Azure Cosmos DB Account page, enter the basic settings for the new Azure Cosmos account.

    Setting Value Description
    Subscription Subscription name Select the Azure subscription that you want to use for this Azure Cosmos account.
    Resource Group Resource group name Select a resource group, or select Create new, then enter a unique name for the new resource group.
    Account Name Enter a unique name Enter a name to identify your Azure Cosmos account. Because is appended to the ID that you provide to create your URI, use a unique ID.

    The ID can only contain lowercase letters, numbers, and the hyphen (-) character. It must be between 3-31 characters in length.
    API Core (SQL) The API determines the type of account to create. Azure Cosmos DB provides five APIs: Core (SQL) and MongoDB for document data, Gremlin for graph data, Azure Table, and Cassandra. Currently, you must create a separate account for each API.

    Select Core (SQL) to create a document database and query by using SQL syntax.

    Learn more about the SQL API.
    Location Select the region closest to your users Select a geographic location to host your Azure Cosmos DB account. Use the location that is closest to your users to give them the fastest access to the data.

    The new account page for Azure Cosmos DB

  4. Select Review + create. You can skip the Network and Tags sections.

  5. Review the account settings, and then select Create. It takes a few minutes to create the account. Wait for the portal page to display Your deployment is complete.

    The Azure portal Notifications pane

  6. Select Go to resource to go to the Azure Cosmos DB account page.

    The Azure Cosmos DB account page

Now navigate to the Azure Cosmos DB account page, and click Keys, as these values are used in the web application you create next.

Screenshot of the Azure portal with the Keys button highlighted on the Azure Cosmos DB account page

Step 2: Create the Java JSP application

To create the JSP application:

  1. First, we’ll start off by creating a Java project. Start Eclipse, then click File, click New, and then click Dynamic Web Project. If you don’t see Dynamic Web Project listed as an available project, do the following: click File, click New, click Project…, expand Web, click Dynamic Web Project, and click Next.

    JSP Java Application Development

  2. Enter a project name in the Project name box, and in the Target Runtime drop-down menu, optionally select a value (e.g. Apache Tomcat v7.0), and then click Finish. Selecting a target runtime enables you to run your project locally through Eclipse.

  3. In Eclipse, in the Project Explorer view, expand your project. Right-click WebContent, click New, and then click JSP File.

  4. In the New JSP File dialog box, name the file index.jsp. Keep the parent folder as WebContent, as shown in the following illustration, and then click Next.

    Make a New JSP File - Java Web Application Tutorial

  5. In the Select JSP Template dialog box, for the purpose of this tutorial select New JSP File (html), and then click Finish.

  6. When the index.jsp file opens in Eclipse, add text to display Hello World! within the existing <body> element. The updated <body> content should look like the following code:

         <% out.println("Hello World!"); %>
  7. Save the index.jsp file.

  8. If you set a target runtime in step 2, you can click Project and then Run to run your JSP application locally:

    Hello World – Java Application Tutorial

Step 3: Install the SQL Java SDK

The easiest way to pull in the SQL Java SDK and its dependencies is through Apache Maven.

To do this, you will need to convert your project to a maven project by completing the following steps:

  1. Right-click your project in the Project Explorer, click Configure, click Convert to Maven Project.

  2. In the Create new POM window, accept the defaults, and click Finish.

  3. In Project Explorer, open the pom.xml file.

  4. On the Dependencies tab, in the Dependencies pane, click Add.

  5. In the Select Dependency window, do the following:

    • In the Group Id box, enter
    • In the Artifact Id box, enter azure-documentdb.
    • In the Version box, enter 1.5.1.

    Install SQL Java Application SDK

    • Or add the dependency XML for Group Id and Artifact Id directly to the pom.xml via a text editor:
  6. Click OK and Maven will install the SQL Java SDK.

  7. Save the pom.xml file.

Step 4: Using the Azure Cosmos DB service in a Java application

  1. First, let's define the TodoItem object in

     public class TodoItem {
         private String category;
         private boolean complete;
         private String id;
         private String name;

    In this project, you are using Project Lombok to generate the constructor, getters, setters, and a builder. Alternatively, you can write this code manually or have the IDE generate it.

  2. To invoke the Azure Cosmos DB service, you must instantiate a new DocumentClient. In general, it is best to reuse the DocumentClient - rather than construct a new client for each subsequent request. We can reuse the client by wrapping the client in a DocumentClientFactory. In, you need to paste the URI and PRIMARY KEY value you saved to your clipboard in step 1. Replace [YOUR_ENDPOINT_HERE] with your URI and replace [YOUR_KEY_HERE] with your PRIMARY KEY.

     private static final String HOST = "[YOUR_ENDPOINT_HERE]";
     private static final String MASTER_KEY = "[YOUR_KEY_HERE]";
     private static DocumentClient documentClient = new DocumentClient(HOST, MASTER_KEY,
                     ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
     public static DocumentClient getDocumentClient() {
         return documentClient;
  3. Now let's create a Data Access Object (DAO) to abstract persisting our ToDo items to Azure Cosmos DB.

    In order to save ToDo items to a collection, the client needs to know which database and collection to persist to (as referenced by self-links). In general, it is best to cache the database and collection when possible to avoid additional round-trips to the database.

    The following code illustrates how to retrieve our database and collection, if it exists, or create a new one if it doesn't exist:

     public class DocDbDao implements TodoDao {
         // The name of our database.
         private static final String DATABASE_ID = "TodoDB";
         // The name of our collection.
         private static final String COLLECTION_ID = "TodoCollection";
         // The Azure Cosmos DB Client
         private static DocumentClient documentClient = DocumentClientFactory
         // Cache for the database object, so we don't have to query for it to
         // retrieve self links.
         private static Database databaseCache;
         // Cache for the collection object, so we don't have to query for it to
         // retrieve self links.
         private static DocumentCollection collectionCache;
         private Database getTodoDatabase() {
             if (databaseCache == null) {
                 // Get the database if it exists
                 List<Database> databaseList = documentClient
                                 "SELECT * FROM root r WHERE'" + DATABASE_ID
                                         + "'", null).getQueryIterable().toList();
                 if (databaseList.size() > 0) {
                     // Cache the database object so we won't have to query for it
                     // later to retrieve the selfLink.
                     databaseCache = databaseList.get(0);
                 } else {
                     // Create the database if it doesn't exist.
                     try {
                         Database databaseDefinition = new Database();
                         databaseCache = documentClient.createDatabase(
                                 databaseDefinition, null).getResource();
                     } catch (DocumentClientException e) {
                         // TODO: Something has gone terribly wrong - the app wasn't
                         // able to query or create the collection.
                         // Verify your connection, endpoint, and key.
             return databaseCache;
         private DocumentCollection getTodoCollection() {
             if (collectionCache == null) {
                 // Get the collection if it exists.
                 List<DocumentCollection> collectionList = documentClient
                                 "SELECT * FROM root r WHERE'" + COLLECTION_ID
                                         + "'", null).getQueryIterable().toList();
                 if (collectionList.size() > 0) {
                     // Cache the collection object so we won't have to query for it
                     // later to retrieve the selfLink.
                     collectionCache = collectionList.get(0);
                 } else {
                     // Create the collection if it doesn't exist.
                     try {
                         DocumentCollection collectionDefinition = new DocumentCollection();
                         collectionCache = documentClient.createCollection(
                                 collectionDefinition, null).getResource();
                     } catch (DocumentClientException e) {
                         // TODO: Something has gone terribly wrong - the app wasn't
                         // able to query or create the collection.
                         // Verify your connection, endpoint, and key.
             return collectionCache;
  4. The next step is to write some code to persist the TodoItems into the collection. In this example, we will use Gson to serialize and de-serialize TodoItem Plain Old Java Objects (POJOs) to JSON documents.

     // We'll use Gson for POJO <=> JSON serialization for this example.
     private static Gson gson = new Gson();
     public TodoItem createTodoItem(TodoItem todoItem) {
         // Serialize the TodoItem as a JSON Document.
         Document todoItemDocument = new Document(gson.toJson(todoItem));
         // Annotate the document as a TodoItem for retrieval (so that we can
         // store multiple entity types in the collection).
         todoItemDocument.set("entityType", "todoItem");
         try {
             // Persist the document using the DocumentClient.
             todoItemDocument = documentClient.createDocument(
                     getTodoCollection().getSelfLink(), todoItemDocument, null,
         } catch (DocumentClientException e) {
             return null;
         return gson.fromJson(todoItemDocument.toString(), TodoItem.class);
  5. Like Azure Cosmos DB databases and collections, documents are also referenced by self-links. The following helper function lets us retrieve documents by another attribute (e.g. "id") rather than self-link:

     private Document getDocumentById(String id) {
         // Retrieve the document using the DocumentClient.
         List<Document> documentList = documentClient
                         "SELECT * FROM root r WHERE'" + id + "'", null)
         if (documentList.size() > 0) {
             return documentList.get(0);
         } else {
             return null;
  6. We can use the helper method in step 5 to retrieve a TodoItem JSON document by id and then deserialize it to a POJO:

     public TodoItem readTodoItem(String id) {
         // Retrieve the document by id using our helper method.
         Document todoItemDocument = getDocumentById(id);
         if (todoItemDocument != null) {
             // De-serialize the document in to a TodoItem.
             return gson.fromJson(todoItemDocument.toString(), TodoItem.class);
         } else {
             return null;
  7. We can also use the DocumentClient to get a collection or list of TodoItems using SQL:

     public List<TodoItem> readTodoItems() {
         List<TodoItem> todoItems = new ArrayList<TodoItem>();
         // Retrieve the TodoItem documents
         List<Document> documentList = documentClient
                         "SELECT * FROM root r WHERE r.entityType = 'todoItem'",
         // De-serialize the documents in to TodoItems.
         for (Document todoItemDocument : documentList) {
         return todoItems;
  8. There are many ways to update a document with the DocumentClient. In our Todo list application, we want to be able to toggle whether a TodoItem is complete. This can be achieved by updating the "complete" attribute within the document:

     public TodoItem updateTodoItem(String id, boolean isComplete) {
         // Retrieve the document from the database
         Document todoItemDocument = getDocumentById(id);
         // You can update the document as a JSON document directly.
         // For more complex operations - you could de-serialize the document in
         // to a POJO, update the POJO, and then re-serialize the POJO back in to
         // a document.
         todoItemDocument.set("complete", isComplete);
         try {
             // Persist/replace the updated document.
             todoItemDocument = documentClient.replaceDocument(todoItemDocument,
         } catch (DocumentClientException e) {
             return null;
         return gson.fromJson(todoItemDocument.toString(), TodoItem.class);
  9. Finally, we want the ability to delete a TodoItem from our list. To do this, we can use the helper method we wrote earlier to retrieve the self-link and then tell the client to delete it:

     public boolean deleteTodoItem(String id) {
         // Azure Cosmos DB refers to documents by self link rather than id.
         // Query for the document to retrieve the self link.
         Document todoItemDocument = getDocumentById(id);
         try {
             // Delete the document by self link.
             documentClient.deleteDocument(todoItemDocument.getSelfLink(), null);
         } catch (DocumentClientException e) {
             return false;
         return true;

Step 5: Wiring the rest of the of Java application development project together

Now that we've finished the fun bits - all that's left is to build a quick user interface and wire it up to our DAO.

  1. First, let's start with building a controller to call our DAO:

     public class TodoItemController {
         public static TodoItemController getInstance() {
             if (todoItemController == null) {
                 todoItemController = new TodoItemController(TodoDaoFactory.getDao());
             return todoItemController;
         private static TodoItemController todoItemController;
         private final TodoDao todoDao;
         TodoItemController(TodoDao todoDao) {
             this.todoDao = todoDao;
         public TodoItem createTodoItem(@NonNull String name,
                 @NonNull String category, boolean isComplete) {
             TodoItem todoItem = TodoItem.builder().name(name).category(category)
             return todoDao.createTodoItem(todoItem);
         public boolean deleteTodoItem(@NonNull String id) {
             return todoDao.deleteTodoItem(id);
         public TodoItem getTodoItemById(@NonNull String id) {
             return todoDao.readTodoItem(id);
         public List<TodoItem> getTodoItems() {
             return todoDao.readTodoItems();
         public TodoItem updateTodoItem(@NonNull String id, boolean isComplete) {
             return todoDao.updateTodoItem(id, isComplete);

    In a more complex application, the controller may house complicated business logic on top of the DAO.

  2. Next, we'll create a servlet to route HTTP requests to the controller:

     public class TodoServlet extends HttpServlet {
         // API Keys
         public static final String API_METHOD = "method";
         // API Methods
         public static final String CREATE_TODO_ITEM = "createTodoItem";
         public static final String GET_TODO_ITEMS = "getTodoItems";
         public static final String UPDATE_TODO_ITEM = "updateTodoItem";
         // API Parameters
         public static final String TODO_ITEM_ID = "todoItemId";
         public static final String TODO_ITEM_NAME = "todoItemName";
         public static final String TODO_ITEM_CATEGORY = "todoItemCategory";
         public static final String TODO_ITEM_COMPLETE = "todoItemComplete";
         public static final String MESSAGE_ERROR_INVALID_METHOD = "{'error': 'Invalid method'}";
         private static final long serialVersionUID = 1L;
         private static final Gson gson = new Gson();
         protected void doGet(HttpServletRequest request,
                 HttpServletResponse response) throws ServletException, IOException {
             String apiResponse = MESSAGE_ERROR_INVALID_METHOD;
             TodoItemController todoItemController = TodoItemController
             String id = request.getParameter(TODO_ITEM_ID);
             String name = request.getParameter(TODO_ITEM_NAME);
             String category = request.getParameter(TODO_ITEM_CATEGORY);
             boolean isComplete = StringUtils.equalsIgnoreCase("true",
                     request.getParameter(TODO_ITEM_COMPLETE)) ? true : false;
             switch (request.getParameter(API_METHOD)) {
             case CREATE_TODO_ITEM:
                 apiResponse = gson.toJson(todoItemController.createTodoItem(name,
                         category, isComplete));
             case GET_TODO_ITEMS:
                 apiResponse = gson.toJson(todoItemController.getTodoItems());
             case UPDATE_TODO_ITEM:
                 apiResponse = gson.toJson(todoItemController.updateTodoItem(id,
         protected void doPost(HttpServletRequest request,
                 HttpServletResponse response) throws ServletException, IOException {
             doGet(request, response);
  3. We'll need a web user interface to display to the user. Let's re-write the index.jsp we created earlier:

          <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
          <meta http-equiv="X-UA-Compatible" content="IE=edge;" />
          <title>Azure Cosmos DB Java Sample</title>
          <!-- Bootstrap -->
          <link href="//" rel="stylesheet">
            /* Add padding to body for fixed nav bar */
            body {
              padding-top: 50px;
          <!-- Nav Bar -->
          <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
            <div class="container">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">My Tasks</a>
          <!-- Body -->
          <div class="container">
            <h1>My ToDo List</h1>
            <!-- The ToDo List -->
            <div class = "todoList">
              <table class="table table-bordered table-striped" id="todoItems">
              <!-- Update Button -->
              <div class="todoUpdatePanel">
                <form class="form-horizontal" role="form">
                  <button type="button" class="btn btn-primary">Update Tasks</button>
            <!-- Item Input Form -->
            <div class="todoForm">
              <form class="form-horizontal" role="form">
                <div class="form-group">
                  <label for="inputItemName" class="col-sm-2">Task Name</label>
                  <div class="col-sm-10">
                    <input type="text" class="form-control" id="inputItemName" placeholder="Enter name">
                <div class="form-group">
                  <label for="inputItemCategory" class="col-sm-2">Task Category</label>
                  <div class="col-sm-10">
                    <input type="text" class="form-control" id="inputItemCategory" placeholder="Enter category">
                <button type="button" class="btn btn-primary">Add Task</button>
          <!-- Placed at the end of the document so the pages load faster -->
          <script src="//"></script>
          <script src="//"></script>
          <script src="assets/todo.js"></script>
  4. And finally, write some client-side JavaScript to tie the web user interface and the servlet together:

     var todoApp = {
        * API methods to call Java backend.
       apiEndpoint: "api",
       createTodoItem: function(name, category, isComplete) {
         $.post(todoApp.apiEndpoint, {
             "method": "createTodoItem",
             "todoItemName": name,
             "todoItemCategory": category,
             "todoItemComplete": isComplete
           function(data) {
             var todoItem = data;
             todoApp.addTodoItemToTable(,, todoItem.category, todoItem.complete);
       getTodoItems: function() {
         $.post(todoApp.apiEndpoint, {
             "method": "getTodoItems"
           function(data) {
             var todoItemArr = data;
             $.each(todoItemArr, function(index, value) {
               todoApp.addTodoItemToTable(,, value.category, value.complete);
       updateTodoItem: function(id, isComplete) {
         $.post(todoApp.apiEndpoint, {
             "method": "updateTodoItem",
             "todoItemId": id,
             "todoItemComplete": isComplete
           function(data) {},
        * UI Methods
       addTodoItemToTable: function(id, name, category, isComplete) {
         var rowColor = isComplete ? "active" : "warning";
               .attr("type", "checkbox")
               .attr("id", id)
               .attr("checked", isComplete)
               .attr("class", "isComplete")
        * UI Bindings
       bindCreateButton: function() {
         todoApp.ui_createButton().click(function() {
           todoApp.createTodoItem(todoApp.ui_createNameInput().val(), todoApp.ui_createCategoryInput().val(), false);
       bindUpdateButton: function() {
         todoApp.ui_updateButton().click(function() {
           // Disable button temporarily.
           var myButton = $(this);
           var originalText = myButton.text();
           $(this).prop("disabled", true);
           // Call api to update todo items.
           $.each(todoApp.ui_updateId(), function(index, value) {
             todoApp.updateTodoItem(, value.value);
           // Re-enable button.
           setTimeout(function() {
             myButton.prop("disabled", false);
           }, 500);
       bindUpdateCheckboxes: function() {
         todoApp.ui_table().on("click", ".isComplete", function(event) {
           var checkboxElement = $(event.currentTarget);
           var rowElement = $(event.currentTarget).parents('tr');
           var id = checkboxElement.attr('id');
           var isComplete =':checked');
           // Toggle table row color
           if (isComplete) {
           } else {
           // Update hidden inputs for update panel.
           todoApp.ui_updateForm().children("input[name='" + id + "']").remove();
             .attr("type", "hidden")
             .attr("class", "updateComplete")
             .attr("name", id)
             .attr("value", isComplete));
        * UI Elements
       ui_createNameInput: function() {
         return $(".todoForm #inputItemName");
       ui_createCategoryInput: function() {
         return $(".todoForm #inputItemCategory");
       ui_createButton: function() {
         return $(".todoForm button");
       ui_table: function() {
         return $(".todoList table tbody");
       ui_updateButton: function() {
         return $(".todoUpdatePanel button");
       ui_updateForm: function() {
         return $(".todoUpdatePanel form");
       ui_updateId: function() {
         return $(".todoUpdatePanel .updateComplete");
        * Install the TodoApp
       install: function() {
     $(document).ready(function() {
  5. Awesome! Now all that's left is to test the application. Run the application locally, and add some Todo items by filling in the item name and category and clicking Add Task.

  6. Once the item appears, you can update whether it's complete by toggling the checkbox and clicking Update Tasks.

Step 6: Deploy your Java application to Azure Web Sites

Azure Web Sites makes deploying Java applications as simple as exporting your application as a WAR file and either uploading it via source control (e.g. Git) or FTP.

  1. To export your application as a WAR file, right-click on your project in Project Explorer, click Export, and then click WAR File.

  2. In the WAR Export window, do the following:

    • In the Web project box, enter azure-documentdb-java-sample.
    • In the Destination box, choose a destination to save the WAR file.
    • Click Finish.
  3. Now that you have a WAR file in hand, you can simply upload it to your Azure Web Site's webapps directory. For instructions on uploading the file, see Add a Java application to Azure App Service Web Apps.

    Once the WAR file is uploaded to the webapps directory, the runtime environment will detect that you've added it and will automatically load it.

  4. To view your finished product, navigate to http://YOUR\_SITE\ and start adding your tasks!

Get the project from GitHub

All the samples in this tutorial are included in the todo project on GitHub. To import the todo project into Eclipse, ensure you have the software and resources listed in the Prerequisites section, then do the following:

  1. Install Project Lombok. Lombok is used to generate constructors, getters, setters in the project. Once you have downloaded the lombok.jar file, double-click it to install it or install it from the command line.
  2. If Eclipse is open, close it and restart it to load Lombok.
  3. In Eclipse, on the File menu, click Import.
  4. In the Import window, click Git, click Projects from Git, and then click Next.
  5. On the Select Repository Source screen, click Clone URI.
  6. On the Source Git Repository screen, in the URI box, enter, and then click Next.
  7. On the Branch Selection screen, ensure that master is selected, and then click Next.
  8. On the Local Destination screen, click Browse to select a folder where the repository can be copied, and then click Next.
  9. On the Select a wizard to use for importing projects screen, ensure that Import existing projects is selected, and then click Next.
  10. On the Import Projects screen, unselect the DocumentDB project, and then click Finish. The DocumentDB project contains the Azure Cosmos DB Java SDK, which we will add as a dependency instead.
  11. In Project Explorer, navigate to azure-documentdb-java-sample\src\\ and replace the HOST and MASTER_KEY values with the URI and PRIMARY KEY for your Azure Cosmos DB account, and then save the file. For more information, see Step 1. Create an Azure Cosmos DB database account.
  12. In Project Explorer, right-click the azure-documentdb-java-sample, click Build Path, and then click Configure Build Path.
  13. On the Java Build Path screen, in the right pane, select the Libraries tab, and then click Add External JARs. Navigate to the location of the lombok.jar file, and click Open, and then click OK.
  14. Use step 12 to open the Properties window again, and then in the left pane click Targeted Runtimes.
  15. On the Targeted Runtimes screen, click New, select Apache Tomcat v7.0, and then click OK.
  16. Use step 12 to open the Properties window again, and then in the left pane click Project Facets.
  17. On the Project Facets screen, select Dynamic Web Module and Java, and then click OK.
  18. On the Servers tab at the bottom of the screen, right-click Tomcat v7.0 Server at localhost and then click Add and Remove.
  19. On the Add and Remove window, move azure-documentdb-java-sample to the Configured box, and then click Finish.
  20. In the Servers tab, right-click Tomcat v7.0 Server at localhost, and then click Restart.
  21. In a browser, navigate to http://localhost:8080/azure-documentdb-java-sample/ and start adding to your task list. Note that if you changed your default port values, change 8080 to the value you selected.
  22. To deploy your project to an Azure web site, see Step 6. Deploy your application to Azure Web Sites.