SpringJPAHibernate
SpringJPAHibernate
Objectives
Explain ORM implementation with Hibernate XML Configuration and Annotation Configuration
o XML Configuration - persistence class, mapping xml, configuration xml, loading hibernate configuration xml file;
Annotation Configuration - persistence class, @Entity, @Table, @Id, @Column, hibernate configuration xml file
Loading hibernate configuration and interacting with database get the session factory, open session, begin
transaction, commit transaction, close session
XML Configuration Example - https://www.tutorialspoint.com/hibernate/hibernate_examples.htm
Hibernate Configuration Example - https://www.tutorialspoint.com/hibernate/hibernate_annotations.htm
Explain the difference between Java Persistence API, Hibernate and Spring Data JPA
o JPA (Java Persistence API), JPA is a specification (JSR 338), JPA does not have implementation, Hibernate is
one of the implementation for JPA, Hibernate is a ORM tool, Spring Data JPA is an abstraction above Hibernate to
remove boiler plate code when persisting data using Hibernate.
Difference between Spring Data JPA and Hibernate - https://dzone.com/articles/what-is-the-difference-
between-hibernate-and-sprin-1
Intro to JPA - https://www.javaworld.com/article/3379043/what-is-jpa-introduction-to-the-java-
persistence-api.html
Demonstrate implementation of DML using Spring Data JPA on a single database table
o Hibernate log configuration and ddl-auto configuration, JpaRepsitory.findById(), defining Query Methods,
JpaRespository.save(), JpaRepository.deleteById()
Spring Data JPA Ref Repository methods -
https://docs.spring.io/spring-data/jpa/docs/2.2.0.RELEASE/reference/html/#repositories.core-concepts
Query methods - https://docs.spring.io/spring-data/jpa/docs/2.2.0.RELEASE/reference/html/
#repositories.query-methods
Go to https://start.spring.io/
Change Group as “com.cognizant”
Change Artifact Id as “orm-learn”
In Options > Description enter "Demo project for Spring Data JPA and Hibernate"
Click on menu and select "Spring Boot DevTools", "Spring Data JPA" and "MySQL Driver"
Click Generate and download the project as zip
Extract the zip in root folder to Eclipse Workspace
Import the project in Eclipse "File > Import > Maven > Existing Maven Projects > Click Browse
and select extracted folder > Finish"
Create a new schema "ormlearn" in MySQL database. Execute the following commands to open
MySQL client and create schema.
# Log pattern
logging.pattern.console=%d{dd-MM-yy} %d{HH:mm:ss.SSS} %-20.20thread %5p %-25.25logger{25} %25M %4L %m%n
# Database configuration
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ormlearn
spring.datasource.username=root
spring.datasource.password=root
# Hibernate configuration
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Build the project using ‘mvn clean package -Dhttp.proxyHost=proxy.cognizant.com -
Dhttp.proxyPort=6050 -Dhttps.proxyHost=proxy.cognizant.com -Dhttps.proxyPort=6050 -
Dhttp.proxyUser=123456’ command in command line
Include logs for verifying if main() method is called.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
SME to walk through the following aspects related to the project created:
Create a new table country with columns for code and name. For sample, let us insert one
country with values 'IN' and 'India' in this table.
@Entity
@Table(name="country")
public class Country {
@Id
@Column(name="code")
private String code;
@Column(name="name")
private String name;
// toString()
Notes:
@Entity is an indicator to Spring Data JPA that it is an entity class for the application
@Table helps in defining the mapping database table
@Id helps is defining the primary key
@Column helps in defining the mapping table column
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cognizant.ormlearn.model.Country;
@Repository
public interface CountryRepository extends JpaRepository<Country, String> {
Testing in OrmLearnApplication.java
Modify SpringApplication.run() invocation to set the application context and the CountryService
reference from the application context.
testGetAllCountries();
Explanation Topics
Explain how object to relational database mapping done in hibernate xml configuration file
Explain about following aspects of implementing the end to end operations in Hibernate:
o SessionFactory
o Session
o Transaction
o beginTransaction()
o commit()
o rollback()
o session.save()
o session.createQuery().list()
o session.get()
o session.delete()
Explanation Topics
Explain how object to relational database mapping done in persistence class file Employee
Explain about following aspects of implementing the end to end operations in Hibernate:
o @Entity
o @Table
o @Id
o @GeneratedValue
o @Column
o Hibernate Configuration (hibernate.cfg.xml)
Dialect
Driver
Connection URL
Username
Password
JSR 338 Specification for persisting, reading and managing data from Java objects
Does not contain concrete implementation of the specification
Hibernate is one of the implementation of JPA
Hibernate
Does not have JPA implementation, but reduces boiler plate code
This is another level of abstraction over JPA implementation provider like Hibernate
Manages transactions
Refer code snippets below on how the code compares between Hibernate and Spring Data JPA
Hibernate
/* Method to CREATE an employee in the database */
public Integer addEmployee(Employee employee){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
EmployeeService.java
@Autowire
private EmployeeRepository employeeRepository;
@Transactional
public void addEmployee(Employee employee) {
employeeRepository.save(employee);
}
Reference Links:
https://dzone.com/articles/what-is-the-difference-between-hibernate-and-sprin-1
https://www.javaworld.com/article/3379043/what-is-jpa-introduction-to-the-java-persistence-api.html
Before starting the implementation of the above features, there are few configuration and data population
that needs to be incorporated. Please refer each topic below and implement the same.
Moreover the ddl-auto defines how hibernate behaves if a specific table or column is not present
in the database.
o create - drops existing tables data and structure, then creates new tables
o validate - check if the table and columns exist or not, throws an exception if a matching
table or column is not found
o update - if a table does not exists, it creates a new table; if a column does not exists, it
creates a new column
o create-drop - creates the table, once all operations are completed, the table is dropped
Delete all the records in Country table and then use the below script to create the actual list of all
countries in our world.
@Transactional
public Country findCountryByCode(String countryCode) throws CountryNotFoundException
From the result, check if a country is found. If not found, throw CountryNotFoundException
if (!result.isPresent())
Include new test method in OrmLearnApplication to find a country based on country code and
compare the country name to check if it is valid.
NOTE: SME to explain the importance of @Transactional annotation. Spring takes care of creating the
Hibernate session and manages the transactionality when executing the service method.
@Transactional
public void addCountry(Country country)
countryRepository.save(country)
Create a new method updateCountry() in CountryService with parameters code and name.
Annotate this method with @Transactional. Implement following steps in this method.
o Get the reference of the country using findById() method in repository
o In the country reference obtained, update the name of country using setter method
o Call countryRepository.save() method to update the name
Include new test method in OrmLearnApplication, which invokes updateCountry() method in
CountryService passing a country's code and different name for the country.
Check in database table if name is modified.
An application has a search text box for searching by country. When typing characters on the text
box, a list of all the matching countries should be displayed. For example, if 'ou' is entered in the
search box the following countries should be displayed. Write a Query Method to achieve this
feature. Implement this method in CountryRepository.
BV Bouvet Island
DJ Djibouti
GP Guadeloupe
GS South Georgia and the South Sandwich Islands
LU Luxembourg
SS South Sudan
TF French Southern Territories
UM United States Minor Outlying Islands
ZA South Africa
Enhance the above method to return the countries in ascending order. Modify the query method
name defined in the previous problem to achieve this.
BV Bouvet Island
DJ Djibouti
TF French Southern Territories
GP Guadeloupe
LU Luxembourg
ZA South Africa
GS South Georgia and the South Sandwich Islands
SS South Sudan
UM United States Minor Outlying Islands
To select a country an alphabet index is displayed in a web page, when the user clicks on the
alphabet, all the countries starting that alphabet needs to be displayed. For example if the
alphabet choose is 'Z', then the following countries should be displayed. Write a query method to
get this feature incorporated.
ZM Zambia
ZW Zimbabwe
Test Cases
The file stock-data.csv in spring-data-jpa-files folder contains the stock data of Facebook, Google
and Netflix from 18 Oct 2018 to 17 Oct 2019. This is public data downloaded from
finance.yahoo.com.
Open stock-data.csv file in Excel
Include the following formula in F2 cell, this will display the insert script in F2 cell.
=CONCATENATE("insert into stock (st_code, st_date, st_open, st_close, st_volume) values (""", B2, """,
""", YEAR(A2), "-", MONTH(A2), "-", DAY(A2), """, ", C2, ", ", D2, ", ", E2, ");")
mysql>source D:\spring-data-jpa-files\stock-data.sql
Create new class Stock in orm-learn project and define the required mapping annotations.
Create StockRepository class to write the Query Methods
Create methods in OrmLearnApplication to test by autowiring StockRepository directly.
Get all stock details of Facebook in the month of September 2019. Expected data result of Query
Method below.
+---------+------------+---------+----------+-----------+
| st_code | st_date | st_open | st_close | st_volume |
+---------+------------+---------+----------+-----------+
| FB | 2019-09-03 | 184.00 | 182.39 | 9779400 |
| FB | 2019-09-04 | 184.65 | 187.14 | 11308000 |
| FB | 2019-09-05 | 188.53 | 190.90 | 13876700 |
| FB | 2019-09-06 | 190.21 | 187.49 | 15226800 |
| FB | 2019-09-09 | 187.73 | 188.76 | 14722400 |
| FB | 2019-09-10 | 187.44 | 186.17 | 15455900 |
| FB | 2019-09-11 | 186.46 | 188.49 | 11761700 |
| FB | 2019-09-12 | 189.86 | 187.47 | 11419800 |
| FB | 2019-09-13 | 187.33 | 187.19 | 11441100 |
| FB | 2019-09-16 | 186.93 | 186.22 | 8444800 |
| FB | 2019-09-17 | 186.66 | 188.08 | 9671100 |
| FB | 2019-09-18 | 188.09 | 188.14 | 9681900 |
| FB | 2019-09-19 | 188.66 | 190.14 | 10392700 |
| FB | 2019-09-20 | 190.66 | 189.93 | 19934200 |
| FB | 2019-09-23 | 189.34 | 186.82 | 13327600 |
| FB | 2019-09-24 | 187.98 | 181.28 | 18546600 |
| FB | 2019-09-25 | 181.45 | 182.80 | 18068300 |
| FB | 2019-09-26 | 181.33 | 180.11 | 16083300 |
| FB | 2019-09-27 | 180.49 | 177.10 | 14656200 |
+---------+------------+---------+----------+-----------+
Get all google stock details where the stock price was greater than 1250
+---------+------------+---------+----------+-----------+
| st_code | st_date | st_open | st_close | st_volume |
+---------+------------+---------+----------+-----------+
| GOOGL | 2019-04-22 | 1236.67 | 1253.76 | 954200 |
| GOOGL | 2019-04-23 | 1256.64 | 1270.59 | 1593400 |
| GOOGL | 2019-04-24 | 1270.59 | 1260.05 | 1169800 |
| GOOGL | 2019-04-25 | 1270.30 | 1267.34 | 1567200 |
| GOOGL | 2019-04-26 | 1273.38 | 1277.42 | 1361400 |
| GOOGL | 2019-04-29 | 1280.51 | 1296.20 | 3618400 |
| GOOGL | 2019-10-17 | 1251.40 | 1252.80 | 1047900 |
+---------+------------+---------+----------+-----------+
+---------+------------+---------+----------+-----------+
| st_code | st_date | st_open | st_close | st_volume |
+---------+------------+---------+----------+-----------+
| FB | 2019-01-31 | 165.60 | 166.69 | 77233600 |
| FB | 2018-10-31 | 155.00 | 151.79 | 60101300 |
| FB | 2018-12-19 | 141.21 | 133.24 | 57404900 |
+---------+------------+---------+----------+-----------+
+---------+------------+---------+----------+-----------+
| st_code | st_date | st_open | st_close | st_volume |
+---------+------------+---------+----------+-----------+
| NFLX | 2018-12-24 | 242.00 | 233.88 | 9547600 |
| NFLX | 2018-12-21 | 263.83 | 246.39 | 21397600 |
| NFLX | 2018-12-26 | 233.92 | 253.67 | 14402700 |
+---------+------------+---------+----------+-----------+
Schema Structure
@Transactional
public Employee get(int id) {
LOGGER.info("Start");
return employeeRepository.findById(id).get();
}
@Transactional
public void save(Employee employee) {
LOGGER.info("Start");
employeeRepository.save(employee);
LOGGER.info("End");
}
Define department in Employee bean with @ManyToOne and @JoinTable annotation. This
defines the relationship between the entities.
@ManyToOne
@JoinColumn(name = "em_dp_id")
private Department department;
The above implementation gets the employee with id 1 and displays the employee details and
department details.
Include testGetEmployee() method in main and comment the other test method calls.
Execute the main method and observe the following:
o In the logs check the lines where the query is generated.
o Since the relationship is defined, hibernate fetches department data as well. The query
should look something like the below. Observe the department table join in this query.
The query is formatted for better readability.
NOTE: SME to explain the learners about Eager Fetch and Lazy Fetch. As per JPA specification by
default, Eager Fetch is applied For ManyToOne and OneToOne relationships. Hence department details
as well is joined and fetched by Hibernate.
Add Employee
Update Employee
Include new instance variable for set of employees and define the OneToMay annotation
@OneToMany(mappedBy = "department")
private Set<Employee> employeeList;
OrmLearnApplication.java
After this change try executing the main() method, which will fetch both department and employee
Include set of skill list in Employee.java with appropriate getter and setter
Include set of employee list in Skill.java with appropriate getter and setter
Include ManyToMany definition in Employee.java as specified below:
@ManyToMany
@JoinTable(name = "employee_skill",
joinColumns = @JoinColumn(name = "es_em_id"),
inverseJoinColumns = @JoinColumn(name = "es_sk_id"))
private Set<Skill> skillList;
@ManyToMany(mappedBy = "skillList")
private Set<Employee> employeeList;
LOGGER.debug("Skills:{}", employee.getSkillList());
Reference - https://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/ch11.html
HQL Solution
// NOTE: HQL looks like SQL, instead of table, Java classes and it's
// instance variables are addressed here
Check the list of SQL queries executed in the log file. Following queries would have got executed.
An optimal solution should not execute multiple queries, we have defined unnecessary fetch
configuration in
Eager fetch configuration is defined for employeeList in Department.java and skillList of
Employee.java
Remove these two eager fetch configurations and check the logs. The following queries would
have got executed. It would have failed when getting the skill list. Since we have remove the
eager fetch skill is not retrieved.
@Query(value="SELECT e FROM Employee e left join e.department d left join e.skillList WHERE e.permanent =
1")
The above query still fails to get skill details. Include fetch after each join. Wherever data is
required we can include fetch, which will populate the respective data. Change the query as
specified below:
@Query(value="SELECT e FROM Employee e left join fetch e.department d left join fetch e.skillList WHERE
e.permanent = 1")
IMPORTANT TAKEAWAY: Join keyword links the table, but does not populate
the beans. Fetch ensures that the beans are populated. Based on our need
wherever we need data, we can define fetch. When joining table data is not
needed the fetch can be ignored.
Username
Attempted Date
All questions as part of the attempt
List of options under each quiz
The option that is correct answer
The score for correct answer
Schema Diagram
Notes on Schema:
Tables user, question and options are self explanatory. They hold the respective master data.
Tables attempt, attempt_question and attempt_option are used to hold the data of attempts made
by each user.
What is the maximum level of heading tag can be used in a HTML page?
1) 5 0.0 false
2) 3 0.0 true
3) 4 0.0 false
4) 6 1.0 false
The HTML document itself begins with <html> and ends </html>. State True of False
1) false 0.0 false
2) true 1.0 true
Include new method with above signature in EmployeeService and include test method in
OrmLearnApplication
The above query does not filter the result based on department id. Modify the query and method
signature as specified below to accept department.
NOTES:
Native queries are direct SQL queries to the database instead of using HQL
Try to avoid Native Queries and make it minimal.
Avoiding native queries helps in easier portability of database
Criteria Query
Find below a online retail user scenario
The where clause varies based on the criteria selected by the user. We have to dynamically frame the
where clause filters based on the criteria selected by user.
Criteria Query helps in handling this scenario in a better way. The filter criteria can be programmatically
added, rather than fixing the HQL Statement.
Go through the examples in the link below to understand how Criteria Query has to be implemented.
https://howtodoinjava.com/hibernate/hibernate-criteria-queries-tutorial/
Demonstrate implementation of RESTful Web Service integrated with Spring Data JPA
o @JsonIgnore, @JsonManagedReference, @JsonBackReference, @JsonIdentityInfo, data transfer objects,
persisting data in POST and PUT methods
Reference to resolve cyclic dependency - https://www.baeldung.com/jackson-bidirectional-
relationships-and-infinite-recursion
Using the approach defined in the previous hands on implement the following REST API services related
to country:
{"code":"IN","name":"India"}
Get country based on keyword with result sorted based on country name
o Endpoint - /countries?key=ambia
o Method - GET
o Expected Output
[{"code":"GM","name":"Gambia"}, {"code":"ZM","name":"Zambia"}]
Add Country
o Endpoint - /countries
o Method - POST
o Request Body - New country details in JSON format {"code":"IN","name":"India"}
o Validations
code is required
code cannot exceed 2 characters
name is required
name cannot exceed 50 characters
o Response - HTTP Status code 200
Update Country
o Endpoint - /countries
o Method - PUT
o Request Body - New country details in JSON format {"code":"IN","name":"India"}
o Same validations as specified for add country
o Response - HTTP Status code 200
Delete Country
o Endpoint - /countries/IN
o Method - DELETE
o Response - HTTP Status code 200
Endpoint - /employees
Method - GET
Expected Result - Due to cyclic dependency of objects, it goes into a recursive loop and it does
not result in the result that we expect. We will look at possible solutions in the next hands on.
Test Cases
Department.employeeList
Skill.employeeList
The above changes will resolve the issue and data will be retrieved as expected. But there is a
disadvantage to this approach. If there is a need to get all employees based on Skill, the employee list
cannot be retrieved due to @JsonIgnore.
Refer implementation available in the link below and check if this solves the cyclic dependency issue.
There is possibility that few employee details are repeated in the result. Hence this might not bean ideal
solution.
https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
Comment out the @JsonManagedReference and @JsonBackReference annotations and try the
@JsonIdentityInfo feature provided in the above link. This goes for a recursive data retrieval and will not
be in the form that we need.
A new set of beans for Employee, Department and Skill needs to be created with DTO suffixed. Then
transfer the data from repository into these new DTO objects and return the EmployeeDTO reference
instead of the entity Employee reference. Follow steps below to implement this approach:
In this method create new EmployeeDTO instance of each Employee. For each employee create
necessary DepartmentDTO and SkillDTO instances. Call respective DTO's setter method to set
the data.
Invoke this method in getAllEmployees() method after getting the employee list from repository.
Return EmployeeDTO reference returned by the above method as return type for
EmployeeController.getAllEmployees() method.
Update Employee
Endpoint - /employees
Method - PUT
Request Body - Employee details in JSON Format
Response - Status 200
Implementation Steps
o Copy necessary repository and service classes
o Implement the REST API in EmployeeController
o Use the existing request availablein Postman to make the PUT call and test if employee
details are getting save
o Kindly note that DTO classes are not required for this implementation. The entity objects
can be directly used.
Add Employee
Endpoint - /employees
Method - PUT
Request Body - Employee details in JSON Format
Response - Status 200
Insert SQL for employee table would have got executed successfully
After that it would have failed due to non-availability of department id
If we go to the database and check employee table, the newly inserted record will not be existing
Due to failure to update the department details, the insertion had got rolled back
Create relevant tables for storing user and role in ormlearn schema. (Refer the ER diagram in the
end)
Create classes User and Role with necessary many-to-many mapping
Define roleList in User with eager fetch
Create UserRepository with inclusion of a Query Method 'findByUsername' to get an user based
on username.
In user table create two users one for user and one for admin
Make the password
as $2a$10$R/lZJuT9skteNmAku9Y7aeutxbOKstD5xE5bHOf74M2PHZipyt3yK, which is the
bcrypt encoding of the text 'pwd'
Test if findByUsername() method works fine and retrieves the user and roles
AppUser.java
This new bean class has to be implement UserDetails class of spring security framework, so that spring
framework can read user details from this bean. Refer steps below to implement.
Create bean class AppUser to hold the user details. This needs to be implement UserDetails
class of spring security framework, so that spring framework can read user details from this bean.
Refer steps below to implement:
Right click on com.cognizant.spring-learn.security > New > Class
Enter "Name" as "AppUser"
In "Interfaces" click "Add.." and select "org.springframework.security.core.userdetails.UserDetails"
Click Finish
The above steps will create AppUser class and populate the code with all the methods that needs
to be implemented.
Include below instance variables in this class:
Create a constructor with user as parameter. Obtain the roles from the user and convert them to
authorities. Refer code below for authorities conversion that needs to be included in the
constructor.
this.authorities = user.getRoleList().stream()
.map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());
The above code converts the list of roles into a list of SimpleGrantedAuthority.
Return authorities in getAuthorities() method
Return user.getPassword() in getPassword() method
Return true in all the below methods:
o isAccountNonExpired()
o isAccountNonLocked()
o isCredentialsNonExpired()
o isEnabled()
AppUserDetailsService.java
SecurityConfig.java
Autowire AppUserDetailsService
In configure() method, comment out the in memory definition and bind spring framework to use
the appUserDetailsService for authentication.
auth.userDetailsService(appUserDetailsService).passwordEncoder(passwordEncoder());
Let us try to understand this with an example. Consider a Service method that calls a method in
Repository. The service method is dependent on repository and the repository is dependent on
database. When we have to test a service method, we should test it without the dependency on
repository.
A good unit test should be isolated. Avoid dependencies such as environment settings, register
values, or databases.
In this code below, find out the lines that has dependency on repository and database.
SME to walkthrough each line of the above code and identify the lines that has dependency.
In the subsequent hands on we will identify how to avoid the dependency using mockito.
@RunWith(SpringRunner.class)
@SpringBootTest
Autowire UserDetailsService and implement the below test method. This method validates if the
password returned is as per what is available in the database.
@Test
public void testLoadByUserName() {
LOGGER.info("Start");
UserDetails user = userDetailsService.loadUserByUsername("usr");
String expected = "$2a$10$R/lZJuT9skteNmAku9Y7aeutxbOKstD5xE5bHOf74M2PHZipyt3yK";
assertEquals(expected, user.getPassword());
LOGGER.info("End");
}
Execute this as JUnit Test Case by right clicking on this test class and selecting Run > JUnit Test
Check the logs to see that the service calls repository and it retrieves the data from database
Ask yourself the following questions:
o Is this method executed in isolation?
o Is this test unit testing?
In the next hands on we will see how to isolate the testing using Mockito.
Our unit test cases should ensure that all the lines and all possible scenarios are tested.
Using below line of code define what happens when findByUsername() method in repository is
called. This is how we are isolating the dependency.
when(repository.findByUsername("usr")).thenReturn(createUser());
Due to the above defintion the database call will not happen, we need to simulate the return of
User as part of this call. We achieve this by using a new createUser() method that takes care of
creating a user instance with necessary password and role that is expected. Implement this
method within the test class.
Create a new constructor in AppUserDetailsService that accepts UserRepository as input and
sets the userRepository instance variable.
Create AppUserDetailsService instance using the mocked repository
Invoke the method we want to test. When this method is executed, the repository's find method
will not be invoke, but mockito will just return whatever is returned by createUser() method.
Run the class as JUnit test and check if the test passes.
Implement the mockito test for the second scenario when user is returned as null
Currently the above implementations are done with in memory static data.
Using repository and appropriate beans implement this with repository and service.
Test in the angular application to see if the features work end to end.
Currently the above implementations are done with in memory static data.
Using repository and appropriate beans implement this with repository and service.
Test in the angular application to see if the features work end to end.
This component should have a text box and a div in the bottom of the text box. This div will list the
countries that matches with the keyword entered in text box. The countries within the div needs to be
displayed line by line.
Create necessary service in angular application that invokes the respective REST API created for
returning the country list based on keyword.
This REST API needs to be called on the key press event of the search text box.