Scoped Value in Java

Scoped Value in Java is a Java feature that allows us to get immutable data anywhere in related code we want, without having to pass this data from this method to another method so that it can be used later in a method that needs it.

You can imagine an example in a RESTful API to get a user’s information. When the user request comes, this request handler method will have the user information. Next, our code will need to handle some business logic without user information. Only when manipulating the database, the code actually need the user information to retrieve data from the database. Normally, we will need to pass user information in methods that only handle business logic so that when we operate with the database, we will retrieve this user information for use. With the Scoped Value feature from Java 20, you don’t need to do that anymore.

As an example, I have the following 2 classes:

and:

And a class with main() method to run the example:

The UserService class has a method validateUser() with the username parameter to validate user information. For simplicity, I will always return true for this method. The StudentManagement class with the getLoggedUserinfo() method is used to get user information based on the username, after using the UserService class to validate the username information. As you can see, username information will need to be passed back and forth during the process of handling the request, although it is possible that in a certain method, this username information is not necessary. We can eliminate this by using Java’s Scoped Value to get the username information when we want it!

To use Scoped Value, first declare a static variable for the object of the ScopedValue class in the Application class so that this variable can be accessed anywhere in the code:

After defining the username information, we will use the static where() method of the ScopedValue class to define this username information so that it can be used throughout the methods we want. My example is as follows:

As you can see, I have defined Scoped Value for user information using the where() method. The where() method’s return object is a Carrier object. You need to call the methods we want to use Scoped Value in the run() method of this Carrier object. The getLoggedUserInfo() method and the methods called inside the getLoggedUserInfo() method can get and use the user information we have defined. The getLoggedUserInfo() method no longer needs to pass user information:

The validateUser() method in the UserService class also no longer needs to pass user information. It can retrieve user information as follows:

Rerun the above example, you can see the user information printed in the validateUser() method of the UserService class as follows:

If I define another method in the UserService class:

and call it inside the run() method above:

The doSomething() method also retrieves user information as follows:

You may see that Scoped Value is similar to Thread Local which I introduced in the previous tutorial. That’s right, but there are also differences between Scoped Value and Thread Local:

  • The value that Scoped Value contains is immutable data, meaning its value cannot be changed once initialized. The ScopedValue class only has the get() method to get the value, while the ThreadLocal class has both get() and set() methods to get and assign the value whenever we want.
  • The value in the ThreadLocal object can exist forever during the application’s runtime if you do not remove that value. The value in the ScopedValue object will be destroyed after the run() method of the Carrier object finishes running. You will see an error in our program when trying to get the value in ScopedValue object after the run() method has finished running:

Result:

Add Comment