JPA / Hibernate @Embeddable and @Embedded Example with Spring Boot
Spring BootNovember 25, 20173 mins readIn this article, you’ll learn how to use Embeddable types in hibernate to map a linear database table into an Entity class composed of various value types.
Consider the following table which stores information about the users of an application. The information includes user’s basic details like name, email and his address -
From the database perspective, the table structure is fine. But If we need to map this table into an entity class in our application, we might want to abstract out the Name
and Address
details into separate classes for better abstraction and re-usability -
Embeddable types can be re-used across your project by any number of entities. We’ll create a project from scratch and learn how to map the above users
table into an entity class that abstracts out the name and address details into separate classes.
Creating the Application
We’ll use Spring Boot CLI to generate our application. Open your terminal and type the following command to generate the application -
spring init -n=jpa-embeddable-demo -d=web,jpa,mysql --package-name=com.example.jpa jpa-embeddable-demo
You can also use Spring Initializr web app to generate the application. Follow the instructions below to generate the app using Spring Initializr web tool -
- Head over to http://start.spring.io
- Enter Artifact as “jpa-embeddable-demo”
- Click Options dropdown to see all the options related to project metadata.
- Change Package Name to “com.example.jpa”
- Select Web, JPA and Mysql dependencies.
- Click Generate to generate and download the project.
Following is the directory structure of the complete application for your reference -
Your bootstrapped project won’t have model
and repository
packages and all the other classes at this point. We’ll create them as we proceed to the next sections.
Configuring the Database and Hibernate Log levels
We’ll need to configure the MySQL database URL, username, and password. Open src/main/resources/application.properties
file and add the following properties to it -
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_embeddable_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
I have specified the Hibernate’s ddl-auto
property to update
. This will automatically create/update the database tables whenever we update the corresponding entity class in our application.
Note that, You’ll need to create a database named jpa_embeddable_demo
. Also, don’t forget to change the spring.datasource.username
and spring.datasource.password
properties as per your MySQL installation.
Defining the Domain Model
Let’s first define the embeddable types that will be embedded in the User
model. We’ll create a package named model
inside com.example.jpa
package and add all the model classes in this package.
Embeddable Types
We use JPA’s @Embeddable
annotation to declare that a class is meant to be embedded by other entities.
1. Name
package com.example.jpa.model;
import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Embeddable
public class Name {
@NotNull
@Size(max = 40)
private String firstName;
@Size(max = 40)
private String middleName;
@Size(max = 40)
private String lastName;
public Name() {
}
public Name(String firstName, String middleName, String lastName) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
}
// Getters and Setters (Omitted for brevity)
}
2. Address
package com.example.jpa.model;
import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Embeddable
public class Address {
@NotNull
@Size(max = 100)
private String addressLine1;
@NotNull
@Size(max = 100)
private String addressLine2;
@NotNull
@Size(max = 100)
private String city;
@NotNull
@Size(max = 100)
private String state;
@NotNull
@Size(max = 100)
private String country;
@NotNull
@Size(max = 6)
private String zipCode;
public Address() {
}
public Address(String addressLine1, String addressLine2, String city,
String state, String country, String zipCode) {
this.addressLine1 = addressLine1;
this.addressLine2 = addressLine2;
this.city = city;
this.state = state;
this.country = country;
this.zipCode = zipCode;
}
// Getters and Setters (Omitted for brevity)
}
User Entity
Let’s now create the User
model that will embed the Name
and Address
types -
package com.example.jpa.model;
import org.hibernate.validator.constraints.Email;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private Name name;
@NotNull
@Email
@Column(unique = true)
private String email;
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name = "addressLine1", column = @Column(name = "house_number")),
@AttributeOverride(name = "addressLine2", column = @Column(name = "street"))
})
private Address address;
public User() {
}
public User(Name name, String email, Address address) {
this.name = name;
this.email = email;
this.address = address;
}
// Getters and Setters (Omitted for brevity)
}
We use JPA’s @Embedded
annotation to embed a type in the model class. Notice the use of @AttributeOverrides
and @AttributeOverride
annotations. These annotations help you customize/override the fields of embeddable types.
Creating the Repository
Next, Let’s create the repository for accessing the user’s data from the database. First, create a package named repository
in the com.example.jpa
package, then add the following interface inside the repository
package -
package com.example.jpa.repository;
import com.example.jpa.model.Name;
import com.example.jpa.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
We’ve extended the UserRepository
from Spring Data JPA’s JpaRepository
interface. The JpaRepository
interface contains methods for all the CRUD operations on the entity. Spring Boot automatically injects an implementation of this interface called SimpleJpaRepository
at runtime.
This helps us perform all the CRUD operations on the entity without implementing anything ourselves.
Testing the Embeddable and Embedded Setup
Finally, Let’s write some code to test our Embeddable type setup. Open the main class JpaEmbeddableDemoApplication.java
and replace it with the following code -
package com.example.jpa;
import com.example.jpa.model.Address;
import com.example.jpa.model.Name;
import com.example.jpa.model.User;
import com.example.jpa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JpaEmbeddableDemoApplication implements CommandLineRunner {
@Autowired
private UserRepository userRepository;
public static void main(String[] args) {
SpringApplication.run(JpaEmbeddableDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Cleanup the users table
userRepository.deleteAllInBatch();
// Insert a new user in the database
Name name = new Name("Rajeev", "Kumar", "Singh");
Address address = new Address("747", "Golf View Road", "Bangalore", "Karnataka", "India", "560008");
User user = new User(name, "rajeev@callicoder.com", address);
userRepository.save(user);
}
}
In the above class, I’ve implemented Spring’s CommandLineRunner interface and written the code to test our setup in the run()
method. The run()
method is called when the application is successfully started.
In the run()
method, we first clean up the user’s table and then insert a new User in the database.
Running the Application
You can run the application by typing the following command from the root directory of the project -
mvn spring-boot:run
Check out the logs to see the SQL statements that hibernate has executed -
org.hibernate.SQL : delete from users
org.hibernate.SQL : insert into users (city, country, house_number, state, street, zip_code, email, first_name, last_name, middle_name) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
If you check the users
table in MySQL after running the application, you’ll find the entry that we inserted using hibernate.
mysql> select * from users;
+----+------------+-------------+-----------+-----------------------+--------------+----------------+-----------+-----------+---------+----------+
| id | first_name | middle_name | last_name | email | house_number | street | city | state | country | zip_code |
+----+------------+-------------+-----------+-----------------------+--------------+----------------+-----------+-----------+---------+----------+
| 1 | Rajeev | Kumar | Singh | rajeev@callicoder.com | 747 | Golf View Road | Bangalore | Karnataka | India | 560008 |
+----+------------+-------------+-----------+-----------------------+--------------+----------------+-----------+-----------+---------+----------+
1 row in set (0.00 sec)
Notice how the table structure is linear but at the application level, we abstracted out the Name
and Address
details into separate classes.
Spring Data JPA Query Methods using Embeddable Types
Spring Data JPA has an excellent feature that generates queries from method names that we specify in the repository.
For example, To find a User with an email, you can add a query method like the following in the UserRepository
and Spring Data JPA will automatically generate a query from it without you having to implement anything -
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Find user by email
User findByEmail(String email);
}
You can check out the official Spring Data JPA’s documentation for understanding more about Query methods.
So the idea is that you write a query method using the field names of the entity class. When you use an embeddable type and you need to query the Entity using a field of the embeddable type, then you can specify query methods like this -
// Find users by firstName
List<User> findByNameFirstName(String firstName);
// Find users by lastName
List<User> findByNameLastName(String lastName);
// Find users by country
List<User> findByAddressCountry(String country);
Conclusion
That’s all in this article guys. I hope you understood the idea of Embeddable types in JPA and Hibernate.
You can find the entire code for the application that we built in this article on my jpa-hibernate-tutorials github repository.
Feel free to fork the project and build upon it. Thanks for reading. See you in the next post.