Banking System

  1. We have Bank Account with 2 Fields – balance and Account Number
  2. We have Transaction class implementing Runnable
  3. We create object for account with some initial balance and try to pass as parameter to runnable Transaction Object

BankAccount.java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {
    private Integer balance;
    private Integer accountNumber;

    private final Lock reLock = new ReentrantLock();

    public BankAccount(Integer balance, Integer accountNumber){
        this.balance = balance;
        this.accountNumber = accountNumber;
    }

    public void debitAmount(Integer amount){
        reLock.lock();

        try{
            balance -= amount;
        }finally {
            reLock.unlock();
        }

    }

    public void creditAmount(Integer amount){
        reLock.lock();

        try{
            balance += amount;
        }finally {
            reLock.unlock();
        }
    }

    public Integer getAccountNumber(){
        return this.accountNumber;
    }

    public Integer getBalance(){
        return this.balance;
    }

}

BankTransaction.java

public class BankTransaction implements Runnable{
    public Integer transAmount;
    public BankAccount bankAccount;

    public BankTransaction(Integer transAmount, BankAccount bankAccount){
        this.transAmount  = transAmount;
        this.bankAccount  = bankAccount;
    }


    @Override
    public void run() {
        if(transAmount >= 0){
            bankAccount.creditAmount(transAmount);
        }else{
            bankAccount.debitAmount(Math.abs(transAmount));
        }
    }
}

BankSystem.java

public class BankSystem {
    public static void main(String[] args) {
        BankAccount objAcc1 = new BankAccount(1000, 101);
        BankAccount objAcc2 = new BankAccount(2000, 102);

        Thread objThread1 = new Thread(new BankTransaction(50, objAcc1));
        Thread objThread2 = new Thread(new BankTransaction(-150, objAcc2));
        Thread objThread3 = new Thread(new BankTransaction(250, objAcc2));
        Thread objThread4 = new Thread(new BankTransaction(250, objAcc1));

        objThread1.start();
        objThread2.start();
        objThread3.start();
        objThread4.start();

        try{
            objThread1.join();
            objThread2.join();
            objThread3.join();
            objThread4.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("Final Balance in Account " + objAcc1.getAccountNumber() + " with balance " + objAcc1.getBalance());
        System.out.println("Final Balance in Account " + objAcc2.getAccountNumber() + " with balance " + objAcc2.getBalance());
    }
}

Output

Final Balance in Account 101 with balance 1300
Final Balance in Account 102 with balance 2100
  1. We use ReentrantLock for locking the Resource(totalSeats)
  2. Incase anything goes wrong (Exception being thrown etc.) you want to make sure the lock is released no matter what.
  3. Calling the reserveSeats method should be done inside separate threads

ReservationSystem.java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReservationSystem {
    private Integer totalSeats;
    private final Lock lock = new ReentrantLock();

    public ReservationSystem(Integer totalSeats){
        this.totalSeats = totalSeats;
    }

    public Integer getTotalSeats(){
        return totalSeats;
    }

    public void reserveSeats(String userName, int numOfSeats){
        lock.lock();

        try{
            if(numOfSeats >0 && totalSeats>numOfSeats){
                totalSeats -= numOfSeats;
                System.out.println(userName + " has reserved "+ numOfSeats + " with " + totalSeats + " still available");
            }else{
                System.out.println("Seats not Available");
            }
        }finally {
            lock.unlock();
        }
    }
}

BookSeat.java

public class BookSeat {
    public static void main(String[] args) {
        ReservationSystem objResSys = new ReservationSystem(100);

        System.out.println("Total available Seats "+ objResSys.getTotalSeats());

        Thread objThread1 = new Thread(() -> {objResSys.reserveSeats("User1", 10);});
        Thread objThread2 = new Thread(() -> {objResSys.reserveSeats("User2", 20);});
        Thread objThread3 = new Thread(() -> {objResSys.reserveSeats("User3", 5);});


        objThread1.start();
        objThread2.start();
        objThread3.start();

        try {
            objThread1.join();
            objThread2.join();
            objThread3.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("Remaining available Seats "+ objResSys.getTotalSeats());
    }
}


Total available Seats 100
User2 has reserved 20 with 80 still available
User1 has reserved 10 with 70 still available
User3 has reserved 5 with 65 still available
Remaining available Seats 65
  1. NEW – a newly created thread that has not yet started the execution
  2. RUNNABLE – either running or ready for execution but it’s waiting for resource allocation
  3. BLOCKED – waiting to acquire a monitor lock to enter or re-enter a synchronized block/method
  4. WAITING – waiting for some other thread to perform a particular action without any time limit
  5. TIMED_WAITING – waiting for some other thread to perform a specific action for a specified period
  6. TERMINATED – has completed its execution

NEW Thread (or a Born Thread) is a thread that’s been created but not yet started.
It remains in this state until we start it using the start() method

NewState.java

public class NewState implements Runnable{
    public void run(){
        System.out.println("I am in new State");
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
       Thread objThread = new Thread(new NewState());
       System.out.println(objThread.getState());
    }
}

Output

NEW

Runnable When we’ve created a new thread and called the start() method on that, it’s moved from NEW to RUNNABLE state. Threads in this state are either running or ready to run, but
they’re waiting for resource allocation from the system. In a multi-threaded environment, the Thread-Scheduler (which is part of JVM) allocates a fixed amount of time to each thread. So it runs for a particular amount of time, then leaves the control to other RUNNABLE threads.

RunnableState .java

public class RunnableState implements Runnable{
    public void run(){
        System.out.println("I would be in Runnable State");
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
       Thread objRThread = new Thread(new RunnableState());
       objRThread.start();
       System.out.println(objRThread.getState());
    }
}

Output

RUNNABLE
I would be in Runnable State

This is the state of a dead thread. It’s in the TERMINATED state when it has either finished execution or was terminated abnormally.
TerminatedState.java

public class TerminatedState implements Runnable{
    public void run(){
        Thread objNewState = new Thread(new NewState());
        objNewState.start();
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
       Thread objTState = new Thread(new TerminatedState());
       objTState.start();
       objTState.sleep(1000);
       System.out.println("T1 : "+ objTState.getState());
    }
}

Output

I am in new State
T1 : TERMINATED

A thread is in the BLOCKED state when it’s currently not eligible to run. It enters this state when it is waiting for a monitor lock and is trying to access a section of code that is locked by some other thread.
BlockedState.java

public class BlockedState implements Runnable{
    public void run(){
      blockedResource();
    }

    public static synchronized void blockedResource(){
        while(true){
            //Do Nothing
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread objB1Thread = new Thread(new BlockedState());
        Thread objB2Thread = new Thread(new BlockedState());

        objB1Thread.start();
        objB2Thread.start();

        Thread.sleep(1000);

        System.out.println(objB1Thread.getState());
        System.out.println(objB2Thread.getState());
        System.exit(0);
    }
}

Output

RUNNABLE
BLOCKED

A thread is in WAITING state when it’s waiting for some other thread to perform a particular action. According to JavaDocs, any thread can enter this state by calling any one of the following
object.wait() (or) thread.join() (or) LockSupport.park()

WaitingState.java

public class WaitingState implements Runnable{
    public void run(){
        Thread objWaitState = new Thread(new SleepState());

        objWaitState.start();

        try {
            objWaitState.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

SleepState.java

public class SleepState implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
       Thread objWaitingThread = new Thread(new WaitingState());
       objWaitingThread.start();
       objWaitingThread.sleep(1000);
       System.out.println("T1 : "+ objWaitingThread.getState());
       System.out.println("Main : "+Thread.currentThread().getState());
    }
}

Output

T1 : WAITING
Main : RUNNABLE

A thread is in TIMED_WAITING state when it’s waiting for another thread to perform a particular action within a stipulated amount of time. According to JavaDocs, there are five ways to put a thread on TIMED_WAITING state:
thread.sleep(long millis) (or) wait(int timeout) (or) wait(int timeout, int nanos) thread.join(long millis) (or) LockSupport.parkNanos (or) LockSupport.parkUntil

TimedWaitState.java

public class TimedWaitState implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread objTWState = new Thread(new TimedWaitState());
        objTWState.start();
        Thread.sleep(2000);
        System.out.println("T1 : "+ objTWState.getState());
    }
}

Output

T1 : TIMED_WAITING

Simple Program to print numbers using threads
NumberPrinter.java

public class NumberPrinter implements Runnable{
    int number;
    public NumberPrinter(int number){
        this.number = number;
    }

    public void run(){
        System.out.println("Printing Number from Thread "+ this.number);
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        for (int idx=1;idx<=5;idx++){
            Thread objthread = new Thread(new NumberPrinter(idx));
            objthread.start();
        }
    }
}

Output

Printing Number from Thread 5
Printing Number from Thread 1
Printing Number from Thread 4
Printing Number from Thread 3
Printing Number from Thread 2

What is Class Loading?
Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation.

When Class is Loaded?

  1. Class loading done by Class Loaders may eagerly load a class or does lazy load
  2. Eager loading happens as soon as another class references it and lazy load happens when a need of class initialization occurs.
  3. If a Class is loaded before it’s actually being used, it can sit inside before being initialized which may vary from JVM to JVM.
  4. However, it’s guaranteed by JLS that a class will be loaded when there is a need of static initialization.

Whenever the JVM determines it needs a class (to use its static variables, to create a new object, to use its static methods etc) it will load the class and static initialization blocks will run, static variables are initialized etc. This is (at least under normal circumstances) done only once

SomeClass.someStaticMethod(); //SomeClass is loaded (if its not already)
SomeClass.someStaticVariable; //SomeClass is loaded (if its not already)
SomeClass var=new SomeClass(); //SomeClass is BOTH loaded (if its not already) AND instantiated

Class loader actually loads byte code into JVM , runs static initializers when you want to use static fields within class without creating an instance of it, class must be loaded by class loader first.Default classloader in java is java.lang.ClassLoader

Class Loading is mostly unpredictable

When Class is Initialized?
Class Initialization happens after class loading. A class is initialized in Java when

  1. An Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
  2. an static method of Class is invoked.
  3. an static field of Class is assigned.
  4. an static field of class is used which is not a constant variable.
  5. if Class is a top level class and an assert statement lexically nested within class is

Which classes are Eagerly Loaded and Lazily Loaded

Eagerly Loaded Classes
are those the JVM must be able to load JVM class files. The JVM class loader loads referenced JVM classes that have not already been linked to the runtime system. Classes are loaded implicitly because: The initial class file – the class file containing the public static void main(String args[]) method – must be loaded at startup. Depending on the class policy adopted by the JVM, classes referenced by this initial class can be loaded in either a lazy or eager manner.

An eager class loader loads all the classes comprising the application code at startup. Lazy class loaders wait until the first active use of a class before loading and linking its class file.

The first active use of a class occurs when one of the following occurs: • An instance of that class is created • An instance of one of its subclasses is initialized • One of its static fields is initialized. Certain classes, such as ClassNotFoundException, are loaded implicitly by the JVM to support execution. You may also load classes explicitly using the java.lang.Class.forName() method in the Java API, or through the creation of a user class loader.

Based on the above rules, lazy class loading can be forced on the system.

Use java -XX:+TraceClassLoading to trace the loading of classes.

Use java -XX:+PrintCompilation to trace when methods are JITed.

Thread – direction or path that is taken while a program is executed

  1. Below code would explain how dirty read happens when multiple thread(2 threads) tries to access Instance variable at once from two different class objects
  2. Below we have 3 classes, One for Printing Report and Other for removing the report printed. Third for tracking the report status
  3. The Output of the code would be Consistently 0 every time which is expected when the number of reports to be printed is in range of less than 100. However the output changes with more the no of reports to be printed. I.E. totalReportsToBePrinted = 10000000
  4. This happens because for lower value of reports to be printed the thread executes fast with out context switching however for higher values other thread(RemovePrintedReports thread takes control before PrintExcelReports get completed) takes control which leads to inconsistency
  5. The Same code would return 0 every time if one thread(PrintExcelReports) completes before other(RemovePrintedReports) as below when we use join and didn’t start both the threads at once.
    .
    .
            t1.start();
            t1.join();
            
            t2.start();
            t2.join();
    
    .
    .
    

PrintExcelReports.java

public class PrintExcelReports implements Runnable {
    TotalReportCount totalReportCount;

    public PrintExcelReports(TotalReportCount totalReportCount) {
        this.totalReportCount = totalReportCount;
    }

    int totalReportsToBePrinted = 1000000;

    @Override
    public void run() {
        for(int i=0;i<totalReportsToBePrinted;i++){
            totalReportCount.totalReportsCntVal -= i;
        }
    }
}

RemovePrintedReports.java

public class RemovePrintedReports implements Runnable {
    TotalReportCount totalReportCount;

    public RemovePrintedReports(TotalReportCount totalReportCount) {
        this.totalReportCount = totalReportCount;
    }

    int totalReportsToBePrinted = 1000000;

    @Override
    public void run() {
        for(int i=0;i<totalReportsToBePrinted;i++){
            totalReportCount.totalReportsCntVal -= i;
        }
    }
}

ReportCurrentStatus.java

public class ReportCurrentStatus {
    public static void main(String[] args) throws InterruptedException {
        TotalReportCount objTotalReportCount = new TotalReportCount();
        objTotalReportCount.totalReportsCntVal = 0;

        PrintExcelReports objPrinter1 = new PrintExcelReports(objTotalReportCount);
        RemovePrintedReports objPrinter2 = new RemovePrintedReports(objTotalReportCount);

        Thread t1 = new Thread(objPrinter1);
        Thread t2 = new Thread(objPrinter2);

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println(objTotalReportCount.totalReportsCntVal);
    }
}

Output when totalReportsToBePrinted is greater than 1000

RANDOM NUMBER

Output when totalReportsToBePrinted is less than 100

0

Why we need Custom Exception
Exceptions are technical causes which should be wrapped in a presentable way with a specific business logic and workflow. adding a higher abstraction layer for the exception handling, which results in more meaningful and readable API

How to write Custom Exception
All you need to do is create a new class and have it extend Exception. If you want an Exception that is unchecked, you need to extend RuntimeException.
Note: A checked Exception is one that requires you to either surround the Exception in a try/catch block or have a ‘throws’ clause on the method declaration. (like IOException) Unchecked Exceptions may be thrown just like checked Exceptions, but you aren’t required to explicitly handle them in any way (IndexOutOfBoundsException).

Exception, if you want your exception to be checked (i.e: required in a throws clause).RuntimeException, if you want your exception to be unchecked.

Creating Custom Checked Exception
Note:constructor takes a Throwable’s subclass which is the origin (cause) of the current exception

public class StudentStoreException extends Exception {
     public StudentStoreException(String message, Throwable cause) {
        super(message, cause);
    }
}

Creating Custom Unchecked Exception

public class IncorrectFileExtensionException 
  extends RuntimeException {
    public IncorrectFileExtensionException(String errorMessage, Throwable err) {
        super(errorMessage, err);
    }
}

Methods in Custom Exception

public class MyOwnException extends Exception {
    public MyOwnException() {

    }

    public MyOwnException(String message) {
        super(message);
    }

    public MyOwnException(Throwable cause) {
        super(cause);
    }

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

Minimal Requirment

  1. Java 17 or higher
  2. Jakarta EE 10
  3. Spring Framework 6
  4. Works on Maven 3.5+
  5. Tomcat 10.0
  6. Improved observability with Micrometer and Micrometer Tracing

Improvements
Performance enhancements and optimizations to boost application responsiveness and efficiency.These improvements focus on reducing startup times, minimizing memory footprint, and optimizing resource utilization.

Changes in Code

  1. When we wanted to configure the Security settings, we had to extend the WebSecurityConfigurerAdapter class.This class has been deprecated and removed in Spring Security 6.
    Instead, we should now take a more component-based approach and create a bean of type SecurityFilterChain.

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig {
     @Bean
      public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(requests -> requests
                .requestMatchers(new AntPathRequestMatcher("/openapi/openapi.yml")).permitAll()
                .anyRequest().authenticated())
            .httpBasic();
        return http.build();
      }
    }
    
  2. Instead of using authorizeRequests, which has been deprecated, we should now use authorizeHttpRequests.This method is part of the HttpSecurity configuration and allows you to configure fine-grained request matching for access control.
  3. Spring Security 6, AntMatcher, MvcMatcher, and RegexMatcher have been depreciated and replaced by requestMatchers or securityMatchers for path-based access control. This allows us to match requests based on patterns or other criteria without relying on specific matchers.
  1. forEach method in java.lang.Iterable interface

    Java 8 has introduced forEach method in java.lang.Iterable interface so that while writing code we focus on business logic. The forEach method takes java.util.function.Consumer object as an argument, so it helps in having our business logic at a separate location that we can reuse.

  2. myList.forEach(new Consumer < Integer > () {
        public void accept(Integer t) {
            System.out.println("forEach anonymous class Value::" + t);
        }
    
    });
    
    //traversing with Consumer interface implementation
    MyConsumer action = new MyConsumer();
    myList.forEach(action);
    

    Consumer implementation that can be reused

    class MyConsumer implements Consumer<Integer>{
    
    	public void accept(Integer t) {
    		System.out.println("Consumer impl Value::"+t);
    	}
    }
    
  3. Interfaces with default and static methods

    From Java 8, interfaces are enhanced to have a method with implementation. We can use default and static keyword to create interfaces with method implementation

  4. We know that Java doesn’t provide multiple inheritance in Classes because it leads to Diamond Problem. So how it will be handled with interfaces now since interfaces are now similar to abstract classes. Compiler will throw an exception in this scenario and we will have to provide implementation logic in the class implementing the interfaces.

    @FunctionalInterface
    public interface Interface1 {
    
        void method1(String str);
    
        default void log(String str) {
            System.out.println("I1 logging::" + str);
        }
    
        static void print(String str) {
            System.out.println("Printing " + str);
        }
    }    
    

    interfaces are not allowed to have Object default methods.

  5. @FunctionalInterface annotation. Functional interfaces are a new concept introduced in Java 8. An interface with exactly one abstract method becomes a Functional Interface. We don’t need to use @FunctionalInterface annotation to mark an interface as a Functional Interface.

    @FunctionalInterface annotation is a facility to avoid the accidental addition of abstract methods in the functional interfaces. You can think of it like @Override annotation and it’s best practice to use it. java.lang.Runnable with a single abstract method run() is a great example of a functional interface.

    Anonymous Class Implementation

    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("My Runnable");
        }
    };
    

    Lambda Expression Implementation

    Runnable r1 = () - > {
        System.out.println("My Runnable");
    };
    

    If you have single statement in method implementation anonymous class can be instantiated using lambda expression as below
    lambda expressions Implementation

    Interface1 i1 = (s) -> System.out.println(s);		
    i1.method1("abc");
    
  6. New java.util.stream has been added in Java 8 to perform filter/map/reduce like operations with the collection. Stream API will allow sequential as well as parallel execution.
    public static void main(String[] args) {
    
        List < Integer > myList = new ArrayList < > ();
        for (int i = 0; i < 100; i++) myList.add(i);
    
        //sequential stream
        Stream < Integer > sequentialStream = myList.stream();
    
        //parallel stream
        Stream < Integer > parallelStream = myList.parallelStream();
    
        //using lambda with Stream API, filter example
        Stream < Integer > highNums = parallelStream.filter(p - > p > 90);
        //using lambda in forEach
        highNums.forEach(p - > System.out.println("High Nums parallel=" + p));
    
        Stream < Integer > highNumsSeq = sequentialStream.filter(p - > p > 90);
        highNumsSeq.forEach(p - > System.out.println("High Nums sequential=" + p));
    
    }
    

    parallel processing values are not in order, so parallel processing will be very helpful while working with huge collections.

  7. IO improvements known to me are:

    Files.list(Path dir) that returns a lazily populated Stream, the elements of which are the entries in the directory.
    Files.lines(Path path) that reads all lines from a file as a Stream.
    Files.find() that returns a Stream that is lazily populated with Path by searching for files in a file tree rooted at a given starting file.
    BufferedReader.lines() that return a Stream, the elements of which are lines read from this BufferedReader.

  8. Java Time API packages, I can sense that they will be very easy to use. It has some sub-packages java.time.format that provides classes to print and parse dates and times and java.time.zone provides support for time zones and their rules.
## Summary

Below are the List of Features available in Code

1. Reading payload from JSON File and using it as mocked Response
2. Object creation from JSON File
---

## Things Newly Implemented

1. JSON Payload files are found in src/test/resources/json-data
2. In the Code Converstion to Employee Object after reading Employee JSON and Stringify of JSON Object are both done  
3. MockMvc Testing is implemented for Controllers	
	- For AddEmployee Endpoint - Request from JSON file, Response from mocked response  
	- For GetEmployee Endpoint - Request by URL, Response from mocked Employee object constructed from JSON File
	- For GetAllEmployees Endpoint - Request by URL, Response from method returning Employee Object
	- For DeleteEmployee Endpoint - Request by URL, Response from mocked method	 	  
---

## Changes in pom.xml 
```xml
<build>
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/test/resources</directory>
        </testResource>			
    </testResources>
    .
    .
    .
</build>
```
---

# API endpoints
## GET
`Get All Employees Detail` [/empmgmt/employees](#getallemployee) <br/>
`Get Employee Details` [/empmgmt/employees/{empId}](#getemployeesempid) <br/>

## POST
`Add Employee Details` [/empmgmt/employees](#addemployee) <br/>

## DELETE
`Delete EmpDetails` [/empmgmt/employees/{empId}](#deleteemployee) <br/>
___

<a name="getemployeesempid"></a>
### GET /empmgmt/employees/{empId}
Get Employee Detail

**Parameters**

|          Name | Required |  Type   | Description                                                                                                                                                           |
| -------------:|:--------:|:-------:| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `empId` | required | string  | Employee Id

**Response**

```
// Employee Details added Succesfully
[
    {
        "empID": 1,
        "empName": "Mugil",
        "empAge": "36"
    }
]
```
___

<a name="getallemployee"></a>
### GET /empmgmt/employees

**Response**
```
// Employee Details added Succesfully
[
    {
        "empID": 1,
        "empName": "Mugil",
        "empAge": "36"
    }
]
```
___

<a name="addemployee"></a>
### POST /empmgmt/employees
Add Employee Details

**Parameters**

|          Name | Required |  Type   | Description                                                                                                                                                           |
| -------------:|:--------:|:-------:| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `empName` | required | string  | Name of Employee
|     `empAge` | required | string  | Age of Employee

**Request**
```
// Employee Details 
{
    "empName" : "Mugil",
    "empAge" : "36"
}
```


**Response**

```
// Employee Details added Succesfully
[
    {
        "empID": 1,
        "empName": "Mugil",
        "empAge": "36"
    }
]
```
___

<a name="deleteemployee"></a>
### DELETE /empmgmt/employees/{empId}

**Parameters**

|          Name | Required |  Type   | Description                                                                                                                                                           |
| -------------:|:--------:|:-------:| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `empId` | required | string  | Employee Id


**Response**

```
Employee Deleted Successfully
```
___



## Note

* While reading file from resources folder I continously got error telling the file doesnot exists. 
  The Same problem is faced while working in office project. After adding above lines in pom.xml it started 
  working. It kept working, even after removing above lines
* The URL returned in _Link in add employee wont have a port number. The test keeps failing if you copy and paste
  URL from postman and try to asset the _links in mockMVC

___    

Copy paste the code in URL to see in action : https://markdownlivepreview.com/

Readme file screen shot for above code