Java Feature Toggle: A step-by-step guide with working Java application

By Abhishek Agarwal on November 15, 2022

Introduction to Java feature toggle

In this tutorial, we will learn how to use Flagsmith Java SDK (Java Feature Toggle Software) for our Java application. We will be learning everything from scratch about feature flags/toggles, how to build a basic Java server application, and how to integrate Flagsmith feature flags SDK in order to make the application much more powerful. This is a 0 pre-requisite doc.

So, let's dive deeper into the Java feature toggle topic!

What are Feature Toggles? 

Before we dive into the development work, let’s first understand what Feature flags or Feature toggles (that's the same thing with 2 different names) are and why they are required. 

Feature flags are one of the most important components of any application. They offer the capability to modify the functionality of your code without the need for any code merge, redeployment, or any other heavy lifting. Toggling a feature flag is (in general) as simple as clicking a UI button. 

Not only do feature flags allow you to turn some behavior of code on/off, they also provide the ability to alter the code behavior based on the feature flag value. As a basic example, if you frequently want to change the price of an article on your website without needing to redeploy code, it can be added behind a feature flag. There are various ways in which these are implemented - a) fetch the value periodically from the server, b) fetch the value every time it is required. We will be looking at both of these methods in detail below.

Why are Feature Flags required?

Let’s understand this through a very simple real-life example - 

Imagine you are driving a car and suddenly the air conditioner in your car starts making a weird noise. I’m sure as a first thing you would try to change the fan speed/modes of the air conditioner and if that doesn’t help, you will turn it off. Next, you will reach out to a mechanic and once the part is fixed, you will turn the AC back on and continue with your journey.

This is analogous to how you would use feature flags when anything goes wrong with your application. The fan speed/modes that we talked about above are the feature flag values that can be updated. Turning it off is the same as disabling the feature flag. This would prevent your app clients from viewing a weird unexpected error screen on that page. Ideally, when the feature flag is disabled, you would show users a message like “This page is under maintenance, please come back later”. Once the issue is fixed, you can re-enable the feature flag. 

Why Flagsmith?

It’s FREE! Flagsmith provides an all-in-one platform for developing, implementing, and managing your feature flags. It offers you the capability to leverage feature flags to their maximum potential by storing values inside them. These values can be used to toggle multiple kinds of behaviors as illustrated in the “What are Feature Flags” section. 

Flagsmith is an open-source tool which makes it very trustworthy. 

Flagsmith provides very seamless integration with well-maintained documents for multiple programming languages across web, mobile, and server-side applications.  It offers various customizations which makes it very convenient to use. It has a very simplistic UI that allows you to alter your code behavior without needing to focus on feature flag internal implementation at all.

Let’s get started with Java Feature Toggles!

As a first step, we need to create an account on https://flagsmith.com/. It offers simple sign-in with Google or GitHub options. Or you can just fill in your basic details at https://app.flagsmith.com/signup. The below screenshot shows the signup process:

Java feature toggle set up

It will then ask you to create an organization. For the purpose of this tutorial, I’ll name it Java Tutorial. You can name it anything you prefer.

Feature Toggle Java Create

Next, we need to create a project inside this organisation

How to use Java Feature Toggle

Click on “Create A Project”. The below screen should pop up. Enter your project name. I’m creating a project with the name “Java WebServer”. Feel free to name it as you want.

Java Feature Toggle Project

Congrats! You have already completed the Flagsmith setup process. You should see the below screen now.

Feature Flag Java

We will come back to this screen when we want to add a Java feature toggle to our application. 

Now, let’s start by creating a Java WebServer application. 

Let’s code!

To keep this tutorial simple, we will create a rudimentary Java server application. It will be exposed on localhost and will use the local system storage.  This server maintains a list of books and exposes two APIs:

  1. to add a new book and
  2. to query the books present in its records. 

If you do not have Java installed on your system, download and install the latest stable version from this link based on your OS and System specifications. 
TL;DR: All the code is present at https://github.com/abhishekag03/flagsmith-java-feature-flag-demo.git with step-by-step commits. Feel free to refer to it at any time if you feel confused. 

STEP 1: Java setup 

Make sure you have Java installed by running this command on your terminal:

1java -version

I’m on version 1.19.1, thus getting the below output.

Feature Toggle Java Tutorial

STEP 2: Create a blank Maven / Gradle project

Most modern IDEs offer the functionality to create a Maven or Gradle project with just a few clicks of buttons. Here, I will be creating a Maven project on IntelliJ.

I have kept the project specifications as shown below:

feature toggle java example

The image below shows the base directory structure that got auto-created. The Main.java file below has a basic “Hello world” function.

feature toggle framework java

STEP 3: Use the HttpServer library to create a basic HTTP server

We will expose port 8000 and expose a single endpoint. The below code exposes localhost:8000/test and just returns “This is the response” with a Status code 200.  

1package org.flagsmith;
2
3import com.sun.net.httpserver.HttpExchange;
4import com.sun.net.httpserver.HttpHandler;
5import com.sun.net.httpserver.HttpServer;
6
7import java.io.IOException;
8import java.io.OutputStream;
9import java.net.InetSocketAddress;
10
11public class Main {
12    public static void main(String[] args) throws Exception {
13        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
14        server.createContext("/test", new MyHandler());
15        server.setExecutor(null); // creates a default executor
16
17        server.start();
18    }
19
20    static class MyHandler implements HttpHandler {
21        @Override
22        public void handle(HttpExchange t) throws IOException {
23            String response = "This is the response";
24            t.sendResponseHeaders(200, response.length());
25            OutputStream os = t.getResponseBody();
26            os.write(response.getBytes());
27            os.close();
28        }
29    }
30}

Run your application by clicking the green “Run” button on your IDE.

The same can be verified by hitting the `test` endpoint via curl from your terminal. 

1curl localhost:8000/test

The output should be as shown below

Java Feature Flag

STEP 4: Add GET and POST handlers

Modify the `handle` function so that it can call the appropriate method based on the Request type. We are using a common endpoint for GET and POST requests. The implementation of both of these methods will be added in the steps that follow.

1@Override
2public void handle(HttpExchange t) throws IOException {
3    if ("GET".equals(t.getRequestMethod())) {
4        handleGetBooksRequest(t);
5    } else if ("POST".equals(t.getRequestMethod())) {
6        handlePostBooksRequest(t);
7    }
8}
9
10private void handleGetBooksRequest(HttpExchange t) throws IOException {
11
12}
13
14
15private void handlePostBooksRequest(HttpExchange t) throws IOException {
16
17}

STEP 5: Create a Book class to structure the data 

Here I’m creating a Book class with 4 attributes - 

  • id
  • title
  • author 
  • price. 

This class should be in the same directory as your `main.java` file. 

Also, add getters, setters, and a constructor for the same.

1package org.flagsmith;
2
3public class Book {
4    String id;
5    String title;
6    String author;
7    String price;
8
9    public Book(String id, String title, String author, String price) {
10        this.id = id;
11        this.title = title;
12        this.author = author;
13        this.price = price;
14    }
15
16    public String getId() {
17        return id;
18    }
19
20    public void setId(String id) {
21        this.id = id;
22    }
23
24    public String getTitle() {
25        return title;
26    }
27
28    public void setTitle(String title) {
29        this.title = title;
30    }
31
32    public String getAuthor() {
33        return author;
34    }
35
36    public void setAuthor(String author) {
37        this.author = author;
38    }
39
40    public String getPrice() {
41        return price;
42    }
43
44    public void setPrice(String price) {
45        this.price = price;
46    }
47}
48

STEP 6: Populate dummy data

First, we need to populate some dummy data containing books.  We will have a global book variable to store the new and existing books. Initialize this in the Main class.

1static List<Book> books = new ArrayList<>();

Populate this books list with 3 same books using the below function:

1private static void populateDummyData() {
2        books.add(new Book("1", "Harry Potter", "J.K. Rowling", "20.99"));
3        books.add(new Book("2", "War and Peace", "Leo Tolstoy", "26.99"));
4        books.add(new Book("3", "The Kite Runner", "Khaled Hosseini", "30.99"));
5}

Your `main` method should now look as follows:

Note that the endpoint name has been updated to `books` now.

1    public static void main(String[] args) throws Exception {
2        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
3        server.createContext("/books", new MyHandler());
4        server.setExecutor(null); // creates a default executor
5        populateDummyData();
6        server.start();
7    }

STEP 7: Complete the GET endpoint

We need to add the `gson` library to our pom.xml dependencies since it makes string <-> json conversion much easier. Add the below lines to `pom.xml` file:

1<dependency>
2    <groupId>com.google.code.gson</groupId>
3    <artifactId>gson</artifactId>
4    <version>2.8.5</version>
5</dependency>

Update the `handleGetBooksRequest` implementation to return the books list that we populated above with 200 Response code. 

Add this import to the Main.java file:

1import com.google.gson.Gson;
1private void handleGetBooksRequest(HttpExchange t) throws IOException {
2    OutputStream os = t.getResponseBody();
3    String json = new Gson().toJson(books);
4    t.sendResponseHeaders(200, json.length());
5    os.write(json.getBytes());
6    os.close();
7}

Run the application and test it from your terminal:

1curl localhost:8000/books

This image shows the expected output. You should be able to see all the books we populated above.

Java Feature Flagging

STEP 7: Complete the POST endpoint

From our POST endpoint, we should be able to add new books to our existing collection. We will allow adding one book at a time only. 

We need a utility function to parse the request and extract a `book` object from the same. Below function helps us do the same:

1private static Book getBookFromRequest(HttpExchange t) throws IOException {
2    InputStreamReader isr = new InputStreamReader(t.getRequestBody(), StandardCharsets.UTF_8);
3    BufferedReader br = new BufferedReader(isr);
4    String query = br.readLine();
5    Gson gson = new Gson();
6    return gson.fromJson(query, Book.class);
7}

The following imports will also be required:

1import java.io.BufferedReader;
2import java.io.InputStreamReader;
3import java.nio.charset.StandardCharsets;

Handling the POST request can be done with the following code. We will print a message saying “book added successfully”, once the book has been added.

1private void handlePostBooksRequest(HttpExchange t) throws IOException {
2    Book book = getBookFromRequest(t);
3    books.add(book);
4    OutputStream os = t.getResponseBody();
5    String resp = "book added successfully";
6    t.sendResponseHeaders(200, resp.length());
7    os.write(resp.getBytes());
8    os.close();
9}

Run the application and try out the below POST request to add a book titled “Famous Five”:

1curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 20}"

The Terminal must show “book added successfully”

Java Feature Toggles Library

Since this book is now added to the global storage, hitting the GET endpoint now should return 4 books in total.

1curl localhost:8000/books
Java Feature Flag Guide

STEP 8: Add the power of Flagsmith Java Feature Toggle Software

With Flagsmith, we can control a variety of components of our Web Server. Let’s imagine a case where we do not want to allow adding new books for a certain interval of time. The naive way is to edit the code and put a logic there to stop adding new books and then remove this logic once we want to allow it back. 

What if this could be done with the click of a button? Flagsmith allows us to do that with a very minimal one-time configuration. We will create a new feature that will stop allowing users to add new books when turned off. 

Time to return to our Flagsmith UI. Click on the “Create your first feature” button on the screen we left off above. 

Add a new feature flag by the name “add_books”. This will control whether or not we allow adding new books. Turn `Enabled by default` to “true”. The below screenshot shows the configuration.

feature toggle java example

Value can be left blank, we will come back to it later. Click on “Create Feature” (Make sure you have enabled it). The UI should show the following:

Java Feature Flag Management

We will also need a Flagsmith Server-side environment key to initialize the feature flag client. Let’s generate that. 

Navigate to “Settings” from the left bar on the Flagsmith page. Click on “Create Server-Side Environment Key”. Give it a name for e.g: “java-web-server-key”

Java Feature Toggle Tutorial For Beginners

Keep the key handy in your notes. It should be of the form “ser.******....”

STEP 9: Integrate Flagsmith with our application

Let’s go back to our code now and add a one-time logic to read these feature flag values. 

Flagsmith provides Java SDK, which is very easy to integrate. We just need to add the below dependency to our pom.xml file and recompile the dependencies. 

1<dependency>
2    <groupId>com.flagsmith</groupId>
3    <artifactId>flagsmith-java-client</artifactId>
4    <version>5.1.1</version>
5</dependency>

OR if you have a Gradle project:

1implementation 'com.flagsmith:flagsmith-java-client:5.0.0'
2
3

Add this import to the `Main.java` file

1import com.flagsmith.FlagsmithClient;
2
3

We first need to add the API key that we copied above to a properties file in our source code. Create a new file by the name `config.properties` in the `resources` directory.

The `config.properties` file should have one property:

1apiKey=ser.********
2
3

The below utility function will help us extract the API key from the properties file.  This can be added to the Main class. In an ideal scenario, these helper methods must reside in a utility class such as `FeatureFlagService.java`.

1import java.util.Properties;
2import java.io.*;
3
4private static String readFlagsmithApiKey() {
5        Properties prop = new Properties();
6        String propFileName = "config.properties";  // if this does not work, use propFileName = "resources/config.properties"
7        InputStream inputStream = ClassLoader.getSystemResourceAsStream(propFileName);
8        if (inputStream != null) {
9            try {
10                prop.load(inputStream);
11            } catch (IOException e) {
12                throw new RuntimeException(e);
13            }
14        } else {
15            throw new RuntimeException("config file input stream is null");
16        }
17        return prop.getProperty("apiKey");
18    }
19

This function will be used to initialize the Flagsmith client. 

1private static FlagsmithClient getFlagsmithClient() {
2        String apiKey = readFlagsmithApiKey();
3        return FlagsmithClient
4                .newBuilder()
5                .setApiKey(apiKey)
6                .build();
7}

Create a global Flagsmith client variable that can be used by all the handlers. This client must be initialized before starting the server.

1public class Main {
2    static List<Book> books = new ArrayList<>();
3    static FlagsmithClient fsClient;
4// rest of the code follows
5

Initialize the `fsClient` inside the `main` function:

1public static void main(String[] args) throws Exception {
2    HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
3    populateDummyData();
4    fsClient = getFlagsmithClient();
5    server.createContext("/books", new MyHandler());
6    server.setExecutor(null); // creates a default executor
7    server.start();
8}

STEP 10: Use the Java feature toggle to control API behavior

We will now modify our POST request handler so that it allows adding new books only when the feature flag is enabled. The modified `handlePostRequest` method looks as follows:

1private void handlePostBooksRequest(HttpExchange t) throws IOException {
2    Boolean allowAddBooks;
3    try {
4        Flags flags = fsClient.getEnvironmentFlags(); // get all environment flags
5        allowAddBooks = flags.isFeatureEnabled("add_books"); // check value of add_books env flag
6    } catch (FlagsmithClientError e) {
7        throw new RuntimeException(e);
8    }
9    String resp;
10    int respCode;
11    if (allowAddBooks) { // allow adding books only if feature flag returns True
12        Book book = getBookFromRequest(t); // parse book data from request
13        books.add(book);
14        resp = "book added successfully";
15        respCode = 201;
16    } else {
17        resp = "method not allowed. Please come back later";
18        respCode = 405;
19    }
20    OutputStream os = t.getResponseBody();
21    t.sendResponseHeaders(respCode, resp.length());
22    os.write(resp.getBytes());
23    os.close();
24}

The above code will require adding the below two imports as well:

1import com.flagsmith.exceptions.FlagsmithClientError;
2import com.flagsmith.models.Flags;

By default, the feature flag is on and hence we should be able to add a new book.

Run the application and try adding a new book with the below request.

1curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 20}"

You should be able to see a success message. This book gets added successfully.

Feature Toggle Java Tutorial

Now, we will try turning the `add_books` feature off. Navigate to the Flagsmith UI and toggle it “off” as shown below.

Feature Toggle Java Set Up

Trying the same POST request as above now gives an error message saying “method not allowed. Please come back later”. 

Java Feature Toggle Guide

This is how powerful Flagsmith is. With just one click, we could change the functionality of our application entirely. 

STEP 11: Leveraging Java feature toggle values

While creating a new feature, we saw an option to add a feature value. Let’s understand how that can be useful. 

For instance, due to some requirements, we only want to accept books that have a price greater than $20. This is to avoid filling up our library with cheap and less selling books. Also, helps us maintain a standard. 

However, we want to keep varying this threshold price based on the rush and staff capacity. It is definitely not feasible to amend the code every time as per the requirement.

What if this can also be achieved with the click of a button? Yes, with Flagsmith it can be.

Go ahead and update the feature flag value to 20 as shown in the below image. Also, do enable the feature back so that we can continue testing.

Java Feature Flags Flagsmith

We need to update our code slightly to also read the feature flag value and act accordingly. 

1private void handlePostBooksRequest(HttpExchange t) throws IOException {
2    Boolean allowAddBooks;
3    int minPrice;
4    try {
5        Flags flags = fsClient.getEnvironmentFlags(); // get all environment flags
6        allowAddBooks = flags.isFeatureEnabled(ADD_BOOKS_FEATURE_FLAG); // check value of add_books env flag
7        minPrice = (int) flags.getFeatureValue(ADD_BOOKS_FEATURE_FLAG); // get minimum price of book that can be added
8    } catch (FlagsmithClientError e) {
9        throw new RuntimeException(e);
10    }
11    String resp;
12    int respCode;
13    if (allowAddBooks) { // allow adding books only if feature flag returns True
14        Book book = getBookFromRequest(t); // parse book data from request
15        if (Integer.parseInt(book.price) >= minPrice) {
16            books.add(book);
17            resp = "book added successfully";
18            respCode = 201;    
19        } else {
20            resp = "book value less than minimum price allowed";
21            respCode = 406;
22        }
23        
24    } else {
25.....
26// rest code remains as it is

Note the following things:

  • The if condition inside `allowAddBooks` checks if the book price meets our minimum price condition. If it does, it would add it to the books list, else return an error message. 
  • The “add_books” feature flag string has been replaced with a constant “ADD_BOOKS_FEATURE_FLAG” which has the value “add_books”

Testing the above change:

Make sure to re-run the application after the code changes are complete. 

  1. Adding a book with a price $25 (should work):
1curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 25}"
Java Feature Toggle Management

  1. Adding a book with price $15 (should throw an error):
1curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 15}"
Java Feature Toggling

Both the results are as expected. The first one worked successfully and the second one threw an error. 

STEP 12: Flagsmith Local evaluation mode

We just saw above that every time a POST request is made to our server, it will make an additional API call to fetch the feature flag value. This sounds like an expensive operation, especially in the case when our server receives thousands or millions of requests per minute. 

In such cases, the Local evaluation mode is the best suited. With this, the feature flag value gets auto-fetched periodically after a defined interval (say 1 minute). Thus, it would not make a call every time to the Flagsmith server. This saves us a lot of time per request in large-scale systems. 

A thing to keep in mind is that this does not allow a sudden change in the behavior of our application. Hence, this should not be used in the case when we are dealing with financial data or some millisecond-sensitive updates. The change will take up to X seconds to reflect in your code, where X is the refresh time interval you set while initializing the client. 

Let’s look at an example with the Local Evaluation mode client which refreshes every 1 minute. We need to modify the `getFlagsmithClient` function with config as shown below:

1private static FlagsmithClient getFlagsmithClient() {
2    String apiKey = readFlagsmithApiKey();
3    FlagsmithConfig flagsmithConfig = FlagsmithConfig
4            .newBuilder()
5            .withLocalEvaluation(true)
6            .withEnvironmentRefreshIntervalSeconds(60)
7            .build();
8    return FlagsmithClient
9            .newBuilder()
10            .setApiKey(apiKey)
11            .withConfiguration(flagsmithConfig)
12            .build();
13}

Let’s create a basic python script that will help us fire 50 POST requests in succession. This will help us compare the performance.

1import requests
2import time
3
4
5data = {
6    'id': '4',
7    'title': 'Test book',
8    'author': 'Betty Carter',
9    'price': 49.99,
10}
11
12start = time.time()
13for i in range(50):
14    x = requests.post('http://localhost:8000/books', json=data)
15
16end = time.time()
17print("Total time taken: ", end - start)

Save the above script and run it in two cases:

  1. Without local evaluation config applied
java feature flag scenarios
  1. With local evaluation config applied
Feature Toggles Java Guide

Notice the difference in time. It’s 6.24 seconds v/s 0.25 seconds

This is a huge difference. This is just an example of how much time the local evaluation mode saves in our application. In servers getting loads of requests, this will be especially very helpful.

Conclusion

If you want to start using Flagsmith as your Java feature toggle software- just create your account here or contact us for the on-prem solution.

P.S. If you like this "Java feature toggle" guide, you can check out our other guides: