Why don’t browsers support PUT and DELETE requests ?

why-dont-browsers-support-put-and-delete-requests

Browsers do support PUT and DELETE, but it is HTML that doesn’t.

This is because HTML 4.01 and the final W3C HTML 5.0 spec both say that the only HTTP methods that their form elements should allow are GET and POST.

Web pages trying to use forms with method="PUT" or method="DELETE" would fall back to the default method, GET for all current browsers. This breaks the web applications’ attempts to use appropriate methods in HTML forms for the intended action, and ends up giving a worse result — GET being used to delete things!

PUT as a form method makes no sense, you wouldn’t want to PUT a form payload. DELETE only makes sense if there is no payload, so it doesn’t make much sense with forms either.

Conclusion

If using web browser to test a rest api of http method PUT or DELETE, it will not work and would fall back to default GET method and hence the REST API URL will not give proper response.


Spring boot Exception Handling – Using @ExceptionHandler @ControllerAdvice

In this tutorial of Spring boot Exception Handling we will see how to create own custom exception handler and a mechanism to handle various kinds of exceptions in REST endpoints.

And in the below exception handler you can add your own thought of methods to handle exceptions.

Let’s Begin

1. RestController – Create

@GetMapping("/dependant/dept-id/{id}")
@ResponseBody
public Dependant getDependantbyId(@PathVariable int id){

	if(id>10){
		throw new MyCustomException("the id is not in range");
	}
	Dependant dept = new Dependant();
	dept = dependantRepository.findBydeptid(id);

	return dept;
}

2. Custom Exception Class – Create

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

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class MyCustomException extends RuntimeException {

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

3. Controller Advice – Custom Exception Handler

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
  
	System.out.println("Inside handleAllExceptions() method of CustomExceptionHandler");
	return new ResponseEntity("This is a General Exception....", HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(MyCustomException.class)
public final ResponseEntity<Object> handleUserNotFoundException(MyCustomException ex, WebRequest request) {
	
	System.out.println("Inside handleUserNotFoundException() method of CustomExceptionHandler method");
	return new ResponseEntity("This is MyCustomException.....", HttpStatus.NOT_FOUND);
}

}

OUTPUT

GET API : http://localhost:8080/api/dependant/dept-id/11

Considering id=11 is not present in the database

We handle this exception using Handler – below is the output of the above code

Status : 404 Not Found

This is MyCustomException…..

Summary

In this tutorial, we learnt how to create own custom exception handler and a mechanism to handle various kinds of exceptions in REST endpoints.

We Used spring annotations to achieve that using @ExceptionHandler, @ControllerAdvice.

I hope you liked it !


Angular : How to make REST API Calls ?

In this tutorial we will learn about Angular REST API Calls.

Note : Module to be used for REST API Call

import { HttpClientModule } from '@angular/common/http';

In src/app/app.module.ts file import HttpClientModule and add it to the imports array:

...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    // [...]
    HttpClientModule,
  ],
  // [...]
})
export class AppModule { }

SERVICE class : to write all the CRUD API requests

import {Injectable} from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
 
const httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
 
@Injectable()
export class ApiService {
 
    constructor(private http:HttpClient) {}
}

GET API Request in Angular

Now adding a get method in ApiService for the GET API request.

    // Uses http.get() to load data from a single API endpoint
    getEmployees() {
        return this.http.get('/api/employees');
    }

Our ApiService makes the HTTP request and returns an Observable object. To actually get the data from the service, we need to update our component to subscribe to the Observable. Lets check below.

app.component.ts

ngOnInit() {
    this.getEmployees();
  }
 
  getEmployees() {
   this._apiService.getEmployees().subscribe(
      data => { this.employees = employees },
      err => console.error(err),
      () => console.log('done loading employees')
    );
  }
}

The subscribe() method takes three arguments which are event handlers. They are called onNext, onError, and onCompleted.

The onNext method will receive the HTTP response data. Observables support streams of data and can call this event handler multiple times. In the case of the HTTP request, however, the Observable will usually emit the whole data set in one call.

The onError event handler is called if the HTTP request returns an error code such as a 404.

The onCompleted event handler executes after the Observable has finished returning all its data. This is less useful in the case of the Http.get() call, because all the data we need is passed into the onNext handler.

Other HTTP Request : PUT, Delete, POST http requests

Now we will write other HTTP methods like PUT, POST and DELETE in our ApiService layer.

@Injectable()
export class ApiService {
 
    constructor(private http:HttpClient) {}
 
    ...
 
    createEmployee(employee) {
        let body = JSON.stringify(employee);
        return this.http.post('/api/employee/', body, httpOptions);
    }

    updateEmployee(employee) {
        let body = JSON.stringify(employee);
        return this.http.put('/api/employee/' + employee.id, body, 
                             httpOptions);
    }

    deleteEmployee(employee) {
        return this.http.delete('/api/employee/' + employee.id);
    }
 
}

Retrying – retry GET API call on fail

Sometimes the error is transient and will go away automatically if you try again. For example, network interruptions are common in mobile scenarios, and trying again may produce a successful result.

The RxJS library offers several retry operators that are worth exploring. The simplest is called retry() and it automatically re-subscribes to a failed Observable a specified number of times. Re-subscribing to the result of an HttpClient method call has the effect of reissuing the HTTP request.

Pipe it onto the HttpClient method result just before the error handler.

getConfig() {
  return this.http.get<Config>(this.configUrl)
    .pipe(
      retry(3), // retry a failed request up to 3 times
      catchError(this.handleError) // then handle the error
    );
}

Executing multiple concurrent HTTP requests – using forkJoin ()

Many times, we need to load data from more than one source, and we need to delay the post-loading logic until all the data has loaded. ReactiveX Observables provide a method called forkJoin() to wrap multiple Observables. Its subscribe() method sets the handlers on the entire set of Observables.

...

@Injectable()
export class ApiDemoService {
 
    constructor(private http:HttpClient) {}
 
    // Uses Observable.forkJoin() to run multiple concurrent http.get() 
    // requests.
    // The entire operation will result in an error state if any single 
    // request fails.
    
    getEmployeesAndRole() {
        return Observable.forkJoin(
        this.http.get('/api/employees'),
        this.http.get('/api/roles')
        );
    }
}

Now subscribe to the service

export class AppComponent {
 
+  public employees;
+  public roles;

 
+  getEmployeesAndRole() {
+    this._apiDemoService.getEmployeesAndRole().subscribe(
+      data => {
+        this.employees= data[0]
+        this.roles= data[1]
+      }
+      // No error or completion callbacks here. They are optional, but
+      // you will get console errors if the Observable is in an error state.
+    );
+  }
 
}

Summary

In this tutorial we learnt about Angular REST API Calls. We saw examples of all the CRUD api calls in angular, we saw how to retry an api call on fail and we also learnt how to make multiple concurrent HTTP requests using forkJoin Observable method.
I hope you liked it !


Hibernate Entity Object States | LifeCycle States

Hibernate Entity persistent object can be in four different states transient, persistent, detached.

Hibernate basically works on a java object and that java object when linked with hibernate annotations passes through these states in its complete lifecycle.

Let’s look at all the Three lifecycle states:

1. Transient Object

An object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session.

Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes.

2. Persistent Object

Persistent objects exist in the database, and Hibernate manages the persistence for persistent objects.

3. Detached Object

A detached instance is an object that has been in the persistent state, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state.

Summary

In this article we read about the Hibernate Entity Object States or the LifeCycle States, how hibernate maintains the lifecycle of an entity object.
I hope you liked the article !


Hibernate Native Query with example

You can express a query in SQL, using createSQLQuery() and let Hibernate manage the mapping from result sets to objects.

Although we should use HQL wherever possible but there could be a few reasons where you want to use native SQL funtionalities, such as :

  1. Calling stored procedures
  2. Calling stored functions
  3. DB support some special features which are not present in HQL

How to write a native query in hibernate ?

You can specify all properties on an object with {objectname.*}, or you can specify the aliases directly with {objectname.property}.

public SQLQuery createSQLQuery(String queryString) throws 
                                                                                                   HibernateException

If using Oracle DB: using ROWNUM

List emps = session.createSQLQuery("SELECT {emp.*} FROM Employee 
                {emp} WHERE ROWNUM<10")
                .addEntity("emp", Employee.class)
                .list();
        System.out.println("Native Query result list :: "+emps);

If using mySql DB: using LIMIT

List emps = session.createSQLQuery("SELECT {emp.*} FROM Employee 
                {emp} LIMIT 10")
                .addEntity("emp", Employee.class)
                .list();
        System.out.println("Native Query result list :: "+emps);

Output

Native Query result list ::
[Employee{id=2, firstName='Mak', lastName='S', address='mak@pt.com'}, 
Employee{id=3, firstName='Mak', lastName='S', address='mak@pt.com'},  
Employee{id=4, firstName='mak', lastName='robins', address='NA'}]

Summary

In this article, we looked into Hibernate Native Query with some example, the reason why to use native query and when to use it.
I hope you liked the article !


Hibernate Interceptors with Example

In Hibernate, interceptors are used to inspect the changes in entity’s property values before they are written and after they are read from a database.

You can use the Hibernate interceptor to perform the various operations such as logging, auditing, profiling etc.

1. Registering Interceptors

In Hibernate, an interceptor can either be Session-scoped or SessionFactory-scoped.

1. Session-scoped interceptors are used when a Session is opened. The following code snippet shows how to add an interceptor to a Session.

Session session = HibernateUtil.getSessionFactory()
	.withOptions()
	.interceptor(new MyLogInterceptor())
	.openSession();

2. SessionFactory-scoped or global interceptors are used when SessionFactory is configured and these interceptors will be applied to applied to all Session opened from that SessionFactory. The following code snippet shows how to add an interceptor to a SessionFactory.

SessionFactory sessionFactory = metadata.getSessionFactoryBuilder()
	.applyInterceptor(new MyLogInterceptor())
	.build();

2. How to Create Hibernate Interceptors?

There are two ways of defining interceptors:

1. implementing the org.hibernate.Interceptor interface
2. extending the org.hibernate.EmptyInterceptor class 

There are around 14 callback methods which the interceptor provides for us to override and use.

Some of them are onLoad, onDelete, onSave, onFlushDirty, findDirty, etc

If you are creating your interceptor implementing the Interceptor interface then you may need to override all the methods provided.

Instead of implementing this interface directly, it is usually better to extend EmptyInterceptor and override only the callback methods of interest.

3. Example Hibernate Interceptor

1. Create Interceptor Class

By extending EmptyInterceptor Class

import com.pt.entities.Employee;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import java.io.Serializable;

public class MyLogInterceptor extends EmptyInterceptor {

    public boolean onSave(Object entity, Serializable id, Object[] state,
                          String[] propertyNames, Type[] types) {
        if (entity instanceof Employee) {
            Employee emp = (Employee) entity;
            System.out.println(emp.toString());
        }
        return super.onSave(entity, id, state, propertyNames, types);
    }
}

2. Employee Entity looks like this

Create your own set of Entity class like this.

@Entity
@Table(name = "Employee")
@NamedQueries({
        @NamedQuery(name = "Employee.findAll", query = "from Employee emp"),
        @NamedQuery(name = "Employee.findByName",
                query = "from Employee emp where emp.firstName=:firstName"),
})
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

// getters & setters & toString()
// ...
}

3. Create HibernateUtility Class – to create session a session factory

Below is the code of HibernateUtility Class – in this we are creating a sessionfactory and registering our Employee Enitity class.

package com.pt.standalone;

import com.pt.entities.Employee;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;

import java.util.HashMap;
import java.util.Map;

public class HibernateUtility {

    private static StandardServiceRegistry registry;
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {

                // Create registry builder
                StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();

                // Hibernate settings equivalent to hibernate.cfg.xml's properties
                Map<String, String> settings = new HashMap<>();
                settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver");
                settings.put(Environment.URL, "jdbc:mysql://localhost:3306/testdb");
                settings.put(Environment.USER, "root");
                settings.put(Environment.PASS, "root");
                settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL57Dialect");

                // Apply settings
                registryBuilder.applySettings(settings);

                // Create registry
                registry = registryBuilder.build();

                // Create MetadataSources
                MetadataSources sources = new MetadataSources(registry).addAnnotatedClass(Employee.class);

                // Create Metadata
                Metadata metadata = sources.getMetadataBuilder().build();

                // Create SessionFactory

                sessionFactory = metadata.getSessionFactoryBuilder().build();
            } catch (Exception e) {
                e.printStackTrace();
                if (registry != null) {
                    StandardServiceRegistryBuilder.destroy(registry);
                }
            }
        }
        return sessionFactory;
    }

    public static void shutdown() {
        if (registry != null) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}

4. Run – main method Class

Now run the main class.

import com.pt.entities.Employee;
import org.hibernate.Session;

public class TestHB {

    public static void main(String[] args) {

        Session session = HibernateUtility.getSessionFactory().withOptions().
                interceptor(new MyLogInterceptor()).openSession();
        session.beginTransaction();
        
        System.out.println("Save Employee...");

        // saving an object
        Employee emp = new Employee(10,"mak","robins","NA");
        session.save(emp);
  }
}

5. Output

Save Employee...
Employee{id=10, firstName='mak', lastName='robins', address='NA'}

Summary

In this article, we learnt about Hibernate Interceptors, how to create hibernate interceptors, its various uses and a working example.
I hope you liked it !


Hibernate Named Query

Hibernate Named Queries are created via class-level annotations on entities; normally, the queries apply to the entity in whose source file they occur, but there’s no absolute requirement for this to be true.

Named queries are created with the @NamedQueries annotation, which contains an array of @NamedQuery sets; each has a query and a name.

Example :

@Entity
@Table(name = "Employee")
@NamedQueries({
        @NamedQuery(name = "Employee.findAll", query = "from Employee emp"),
        @NamedQuery(name = "Employee.findByName",
                query = "from Employee emp where emp.firstName=:firstName"),
})
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

// getters & setters & toString()
// ...
}

Executing above named query  :

Query namedQuery = session.getNamedQuery("Employee.findAll");
List<Employee> employees = namedQuery.list();
employees.forEach(System.out::println);  

Summary

In this tutorial, we learnt about what is hibernate named query and understood by seeing an example of how to declare a named query.
I hope you liked it !


Hibernate Query Language | HQL examples

Hibernate Query Language a.k.a HQL is a query language which deals directly with the persistent entity object instead of the database table directly.

In this section we will see what is hibernate query language, syntax to write various kinds of HQL like Select, updates, insert, delete.

Syntax

Query query=session.createQuery("HQL query comes here....Example.... 
FROM Employee set age=:age where name=:name");

1. SELECT Query

You can write it as “Select * from employee” or as “From Employee”.

Example:

Query query = session.createQuery("From Employee");
List<Employee> list = query.getResultList();

2. Update Query

Example:

Query query=session.createQuery("update Employee 
                                set age=:age where name=:name");
query.setInteger("age", 30);
query.setString("name", "John Doe");
int result=query.executeUpdate();
System.out.println("Rows affected: " + result);

3. Insert Query

Example:

String hql = "INSERT INTO Employee(firstName, lastName, address)"
           + "SELECT firstName, lastName, address FROM old_employee"
           + "where id=:id";
Query query = session.createQuery(hql);
query.setString("id", 101);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

4. Delete Query

Example:

String hql = "DELETE FROM Employee "  + 
             "WHERE id = :emp_id";
Query query = session.createQuery(hql);
query.setParameter("emp_id", 101);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

5. Pagination in HQL Query

Two methods to set the start and end positions.

Query setFirstResult(int startPosition) : start index position
Query setMaxResults(int maxResult) : number of results from the index set above

Example:

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(5);
query.setMaxResults(10);
List results = query.list();

6. Aggregate functions in HQL Query

The aggregate functions available in HQL includes the following:

  1. avg(property name): The average of a property’s value.
  2. count(property name or *): The number of times a property occurs in the results.
  3. min(property name): The minimum value of the property values.
  4. max(property name): The maximum value of the property values.
  5. sum(property name): The sum total of the property values.

Example:

String hql = "SELECT count(distinct Emp.firstName) FROM Employee Emp";
Query query = session.createQuery(hql);
List results = query.list();

Summary

In this tutorial we learnt how to write HQL(hibernate query language) which is simple, easy for java developers. We went through CRUD operations syntax and examples in HQL, then went through the pagination and aggregate functions with examples.
I hope you liked it !


Hibernate Cache Levels

Hibernate has 2 Cache’s, First level default session cache and the Second level explicitly configured cache. The main purpose of Cache’s is to reduce the number of Database hits from the application.

In this tutorial, You will find a very Simple easy to follow example using ehcache configuration as second level cache in hibernate.

When does Hibernate Use Second level Cache ?

  1. When Hibernate Session try to load an entity, it looks for the value in first level cache. If the cached copy is present in the first level cache then it is returned on call to load() method.
  2. If there is no cached entity in first level cache then it looks in the second level cache. If the entity is cached in second level then it is returned as result of load() method. But before returning the entity, it is stored in first level cache, so that for the next invocation the entity is loaded from the first level cache and not the second again.
  3. If the entity is not found in first and the second level cache, then the entity data is fetched from the database itself and is also stored in both the caches before returning the response.

How do cache verify updated data ?

  1. Second level cache validate itself for modified entities, if modification has been done through hibernate session APIs.
  2. But in some cases where someone modifies the data directly inside the database then that data will not be cached itself in the second level cache until “timeToLiveSeconds” duration has passed for that cache region. In that case, you can invalidate the cache and let hibernate build it again.

Configure EhCache

1. Add ehcache dependency in pom.xml

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-ehcache</artifactId>
     <version>5.4.11.Final</version>
</dependency>

2. Add ehcache properties in properties file

You can add the cache properties in any property files like the “application.properties” or you name it anything and keep it in the resource folder of the project.

In this example, i have placed the properties in a file called “db.properties”.

# Hibernate Second level Cache
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory

3. Add @ annotations in Entity Objects Class

For Example : Employee.java

add @Cacheable & @org.hibernate.annotations.Cache

package com.pt.entities;

import org.hibernate.annotations.CacheConcurrencyStrategy;

import javax.persistence.*;

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

    public Employee() {}

    public Employee(int id, String firstName, 
                    String lastName, String address) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    public int getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName( String first_name ) {
        this.firstName = first_name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName( String last_name ) {
        this.lastName = last_name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

4. Service method call

In the basic code example in our previous tutorial add the below method in DAO implementation layer.

We will create 2 sessions and try to load the same Employee for example of id=6.

private void getEmployee() {

System.out.println("We are inside getEmployee method...");

Session session = sessionFactory.openSession();
Employee emp = session.load(Employee.class,6);
System.out.println("Employee load 1st time");
System.out.println(emp.getId()+" "+emp.getFirstName()+" "
                   +emp.getLastName());

Session session2 = sessionFactory.openSession();
Employee emp2 = session2.load(Employee.class,6);
System.out.println("Employee load 2nd time");
System.out.println(emp2.getId()+" "+emp2.getFirstName()+" "
                   +emp2.getLastName());

}

5. Output

Observation : Please see carefully in the below output, you will find there is only one select query on 1st load time, and no select query call on second call of load method,
this means that 1st time when the entity is loaded, it is being loaded from the database and internally also sent to both the caches before returning the entity object, but the 2nd time the data was loaded from the second level Cache itself(why not from the First level cache – the answer is because since we are using 2 different session objects in this example).

INFO: HHH000490: Using JtaPlatform implementation: 
 [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
We are inside getEmployee method...
Employee load 1st time
Hibernate: select employee0_.id as id1_0_0_, employee0_.address as 
address2_0_0_, employee0_.first_name as first_na3_0_0_, 
employee0_.last_name as last_nam4_0_0_ from EMPLOYEE employee0_ 
where employee0_.id=?
6 Mak S
Employee load 2nd time
6 Mak S

Summary

In this tutorial, we learnt and experienced in details how hibernate cache’s work. Try out the above code in your system and let us know your experience in comments.
I hope you liked it !


Hibernate Entity Mappings

Now as you you have seen in the previous article how to create an Entity, now let’s see how to create relationships between Entities also called as Entity mappings, JPA defines four annotations for defining entities:

1. @OneToOne
2. @OneToMany
3. @ManyToOne
4. @ManyToMany

1. One-to-one relationships

The @OneToOne annotation is used to define a one-to-one relationship between two entities.

For example, you have a table EMPLOYEE and you want to store employee’s personal information(such as age, gender and grade) in another table, in that case you create another Entity and map both the entities by @OneToOne mapping, one instance of an Employee Entity class mapped to one instance of EmployeeProfile Entity.

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;
	
    @OneToOne(mappedBy="emp")
    private EmployeeProfile profile;
	...
	
}
@Entity
public class EmployeeProfile {
   @Id
   private Integer id;
   private int age;
   private String gender;
   private String grade;
   @OneToOne
   private Employee emp;
   ...
}

The JPA provider uses EmployeeProfile’s emp field to map EmployeeProfile to Employee. The mapping is specified in the mappedBy attribute in the @OneToOne annotation.

2. One-to-many and many-to-one relationships

The @OneToMany and @ManyToOne annotations facilitate both sides of the same relationship.

Here’s an example where one Employee can have multiple Projects and a Project may have many other employees as well.
The Employee entity would define a @ManyToMany relationship with Project and the Project Entity would define a @OneToMany relationship with an Employee.

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

	@ManyToOne
    @JoinColumn(name="PROJECT_ID")
    private Project project;
	...
}
@Entity
public class Project {
   @Id
   private Integer projectId;
   private String projectDescription;
   private String projectDuration;
   @OneToMany(mappedBy = "project")
   private List<Employee> emp = new ArrayList<>();
   ...
}

3. many-to-many relationships

Here’s a case where an Employee entity has many projects.

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "EMP_ID")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

	@ManyToMany
    @JoinTable(name="EMP_PROJECTS",
    		   joinColumns=@JoinColumn(name="EMP_ID"),
    		   inverseJoinColumns=@JoinColumn(name="PROJECT_ID"))
    private Set<Project> projects = new HashSet<>();
	...
}
@Entity
public class Project {
   @Id
   private Integer projectId;
   private String projectDescription;
   private String projectDuration;
  
   @ManyToMany(mappedBy = "projects")
   private Set<Employee> projects = new HashSet<>();
   ...
}

In this example, we create a new table, EMP_PROJECTS, with two columns: EMP_ID and PROJECT_ID. Using the joinColumns and inverseJoinColumns attributes tells your JPA framework how to map these classes in a many-to-many relationship. The @ManyToMany annotation in the Employee class references the field in the Project class that manages the relationship; namely the projects property.

Summary

In this article we looked into the relational mapping between tables or entities in a JPA ORM way.
Hope you liked it !