In this tutorial, we will see the @ElementCollection Example in Hibernate/JPA Using Spring Boot and Oracle.
Understanding @ElementCollection annotation.
We will see how to use @ElementCollection annotation to map a collection of a basic type(String, Integer etc) and embeddable types(User Defined class for example Book.java).
Consider we have an entity called Student.java. A student can have a list of book and list of a phone number. Let’s see how to map classes using @ElementCollection, @CollectionTable and @Embeddable annotation.
For bookList we will define the Book.java class as @Embeddable because we may need to define some other information like bookName, author, numberOfPage etc. For the phoneNumbers we might want just phone number so we will define this one basic type(for example String). We will see more details about @ElementCollection, @CollectionTable and @Embeddable annotations at the end of the tutorial. Let’s see how to use @ElementCollection with embeddable types or Basic types.
Book.java
package com.javatute.entity; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class Book { @Column(name = "book_name") private String bookName; @Column(name = "number_of_page") private String numberOfPage; @Column(name = "author") private String author; }
Student.java
package com.javatute.entity; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; @Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "student_name") private String studentName; @Column(name = "roll_number") private String rollNumber; @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "student_book", joinColumns = @JoinColumn(name = "student_id")) private List<Book> bookList = new ArrayList<Book>(); @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "student_phone_number", joinColumns = @JoinColumn(name = "student_id")) private Set<String> phoneNumbers = new HashSet<String>(); }
Observe both classes. Did you notice that with Book.java we are using @Embeddable annotation, we are not using @Entity annotation.
Before moving forward let’s see what we are going to do in this example.
We will have two REST endpoint to save and retrieve data.
POST – http://localhost:9091/student/save
http://localhost:9091/student/allstudents
Database entry and structure after saving the record.
Note – In the above diagram for student_book and student_phone_number table, the student_id is the foreign key. We are not going to create all these tables manually, let’s hibernate do this job(we will have configurations in application.properties file).
@ElementCollection Example in Hibernate Using Spring Boot and Oracle.
Open eclipse and create maven project, Don’t forget to check ‘Create a simple project (skip)’ click on next. Fill all details(GroupId – elementcollection, ArtifactId – elementcollection and name – elementcollection) and click on finish. Keep packaging as the jar.
Modify pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>elementcollection</groupId> <artifactId>elementcollection</artifactId> <version>0.0.1-SNAPSHOT</version> <name>elementcollection</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <fork>true</fork> <executable>C:\Program Files\Java\jdk1.8.0_131\bin\javac.exe</executable> </configuration> </plugin> </plugins> </build> </project>
Note – In pom.xml we have defined javac.exe path in configuration tag. You need to change accordingly i.e where you have installed JDK.
If you see any error for oracle dependency then follow these steps.
Let’s see the directory structure of @ElementCollection Example in Hibernate/JPA Using Spring Boot below.
Directory structure –
Entity for @ElementCollection Example in Hibernate/JPA Using Spring Boot.
Student.java
package com.javatute.entity; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; @Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "student_name") private String studentName; @Column(name = "roll_number") private String rollNumber; @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "student_book", joinColumns = @JoinColumn(name = "student_id")) private List<Book> bookList = new ArrayList<Book>(); @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "student_phone_number", joinColumns = @JoinColumn(name = "student_id")) private Set<String> phoneNumbers = new HashSet<String>(); public int getId() { return id; } public void setId(int id) { this.id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public String getRollNumber() { return rollNumber; } public void setRollNumber(String rollNumber) { this.rollNumber = rollNumber; } public List<Book> getBookList() { return bookList; } public void setBookList(List<Book> bookList) { this.bookList = bookList; } public Set<String> getPhoneNumbers() { return phoneNumbers; } public void setPhoneNumbesr(Set<String> phoneNumbers) { this.phoneNumbers = phoneNumbers; } }
Book.java
package com.javatute.entity; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class Book { @Column(name = "book_name") private String bookName; @Column(name = "number_of_page") private String numberOfPage; @Column(name = "author") private String author; public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getNumberOfPage() { return numberOfPage; } public void setNumberOfPage(String numberOfPage) { this.numberOfPage = numberOfPage; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
StudentController.java
package com.javatute.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.javatute.entity.Student; import com.javatute.service.StudentService; @RestController @RequestMapping(value = "/student") public class StudentController { @Autowired private StudentService studentService; @RequestMapping(value = "/save", method = RequestMethod.POST) @ResponseBody public Student saveBook(@RequestBody Student student) { Student studentResponse = (Student) studentService.saveStudent(student); return studentResponse; } @RequestMapping(value = "/allstudents", method = RequestMethod.GET) @ResponseBody public List<Student> getAllStudents() { List<Student> studentList = (List<Student>) studentService.findAll(); return studentList; } }
We have seen controller and serviceimpl, interface for@ElementCollection Example in Hibernate/JPA Using Spring Boot
Note – See more details about @Controller and RestController here.
StudentService.java – interface
package com.javatute.service; import java.util.List; import org.springframework.stereotype.Component; import com.javatute.entity.Student; @Component public interface StudentService { public Student saveStudent(Student student); public List<Student> findAll(); }
Note – See here more about @Component, @Controller, @Service and @Repository annotations here.
StudentServiceImpl.java
package com.javatute.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.javatute.entity.Student; import com.javatute.repository.StudentRepository; import com.javatute.service.StudentService; @Service("studentServiceImpl") public class StudentServiceImpl implements StudentService { @Autowired private StudentRepository studentRepository; @Transactional public Student saveStudent(Student student) { Student studentresponse = studentRepository.save(student); return studentresponse; } @Transactional public List<Student> findAll() { List<Student> studentList = (List<Student>) studentRepository.findAll(); return studentList; } }
SpringMain.java
package com.javatute.main; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan(basePackages = "com.*") @EntityScan("com.javatute.entity") public class SpringMain { public static void main(String[] args) { SpringApplication.run(SpringMain.class, args); } }
Note – See more details about @ComponentScan here.
Configuration file @ElementCollection Example in Hibernate/JPA Using Spring Boot.
JpaConfig.java
package com.javatute.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Configuration @EnableJpaRepositories(basePackages = "com.javatute.repository") public class JpaConfig { }
Note – See more details about @Configuration annotations here.
application.properties
# Connection url for the database spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE spring.datasource.username=SYSTEM spring.datasource.password=oracle2 spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver # Show or not log for each sql query spring.jpa.show-sql = true spring.jpa.properties.hibernate.format_sql=true spring.jpa.hibernate.ddl-auto =create spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect server.port = 9091 #show sql values #logging.level.org.hibernate.type.descriptor.sql=trace hibernate.show_sql = true #spring.jpa.hibernate.logging.level.sql =FINE #show sql statement #logging.level.org.hibernate.SQL=debug
Let’s run the SpringMain class(run as java application).
Perform save operation first using below REST API.
POST – http://localhost:9091/student/save
{ "studentName": "John", "rollNumber": "0126CS01", "bookList": [{ "bookName": "Rich Dad Poor Dad", "numberOfPage": "300", "author": "Robert T. Kiyosaki" }, { "bookName": "Godan", "numberOfPage": "500", "author": "Premchand" } ], "phoneNumbers": [ "7415623488", "7899111111", "7899111111" ] }
Response Data.
{ "id": 1, "studentName": "John", "rollNumber": "0126CS01", "bookList": [ { "bookName": "Rich Dad Poor Dad", "numberOfPage": "300", "author": "Robert T. Kiyosaki" }, { "bookName": "Godan", "numberOfPage": "500", "author": "Premchand" } ], "phoneNumbers": [ "7415623488", "7899111111" ] }
Let’s perform GET call for @ElementCollection Example in Hibernate/JPA Using Spring Boot.
GET – http://localhost:9091/student/allstudents
[ { "id": 1, "studentName": "John", "rollNumber": "0126CS01", "bookList": [ { "bookName": "Rich Dad Poor Dad", "numberOfPage": "300", "author": "Robert T. Kiyosaki" }, { "bookName": "Godan", "numberOfPage": "500", "author": "Premchand" } ], "phoneNumbers": [ "7415623488", "7899111111" ] } ]
Below queries will get fired while performing get operation.
Hibernate: select student0_.id as id1_0_, student0_.roll_number as roll_number2_0_, student0_.student_name as student_name3_0_ from student student0_
Hibernate: select phonenumbe0_.student_id as student_id1_2_0_, phonenumbe0_.phone_numbers as phone_numbers2_2_0_ from student_phone_number phonenumbe0_ where phonenumbe0_.student_id=?
Hibernate: select booklist0_.student_id as student_id1_1_0_, booklist0_.author as author2_1_0_, booklist0_.book_name as book_name3_1_0_, booklist0_.number_of_page as number_of_page4_1_0_ from student_book booklist0_ where booklist0_.student_id=?
Difference between @ElementCollection and @OneToMany annotation.
Both @ElementCollection and @OneToMany annotation used with collection type of fields. First, see some basic difference between these annotations later we will see when we should use @ElementCollection.
The @ElementCollection annotation introduced in JPA 2.0 whereas @OneToMany introduced in JPA 1.0.
In the case of the @ElementCollection, child entity(Book.java) need to annotate with @Embeddable annotation while in case of @OneToOne child class need to annotate with @Entity. The @ElementCollection has only two elements targetClass and fetch, @OneToMany annotation contains some other elements like cascade, mappedBy, orphanRemoval etc.
If we have @ElementCollection type filed then target objects cannot be queried, persisted, merged independently of their parent object. Since they are tightly dependent on the parent entity. In the case of @OneToMany, the child entity can be independently queried, persisted or merged.
The @ElementCollection is used to map non-entities (embeddable or basic) while @OneToMany is used to map entities. We need to use @Embeddable annotation to make an embeddable class(generally @Embeddable used with User defined class). When we say basic types that means String or any other wrapper classes.
The embeddable classes totally depend on the owner entity. Without an owner entity, there is no existence of embeddable classes. But in the case of @OneToMany annotation, all entities have an independent existence. In the case of OneToMany, even parent/owner entity doesn’t exist child entity can exist. But If we use @ElementCollection it is not possible.
Conclusion – Use @OneToMany annotation for aggregation kind of relationship and use @ElementCollection for composition kind of relationship.
Some more Basic points about @ElementCollection, @CollectionTable and @Embeddable annotations.
@ElementCollection.
- This annotation is introduced in JPA 2.0 and available in javax.persistence package.
- This annotation can be used with method or field.
- It contains two elements fetch and targetClass. we have already used fetchType in our example. Both elements are optional.
- Before introducing @ElementCollection, hibernate had similar kind of annotation @CollectionOfElements(see docs here) which has been deprecated.
@Embeddable.
- This annotation is introduced in JPA 1.0 and available in javax.persistence package.
- This annotation can be used with the class only.
@CollectionTable.
- This annotation is introduced in JPA 2.0 and available in javax.persistence package.
- This annotation can be used with method or field.
- It contains below elements.
public @interface CollectionTable { String name() default ""; String catalog() default ""; String schema() default ""; JoinColumn[] joinColumns() default {}; UniqueConstraint[] uniqueConstraints() default {}; Index[] indexes() default {}; ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
That’s all about @ElementCollection Example in Hibernate/JPA Using Spring Boot and Oracle.
You may like.
- Hibernate Table Per Concrete Class Spring Boot.
- Hibernate Table Per Subclass Inheritance Spring Boot.
- Hibernate Single Table Inheritance using Spring Boot.
- One To One Mapping Annotation Example in Hibernate/JPA using Spring Boot and Oracle.
- One To One Bidirectional Mapping Example In Hibernate/JPA Using Spring Boot and Oracle.
- One To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot And Oracle.
- Many To One Unidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.
- One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.
- Many To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot.
- @Version Annotation Example In Hibernate.
- Hibernate Validator Constraints Example Using Spring Boot.
- @Temporal Annotation Example In Hibernate/Jpa Using Spring Boot.
@ElementCollection docs.
Summary – We have seen about @ElementCollection Example in Hibernate/JPA.