Hibernate @Embeddable and @Embedded Annotation Example
In this tutorial we show how to embed one entity inside another entity, so they are mapped to a single table. With Hibernate we can use the @Embeddable
annotation to mark a class to be eligible as an embeddable class. We can use the @Embedded
annotation to embed an embeddable class. The attributes of embedded class can be overridden using the @AttributeOverrides
and the @AttributeOverride
annotations. Let’s see how this works, by following this example.
Maven Dependencies
We use Apache Maven to manage the projects dependencies. Add the following dependencies to your projects pom.xml
file.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.3.Final</version>
</dependency>
Creating an Embeddable Class using @Embeddable
Let’s presume we want to embed the following Address
class inside another class. The advantage of using embedded objects is that they are reusable and you can map two entities to the same database table.
package com.memorynotfound.hibernate;
import javax.persistence.Embeddable;
@Embeddable
public class Address {
private String street;
private String city;
private String zip;
private String state;
public Address() {
}
public Address(String street, String city, String zip, String state) {
street = street;
this.city = city;
this.zip = zip;
this.state = state;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public String toString() {
return "Address{" +
"street='" + street + '\'' +
", city='" + city + '\'' +
", zip='" + zip + '\'' +
", state='" + state + '\'' +
'}';
}
}
Embedding an Embeddable object with @Embedded
We can simply embed an embeddable class using the @Embedded
annotation. This class will be embedded in the same database table as the source. We can optionally override the attributes of the embedded class using the @AttributeOverrides
and @AttributeOverride
annotation. We first specify – by name – which attribute we wish to override. Afterwards we can override the attribute by using the @Column
annotation.
package com.memorynotfound.hibernate;
import javax.persistence.*;
import java.util.Date;
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name = "zip", column = @Column(length = 10)),
@AttributeOverride(name = "city", column = @Column(nullable = false))
})
private Address address;
public Person() {
}
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", address=" + address +
'}';
}
}
Embedding an Embeddable object using Hibernate HBM XML Configuration
If you prefer Hibernate XML HBM Mapping files over Annotations, you can use the equivalent hibernate xml mapping. This file is located in the src/main/resources
folder and is named Person.hbm.xml
.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.memorynotfound.hibernate.Person">
<id name="id" type="java.lang.Integer">
<generator class="identity" />
</id>
<property name="name"/>
<component name="address">
<property name="zip" length="10"/>
<property name="city" not-null="true"/>
</component>
</class>
</hibernate-mapping>
Configure Hibernate Connection Properties
We can configure the database properties using the hibernate hibernate.cfg.xml
file, located on the classpath in the src/main/resources
folder.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- database connection properties -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/datestore?serverTimezone=Europe/Brussels</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- show mysql queries output in console -->
<property name="hibernate.show_sql">true</property>
<!-- manage automatic database creation -->
<property name="hibernate.hbm2ddl.auto">create-drop</property>
<!-- add annotated resources here-->
<mapping class="com.memorynotfound.hibernate.Person"/>
</session-factory>
</hibernate-configuration>
HibernateUtil
This class is used to configure hibernate during startup and create a standalone SessionFactory
.
package com.memorynotfound.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}
public static void shutdown() {
sessionFactory.close();
}
}
Running and Testing Embeddable Objects
When we execute the following application, a record will be added to the database.
package com.memorynotfound.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.Arrays;
import java.util.List;
public class App {
public static void main (String...args){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
Address address = new Address("street", "city", "1234", "state");
Person person = new Person("John Doe", address);
session.save(person);
tx.commit();
List<Person> activities = (List<Person>)session.createQuery("from Person").list();
System.out.println(Arrays.toString(activities.toArray()));
session.close();
HibernateUtil.shutdown();
}
}
The previous application prints the following output to the console.
...
Hibernate: insert into Person (street, city, state, zip, name) values (?, ?, ?, ?, ?)
Hibernate: select person0_.id as id1_0_, person0_.street as street2_0_, person0_.city as city3_0_, person0_.state as state4_0_, person0_.zip as zip5_0_, person0_.name as name6_0_ from Person person0_
[Person{id=1, name='John Doe', address=Address{street='street', city='city', zip='1234', state='state'}}]
...
A new record is added to the database. Note: that the embeddable object is embedded in the same database table.