Welcome To Fusebes - Dev & Programming Blog

Spring Boot Actuator
30
Mar
2021

Spring Boot Actuator

In this Spring boot actuator tutorial, learn about in-built HTTP endpoints available for any boot application for different monitoring and management purposes. Before the spring framework, if we had to introduce this type of monitoring functionality in our applications then we had to manually develop all those components and that too was very specific to our need. But with spring boot we have Actuator module which makes it very easy.

We just need to configure a few things and we are done – all the management and monitoring related information is easily available. Let’s learn to configure Spring boot 2 actuator endpoints.

1. Spring Boot Actuator Module

Spring boot’s module Actuator allows you to monitor and manage application usages in production environment, without coding and configuration for any of them. These monitoring and management information is exposed via REST like endpoint URLs.

1.1. Actuator Maven Dependency

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
dependencies {implementation 'org.springframework.boot:spring-boot-starter-actuator'}

1.2. Important Actuator Endpoints

Most applications exposes endpoints via HTTP, where the ID of the endpoint along with a prefix of /actuator is mapped to a URL. For example, by default, the health endpoint is mapped to /actuator/health.

By default, only /health and /info are exposed via Web APIs. Rest are exposed via JMX. Use management.endpoints.web.exposure.include=* to expose all endpoints through the Web APIs.

management.endpoints.web.exposure.include=* # To expose only selected endpoints#management.endpoints.jmx.exposure.include=health,info,env,beans

Some of important and widely used actuator endpoints are given below:

ENDPOINTUSAGE
/auditeventsReturns all auto-configuration candidates and the reason why they ‘were’ or ‘were not’ applied.
/beansReturns a complete list of all the Spring beans in your application.
/mappingsDisplays a collated list of all @RequestMapping paths..
/envReturns list of properties in current environment
/healthReturns application health information.
/cachesIt exposes available caches.
/conditionsShows the conditions that were evaluated on configuration and auto-configuration.
/configpropsIt displays a collated list of all @ConfigurationProperties.
/integrationgraphIt shows the Spring Integration graph. Requires a dependency on spring-integration-core.
/loggersThe configuration of loggers in the application..
/scheduledtasksDisplays the scheduled tasks in the application.
/sessionsReturns trace logs (by default the last 100 HTTP requests). Requires an HttpTraceRepository bean.
/httptraceIt allows retrieval and deletion of user sessions from a Spring Session-backed session store. Requires a Servlet-based web application using Spring Session.
/shutdownLets the application be gracefully shutdown. Disabled by default.
/threaddumpIt performs a thread dump.
/metricsIt shows several useful metrics information like JVM memory used, system CPU usage, open files, and much more.

The Spring web application (Spring MVC, Spring WebFlux, or Jersey) provide the following additional endpoints:

ENDPOINTUSAGE
/heapdumpReturns an hprof heap dump file.
/logfileReturns the contents of the logfile if logging.file.name or logging.file.path properties have been set.

1.3. Securing Endpoints

By default, Spring Security is enabled for all actuator endpoints if it available in the classpath.

If you wish to configure custom security for HTTP endpoints, for example, only allow users with a certain role to access then configure WebSecurityConfigurerAdapter in following manner:

@Configuration(proxyBeanMethods = false)public class ActuatorSecurity extends WebSecurityConfigurerAdapter { @Overrideprotected void configure(HttpSecurity http) throws Exception {http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->requests.anyRequest().hasRole("ENDPOINT_ADMIN"));http.httpBasic();} }

The above configuration ensures that only users with role ENDPOINT_ADMIN have access to actuation endpoints.

1.4. Enabling Endpoints

By default, all endpoints (except /shutdown) are enabled. To disable all endpoints, by default, use property:

management.endpoints.enabled-by-default=false

Then use the only required endpoints which the application need to expose using the pattern management.endpoint.<id>.enabled.

management.endpoint.health.enabled=truemanagement.endpoint.loggers.enabled=true

1.5. CORS support

CORS Support is disabled by default and is only enabled once the endpoints.cors.allowed-origins property has been set.

management.endpoints.web.cors.allowed-origins=https://example.commanagement.endpoints.web.cors.allowed-methods=GET,POST

Here the management context path is /management.

1.6. Caching the Response

Actuator endpoints automatically cache the responses to read operations that do not take any parameters. Use cache.time-to-live property to configure the amount of time for which an endpoint will cache the response.

management.endpoint.beans.cache.time-to-live=20s

2. Spring Boot Actuator Endpoint Example

In this example, we will create a simple spring boot application and access the actuator endpoints to know more about them.

2.1. Development environment

  • JDK 1.8, Eclipse, Maven – Development environment
  • Spring-boot – Underlying application framework
  • Spring-boot Actuator – Management endpoints

2.2. Create Maven Project

Start with creating one spring boot project from Spring Initializer site with WebRest Repositories and Actuator dependencies. Download project in zipped format. Unzip and then import project in eclipse as maven project.

Generate Spring Boot Project
Generate Spring Boot Project

2.3. Add simple Rest endpoint

Now add one simple Rest endpoint /example to the application.

package com.example.springbootmanagementexample; import java.util.Date;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController; @RestControllerpublic class SimpleRestController {@GetMapping("/example")public String example() {return "Hello User !! " + new Date();}}

3. Spring Boot Actuator Endpoints Demo

I have added management.security.enabled=false entry to the application.properties file to disable actuator security. Here I am more interested in actuator endpoints responses.

Do maven build using mvn clean install and start the application using java -jar target\spring-boot-actuator-example-0.0.1-SNAPSHOT.jar command. This will bring up one tomcat server in default port 8080 and application will be deployed in it.

Access /example API in browser to generate few monitoring information on server.

  • http://localhost:8080/actuator/envThis will give all the environmental configuration about the server.Endpoint env outputEndpoint env output
  • http://localhost:8080/actuator/beansThis will give all the spring beans loaded in the context.Endpoint beans outputEndpoint beans output
  • http://localhost:8080/actuator/threaddumpThis will give the current server thread dump.Endpoint threaddump outputEndpoint threaddump output

Those endpoints will give standard information in the browser. These are the basic important endpoints we generally refer, but spring boot provides many more endpoints as mentioned in this link

4. Actuator Advance Configuration Options

4.1. Change the Management endpoint context path

By default all endpoints comes in default context path of the application, suffixed with /actuator. If for some reason, we have existing endpoints in application starting with /actuator then we can customize the base path to something else.

All we need to specify the new base path in the application.properties.

management.endpoints.web.base-path=/manage

Now you will be able to access all actuator endpoints under a new URL. e.g.

  • /manage/health
  • /manage/dump
  • /manage/env
  • /manage/beans

4.2. Customize the management server port

To customize the management endpoint port, we need to add this entry in the application.properties file.

management.server.port=8081

5. Summary

In this spring boot actuator example, we learned to configure management and monitoring endpoints with few easy configurations. So next time, you need to add application health checks or add monitoring support, you should consider adding the Spring actuator project and use these endpoints.

Feel free to drop your questions in the comments section.

Happy Learning !!

Maximum Contiguous Subarray Sum
06
Feb
2021

Maximum Contiguous Subarray Sum

Maximum Contiguous Subarray Sum problem statement

Given an array of integers, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: The subarray [4,-1,2,1] has the largest sum = 6.

Maximum Contiguous Subarray Sum solution in Java

This problem can be solved using Kadane’s algorithm in O(n) time complexity.

The algorithm iterates over all the elements of the array (nums) and computes the maximum sum ending at every index (maxEndingHere). Here is how maxEndingHere is calculated:

  • Initialize maxEndingHere to nums[0]
  • Iterate through the array (1..n). For every iteration:
    • If maxEndingHere + nums[i] < nums[i], that means the previous max was negative and therefore we reset maxEndingHere to nums[i].
    • Otherwise, we set maxEndingHere = maxEndingHere + nums[i]
  • We also keep a variable maxSoFar which indicates the maximum sum found so far. And, with every iteration, we check if the current max (maxEndingHere) is greater than maxSoFar. If yes, then we update the value of maxSoFar.

Here is the complete solution:

import java.util.Scanner;

class MaximumSubarray {

  private static int findMaxSubarraySum(int[] nums) {
    int n = nums.length;
    int maxSoFar = nums[0];
    int maxEndingHere = nums[0];

    for(int i = 1; i < n; i++) {
      if(maxEndingHere + nums[i] < nums[i]) {
        maxEndingHere = nums[i];
      } else {
        maxEndingHere = maxEndingHere + nums[i];
      }

      if(maxEndingHere > maxSoFar) {
        maxSoFar = maxEndingHere;
      }
    }
    return maxSoFar;
  }

  public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);
    int n = keyboard.nextInt();
    int[] nums = new int[n];
    for(int i = 0; i < n; i++) {
      nums[i] = keyboard.nextInt();
    }

    System.out.println(findMaxSubarraySum(nums));
  }
}
# Output
$ javac MaximumSubarray.java
$ java MaximumSubarray
9 -2 1 -3 4 -1 2 1 -5 4
6

Maximum Contiguous Subarray with Indices

It’s also possible to find out the start and end indices of the maximum contiguous subarray. Here is a modification of the above program which does that and prints the subarray –

import java.util.Scanner;

class MaximumSubarray {

  private static int[] findMaxSubarrayIndices(int[] nums) {
    int n = nums.length;
    int maxSoFar = nums[0];
    int maxEndingHere = nums[0];
    int currentStart = 0, maxStart = 0, maxEnd = 0;

    for(int i = 1; i < n; i++) {
      if(maxEndingHere + nums[i] < nums[i]) {
        maxEndingHere = nums[i];
        currentStart = i;
      } else {
        maxEndingHere = maxEndingHere + nums[i];
      }

      if(maxEndingHere > maxSoFar) {
        maxSoFar = maxEndingHere;
        maxStart = currentStart;
        maxEnd = i;
      }
    }

    return new int[]{maxStart, maxEnd};
  }

  public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);
    int n = keyboard.nextInt();
    int[] nums = new int[n];
    for(int i = 0; i < n; i++) {
      nums[i] = keyboard.nextInt();
    }

    int[] indices = findMaxSubarrayIndices(nums);
    int sum = 0;
    System.out.print("Max contiguous subarray: ");
    for(int i = indices[0]; i <= indices[1]; i++) {
      System.out.print(nums[i] + " ");
      sum += nums[i];
    }
    System.out.println();
    System.out.println("Max contiguous subarray sum: " + sum);
  }
}
# Output
$ javac MaximumSubarray.java
$ java MaximumSubarray
9 -2 1 -3 4 -1 2 1 -5 4
Max contiguous subarray: 4 -1 2 1
Max contiguous subarray sum: 6
Log4J Asynchronous Logging
03
Mar
2021

Log4J Asynchronous Logging

Asynchronous Logging

Log4j2 Supports Async loggers. These loggers provide a drastic improvement in performance compared to their synchronous counterparts.

Async Loggers internally use a library called Disruptor for asynchronous logging.

We need to include Disruptor dependency for using async loggers. Add the following to your pom.xml file –

<!-- Needed for Async Logging with Log4j 2 -->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.6</version>
</dependency>
Kotlin Operators with Examples
07
Mar
2021

Kotlin Operators with Examples

In the previous article, you learned how to create variables and what are various basic data types available in Kotlin for creating variables.

In this article, you’ll learn what are various operators provided by kotlin to perform operations on basic data types.

Operations on Numeric Types

Just like other languages, Kotlin provides various operators to perform computations on numbers –

  • Arithmetic operators (+-*/%)
  • Comparison operators (==!=<><=>=)
  • Assignment operators (+=-=*=/=%=)
  • Increment & Decrement operators (++--)

Following are few examples that demonstrate the usage of above operators –

var a = 10
var b = 20
var c = ((a + b) * ( a + b))/2   // 450

var isALessThanB = a < b   // true

a++     // a now becomes 11
b += 5  // b equals to 25 now

Understanding how operators work in Kotlin

Everything in Kotlin is an object, even the basic data types like IntCharDoubleBoolean etc. Kotlin doesn’t have separate primitive types and their corresponding boxed types like Java.

Note that Kotlin may represent basic types like IntCharBoolean etc. as primitive values at runtime to improve performance, but for the end users, all of them are objects.

Since all the data types are objects, the operations on these types are internally represented as function calls.

For example, the addition operation a + b between two numbers a and b is represented as a function call a.plus(b) –

var a = 4
var b = 5

println(a + b)

// equivalent to
println(a.plus(b))

All the operators that we looked at in the previous section have a symbolic name which is used to translate any expression containing those operators into the corresponding function calls –

ExpressionTranslates to
a + ba.plus(b)
a – ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
a++a.inc()
a−−a.dec()
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a += ba.plusAssign(b)

You can check out other expressions and their corresponding function calls on Kotlin’s reference page.

The concept of translating such expressions to function calls enable operator overloading in Kotlin. For example, you can provide implementation for the plus function in a class defined by you, and then you’ll be able to add the objects of that class using + operator like this – object1 + object2.

Kotlin will automatically convert the addition operation object1 + object2 into the corresponding function call object1.plus(object2) (Think of a ComplexNumber class with the + operator overloaded).

You’ll learn more about operator overloading in a future article.

Note that the operations on basic types like IntCharDoubleBoolean etc. are optimized and do not include the overhead of function calls.

Bitwise Operators

Unlike C, C++ and Java, Kotlin doesn’t have bitwise operators like |(bitwise-or), &(bitwise-and), ^(bitwise-xor), << (signed left shift), >>(signed right shift) etc.

For performing bitwise operations, Kotlin provides following methods that work for Int and Long types –

  • shl – signed shift left (equivalent of << operator)
  • shr – signed shift right (equivalent of >> operator)
  • ushr– unsigned shift right (equivalent of >>> operator)
  • and – bitwise and (equivalent of & operator)
  • or – bitwise or (equivalent of | operator)
  • xor – bitwise xor (equivalent of ^ operator)
  • inv – bitwise complement (equivalent of ~ operator)

Here are few examples demonstrating how to use above functions –

1 shl 2   // Equivalent to 1.shl(2), Result = 4
16 shr 2  // Result = 4
2 and 4   // Result = 0
2 or 3    // Result = 3
4 xor 5   // Result = 1
4.inv()   // Result = -5

All the bitwise functions, except inv(), can be called using infix notation. The infix notation of 2.and(4) is 2 and 4. Infix notation allows you to write function calls in a more intuitive way.

Operations on Boolean Types

Kotlin supports following logical operators for performing operations on boolean types –

  • || – Logical OR
  • && – Logical AND
  • !   – Logical NOT

Here are few examples of logical operators –

2 == 2 && 4 != 5  // true
4 > 5 && 2 < 7    // false
!(7 > 12 || 14 < 18)  // false

Logical operators are generally used in control flow statements like ifif-elsewhile etc., to test the validity of a condition.

Operations on Strings

String Concatenation

The + operator is overloaded for String types. It performs String concatenation –

var firstName = "Rajeev"
var lastName = "Singh"
var fullName = firstName + " " + lastName	// "Rajeev Singh"

String Interpolation

Kotlin has an amazing feature called String Interpolation. This feature allows you to directly insert a template expression inside a String. Template expressions are tiny pieces of code that are evaluated and their results are concatenated with the original String.

A template expression is prefixed with $ symbol. Following is an example of String interpolation –

var a = 12
var b = 18
println("Avg of $a and $b is equal to ${ (a + b)/2 }") 

// Prints - Avg of 12 and 18 is equal to 15

If the template expression is a simple variable, you can write it like $variableName. If it is an expression then you need to insert it inside a ${} block.

Conclusion

That’s all folks! In this article, you learned what are various operators provided in Kotlin to perform operations on Numbers, Booleans, and Strings. You also learned how the expressions containing operators are translated to function calls internally.

As always, Thank you for reading.

Nullable Types and Null Safety in Kotlin
07
Mar
2021

Nullable Types and Null Safety in Kotlin

if you have been programming in Java or any other language that has the concept of null reference then you must have heard about or experienced NullPointerException in your programs.

NullPointerExceptions are Runtime Exceptions which are thrown by the program at runtime causing application failure and system crashes.

Wouldn’t it be nice if we could detect possible NullPointerException exception errors at compile time itself and guard against them?

Well, Enter Kotlin!

Nullability and Nullable Types in Kotlin

Kotlin supports nullability as part of its type System. That means You have the ability to declare whether a variable can hold a null value or not.

By supporting nullability in the type system, the compiler can detect possible NullPointerException errors at compile time and reduce the possibility of having them thrown at runtime.

Let’s understand how it works!

All variables in Kotlin are non-nullable by default. So If you try to assign a null value to a regular variable, the compiler will throw an error –

var greeting: String = "Hello, World"
greeting = null // Compilation Error

To allow null values, you have to declare a variable as nullable by appending a question mark in its type declaration –

var nullableGreeting: String? = "Hello, World"
nullableGreeting = null // Works

We know that NullPointerException occurs when we try to call a method or access a property on a variable which is null. Kotlin disallows method calls and property access on nullable variables and thereby prevents many possible NullPointerExceptions.

For example, The following method access works because Kotlin knows that the variable greeting can never be null –

val len = greeting.length 
val upper = greeting.toUpperCase() 

But the same method call won’t work with nullableGreeting variable –

val len = nullableGreeting.length // Compilation Error
val upper = nullableGreeting.toUpperCase()  // Compilation Error

Since Kotlin knows beforehand which variable can be null and which cannot, It can detect and disallow calls which could result in NullPointerException at compile-time itself.

Working with Nullable Types

All right, It’s nice that Kotlin disallows method calls and property access on nullable variables to guard against NullPointerException errors. But we still need to do that right?

Well, There are several ways of safely doing that in Kotlin.

1. Adding a null Check

The most trivial way to work with nullable variables is to perform a null check before accessing a property or calling a method on them –

val nullableName: String? = "John"

if(nullableName != null) {
    println("Hello, ${nullableName.toUpperCase()}.")
    println("Your name is ${nullableName.length} characters long.")
} else {
    println("Hello, Guest")
}

Once you perform a null comparison, the compiler remembers that and allows calls to toUpperCase() and length inside the if branch.

2. Safe call operator: ?.

Null Comparisons are simple but too verbose. Kotlin provides a Safe call operator, ?. that reduces this verbosity. It allows you to combine a null-check and a method call in a single expression.

For example, The following expression –

nullableName?.toUpperCase()

is same as –

if(nullableName != null) 
    nullableName.toUpperCase()
else
    null    

Wow! That saves a lot of keystrokes, right? 🙂

So if you were to print the name in uppercase and its length safely, you could do the following –

val nullableName: String? = null

println(nullableName?.toUpperCase())
println(nullableName?.length)
// Prints 
null
null

That printed null since the variable nullableName is null, otherwise, it would have printed the name in uppercase and its length.

But what if you don’t want to print anything if the variable is null?

Well, To perform an operation only if the variable is not null, you can use the safe call operator with let –

val nullableName: String? = null

nullableName?.let { println(it.toUpperCase()) }
nullableName?.let { println(it.length) }

// Prints nothing

The lambda expression inside let is executed only if the variable nullableName is not null.

That’s great but that’s not all. Safe call operator is even more powerful than you think. For example, You can chain multiple safe calls like this –

val currentCity: String? = user?.address?.city

The variable currentCity will be null if any of useraddress or city is null. (Imagine doing that using null-checks.)

3. Elvis operator: ?:

The Elvis operator is used to provide a default value when the original variable is null –

val name = nullableName ?: "Guest"

The above expression is same as –

val name = if(nullableName != null) nullableName else "Guest"

In other words, The Elvis operator takes two values and returns the first value if it is not null, otherwise, it returns the second value.

The Elvis operator is often used with Safe call operator to provide a default value other than null when the variable on which a method or property is called is null –

val len = nullableName?.length ?: -1

You can have more complex expressions on the left side of Elvis operator –

val currentCity = user?.address?.city ?: "Unknown"

Moreover, You can use throw and return expressions on the right side of Elvis operator. This is very useful while checking preconditions in a function. So instead of providing a default value in the right side of Elvis operator, you can throw an exception like this –

val name = nullableName ?: throw IllegalArgumentException("Name can not be null")

4. Not null assertion : !! Operator

The !! operator converts a nullable type to a non-null type, and throws a NullPointerException if the nullable type holds a null value.

So It’s a way of asking for NullPointerException explicitly. Please don’t use this operator.

val nullableName: String? = null
nullableName!!.toUpperCase() // Results in NullPointerException

Null Safety and Java Interoperability

Kotlin is fully interoperable with Java but Java doesn’t support nullability in its type system. So what happens when you call Java code from Kotlin?

Well, Java types are treated specially in Kotlin. They are called Platform types. Since Kotlin doesn’t have any information about the nullability of a type declared in Java, It relaxes compile-time null checks for these types.

So you don’t get any null safety guarantee for types declared in Java, and you have full responsibility for operations you perform on these types. The compiler will allow all operations. If you know that the Java variable can be null, you should compare it with null before use, otherwise, just like Java, you’ll get a NullPointerException at runtime if the value is null.

Consider the following User class declared in Java –

public class User {
    private final String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Since Kotlin doesn’t know about the nullability of the member variable name, It allows all operations on this variable. You can treat it as nullable or non-nullable, but the compiler won’t enforce anything.

In the following example, We simply treat the variable name as non-nullable and call methods and properties on it –

val javaUser = User(null)

println(javaUser.name.toUpperCase()) // Allowed (Throws NullPointerException)
println(javaUser.name.length) // Allowed (Throws NullPointerException)

The other option is to treat the member variable name as nullable and use the safe operator for calling methods or accessing properties –

val javaUser = User(null)

println(javaUser.name?.toUpperCase()) // Allowed (Prints null)
println(javaUser.name?.length) // Allowed (Prints null)

Nullability Annotations

Although Java doesn’t support nullability in its type system, You can use annotations like @Nullable and @NotNull provided by external packages like javax.validation.constraintsorg.jetbrains.annotations etc to mark a variable as Nullable or Not-null.

Java compiler doesn’t use these annotations, but these annotations are used by IDEs, ORM libraries and other external tools to provide assistance while working with null values.

Kotlin also respects these annotations when they are present in Java code. Java types which have these nullability annotations are represented as actual nullable or non-null Kotlin types instead of platform types.

Nullability and Collections

Kotlin’s collection API is built on top of Java’s collection API but it fully supports nullability on Collections.

Just as regular variables are non-null by default, a normal collection also can’t hold null values –

val regularList: List<Int> = listOf(1, 2, null, 3) // Compiler Error

1. Collection of Nullable Types

Here is how you can declare a Collection of Nullable Types in Kotlin –

val listOfNullableTypes: List<Int?> = listOf(1, 2, null, 3) // Works

To filter non-null values from a list of nullable types, you can use the filterNotNull() function –

val notNullList: List<Int> = listOfNullableTypes.filterNotNull()

2. Nullable Collection

Note that there is a difference between a collection of nullable types and a nullable collection.

A collection of nullable types can hold null values but the collection itself cannot be null –

var listOfNullableTypes: List<Int?> = listOf(1, 2, null, 3) // Works
listOfNullableTypes = null // Compilation Error

You can declare a nullable collection like this –

var nullableList: List<Int>? = listOf(1, 2, 3)
nullableList = null // Works

3. Nullable Collection of Nullable Types

Finally, you can declare a nullable collection of nullable types like this –

var nullableListOfNullableTypes: List<Int?>? = listOf(1, 2, null, 3) // Works
nullableListOfNullableTypes = null // Works

Conclusion

That’s all in this article folks. I hope you understood how kotlin helps you avoid NullPointerException errors with its nullable type concept.

Thanks for reading. See you in the next post.

Three Number Sum Solution
06
Feb
2021

Three Number Sum Solution

Three Number Sum Problem Statement

Given an array of integers, find all triplets in the array that sum up to a given target value.

In other words, given an array arr and a target value target, return all triplets a, b, c such that a + b + c = target.

Example:

Input array: [7, 12, 3, 1, 2, -6, 5, -8, 6]
Target sum: 0

Output: [[2, -8, 6], [3, 5, -8], [1, -6, 5]]

Three Number Sum Problem solution in Java

METHOD 1. Naive approach: Use three for loops

The naive approach is to just use three nested for loops and check if the sum of any three elements in the array is equal to the given target.

Time complexity: O(n^3)

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class ThreeSum {

  // Time complexity: O(n^3)
  private static List<Integer[]> findThreeSum_BruteForce(int[] nums, int target) {
    List<Integer[]> result = new ArrayList<>();
    for (int i = 0; i < nums.length; i++) {
      for (int j = i + 1; j < nums.length; j++) {
        for (int k = j + 1; k < nums.length; k++) {
          if (nums[i] + nums[j] + nums[k] == target) {
            result.add(new Integer[] { nums[i], nums[j], nums[k] });
          }
        }
      }
    }
    return result;
  }

  public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);

    int n = keyboard.nextInt();
    int[] nums = new int[n];

    for (int i = 0; i < n; i++) {
      nums[i] = keyboard.nextInt();
    }
    int target = keyboard.nextInt();

    keyboard.close();

    List<Integer[]> result = findThreeSum_Sorting(nums, target);

    for(Integer[] triplets: result) {
      for(int num: triplets) {
        System.out.print(num + " ");
      }
      System.out.println();
    }
  }
}

METHOD 2. Use Sorting along with the two-pointer sliding window approach

Another approach is to first sort the array, then –

  • Iterate through each element of the array and for every iteration,
    • Fix the first element (nums[i])
    • Try to find the other two elements whose sum along with nums[i] gives target. This boils down to the two sum problem.

Time complexity: O(n^2)

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class ThreeSum {

  // Time complexity: O(n^2)
  private static List<Integer[]> findThreeSum_Sorting(int[] nums, int target) {
    List<Integer[]> result = new ArrayList<>();
    Arrays.sort(nums);
    for (int i = 0; i < nums.length; i++) {
      int left = i + 1;
      int right = nums.length - 1;
      while (left < right) {
        if (nums[i] + nums[left] + nums[right] == target) {
          result.add(new Integer[] { nums[i], nums[left], nums[right] });
          left++;
          right--;
        } else if (nums[i] + nums[left] + nums[right] < target) {
          left++;
        } else {
          right--;
        }
      }
    }
    return result;
  }
}

METHOD 3. Use a Map/Set

Finally, you can also solve the problem using a Map/Set. You just need to iterate through the array, fix the first element, and then try to find the other two elements using the approach similar to the two sum problem.

I’m using a Set in the following solution instead of a Map as used in the two-sum problem because in the two-sum problem, we had to keep track of the index of the elements as well. But In this problem, we just care about the element and not its index.

Time complexity: O(n^2)

import java.util.Set;
import java.util.Scanner;
import java.util.HashSet;

class ThreeSum {

  // Time complexity: O(n^2)
  private static List<Integer[]> findThreeSum(int[] nums, int target) {
    List<Integer[]> result = new ArrayList<>();
    for (int i = 0; i < nums.length; i++) {
      int currentTarget = target - nums[i];
      Set<Integer> existingNums = new HashSet<>();
      for (int j = i + 1; j < nums.length; j++) {
        if (existingNums.contains(currentTarget - nums[j])) {
          result.add(new Integer[] { nums[i], nums[j], currentTarget - nums[j] });
        } else {
          existingNums.add(nums[j]);
        }
      }
    }
    return result;
  }
}

Liked the Article? Share it on Social media!

Spring Boot File Upload / Download Rest API Example
03
Mar
2021

Spring Boot File Upload / Download Rest API Example

Uploading and downloading files are very common tasks for which developers need to write code in their applications.

In this article, You’ll learn how to upload and download files in a RESTful spring boot web service.

We’ll first build the REST APIs for uploading and downloading files, and then test those APIs using Postman. We’ll also write front-end code in javascript to upload files.

Following is the final version of our application –

Spring Boot File Upload and Download AJAX Rest API Web Service

All right! Let’s get started.

Creating the Application

Let’s generate our application using Spring Boot CLI. Fire up your terminal, and type the following command to generate the app –

$ spring init --name=file-demo --dependencies=web file-demo
Using service at https://start.spring.io
Project extracted to '/Users/rajeevkumarsingh/spring-boot/file-demo'

You may also generate the application through Spring Initializr web tool by following the instructions below –

  1. Open http://start.spring.io
  2. Enter file-demo in the “Artifact” field.
  3. Add Web in the dependencies section.
  4. Click Generate to generate and download the project.

That’s it! You may now unzip the downloaded application archive and import it into your favorite IDE.

Configuring Server and File Storage Properties

First thing First! Let’s configure our Spring Boot application to enable Multipart file uploads, and define the maximum file size that can be uploaded. We’ll also configure the directory into which all the uploaded files will be stored.

Open src/main/resources/application.properties file, and add the following properties to it –

## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB

## File Storage Properties
# All files uploaded through the REST API will be stored in this directory
file.upload-dir=/Users/folder/uploads

Note: Please change the file.upload-dir property to the path where you want the uploaded files to be stored.

Automatically binding properties to a POJO class

Spring Boot has an awesome feature called @ConfigurationProperties using which you can automatically bind the properties defined in the application.properties file to a POJO class.

package com.example.filedemo.property;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
    private String uploadDir;

    public String getUploadDir() {
        return uploadDir;
    }

    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }
}

The @ConfigurationProperties(prefix = "file") annotation does its job on application startup and binds all the properties with prefix file to the corresponding fields of the POJO class.

If you define additional file properties in future, you may simply add a corresponding field in the above class, and spring boot will automatically bind the field with the property value.

Enable Configuration Properties

Now, To enable the ConfigurationProperties feature, you need to add @EnableConfigurationProperties annotation to any configuration class.

Open the main class src/main/java/com/example/filedemo/FileDemoApplication.java, and add the @EnableConfigurationProperties annotation to it like so –

package com.example.filedemo;

import com.example.filedemo.property.FileStorageProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties({
        FileStorageProperties.class
})
public class FileDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileDemoApplication.class, args);
    }
}

Writing APIs for File Upload and Download

Let’s now write the REST APIs for uploading and downloading files. Create a new controller class called FileController inside com.example.filedemo.controller package.

Here is the complete code for FileController –

package com.example.filedemo.controller;

import com.example.filedemo.payload.UploadFileResponse;
import com.example.filedemo.service.FileStorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class FileController {

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private FileStorageService fileStorageService;
    
    @PostMapping("/uploadFile")
    public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
        String fileName = fileStorageService.storeFile(file);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();

        return new UploadFileResponse(fileName, fileDownloadUri,
                file.getContentType(), file.getSize());
    }

    @PostMapping("/uploadMultipleFiles")
    public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
        return Arrays.asList(files)
                .stream()
                .map(file -> uploadFile(file))
                .collect(Collectors.toList());
    }

    @GetMapping("/downloadFile/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
        // Load file as Resource
        Resource resource = fileStorageService.loadFileAsResource(fileName);

        // Try to determine file's content type
        String contentType = null;
        try {
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException ex) {
            logger.info("Could not determine file type.");
        }

        // Fallback to the default content type if type could not be determined
        if(contentType == null) {
            contentType = "application/octet-stream";
        }

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }
}

The FileController class uses FileStorageService for storing files in the file system and retrieving them. It returns a payload of type UploadFileResponse after the upload is completed. Let’s define these classes one by one.

UploadFileResponse

As the name suggests, this class is used to return the response from the /uploadFile and /uploadMultipleFiles APIs.

Create UploadFileResponse class inside com.example.filedemo.payload package with the following contents –

package com.example.filedemo.payload;

public class UploadFileResponse {
    private String fileName;
    private String fileDownloadUri;
    private String fileType;
    private long size;

    public UploadFileResponse(String fileName, String fileDownloadUri, String fileType, long size) {
        this.fileName = fileName;
        this.fileDownloadUri = fileDownloadUri;
        this.fileType = fileType;
        this.size = size;
    }

	// Getters and Setters (Omitted for brevity)
}

Service for Storing Files in the FileSystem and retrieving them

Let’s now write the service for storing files in the file system and retrieving them. Create a new class called FileStorageService.java inside com.example.filedemo.service package with the following contents –

package com.example.filedemo.service;

import com.example.filedemo.exception.FileStorageException;
import com.example.filedemo.exception.MyFileNotFoundException;
import com.example.filedemo.property.FileStorageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Service
public class FileStorageService {

    private final Path fileStorageLocation;

    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                .toAbsolutePath().normalize();

        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception ex) {
            throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    public String storeFile(MultipartFile file) {
        // Normalize file name
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());

        try {
            // Check if the file's name contains invalid characters
            if(fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
            }

            // Copy file to the target location (Replacing existing file with the same name)
            Path targetLocation = this.fileStorageLocation.resolve(fileName);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

            return fileName;
        } catch (IOException ex) {
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }

    public Resource loadFileAsResource(String fileName) {
        try {
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if(resource.exists()) {
                return resource;
            } else {
                throw new MyFileNotFoundException("File not found " + fileName);
            }
        } catch (MalformedURLException ex) {
            throw new MyFileNotFoundException("File not found " + fileName, ex);
        }
    }
}

Exception Classes

The FileStorageService class throws some exceptions in case of unexpected situations. Following are the definitions of those exception classes (All the exception classes go inside the package com.example.filedemo.exception).

1. FileStorageException

It’s thrown when an unexpected situation occurs while storing a file in the file system –

package com.example.filedemo.exception;

public class FileStorageException extends RuntimeException {
    public FileStorageException(String message) {
        super(message);
    }

    public FileStorageException(String message, Throwable cause) {
        super(message, cause);
    }
}

2. MyFileNotFoundException

It’s thrown when a file that the user is trying to download is not found.

package com.example.filedemo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class MyFileNotFoundException extends RuntimeException {
    public MyFileNotFoundException(String message) {
        super(message);
    }

    public MyFileNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

Note that, we’ve annotated the above exception class with @ResponseStatus(HttpStatus.NOT_FOUND). This ensures that Spring boot responds with a 404 Not Found status when this exception is thrown.

Running the Application and Testing the APIs via Postman

We’re done developing our backend APIs. Let’s run the application and test the APIs via Postman. Type the following command from the root directory of the project to run the application –

mvn spring-boot:run

Once started, the application can be accessed at http://localhost:8080.

1. Upload File

Spring Boot File Upload Rest API Example

2. Upload Multiple Files

Spring Boot Upload Multiple Files Rest API Example

3. Download File

Spring Boot Download File Rest API Example

Developing the Front End

Our backend APIs are working fine. Let’s now write the front end code to let users upload and download files from our web app.

All the front end files will go inside src/main/resources/static folder. Following is the directory structure of our front-end code –

static
  └── css
       └── main.css
  └── js
       └── main.js
  └── index.html 

A bit of HTML

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
        <title>Spring Boot File Upload / Download Rest API Example</title>
        <link rel="stylesheet" href="/css/main.css" />
    </head>
    <body>
        <noscript>
            <h2>Sorry! Your browser doesn't support Javascript</h2>
        </noscript>
        <div class="upload-container">
            <div class="upload-header">
                <h2>Spring Boot File Upload / Download Rest API Example</h2>
            </div>
            <div class="upload-content">
                <div class="single-upload">
                    <h3>Upload Single File</h3>
                    <form id="singleUploadForm" name="singleUploadForm">
                        <input id="singleFileUploadInput" type="file" name="file" class="file-input" required />
                        <button type="submit" class="primary submit-btn">Submit</button>
                    </form>
                    <div class="upload-response">
                        <div id="singleFileUploadError"></div>
                        <div id="singleFileUploadSuccess"></div>
                    </div>
                </div>
                <div class="multiple-upload">
                    <h3>Upload Multiple Files</h3>
                    <form id="multipleUploadForm" name="multipleUploadForm">
                        <input id="multipleFileUploadInput" type="file" name="files" class="file-input" multiple required />
                        <button type="submit" class="primary submit-btn">Submit</button>
                    </form>
                    <div class="upload-response">
                        <div id="multipleFileUploadError"></div>
                        <div id="multipleFileUploadSuccess"></div>
                    </div>
                </div>
            </div>
        </div>
        <script src="/js/main.js" ></script>
    </body>
</html>

Some Javascript

'use strict';

var singleUploadForm = document.querySelector('#singleUploadForm');
var singleFileUploadInput = document.querySelector('#singleFileUploadInput');
var singleFileUploadError = document.querySelector('#singleFileUploadError');
var singleFileUploadSuccess = document.querySelector('#singleFileUploadSuccess');

var multipleUploadForm = document.querySelector('#multipleUploadForm');
var multipleFileUploadInput = document.querySelector('#multipleFileUploadInput');
var multipleFileUploadError = document.querySelector('#multipleFileUploadError');
var multipleFileUploadSuccess = document.querySelector('#multipleFileUploadSuccess');

function uploadSingleFile(file) {
    var formData = new FormData();
    formData.append("file", file);

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/uploadFile");

    xhr.onload = function() {
        console.log(xhr.responseText);
        var response = JSON.parse(xhr.responseText);
        if(xhr.status == 200) {
            singleFileUploadError.style.display = "none";
            singleFileUploadSuccess.innerHTML = "<p>File Uploaded Successfully.</p><p>DownloadUrl : <a href='" + response.fileDownloadUri + "' target='_blank'>" + response.fileDownloadUri + "</a></p>";
            singleFileUploadSuccess.style.display = "block";
        } else {
            singleFileUploadSuccess.style.display = "none";
            singleFileUploadError.innerHTML = (response && response.message) || "Some Error Occurred";
        }
    }

    xhr.send(formData);
}

function uploadMultipleFiles(files) {
    var formData = new FormData();
    for(var index = 0; index < files.length; index++) {
        formData.append("files", files[index]);
    }

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/uploadMultipleFiles");

    xhr.onload = function() {
        console.log(xhr.responseText);
        var response = JSON.parse(xhr.responseText);
        if(xhr.status == 200) {
            multipleFileUploadError.style.display = "none";
            var content = "<p>All Files Uploaded Successfully</p>";
            for(var i = 0; i < response.length; i++) {
                content += "<p>DownloadUrl : <a href='" + response[i].fileDownloadUri + "' target='_blank'>" + response[i].fileDownloadUri + "</a></p>";
            }
            multipleFileUploadSuccess.innerHTML = content;
            multipleFileUploadSuccess.style.display = "block";
        } else {
            multipleFileUploadSuccess.style.display = "none";
            multipleFileUploadError.innerHTML = (response && response.message) || "Some Error Occurred";
        }
    }

    xhr.send(formData);
}


singleUploadForm.addEventListener('submit', function(event){
    var files = singleFileUploadInput.files;
    if(files.length === 0) {
        singleFileUploadError.innerHTML = "Please select a file";
        singleFileUploadError.style.display = "block";
    }
    uploadSingleFile(files[0]);
    event.preventDefault();
}, true);


multipleUploadForm.addEventListener('submit', function(event){
    var files = multipleFileUploadInput.files;
    if(files.length === 0) {
        multipleFileUploadError.innerHTML = "Please select at least one file";
        multipleFileUploadError.style.display = "block";
    }
    uploadMultipleFiles(files);
    event.preventDefault();
}, true);

The above code is self explanatory. I’m using XMLHttpRequest along with FormData object to upload file(s) as multipart/form-data.

And some CSS

* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

body {
    margin: 0;
    padding: 0;
    font-weight: 400;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 1rem;
    line-height: 1.58;
    color: #333;
    background-color: #f4f4f4;
}

body:before {
    height: 50%;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: #128ff2;
    content: "";
    z-index: 0;
}

.clearfix:after {
    display: block;
    content: "";
    clear: both;
}


h1, h2, h3, h4, h5, h6 {
    margin-top: 20px;
    margin-bottom: 20px;
}

h1 {
    font-size: 1.7em;
}

a {
    color: #128ff2;
}

button {
    box-shadow: none;
    border: 1px solid transparent;
    font-size: 14px;
    outline: none;
    line-height: 100%;
    white-space: nowrap;
    vertical-align: middle;
    padding: 0.6rem 1rem;
    border-radius: 2px;
    transition: all 0.2s ease-in-out;
    cursor: pointer;
    min-height: 38px;
}

button.primary {
    background-color: #128ff2;
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.12);
    color: #fff;
}

input {
    font-size: 1rem;
}

input[type="file"] {
    border: 1px solid #128ff2;
    padding: 6px;
    max-width: 100%;
}

.file-input {
    width: 100%;
}

.submit-btn {
    display: block;
    margin-top: 15px;
    min-width: 100px;
}

@media screen and (min-width: 500px) {
    .file-input {
        width: calc(100% - 115px);
    }

    .submit-btn {
        display: inline-block;
        margin-top: 0;
        margin-left: 10px;
    }
}

.upload-container {
      max-width: 700px;
      margin-left: auto;
      margin-right: auto;
      background-color: #fff;
      box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);
      margin-top: 60px;
      min-height: 400px;
      position: relative;
      padding: 20px;
}

.upload-header {
    border-bottom: 1px solid #ececec;
}

.upload-header h2 {
    font-weight: 500;
}

.single-upload {
    padding-bottom: 20px;
    margin-bottom: 20px;
    border-bottom: 1px solid #e8e8e8;
}

.upload-response {
    overflow-x: hidden;
    word-break: break-all;
}

If you use JQuery

If you prefer using jQuery instead of vanilla javascript, then you can upload files using jQuery.ajax() method like so –

$('#singleUploadForm').submit(function(event) {
    var formElement = this;
    // You can directly create form data from the form element
    // (Or you could get the files from input element and append them to FormData as we did in vanilla javascript)
    var formData = new FormData(formElement);

    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: "/uploadFile",
        data: formData,
        processData: false,
        contentType: false,
        success: function (response) {
            console.log(response);
            // process response
        },
        error: function (error) {
            console.log(error);
            // process error
        }
    });

    event.preventDefault();
});

Conclusion

All right folks! In this article, we learned how to upload single as well as multiple files via REST APIs written in Spring Boot. We also learned how to download files in Spring Boot. Finally, we wrote code to upload files by calling the APIs through javascript.

Thank you for reading! See you in the next post!

Writing your first Kotlin program
07
Mar
2021

Writing your first Kotlin program

The first program that we typically write in any programming language is the “Hello, World” program. Let’s write the “Hello, World” program in Kotlin and understand its internals.

The “Hello, World!” program in Kotlin

Open your favorite editor or an IDE and create a file named hello.kt with the following code –

// Kotlin Hello World Program
fun main(args: Array<String>) {
    println("Hello, World!")
}

You can compile and run the program using Kotlin’s compiler like so –

$ kotlinc hello.kt
$ kotlin HelloKt
Hello, World!

You can also run the program in an IDE like Eclipse or IntelliJ. Learn how to Setup and run Kotlin programs in your system.

Internals of the “Hello, World!” program

  • Line 1. The first line is a comment. Comments are ignored by the compiler. They are used for your own sake (and for others who read your code).Kotlin supports two different styles of comments similar to other languages like C, C++, and Java –
    1. Single Line Comment:// This is a Single line comment
    2. Multi-line Comment:/* This is an example of a multi-line comment. It can span over multiple lines. */
  • Line 2. The second line defines a function called main.fun main(args: Array<String>) { // ... } Functions are the building blocks of a Kotlin program. All functions in Kotlin start with the keyword fun followed by a name of the function (main in this case), a list of zero or more comma-separated parameters, an optional return type, and a body.The main() function takes one argument – an Array of strings, and returns Unit. The Unit type corresponds to void in Java. It is used to indicate that the function doesn’t return any meaningful value.The Unit type is optional. i.e. you don’t need to declare it explicitly in the function declaration –fun main(args: Array<String>): Unit { // `Unit` is optional } If you don’t specify a return type, Unit is assumed.The main() function is not just any ordinary function. It is the entry point of your program. It is the first thing that gets called when you run a Kotlin program.
  • Line 3. The third line is a statement. It prints a String “Hello, World!” to standard output.println("Hello, World!") // No Semicolons needed :) Note that we can directly use println() to print to standard output, unlike Java where we need to use System.out.println().Kotlin provides several wrappers over standard Java library functions, println is one of them.Also, Semicolons are optional in Kotlin, just like many other modern languages.

Conclusion

Congratulations! You just wrote your first program in Kotlin. You learned about the main method, single-line and multi-line comments, and the println library function.

In the next article, you’ll learn how to create variables in Kotlin and also look at various data types that are supported for creating variables.

Building Reactive Rest APIs with Spring WebFlux and Reactive MongoDB
05
Mar
2021

Building Reactive Rest APIs with Spring WebFlux and Reactive MongoDB

Spring 5 has embraced reactive programming paradigm by introducing a brand new reactive framework called Spring WebFlux.

Spring WebFlux is an asynchronous framework from the bottom up. It can run on Servlet Containers using the Servlet 3.1 non-blocking IO API as well as other async runtime environments such as netty or undertow.

It will be available for use alongside Spring MVC. Yes, Spring MVC is not going anywhere. It’s a popular web framework that developers have been using for a long time.

But You now have a choice between the new reactive framework and the traditional Spring MVC. You can choose to use any of them depending on your use case.

Spring WebFlux uses a library called Reactor for its reactive support. Reactor is an implementation of the Reactive Streams specification.

Reactor Provides two main types called Flux and Mono. Both of these types implement the Publisher interface provided by Reactive Streams. Flux is used to represent a stream of 0..N elements and Mono is used to represent a stream of 0..1 element.

Although Spring uses Reactor as a core dependency for most of its internal APIs, It also supports the use of RxJava at the application level.

Programming models supported by Spring WebFlux

Spring WebFlux supports two types of programming models :

  1. Traditional annotation-based model with @Controller@RequestMapping, and other annotations that you have been using in Spring MVC.
  2. A brand new Functional style model based on Java 8 lambdas for routing and handling requests.

In this article, We’ll be using the traditional annotation-based programming model. I will write about functional style model in a future article.

Let’s build a Reactive Restful Service in Spring Boot

In this article, we’ll build a Restful API for a mini twitter application. The application will only have a single domain model called Tweet. Every Tweet will have a text and a createdAt field.

We’ll use MongoDB as our data store along with the reactive mongodb driver. We’ll build REST APIs for creating, retrieving, updating and deleting a Tweet. All the REST APIs will be asynchronous and will return a Publisher.

We’ll also learn how to stream data from the database to the client.

Finally, we’ll write integration tests to test all the APIs using the new asynchronous WebTestClient provided by Spring 5.

Creating the Project

Let’s use Spring Initializr web app to generate our application. Follow the steps below to generate the Project –

  1. Head over to http://start.spring.io
  2. Enter artifact’s value as webflux-demo
  3. Add Reactive Web and Reactive MongoDB dependencies
  4. Click Generate to generate and download the Project.
Spring WebFlux Reactive MongoDB REST API Example

Once the project is downloaded, unzip it and import it into your favorite IDE. The project’s directory structure should look like this –

Spring WebFlux Reactive MongoDB REST API Application Directory Structure

Configuring MongoDB

You can configure MongoDB by simply adding the following property to the application.properties file –

spring.data.mongodb.uri=mongodb://localhost:27017/webflux_demo

Spring Boot will read this configuration on startup and automatically configure the data source.

Creating the Domain Model

Let’s create our domain model – Tweet. Create a new package called model inside com.example.webfluxdemo package and then create a file named Tweet.java with the following contents –

package com.example.webfluxdemo.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;

@Document(collection = "tweets")
public class Tweet {
    @Id
    private String id;

    @NotBlank
    @Size(max = 140)
    private String text;

    @NotNull
    private Date createdAt = new Date();

    public Tweet() {

    }

    public Tweet(String text) {
        this.id = id;
        this.text = text;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
}

Simple enough! The Tweet model contains a text and a createdAt field. The text field is annotated with @NotBlank and @Size annotations to ensure that it is not blank and have a maximum of 140 characters.

Creating the Repository

Next, we’re going to create the data access layer which will be used to access the MongoDB database. Create a new package called repository inside com.example.webfluxdemo and then create a new file called TweetRepository.java with the following contents –

package com.example.webfluxdemo.repository;

import com.example.webfluxdemo.model.Tweet;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TweetRepository extends ReactiveMongoRepository<Tweet, String> {

}

The TweetRepository interface extends from ReactiveMongoRepository which exposes various CRUD methods on the Document.

Spring Boot automatically plugs in an implementation of this interface called SimpleReactiveMongoRepository at runtime.

So you get all the CRUD methods on the Document readily available to you without needing to write any code. Following are some of the methods available from SimpleReactiveMongoRepository –

reactor.core.publisher.Flux<T>  findAll(); 

reactor.core.publisher.Mono<T>  findById(ID id); 

<S extends T> reactor.core.publisher.Mono<S>  save(S entity); 

reactor.core.publisher.Mono<Void>   delete(T entity);

Notice that all the methods are asynchronous and return a publisher in the form of a Flux or a Mono type.

Creating the Controller Endpoints

Finally, Let’s write the APIs that will be exposed to the clients. Create a new package called controller inside com.example.webfluxdemo and then create a new file called TweetController.java with the following contents –

package com.example.webfluxdemo.controller;

import com.example.webfluxdemo.model.Tweet;
import com.example.webfluxdemo.repository.TweetRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.Valid;

@RestController
public class TweetController {

    @Autowired
    private TweetRepository tweetRepository;

    @GetMapping("/tweets")
    public Flux<Tweet> getAllTweets() {
        return tweetRepository.findAll();
    }

    @PostMapping("/tweets")
    public Mono<Tweet> createTweets(@Valid @RequestBody Tweet tweet) {
        return tweetRepository.save(tweet);
    }

    @GetMapping("/tweets/{id}")
    public Mono<ResponseEntity<Tweet>> getTweetById(@PathVariable(value = "id") String tweetId) {
        return tweetRepository.findById(tweetId)
                .map(savedTweet -> ResponseEntity.ok(savedTweet))
                .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @PutMapping("/tweets/{id}")
    public Mono<ResponseEntity<Tweet>> updateTweet(@PathVariable(value = "id") String tweetId,
                                                   @Valid @RequestBody Tweet tweet) {
        return tweetRepository.findById(tweetId)
                .flatMap(existingTweet -> {
                    existingTweet.setText(tweet.getText());
                    return tweetRepository.save(existingTweet);
                })
                .map(updatedTweet -> new ResponseEntity<>(updatedTweet, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @DeleteMapping("/tweets/{id}")
    public Mono<ResponseEntity<Void>> deleteTweet(@PathVariable(value = "id") String tweetId) {

        return tweetRepository.findById(tweetId)
                .flatMap(existingTweet ->
                        tweetRepository.delete(existingTweet)
                            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))
                )
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    // Tweets are Sent to the client as Server Sent Events
    @GetMapping(value = "/stream/tweets", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Tweet> streamAllTweets() {
        return tweetRepository.findAll();
    }
}

All the controller endpoints return a Publisher in the form of a Flux or a Mono. The last endpoint is very interesting where we set the content-type to text/event-stream. It sends the tweets in the form of Server Sent Events to a browser like this –

data: {"id":"59ba5389d2b2a85ed4ebdafa","text":"tweet1","createdAt":1505383305602}
data: {"id":"59ba5587d2b2a85f93b8ece7","text":"tweet2","createdAt":1505383814847}

Now that we’re talking about event-stream, You might ask that doesn’t the following endpoint also return a Stream?

@GetMapping("/tweets")
public Flux<Tweet> getAllTweets() {
    return tweetRepository.findAll();
}

And the answer is Yes. Flux<Tweet> represents a stream of tweets. But, by default, it will produce a JSON array because If a stream of individual JSON objects is sent to the browser then It will not be a valid JSON document as a whole. A browser client has no way to consume a stream other than using Server-Sent-Events or WebSocket.

However, Non-browser clients can request a stream of JSON by setting the Accept header to application/stream+json, and the response will be a stream of JSON similar to Server-Sent-Events but without extra formatting :

{"id":"59ba5389d2b2a85ed4ebdafa","text":"tweet1","createdAt":1505383305602}
{"id":"59ba5587d2b2a85f93b8ece7","text":"tweet2","createdAt":1505383814847}

Integration Test with WebTestClient

Spring 5 also provides an asynchronous and reactive http client called WebClient for working with asynchronous and streaming APIs. It is a reactive alternative to RestTemplate.

Moreover, You also get a WebTestClient for writing integration tests. The test client can be either run on a live server or used with mock request and response.

We’ll use WebTestClient to write integration tests for our REST APIs. Open WebfluxDemoApplicationTests.java file and add the following tests to it –

package com.example.webfluxdemo;

import com.example.webfluxdemo.model.Tweet;
import com.example.webfluxdemo.repository.TweetRepository;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;

import java.util.Collections;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebfluxDemoApplicationTests {

	@Autowired
	private WebTestClient webTestClient;

	@Autowired
    TweetRepository tweetRepository;

	@Test
	public void testCreateTweet() {
		Tweet tweet = new Tweet("This is a Test Tweet");

		webTestClient.post().uri("/tweets")
				.contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .body(Mono.just(tweet), Tweet.class)
				.exchange()
				.expectStatus().isOk()
				.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
				.expectBody()
                .jsonPath("$.id").isNotEmpty()
                .jsonPath("$.text").isEqualTo("This is a Test Tweet");
	}

	@Test
    public void testGetAllTweets() {
	    webTestClient.get().uri("/tweets")
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .exchange()
                .expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                .expectBodyList(Tweet.class);
    }

    @Test
    public void testGetSingleTweet() {
        Tweet tweet = tweetRepository.save(new Tweet("Hello, World!")).block();

        webTestClient.get()
                .uri("/tweets/{id}", Collections.singletonMap("id", tweet.getId()))
                .exchange()
                .expectStatus().isOk()
                .expectBody()
                .consumeWith(response ->
                        Assertions.assertThat(response.getResponseBody()).isNotNull());
    }

    @Test
    public void testUpdateTweet() {
        Tweet tweet = tweetRepository.save(new Tweet("Initial Tweet")).block();

        Tweet newTweetData = new Tweet("Updated Tweet");

        webTestClient.put()
                .uri("/tweets/{id}", Collections.singletonMap("id", tweet.getId()))
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .body(Mono.just(newTweetData), Tweet.class)
                .exchange()
                .expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                .expectBody()
                .jsonPath("$.text").isEqualTo("Updated Tweet");
    }

    @Test
    public void testDeleteTweet() {
	    Tweet tweet = tweetRepository.save(new Tweet("To be deleted")).block();

	    webTestClient.delete()
                .uri("/tweets/{id}", Collections.singletonMap("id",  tweet.getId()))
                .exchange()
                .expectStatus().isOk();
    }
}

In the above example, I have written tests for all the CRUD APIs. You can run the tests by going to the root directory of the project and typing mvn test.

Conclusion

In this article, we learned the basics of reactive programming with Spring and built a simple Restful service with the reactive support provided by Spring WebFlux framework. We also tested all the Rest APIs using WebTestClient.

References

I strongly recommend the following awesome YouTube videos for learning more about reactive programming with Spring and Reactor –

Thanks for reading folks! Let me know what do you think about the new Spring WebFlux framework in the comment section below.

Spring Boot JSP View Resolver Example
30
Mar
2021

Spring Boot JSP View Resolver Example

Learn to create and configure spring boot jsp view resolver which uses JSP template files to render view layer. This example uses embedded Tomcat server to run the application.

Maven dependencies – pom.xml

This application uses given below dependencies.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fusebes</groupId><artifactId>spring-boot-demo</artifactId><packaging>war</packaging><version>0.0.1-SNAPSHOT</version><name>spring-boot-demo Maven Webapp</name><url>http://maven.apache.org</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><!-- Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Tomcat Embed --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><!-- JSTL --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><!-- To compile JSP files --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency></dependencies></project>

Spring Boot Application Initializer

The first step in producing a deployable war file is to provide a SpringBootServletInitializer subclass and override its configure() method. This makes use of Spring Framework’s Servlet 3.0 support and allows you to configure your application when it’s launched by the servlet container.

package com.fusebes.app.controller; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.boot.web.support.SpringBootServletInitializer; @SpringBootApplicationpublic class SpringBootWebApplication extends SpringBootServletInitializer { @Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBootWebApplication.class);} public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}}

Spring Controller

Controller classes can have methods mapped to specific URLs in the application. In given application, it has two views i.e. “/” and “/next”.

package com.fusebes.app.controller; import java.util.Map; import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping; @Controllerpublic class IndexController { @RequestMapping("/")public String home(Map<String, Object> model) {model.put("message", "Fusebes Reader !!");return "index";} @RequestMapping("/next")public String next(Map<String, Object> model) {model.put("message", "You are in new page !!");return "next";} }

Spring Boot JSP ViewResolver Configuration

To resolve JSP files location, you can have two approaches.

1) Add entries in application.properties

spring.mvc.view.prefix=/WEB-INF/view/spring.mvc.view.suffix=.jsp //For detailed logging during development logging.level.org.springframework=TRACElogging.level.com=TRACE

2) Configure InternalResourceViewResolver to serve JSP pages

package com.fusebes.app.controller; import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.servlet.view.InternalResourceViewResolver;import org.springframework.web.servlet.view.JstlView; @Configuration@EnableWebMvc@ComponentScanpublic class MvcConfiguration extends WebMvcConfigurerAdapter{@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/view/");resolver.setSuffix(".jsp");resolver.setViewClass(JstlView.class);registry.viewResolver(resolver);}}

JSP Files

Two used JSP files in this spring boot jsp example – are below.

index.jsp

<!DOCTYPE html><%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%><html lang="en"><body><div><div><h1>Spring Boot JSP Example</h1><h2>Hello ${message}</h2> Click on this <strong><a href="next">link</a></strong> to visit another page.</div></div></body></html>

next.jsp

<!DOCTYPE html><%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%><html lang="en"><body><div><div><h1>Another page</h1><h2>Hello ${message}</h2> Click on this <strong><a href="/">link</a></strong> to visit previous page.</div></div></body></html>

Demo

After whole code is written and placed inside folders, run the application by executing main() method in SpringBootWebApplication class.

Now hit the URL: http://localhost:8080/

And Click next link