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 install Maven artifact with sources

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 do I generate source code for third-party artifacts that my project is using. 
2) How do I 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
Generate source code for project
Following commands 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 drives though 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 services and calling those services.

Why we need Discovery Service

In a Microservices architecture where we have multiple services running, we need a mechanism to know what are the services and how to invoke them. Each service typically will have a different URL or IP address to reach out to. Also, clients of those microservices need to know when a new


microservice is added or an existing microservice was taken down for maintenance. Discovery service provides that mechanism, where services can register themself in the discovery service and clients, can query the discovery service to know more about the available microservices.

Project achievement

In this project, we will go through an end to end use case where we will have a client microservice calling another microservice utilizing Eureka discovery service. Essentially we want to find existing services by looking up in discovery service and then invoking the target service without knowing about their whereabouts like URL, or IP or port, etc. For that, we will build a discovery server one service microservice and one client microservice.
Project Contents
  • Eureka Discovery Service: Provides the registration and discovery
  • Article Microservice: Provides REST services for Article CRUD operation
  • Client Microservice: Invokes the article microservice



Above pictures show what we are going to achieve in very high level
1) We will deploy a Discovery service
2) We will deploy Article Service which registers itself with discovery service with a unique name.
3) We will deploy a consumer application which is another spring boot application which will invoke the
     Article Service by its name.

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

The following section highlights the important code related to Eureka Server. The details can be looked into in the git repo. Mainly we need to add the maven dependency for Eureka Discovery Server, in the spring boot properties file add the server port and defaultZone and annotate the SpringBoot Application class with @EnableEurekaServer.
We need to include the Netflix Eureka Server dependency in the maven pom file.
pom.xml
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.properties
server.port=8761

##Eureka Related
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true
The Eureka Discovery Server is a Spring Boot application that is very simple. We need to annotate the application with @EnableEurekaServer. @EnableEurekaServer allows this application to run as a Eureka server, aided by Spring Boot to instantiate Eureka-related beans based on configuration properties.
ServiceDiscovery.java
package com.bootng.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscovery {
  public static void main(String[] args) {
    SpringApplication.run(ServiceDiscovery.class, args);
  }
}
Now when we build and start the discovery server and access the server through http://localhost:8761 we would see something like bellow. Notice the following screenshots shows no entries under applications because no other services are up yet.


Discovery Service UI


Article Service

Now we will build and deploy the Article microservice which is another spring boot application that registers itself with the discovery service. The name with which this service is registered is "article-service" and is defined in bootstrap.properties file.
pom.xml
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.properties
## Server Related
server.port=9051
## Eureka Related
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=false
eureka.vipAddress=article-service
bootstrap.properties
spring.application.name=article-service
Following is the main application class representing Article Microservice.
ArticleMicroservice
@ComponentScan({ "com.siddb" })
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ArticleMicroservice {
	public static void main(String args[]) {
		SpringApplication.run(ArticleMicroservice.class, args);
	}
}
This Spring Boot Application exposes the following REST endpoints through the ArticleController.java class. And registers itself with the service discovery with the name "article-service"
ArticleController.java
@RestController
@RequestMapping("/api")
public class ArticleController {
  private static final Logger log = LoggerFactory.getLogger(ArticleController.class);
  @Autowired
  ArticleService articleService;

  @RequestMapping(value = {"/articles"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<List<Article>> getArticles() throws AppException {
    List<Article> articles = articleService.getArticles();
    return new ResponseEntity<List<Article>>(articles, HttpStatus.OK);
  }

  @RequestMapping(value = {"/articles/{id}"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<Article> getArticle(@PathVariable(value = "") String id)
      throws AppException, NotFoundException {
    Article articles = articleService.getByID(id);
    return new ResponseEntity<Article>(articles, HttpStatus.OK);
  }
 //other methods for POST and Deleted removed from here for readability.
}
REST Endpoints
  • GET http://localhost:9051/api/articles
  • GET http://localhost:9051/api/articles/ARTICLE_ID
  • POST http://localhost:9051/api/articles PAYLOAD
  • DELETE http://localhost:9051/api/articles/ARTICLE_ID

Sample Response

GET http://localhost:9051/api/articles
[
  {
    "id": "America-Travel",
    "name": "America Travel",
    "description": "Places to travel in AmericaLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum",
    "category": "Travel"
  }
]
GET http://localhost:9051/api/articles
Sample Response: [ { "id": "America-Travel", "name": "America Travel", "description": "Places to travel in AmericaLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "category": "Travel" } ]
[ { "id": "America-Travel", "name": "America Travel", "description": "Places to travel in AmericaLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "category": "Travel" } ]

Article Client Service

Now we will build and deploy the Client Service application which is another Spring Boot application that consumes the REST services deployed by Article Service. Most interesting part
pom.xml
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-loadbalancer</artifactId>
	</dependency>
	<!--ribbon related -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>
application.properties
hostname=localhost
logging.level.org.springframework=info
logging.level.root=info
spring.main.banner-mode=off
server.port=9053

##Management
management.endpoint.health.show-details
management.health.key.ping=enabled
management.endpoints.web.exposure.include=info,health,mappings

##Eureka Related
eureka.instance.leaseRenewalIntervalInSeconds=1
eureka.instance.leaseExpirationDurationInSeconds=90
eureka.instance.hostname=${hostname}
eureka.instance.hostname.metadataMap.instanceId=${spring.application.name}:${server.port}
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true

##Eureka Ribbon
article-service-consumer.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
article-service-consumer.ribbon.DeploymentContextBasedVipAddresses=article-service
Following is the Consumer Application Class. We have annotated it with @EnableDiscoveryClient so that it can discover other services registered with the Discovery Server.
ConsumerApplication
@ComponentScan({"com.siddb", "com.siddb.controller"})
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
  public static void main(String args[]) {
    SpringApplication.run(ConsumerApplication.class, args);
  }
}
Following is the main controller which uses the discovery service internally and invokes services on the service article-service using ribbon. From the ribbon configuration in (application.properties), it knows article-service-consumer is tied to a service with VIP Address (name) article-service.
RibbonController.java
@RestController
public class RibbonController {

  @Autowired
  private RestTemplate restTemplate;

  /**
   * This method calls the microservice GET article-service/api/articles using Ribbon to get a list of
   * Articles and returns the same. it uses RestTemplate to make the API calls.
   * @return
   * @throws Exception
   */
  @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);

    int counter = 1;
    StringBuilder result = new StringBuilder("\n List of Articles");
    if (repos.isArray()) {
      for (JsonNode jsonNode : repos) {
        result.append("\n Repo ").append(counter++).append("::");
        result.append(jsonNode.get("name").asText());
      }
    }
    return new ResponseEntity<String>(result.toString(), HttpStatus.OK);
  }
}
The Consumer Controller uses the ribbon configuration that we have added in the property file to invoke the article service by the ribbon name "article-service-consumer". This is where the Consumer controller will discover the actual API for the corresponding service name. And call GET http://article-service-consumer/api/articles will be actually to http://localhost:9051/api/articles. This is how using the Eureka Discovery service the client becomes independent of the service (IP address, port, etc.). The client simply can refer to the service with its published name.

Start Microservices

Now the fun part, start all the microservices and invoke the /render REST API. We need to start all services (discovery service, article service, consumer service). For that, we first need to check out the repo from git and build/run each project.
1) git clone https://github.com/siddharthagit/spring-boot-sdc.
2) go to the root folder that contains this repo.
3) open 3 Terminals one for each subproject (eureka-service-discovery, ms-article-service, ms-consumer-service).
4) build each project and start the services.
mvn clean install
mvn spring-boot:run
5) Check the status of each service on the discovery server http://localhost:8761
6)Invoke the REST API on consumer service http://localhost:9053/render
This API internally will use the discovery server to resolve the service and will route the call to http://localhost:9051/api/articles.
http://localhost:9053/render
List of Articles Repo 1::America Travel Repo 2::Asia Travel Repo 3::Europe Travel Repo 4::Road Trip Repo 5::Winter Travel Repo 6::Japan Travel

Discovery Server UI with all services running


Conclusion

In this article, we've covered how to use Spring Cloud Eureka for service discovery in the microservice/cloud environment. We created two simple REST services that communicate with each other without hardcoding any hostname/port while making REST calls. Though in this article we have shown how the client can invoke the article service with ribbon, the git repo also contains a Feign client that uses Feign and will be covered in a different article.

References