Best practices for building containers

This page lists online resources covering key concepts about how to build containers which are more efficient and secured

Online Resources for Docker best practices

Pagination and Sorting using Spring Data JPA

Documenting API is very important so that users of the API can get a sense of how to call the API and know about different parameters, data types supported, etc. This article deeps dive into exposing REST API that supports Open API Documentation.

Introduction

API users need to understand how to interact with the API. OpenAPI Specification (OAS) defines a standard interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the API. Swagger implements this interface and in this article, we will walk through changes required to be done to a Spring Boot REST application.

Spring Boot Rest Application

We will use an existing spring boot rest application and will add support for the swagger documentation. This application has few Resources already exposed as RESTFul API,  like
BlogControllerV0,
BlogControllerV1,
BlogControllerV2 etc.

pom.xml changes
Just include the springdoc-openapi-ui dependency and do mvn install
pom.xml changes
<!--  swagger ui -->
<dependency>
	<groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-ui</artifactId>
	<version>1.5.10</version>
</dependency>

Accessing the Swagger documentations

Swagger documentation can be accessed by following URL
http://localhost:8080/swagger-ui/index.html
It will show a page like bellow





If we want to access the JSON data containing the swagger documentation by visiting following URL
http://localhost:8080/v3/api-docs
{
   "openapi":"3.0.1",
   "info":{
      "title":"OpenAPI definition",
      "version":"v0"
   },
   "servers":[
      {
         "url":"http://localhost:8080",
         "description":"Generated server url"
      }
   ],
   "paths":{
      "/blogapi/v2/blogs":{
         "get":{
            "tags":[
               "blog-controller-v-2"
            ],
            "operationId":"getBlogStories",
            "responses":{
               "200":{
                  "description":"OK",
                  "content":{
                     "application/json":{
                        "schema":{
                           "type":"array",
                           "items":{
                              "$ref":"#/components/schemas/BlogStory"
                           }
                        }
                     }
                  }
               }
            }
         },
         "post":{
            "tags":[
               "blog-controller-v-2"
            ],
            "operationId":"addBlogStory",
            "requestBody":{
               "content":{
                  "application/json":{
                     "schema":{
                        "$ref":"#/components/schemas/BlogStory"
                     }
                  }
               },
               "required":true
            },
            "responses":{
               "200":{
                  "description":"OK",
                  "content":{
                     "application/json":{
                        "schema":{
                           "$ref":"#/components/schemas/BlogStory"
                        }
                     }
                  }
               }
            }
         }
      },
      "/blogapi/v1/categories":{
         "get":{
            "tags":[
               "category-controller"
            ],
            "operationId":"getBlogCats",
            "responses":{
               "200":{
                  "description":"OK",
                  "content":{
                     "application/json":{
                        "schema":{
                           "type":"array",
                           "items":{
                              "$ref":"#/components/schemas/BlogCategory"
                           }
                        }
                     }
                  }
               }
            }
         },
         "post":{
            "tags":[
               "category-controller"
            ],
            "operationId":"addCats",
            "requestBody":{
               "content":{
                  "application/json":{
                     "schema":{
                        "$ref":"#/components/schemas/BlogCategory"
                     }
                  }
               },
               "required":true
            },
            "responses":{
               "200":{
                  "description":"OK",
                  "content":{
                     "application/json":{
                        "schema":{
                           "$ref":"#/components/schemas/BlogCategory"
                        }
                     }
                  }
               }
            }
         }
      },
      "/blogapi/v2/blogs/{id}":{
         "get":{
            "tags":[
               "blog-controller-v-2"
            ],
            "operationId":"getBlogStory",
            "parameters":[
               {
                  "name":"id",
                  "in":"path",
                  "required":true,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "responses":{
               "200":{
                  "description":"OK",
                  "content":{
                     "application/json":{
                        "schema":{
                           "$ref":"#/components/schemas/BlogStory"
                        }
                     }
                  }
               }
            }
         }
      }
   },
   "components":{
      "schemas":{
         "BlogStory":{
            "type":"object",
            "properties":{
               "id":{
                  "type":"string"
               },
               "name":{
                  "type":"string"
               },
               "summary":{
                  "type":"string"
               },
               "description":{
                  "type":"string"
               },
               "category":{
                  "type":"string"
               }
            }
         },
         "BlogCategory":{
            "type":"object",
            "properties":{
               "id":{
                  "type":"string"
               },
               "name":{
                  "type":"string"
               }
            }
         }
      }
   }
}

Summary

In this article, we saw how to quickly add support for Swagger documentation in the Spring boot APP. With very few changes we can get working and interactive swagger API documentation. The Swagger implementation can also be used to customize the report.

References

Pagination and Sorting using Spring Data JPA

This article deeps dive into exposing REST API that supports pagination using Spring DATA JPA.

Introduction

Pagination is a way to get a subset(page) of data on a fixed page and be able to retrieve the pages randomly or sequentially. Most important parameters are,

Total number of records
Number of records on a page (page size)
Current Page number (page order number) Based on the above informations we can build the algorithm to fetch the respective data. In the SQL world given the current page and page size, we can retrieve the information using limit and offset like follows, Select * from [TABLE NAME] limit pageSize, offset pageNumber*pageSize Spring Data encapsulates all these algorithms/queries and handles all edge cases to return us paginated data.
In the next section we will walk through a sample REST API Controller which uses Spring Data JPA to return paginated response.

Implementations

Dish.java
Model class representing Dish object which holds information of about dishes.
@Entity
@Table (name = "dish_table")
public class Dish {

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name = "id")
	private Long id;
	
	@NotNull
	@Size(min=2, message="Name should have atleast 5 characters")
	@Column(name = "name")
	private String name;
	
	@Column(name = "description")
	private String description;
	
	@Column(name = "lowprice")
	private Double lowPrice;
	
	@Column(name = "highprice")
	private Double highPrice;
	
	public Dish () {}
	//Getter and Setters
}
DishRepository
Dish Repository extends JpaRepository which extends interface PagingAndSortingRepository that provides methods like Page findAll(Pageable pageable);. On top of that, we have specified our own method which returns a paginated response and takes a name as the first parameter and Pageable as the second parameter.
@Repository
public interface DishRepository extends JpaRepository {
	public Page findByName(String name, Pageable pageable);
}
DishControllerPaginatedV2
Our Rest controller uses repository method findAll(pageRequest). We need to build the pageRequest object and pass it to the repository method. We are getting the pageNo as request parameter.
@RestController
@RequestMapping("api/v2")
public class DishControllerPaginatedV2 {

	private static final int  pageSize = 2;

	@Autowired
	DishRepository repo;
	
	@GetMapping(value="/dishes",produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity> getDish3(@RequestParam (defaultValue = "0") int pageNo) throws Exception {
		Sort sort = Sort.by("name");
		Pageable pageReq =  PageRequest.of(pageNo, pageSize, sort);
		Page result =  repo.findAll(pageReq);
		return ResponseEntity.ok(result);
	}
}
Invoke REST API
invoking the API with the following curl will provide us paginated response as shown in the next block.
curl --request GET \
  --url 'http://localhost:8080/api/v1/dishes3?pageNo=0' \
  --header 'cache-control: no-cache'
REST API RESPONSE
{
    "content": [
        {
            "id": 12,
            "name": "Anchovies",
            "description": "Anchovies",
            "lowPrice": 1987,
            "highPrice": 0
        },
        {
            "id": 14,
            "name": "Celery",
            "description": "Celery",
            "lowPrice": 2928,
            "highPrice": 0
        }
    ],
    "pageable": {
        "sort": {
            "sorted": true,
            "unsorted": false,
            "empty": false
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 2,
        "paged": true,
        "unpaged": false
    },
    "last": false,
    "totalPages": 7,
    "totalElements": 14,
    "size": 2,
    "number": 0,
    "sort": {
        "sorted": true,
        "unsorted": false,
        "empty": false
    },
    "numberOfElements": 2,
    "first": true,
    "empty": false
}

Summary

In this article, we saw how to quickly build paginated REST API using Spring Data JPA. We need to create the PageRequest object and call the repository method findALL(pageRequest). Spring Data will take care of the offset calculation and will return one page of data along with some important information. Spring Data also supports filtering and sorting along with pagination.

References

Restful API using Jersey 3 Jakarta EE 9

This article walks through a sample REST application built using Jersey3 and then we will see how to test the rest endpoints. Last not but least how to deploy it on Server.

Project Structure



Technologies Used
  • Java 15
  • Mvn 3.5.0
  • Jersey 3.0.2
  • JUnit 5.3.1

Java Classes

JakartaRestfulApp.java
Main Jersey Application Class, registers MenuResource class.
public class JakartaRestfulApp extends Application {
	private final Set> classes;

	public JakartaRestfulApp() {
		HashSet> c = new HashSet>();
		c.add(MenuResource.class);
		classes = Collections.unmodifiableSet(c);
	}

	@Override
	public Set> getClasses() {
		return classes;
	}
}
MenuResource.java
Our Resourse class which exposes Restful endpoints for the Menu object. It uses MenuService to store and retrieve Menu items.
@Path("/rest")
public class MenuResource {
	MenuService service = MenuService.getInstance();

	@GET
	@Path("/menus")
	@Produces("application/json")
	public List getMenus() {
		return service.getAll();
	}

	@GET
	@Path("/menus/{menu_ID}")
	@Produces("application/json")
	public Response getMenu(@PathParam("menu_ID") Long menuId) {
		try {
			return Response.ok(service.get(menuId)).build();
		} catch (Exception e) {
			return Response.serverError().status(HttpStatus.BAD_REQUEST_400.getStatusCode(), e.getMessage()).build();
		}
	}

	@POST
	@Path("/menus")
	@Produces("application/json")
	public Response add(Menu c) {
		service.add(c);
		return Response.ok(c).status(HttpStatus.CREATED_201.getStatusCode(), "Created").build();
	}

	@PUT
	@Path("/menus/{menu_ID}")
	@Produces("application/json")
	public Response update(@PathParam("menu_ID") Long menuId, Menu c) {
		try {
			return Response.ok(service.update(menuId,c.getName())).build();
		} catch (Exception e) {
			return Response.serverError().status(HttpStatus.BAD_REQUEST_400.getStatusCode(), e.getMessage()).build();
		}
	}

	@PATCH
	@Path("/menus/{menu_ID}")
	@Produces("application/json")
	public Response update2(@PathParam("menu_ID") Long menuId, @QueryParam("name") String name) {
		try {
			return Response.ok(service.update(menuId,name)).build();
		} catch (Exception e) {
			return Response.serverError().status(HttpStatus.BAD_REQUEST_400.getStatusCode(), e.getMessage()).build();
		}
	}

	@DELETE
	@Path("/menus/{menu_ID}")
	@Produces("application/json")
	public Response delete(@PathParam("menu_ID") Long menuId) {
		try {
			service.delete(menuId);
			return Response.ok().status(HttpStatus.OK_200.getStatusCode()).build();
		} catch (Exception e) {
			return Response.serverError().status(HttpStatus.BAD_REQUEST_400.getStatusCode(), e.getMessage()).build();
		}
	}

	@OPTIONS
	@Path("/menus")
	@Produces("text/plain")
	public String touch() {
		return "options";
	}

	@HEAD
	@Path("/menus")
	@Produces("text/plain")
	public String head() {
		return "head";
	}
}
MenuService.java
This class is used to store and retrieve Menu objects. It uses a HashSet to store objects created.
public class MenuService {

	private static MenuService instance = new MenuService();
	private static HashSet menus;

	private MenuService() {
		menus = new HashSet<>();
		menus.add(new Menu(1L, "Menu One"));
	}

	public static MenuService getInstance() {
		return instance;
	}

	public void add(Menu menu) {
		menus.add(menu);
	}

	public List getAll() {
		return new ArrayList(menus);
	}

	public Menu get(Long id) throws Exception {
		Iterator it = menus.iterator();
		while (it.hasNext()) {
			Menu curr = (Menu) it.next();
			if (curr.getId() == id)
				return curr;
		}
		throw new Exception("Object not found");
	}

	public boolean delete(Long id) throws Exception {
		Iterator it = menus.iterator();
		while (it.hasNext()) {
			Menu curr = (Menu) it.next();
			if (curr.getId() == id) {
				it.remove();
				return true;
			}
		}
		throw new Exception("Object not found");
	}
	
	public Menu update(Long id, String update) throws Exception {
		Iterator it = menus.iterator();
		while (it.hasNext()) {
			Menu curr = (Menu) it.next();
			if (curr.getId() == id) {
				curr.setName(update);
				return curr;
			}
				
		}
		throw new Exception("Object not found");
	}
}
Menu.java
Menu object representing a restaurant menu containing some basic information like id and name.
public class Menu {

	private Long id;

	private String name;

	public Menu() {
	}

	public Menu(Long id, String name) {
		this.id = id;
		this.name = name;
	}

	public Long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
JDKSEServer.java
Jersey supports a number of deployment options. For this example, we will use a lightweight JDK server that comes with JDK.
public class JDKSEServer {
	private static final Logger LOGGER = Logger.getLogger(JDKSEServer.class.getName());
	/**
	 * Starts the JDK HTTP server serving the JAX-RS application.
	 */
	static HttpServer startServer() throws IOException {
		ResourceConfig config = new ResourceConfig(MenuResource.class);
		HttpServer server = JdkHttpServerFactory.createHttpServer(getBaseURI(), config);
		return server;
	}

	public static void main(String[] args) {
		try {
			final HttpServer httpServer = startServer();
			Runtime.getRuntime().addShutdownHook(new Thread(() -> {
				try {
					LOGGER.info("Shutting down the application...");
					httpServer.stop(0);
				} catch (Exception e) {
					LOGGER.log(Level.SEVERE, null, e);
				}
			}));

			LOGGER.info("Application started.%nStop the application using CTRL+C");
			Thread.currentThread().join();
		} catch (Exception ex) {
			LOGGER.log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * Gets base {@link URI}.
	 */
	public static URI getBaseURI() {
		return UriBuilder.fromUri("http://localhost/").port(8080).build();
	}
}

Unit Testing

TestMenuResource.java
We will use JerseyTest to test some of the methods that MenuResource supports.
public class TestMenuResource extends JerseyTest {

	@BeforeEach
	void init() throws Exception {
		super.setUp();
	}

	@Override
	protected Application configure() {
                 //to start a new container in s different port
		forceSet(TestProperties.CONTAINER_PORT, "0");
		return new ResourceConfig(MenuResource.class);
	}

	@Test
	public void get_one() throws Exception {
		Response response = target("/rest/menus/1").request().get();
		System.out.println("sd " + response.getStatus());
		assertEquals(response.getStatus(), 200);
		assertEquals(response.readEntity(Menu.class).getName(), "Menu One");
	}

	protected TestContainerFactory getTestContainerFactory() {
		return new JdkHttpServerTestContainerFactory();
	}

}

Executing Code

mvn clean compile exec:java
Sep 24, 2021 4:57:57 PM org.glassfish.jersey.server.wadl.WadlFeature configure WARNING: JAX-B API not found . WADL feature is disabled. Sep 24, 2021 4:57:57 PM jersey.server.JDKSEServer main INFO: Application started.%nStop the application using CTRL+C

References

Summary
In this article, we saw how to build and test Jakarta Restful API with Jersey 3.

Introduction

In 2000, Roy Fielding proposed Representational State Transfer (REST) as an architectural approach to designing web services. REST is an architectural style for building distributed systems based on hypermedia. REST is independent of any underlying protocol and is not necessarily tied to HTTP.

What is REST

REST stands for representational state transfer. It is a set of constraints that set out how an API (application programming interface) should work.

REST API Design Principles

  • Uniform Interface: REST APIs are designed around resources, which are any kind of object, data, or service that can be accessed by the client. A resource has an identifier, which is a URI that uniquely identifies that resource.
    Use Noun and not verb to represent a resource
    In general, it helps to use plural nouns

  • Client-Server: Client and Server are independent of each others and the only way the client interacts is through the URI of the resources.
    Client and server can evolve independently.
    Client and server can be implemented in different tech stack.

  • Stateless : REST APIs use a stateless request model. HTTP requests should be independent and may occur in any order. The only place where information is stored is in the resources themselves, and each request should be an atomic operation.
    Being stateless means REST API can scale easily.

  • Cacheable: response to a request be implicitly or explicitly labeled as cacheable or non-cacheable.

  • Layered System: Client and Server should not be tightly coupled and if required and added any intermediate layer the API still should work.

Navigating Treemap in Java

Treemap in java is A Red-Black tree-based NavigableMap implementation. NavigableMap interface provides some interesting methods to navigate the map. In this article, we will quickly go through those methods.

NavigableMap

NavigableMap provides a method to navigate the map in interesting ways. For instance, rather than getting value stored for a key, we can retrieve the value stored against the smallest key or get the next immediate bigger key for the given key. Following are some of the interesting methods that we will look into. We can see actually these methods are helping us to access the TreeMap on both ends like (get the lowest key, get the highest key), etc.
Important methods
  • lowerkey (key): Returns the greatest key strictly less than the given key, or null if there is no such key
  • lowerEntry (key): Follows the above and returns the key-value mapping for the key.
  • floorKey (key): Returns the greatest key less than the given key or equal to the given key, or null if there is no such key
  • floorEntry (key): Follows the above and returns the key-value mapping for the key.
  • higherKey (key): Returns the lowest key strictly greater than the given key, or null if there is no such key
  • higherEntry (key): Follows the above and returns the key-value mapping for the key.
  • ceilingKey (key): Returns the least key greater than or equal to the given key, or null if there is no such key
  • ceilingEntry (key): Follows the above and returns the key-value mapping for the key.
  • firstEntry (): Returns a key-value mapping associated with the least key in this map
  • lastEntry (): Returns a key-value mapping associated with the highest key in this map
  • pollFirstEntry (): Remove and returns a key-value mapping associated with the least key in this map
  • pollLastEntry (): Remove and returns a key-value mapping associated with the highest key in this map

Java Code to see above methods

Create
Create and Populate Map
TreeMap<Integer, String> map = new TreeMap<> ();
map.put(15, "banana");
map.put(16, "apple");
lowerKey and lowerEntry Example
Here when we try with lowerKey(16) it looks for available keys and returns the greatest key lower then 16, in this case it is 15.
key = map.lowerKey(16);
test = map.lowerEntry(16);
System.out.println(key);  //15
System.out.println(test); //banana
floorKey and floorKeyEntry Example
Here when we try with floorKey(16) it looks for available keys and returns the greatest key lower than (or equal to 16), in this case, it is 16.
key = map.floorKey(16);
test = map.floorEntry(16);
System.out.println(key);  //16
System.out.println(test); //apple
higherKey and higherEntry
higher key will return the least key strictly greater than the given key and following the same logic higherEntry will return the key-value pair. Note that in this case, 14 key does not exist in the map
key = map.higherKey(14);
test = map.higherEntry(14);
System.out.println(key);  //15
System.out.println(test); //banana
ceilingKey and ceilingEntry
ceilingKey logic is very similar to higherkey, except the fact that it checks for the least key equal to or greater the given key.
key = map.ceilingKey(16);
test = map.ceilingEntry(16);
System.out.println(key); 			  //16
System.out.println(test.getValue()); //apple
Important Points
  • Treemap is Red-Black tree-based implementation.
  • Treemap provides guaranteed log(n) time cost for containsKey(), get(), put(), and remove() .

References

Details about red black tree

Dijkstra's algorithm

Dijkstra's algorithm shortest path algorithm is one of the most commonly used algorithms for finding short distances between two nodes. This article list down some of the important points for this algorithm and list down some of the useful contents available online.

Important Points

It does not work if the edges have negative weights. It is used to find shortest path between source and destination in a graph. Real life uses includes Map, Network communication.

Complexity

The complexity of this algorithm depends on the data structure used. For a graph G with V vertices and E edges, For Adjecency Matrix : Complexity is O(V**2) For Adjecency List and using Priority Queue with O(n) for sorting : O(E + VlogV)

References


An array is monotonic if it is either monotone increasing or monotone decreasing. More formally if all the elements are either in increasing order or decreasing order. That is for an given array nums[], it is monotone increasing if all i <= j, nums[i] <= nums[j]. it is monotone decreasing if for all i <= j, nums[i] >= nums[j]. In in article we will see how to efficiently decide if a given array is monotonic or not.

Examples

Examples of Monotonic arrays
Increasing monotonic array:
[1, 2, 20, 30]
[1, 2, 20, 20, 30]
decreasing monotonic array:
[66, 50, 40, 4]
[66, 50, 40, 40]

Algorithm

Iterate over the array and keep track of the first nonequal comparison to a variable signal. And once the signal is set check if holds true for the next set of array items.

Implementation

Implementation of the monotonic array is not very tough. Here we will see how to implement it in a single pass (single iteration of the input array) in Java.
MonotonicArray
Following Java, the class implement is a monotonic method that checks if an array is monotonic in a single pass.
public class MonotonicArray {
	public boolean isMonotonic(int[] nums) {
		int signal = -1; // -1 = not set, 0 = increasing, 1 = decreasing
		// iterate over the array till the arry.length-1 from 0
		for (int i = 0; i < nums.length - 1; i++) {
			// if signal is not initialized and we see either increasing or decreasing array
			// initialize it accordingly
			if (signal == -1) {
				if (nums[i] < nums[i + 1]) {
					signal = 0; // increasing
				} else if (nums[i] > nums[i + 1]) {
					signal = 1; // decreasing
				}
			} else {
				// once the signal is already initialized
				// then check if for other elements it holds true or not
				if (signal == 0 && nums[i] > nums[i + 1]) {
					return false;
				}
				if (signal == 1 && nums[i] < nums[i + 1]) {
					return false;
				}
			}
		}
		return true;
	}
}
Code Complexity
Runtime complexity: O(n) where n is the number of elements in the array. As we are iterating the array once. Space complexity: O(1) as we are not using extra storage

References


Java TreeMap, TreeSet, and PriorityQueue have something in common, they all maintain some kind of ordering.
HashSet is implemented using a HashMap, TreeSet is implemented using a TreeMap. The TreeMap itself is implemented using a red-black tree which is a self-balancing binary search tree. On the other hand, a HashMap has an average time complexity of O(1) for put(), contains() and remove() operations. The worst-case time complexity for those operations is O(log n) since Java 8, and O(n) before that. Big O complexities are as follows.

PriorityQueue

log(n) operations: offer(), poll(), remove(), add()
O(1) opearations: peek(), size()
O(n) operations: remove(object), contains(object)

HashMap

log(n) operations: get(), put(), contains(), remove()
O(n) operations: clone(), equals(), hashCode(), toArray(), toString()
O(1) opearations: clear(), isEMpty(), size()

TreeMap

log(n) operations: get(), put(), containsKey() and remove()
O(n) operations: clone(), equals(), hashCode(), toArray(), toString(), containsValue()
O(1) opearations: clear(), isEMpty(), size()

TreeSet

log(n) operations: add(), contains(), remove()
O(1) opearations: clear(), first(), isEMpty(), size(), last(), pollFirst(), pollLast()
O(n) operations: clone(), equals(), hashCode(), toArray() and toString()

Java un-initializing Array

We can create and initialize array using different statements, but what will be the content of the arrays if we cont initialize the array after creating it?
Let's create arrays of different data types and then print the content of each array to see what they contain.
Create Different Arrays
Create different arrays of primitive data types and one Object type (Integer)
byte rollNums1[] = new byte[10];
short rollNums2[] = new short[10];
int rollNums3[] = new int[10];
long rollNums4[] = new long[10];
float rollNums5[] = new float[10];
double rollNums6[] = new double[10];
char rollNums7[] = new char[10];
boolean rollNums8[] = new boolean[10];
Integer rollNums9[] = new Integer[10];
Iterate the arrays and print the content.
    byte rollNums1[] = new byte[10];
    System.out.println("\nbyte array");
    for (byte i : rollNums1) {
      System.out.print(i + ", ");
    }
    short rollNums2[] = new short[10];
    System.out.println("\nshort array");
    for (short i : rollNums2) {
      System.out.print(i + ", ");
    }
    
    int rollNums3[] = new int[10];
    System.out.println("\nint array");
    for (int i : rollNums3) {
      System.out.print(i + ", ");
    }
    
    long rollNums4[] = new long[10];
    System.out.println("\nlong array");
    for (long i : rollNums4) {
      System.out.print(i + ", ");
    }
    
    float rollNums5[] = new float[10];
    System.out.println("\nfloat array");
    for (float i : rollNums5) {
      System.out.print(i + ", ");
    }
    
    double rollNums6[] = new double[10];
    System.out.println("\ndouble array");
    for (double i : rollNums6) {
      System.out.print(i + ", ");
    }
    
    
    char rollNums7[] = new char[10];
    System.out.println("\nchar array");
    for (char i : rollNums7) {
      System.out.print(i + ", ");
    }
    
    boolean rollNums8[] = new boolean[10];
    System.out.println("\nboolean array");
    for (boolean i : rollNums8) {
      System.out.print(i + ", ");
    }
    
    Integer rollNums9[] = new Integer[10];
    System.out.println("\nInteger array");
    for (Integer i : rollNums9) {
      System.out.print(i + ", ");
    }
Output
byte array 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
short array 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
int array 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
long array 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
float array 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
double array 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
char array , , , , , , , , , , 
boolean array false, false, false, false, false, false, false, false, false, false, 
Integer array null, null, null, null, null, null, null, null, null, null,

Conclusion
  • If the array is just created and not initialized with data then the content of the arrays depends on the data type.
  • For byte, short, int, long it is 0
  • For float and double it is 0.0
  • for char it is '' (empty character)
  • for boolean it is false
  • for Integer or any other object, it is null
  • The value of the array depends on the type of the array and a default value for the respective data types.

References

Array Initialize

An array is a collection of items stored at contiguous memory locations. The idea is to store multiple items of the same type together. Each item in the array can be accessed with its index very efficiently. In this post we examine different ways to create and initialize arrays in java
Creating array of specific size and populating using for loop
We create a new int array of size 10 and set values using for loop.
//initialize array of size 10 of type int
int rollNums[] = new int[10];
//iterate from 0 to the last index of the array and set values
for (int i = 0; i < rollNums.length; i++) {
      rollNums[i] = i + 1;
}
Assigning value while creating the array.
Here we create a new int array and pass the values in the curly braces.
int rollNums[] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Assigning value while creating the array without specifying array type.
Even shorter versions just assign values in the curly braces.
int rollNums[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Using Arrays.setAll (Lambda)
First, create an int array of size 10, then using setAll to set the value of the corresponding indices. setAll takes IntUranaryOperator as the second argument. IntUranaryOperator is a functional interface and we can use lambda expressions to implement it.
int rollNums[] = new int[10];
Arrays.setAll(rollNums, p -> p + 1);
Using Arrays.setAll (Anonymous Class)
Same as above but rather than lambda expression implementing it as Anonymous class and implementing applyAsInt method.
int rollNums[] = new int[10];
Arrays.setAll(rollNums, new IntUnaryOperator () {
      @Override
      public int applyAsInt(int operand) {
        return operand + 1;
 }} );
Arrays.copyOf
We can also copy contents of an existing array to a different array of the same type.
int rollNums2[] = Arrays.copyOf(rollNums, rollNums.length);
Summary
  • We can create an array in java using a new operator and specify size while creating.
  • We can also specify the content of the array and java will create an array of sufficient size.
  • When we create an array and does not initialize then the content of the array is null if the type of the array is of type object
  • and 0 if the type is int.

Default Method in Java

The default method in Interfaces was introduced in Java 8. It allows the interface to implement a method in the interface which is inherited by implementing classes.

What are default methods?

Before Java 8 methods in the interface could have only public and abstract modifiers for methods and public, static and for fields public and static or blank (blank means public and static field).

Java 5

Following are two interfaces in Java 5, the first one is valid and the second one is not.
Valid Interface in Java 5
interface Java5Interface {
	public static int four = 4;
	int five = 5; // implicitly public static

	public abstract void welcome();
	public void sayHi();
	void bye();
}
Invalid Interface in Java 5
interface Java5Invalid {
	private int six = 6;            //illegal only public static and final is permitted
	private void cleanuup(); // illegal only public and abstract is permitted
}
As you can see for fields only public, static, and final modifiers are allowed. If nothing is mentioned then also all fields in Java 5 is public static and final implicitly. For methods, we can have only public and abstract as modifiers.

Java 8 and onwards

Starting Java 8 methods in the interface can have the following modifiers public, private, abstract, default, static, strictfp. Nothing changes for fields, fields can still have public, static, final modifiers. In the following example, we have a Greetings Interface with two default methods greet and openDoor respectively. This interface also has one static method lockdoor.
Interface Greetings in Java 8
interface Greetings {
	
	public default void greet() {
		openDoor();
		sayHi();
		sayBye();
		closeDoor();
	}
	
	default void openDoor() {
		//open the door
	}
	
	void sayHi();
	
	void sayBye();
	
	private void closeDoor() {
		lockDoor();
	}

	static void lockDoor() {
		//lock door implementation
	}
}
The benefit of having a default method is that now the interface can provide a default implementation of methods through the default modifier. For instance, the interface Greetings provided a default implementation for method greet(). Also the later we can add more default, private or static methods to the Interface without breaking binary compatibility meaning implementing classes don't need to do any modification to be able to compile and run successfully.
Importat Points
  • default methods are public.
  • default methods are inherited by implementation classes.
  • default methods can be overridden by implementation classes.
  • a default method can add more functionality to the Interface without breaking binary compatibility.
  • static methods are also allowed which are Interface level methods and cannot be overridden by subclasses.
  • Java 8 methods can have public, private, abstract, default, static, and strictfp.

References

Convert Java Set to List

In this article, we will go through 4 different ways to convert java Set to Java List object.
Java Set Object
mySet is the Set object which contains 4 Strings.
Set  mySet = new HashSet(Arrays.asList("Red", "Yellow", "Green", "Blue"));
Using Constructor
List  myList = new ArrayList(mySet);
Using addAll
Using the addAll method we can add all the items in the set to list-objects.
List  myList2 = new ArrayList();
myList2.addAll(mySet);
Using for each
By using for each to loop though all the items in the Set we can add them one by one to the List.
List  myList3 = new ArrayList();
mySet.forEach(a->myList3.add(a));
Using Java Stream
List  myList4 = mySet.stream().collect(Collectors.toList());
Full source code
package myjava.work.general;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class JavaListFromSet {

	public static void main(String[] args) {
		Set<String> mySet = new HashSet<String>(Arrays.asList("Red", "Yellow", "Green", "Blue"));

		// Using Constructor
		List<String> myList = new ArrayList<String>(mySet);
		myList.forEach(a -> System.out.println(a));

		// Using addAll
		List<String> myList2 = new ArrayList<String>();
		myList2.addAll(mySet);
		myList2.forEach(a -> System.out.println(a));

		// Using For Each
		List<String> myList3 = new ArrayList<String>();
		mySet.forEach(a -> myList3.add(a));
		myList3.forEach(a -> System.out.println(a));

		// Using Stream
		List<String> myList4 = mySet.stream().collect(Collectors.toList());
		myList4.forEach(a -> System.out.println(a));

	}
}


In this article, we will examine different ways to write Comparators in java to sort the multidimensional arrays. Comparator is a functional interface in java.
java.util.Arrays class contains various utility methods to manipulate arrays one of the important methods is Sort. This method takes two parameters the array that needs to be sorted and the optional Comparator. If we don't pass the Comparator then the array will be sorted based on the natural ordering of the elements.

Sorting Array

Our Array
Let's say we want to represent multiple points with x,y coordinates in an array. The following represents one such example.
{ { 20, 25 },{ 10, 15 }, { 10, 25 }, { 20, 15 }}
We want to sort the array based on x and y-axis values.

Comparators

Comparator Implementation as a Class
Here we are implementing a Comparator called MultiDimArrayComparator and then we can use this comparator to sort Array
class MultiDimArrayComparator implements Comparator {
	@Override
	public int compare(int[] m, int[] n) {
		return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
	}
}

Arrays.sort(arr, new MultiDimArrayComparator());
Comparator as an anonymous class
Here we are implementing Comparator as an anonymous class and providing a definition of compare method.
Arrays.sort(arr, new Comparator() {
	@Override
	public int compare(int[] m, int[] n) {
		return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
	}
});
Comparator as lambda expression (Java 8+)
Here we are implementing Comparator as a lambda function.
Arrays.sort(arr, (m, n) -> m[0] == n[0] ? m[1] - n[1] : m[0] - n[0]);

Full Example


public class ArraysSort {

	public static void main(String[] args) {
		int arr[][] = { { 20, 25 },{ 10, 15 }, { 10, 25 }, { 20, 15 }};

		int arr1[][] = arr;
		
		Arrays.sort(arr1, new MultiDimArrayComparator());
		System.out.println("Sorted Result");
		for (int[] x : arr1) {
			System.out.println(x[0] + " " + x[1]);
		}
		
		arr1 = arr;
		Arrays.sort(arr1, new Comparator<int[]>() {
			@Override
			public int compare(int[] m, int[] n) {
				return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
			}
		});
		System.out.println("Sorted Result");
		for (int[] x : arr1) {
			System.out.println(x[0] + " " + x[1]);
		}

		arr1 = arr;
		Arrays.sort(arr1, (m, n) -> m[0] == n[0] ? m[1] - n[1] : m[0] - n[0]);
		System.out.println("Sorted Result");
		for (int[] x : arr1) {
			System.out.println(x[0] + " " + x[1]);
		}
	}

}

class MultiDimArrayComparator implements Comparator<int[]> {
	@Override
	public int compare(int[] m, int[] n) {
		return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
	}
}

Running the code

Sorted Result 10 15 10 25 20 15 20 25 Sorted Result 10 15 10 25 20 15 20 25 Sorted Result 10 15 10 25 20 15 20 25

Conclusion

Here we implemented the same Comparator to sort two-dimensional arrays in three different styles.

Aws lambda handlers

While implementing AWS lambda functions in java we need to implement a Handler interface . The lambda environment will invoke the implementation of the Handler interface.
The Handler interface is a functional interface It has just one method that needs to be implemented. Broadly speaking AWS supports two different types of handlers. Following are the two interfaces that can be chosen to implement the handler.
The aws-lambda-java-core library defines two interfaces for handler methods.
com.amazonaws.services.lambda.runtime.RequestHandler
com.amazonaws.services.lambda.runtime.RequestStreamHandler

Choosing the right handler

Choosing the right Handler depends on the use cases. If we are working with simple Objects as input like String, Integer, Map, etc then RequestHandler is a good choice. If we want to work with more complicated input/output objects or we want to control the way the input and output get converted to String then RequestStreamHandler is the option.
RequestHandler
This interface is a generic interface. The handleRequest method takes two objects as input and also returns an object. The java runtime in the lambda environment deserializes and serializes input event and returned object from the method
public interface RequestHandler {
    /**
     * Handles a Lambda Function request
     * @param input The Lambda Function input
     * @param context The Lambda execution environment context object.
     * @return The Lambda Function output
     */
    public O handleRequest(I input, Context context);
}
RequestStreamHandler
This handler works with InputStream and OutputStream. It gives more control over how we want to perform the serialization/deserialization etc.
public interface RequestStreamHandler {
    /**
     * Handles a Lambda Function request
     * @param input The Lambda Function input stream
     * @param output The Lambda function output stream
     * @param context The Lambda execution environment context object.
     * @throws IOException
     */
    public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException;
}
Summary
  • RequestStreamHandler : If we need to customize the serialization and deserialization process then RequestStreamHandler is the choice.
  • RequestHandler: It is the most suitable handler in most cases.

References

How to download source for maven artifacts

Maven builds a project using its project object model (POM) and a set of plugins. Dependencies used by the project are mentioned in the pom.xml file. We can also get the dependencies artifact from maven along with source codes.

In the following section, we will cover two use cases
1) How to generate source code for third-party artifacts that my project is using
2) How to generate source code for my project
Download sources for third party artifacts
Executing the following command from the terminal will download the sources for all the artifacts for the project and will attach it to Eclipse IDE.
mvn eclipse:eclipse -DdownloadSources=true
Executing the following command from the terminal will download the sources for all the artifacts only, attaching the sources in the IDE with the binaries needed to be done seperately..
mvn dependency:sources -Dsilent=true
Generate source code for project
This command will generate the sources jar under the target folder for the project.
mvn source:jar install

Generating Random Number in Java

This article summarizes different ways to use the Random() class in java to generate bounded or unbounded random numbers. It also shows another important feature of the class that is using seed to generate same set of random numbers.
java.util.Random used used to generate bounded or unbounded random numbers. It supports specifying a seed which is used to set the internal state of the pseudorandom number generator. Random(): creates new random generator Random(long seed): creates new random generator using specified seed
Unbounded generate 5 random numbers
Following code prints 5 random numbers unbounded without any seed
public static void generateRadom() {
	System.out.println("\nPrinting 10 Random Numbers");
	Random generator = new Random();
	for (int i = 0; i < 5; i++) {
		System.out.print(generator.nextInt() + " ");
	}
}
Invocation 1
Printing 5 Random Numbers -1937915077 75383412 -901884443 1725835531 1371480362
Invocation 2
Printing 5 Random Numbers -1261854044 328673857 -1787159304 446964878 -283294822
Notice that in both the invocations the generated numbers are different. This is because we have not set any seed in the Random Class.
Random Bounded Number
Following method will generate 5 random numbers between 0 and 99
public static void generateRadomBounded() {
	System.out.println("\nPrinting 5 Random Numbers Between 0 and 99");
	Random generator = new Random();
	for (int i = 0; i < 5; i++) {
		System.out.print(generator.nextInt(100) + " ");
	}
}
Invocation 1
Printing 5 Random Numbers Between 0 and 99 25 95 13 60 67
Invocation 2
Printing 5 Random Numbers Between 0 and 99 17 10 21 96 15
Generate Random number bounded with a seed
Bellow function will generate bounded 5 random numbers but since we are setting a seed, if the seed is same on multiple invocation then each invocation will generate the same set of random numbers.
public static void generateRadomWithSeed(long seed) {
	System.out.println("\nPrinting 5 Random Numbers Between 0 and 99 with seed");
	Random generator = new Random(seed);
	for (int i = 0; i < 5; i++) {
		System.out.print(generator.nextInt(100) + " ");
	}
}
Invocation 1
Printing 5 Random Numbers Between 0 and 99 with seed 4 62 52 3 58 67
Invocation 2
Printing 5 Random Numbers Between 0 and 99 with seed 4 62 52 3 58 67
Summary
  • If we want to generate the same set of random numbers, we can set seed.
  • Test cases can use seed to make sure it gets same set of random numbers.
  • We can have bounded or unbounded random numbers.

Change Project Explorer tree view font size in Eclipse

This article shows how to change the Project Explorer text size and style.
Starting with Eclipse 4.17, Eclipse now supports additional options to change the font and style of the IDE.  Bellow sections shows few examples.

Project Explorer
Change the font of the Project Explorer
Window > Preferences > General > Appearance > Colors and Fonts > View and Editor Folders > Tree and Table font for views

Setting the font size

Result of the Project Explorer




Java Editor
Change the font of the Java Editor
Window Menu -> Preferences -> General > Appearance > Color and Fonts > Java > Java Editor Text Font > Edit & Apply

Editor Font Size Setting


Editor Content



Remove Git from a Repo

Sometimes we want to remove the reference to existing repository details, such as cloned from github so that we can check the code in a different git repository or a different version control system. This article covers the steps that we can take to remove git references. If we clone a repo or fork a repo from git, the newly created repository will have git references as version control. If we want to remove the git references from the new repository then we need to delete all the git references. Once we remove the git references then it will not have any reference to old repository and we can use this project folder to create a brand new repository in git or any other version control system. This article talks about how to remove
The good thing is that all the git related information is stored in a folder .git . Normally we would have only one .git folder in the root of the repository, but we might have more than one .git folder based on how the repository is configured. Apart from .git folder we might have following git specific files, .gitignore: allows to include/exclude files to be synced to git remote server
.gitkeep: allows us to include an empty directory to be synced to git remote server
. gitattributes: allows us to ensure consistent git settings across the machine.
Essentially we need to delete all these git related folder/files that will make our repository clean and without any git version details. The following sections show how to achieve the same in a Windows environment and Mac environment

Windows

The rmdir or rd command will not delete/remove any hidden files or folders within the directory you specify, so we should use the del command to be sure that all files are removed from the .git folder. Open the command prompt Navigate to the project directory, i.e. - cd path_to_your_repository
del /F /S /Q /A .git

rmdir .git

Mac

Open a terminal and navigate to the directory of your project, i.e. - cd path_to_your_repository. And run the following commands
rm -rf .git
rm -rf .gitkeep
rm -rf .gitignore
rm -rf .gitattributes
Checking if you have any .git folder left
Go to the directory of your project and run the following command which finds the only the folder with the name .git and prints its path in the console.
find . | grep -i .git

Microservices Registration and Discovery using Spring Cloud, Eureka

This blog post walks through an implementation pattern and a working setup with multiple microservices where they get registered with Eureka and the client can discover them and invoke them.

What is Eureka

Eureka is a REST-based service that provides support for discovering other services so that clients can use the Eureka service to discover and call them.

Why we need Discovery Service

In a microservices architecture, each service typically runs on a different URL or IP address. Clients need a way to know when new microservices are added or existing ones go down for maintenance. Discovery service provides that mechanism—services register themselves, and clients query the discovery service to know available microservices.

Project Achievement

In this project, we will build:

  • A Eureka Discovery Service
  • An Article Microservice (CRUD operations)
  • A Client Microservice (consumes the Article service)

Goal: invoke a target service without hardcoding URLs, IPs, or ports, by resolving via service discovery.

Technology Used

  • Java 11
  • Apache Maven 3.5.0
  • Spring Boot 2.2.6
  • Spring Cloud Hoxton.SR1
  • Netflix Ribbon 2.3.0
  • Open Feign
  • JSON

Discovery Server

Add the Eureka Discovery Server dependency:



  org.springframework.cloud
  spring-cloud-starter-netflix-eureka-server

  

application.properties:


server.port=8761
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true
  

Main Application:


@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscovery {
  public static void main(String[] args) {
    SpringApplication.run(ServiceDiscovery.class, args);
  }
}
  

Article Service

Add Eureka Client dependency:



  org.springframework.cloud
  spring-cloud-starter-netflix-eureka-client

  

application.properties:


server.port=9051
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.register-with-eureka=true
spring.application.name=article-service
  

Main Application:


@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ArticleMicroservice {
  public static void main(String args[]) {
    SpringApplication.run(ArticleMicroservice.class, args);
  }
}
  

REST Endpoints:

  • GET /api/articles
  • GET /api/articles/{id}
  • POST /api/articles
  • DELETE /api/articles/{id}

Sample Response


[
  {
    "id": "America-Travel",
    "name": "America Travel",
    "description": "Places to travel in America ...",
    "category": "Travel"
  }
]
  

Article Client Service

This is another Spring Boot service that discovers and calls the Article service using Ribbon/Feign.

Consumer Controller Example:


@RestController
public class RibbonController {
  @Autowired
  private RestTemplate restTemplate;

  @RequestMapping(value = "render", method = RequestMethod.GET,
                  produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<String> renderArticles() throws Exception {
    JsonNode repos =
      restTemplate.getForObject("http://article-service-consumer/api/articles", JsonNode.class);
    ...
  }
}
  

Start Microservices

  1. Clone repo: git clone https://github.com/siddharthagit/spring-boot-sdc
  2. Run each service: mvn spring-boot:run
  3. Check discovery server: http://localhost:8761
  4. Call consumer service: http://localhost:9053/render

Conclusion

We demonstrated how to use Spring Cloud Eureka for service discovery. The client can invoke services without hardcoding addresses, relying on the discovery service to resolve them dynamically.

References