In Hibernate (or JPA in general), the @Embeddable
and @Embedded
annotations are used to help manage object-relational mapping for complex types (value types) within entities. These annotations allow you to define reusable and nested objects that don’t require their own database table but are saved as part of the owning entity.
Here’s how to use them:
- Define an embeddable class:
A class annotated with@Embeddable
is a value type that can be embedded in an entity. It cannot exist independently in the database — its lifecycle is tied to the owning entity. - Use the
@Embedded
annotation in the entity:
The@Embedded
annotation is used to include an instance of the embeddable class in an entity. - Mapping fields of the
@Embeddable
class:
The fields of the embeddable class are mapped to columns in the table of the owning entity.
Example Usage:
Step 1: Define the Embeddable Class
package org.kodejava.hibernate;
import jakarta.persistence.Embeddable;
@Embeddable
public class Address {
private String street;
private String city;
private String state;
private String zipCode;
// Constructors, getters, and setters
public Address() {}
public Address(String street, String city, String state, String zipCode) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getState() { return state; }
public void setState(String state) { this.state = state; }
public String getZipCode() { return zipCode; }
public void setZipCode(String zipCode) { this.zipCode = zipCode; }
}
Step 2: Use the @Embedded
Class in an Entity
package org.kodejava.hibernate;
import jakarta.persistence.*;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@Embedded
private Address address;
// Constructors, getters, and setters
public Employee() {}
public Employee(String name, Address address) {
this.name = name;
this.address = address;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
}
Step 3: Saving and Retrieving Data
Here is how you can interact with the entity and the embeddable in your code:
package org.kodejava.hibernate;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class MainApp {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// Create an Address object
Address address = new Address("123 Main St", "Springfield", "IL", "62704");
// Create an Employee object with an embedded Address
Employee employee = new Employee("John Doe", address);
// Persist the Employee object
em.persist(employee);
em.getTransaction().commit();
// Retrieve and display the Employee and Address information
Employee retrievedEmployee = em.find(Employee.class, employee.getId());
System.out.println("Employee Name: " + retrievedEmployee.getName());
System.out.println("Employee Address: " + retrievedEmployee.getAddress().getStreet());
em.close();
emf.close();
}
}
Step 4: META-INF/persistence.xml
Here is an example of a persistence.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_1.xsd"
version="3.1">
<!-- Define a persistence unit -->
<persistence-unit name="my-persistence-unit" transaction-type="RESOURCE_LOCAL">
<!-- Specify the entity classes of the project -->
<class>org.kodejava.hibernate.Employee</class>
<class>org.kodejava.hibernate.Address</class>
<!-- Database connection properties -->
<properties>
<!-- JDBC connection settings -->
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="jakarta.persistence.jdbc.user" value="sa"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<!-- Hibernate-specific properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- Options: create, update, validate, none -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
Notes:
- You can further customize the column names for fields in the embeddable class by using the
@AttributeOverrides
and@AttributeOverride
annotations.For example:
@Embedded @AttributeOverrides({ @AttributeOverride(name = "street", column = @Column(name = "home_street")), @AttributeOverride(name = "city", column = @Column(name = "home_city")) }) private Address homeAddress;
In this example, the
street
andcity
fields fromAddress
are mapped to custom column names in the database table. -
You can embed the same embeddable class in multiple entities, promoting code reuse.
- The embeddable class must have a default (no-arg) constructor because JPA requires it for instantiation.
By using @Embeddable
and @Embedded
, you can cleanly separate reusable pieces of data and map them effectively to your relational database.
Maven Dependencies
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.4.Final</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>