Java Persistence API (JPA) Embeddables: Addressing Shared Object Mappings
Introduction to JPA Embeddables
The Java Persistence API (JPA) allows you to map reusable objects using the @Embeddable
annotation. Embeddable objects are particularly useful when the same structure, such as an address, is used across multiple entities. This tutorial demonstrates creating and managing embeddable objects in JPA with a practical example.
Use Case: Address as an Embeddable Object
Consider an Address object shared between Customer
and Orders
. Each entity will use its own table to share the reusable address structure.
Step 1: Create Tables in Oracle
ORDERS Table
CREATE TABLE ORDERS (
ID NUMBER NOT NULL,
ORDER_DATE DATE,
BENF_NAME VARCHAR2(20),
STREET1 VARCHAR2(255),
STREET2 VARCHAR2(225),
ZIPCODE VARCHAR2(6),
STATE VARCHAR2(20),
COUNTRY VARCHAR2(20),
CITY VARCHAR2(50),
CONSTRAINT ORDERS_PK PRIMARY KEY (ID)
);
CUSTOMER Table
CREATE TABLE CUSTOMER (
ID NUMBER NOT NULL,
FIRST_NAME VARCHAR2(20),
LAST_NAME VARCHAR2(45),
PHONE_NUMBER VARCHAR2(15),
EMAIL VARCHAR2(50),
STREET1 VARCHAR2(255),
STREET2 VARCHAR2(255),
ZIPCODE VARCHAR2(6),
STATE VARCHAR2(20),
COUNTRY VARCHAR2(50),
CITY VARCHAR2(50),
CONSTRAINT CUSTOMER_PK PRIMARY KEY (ID)
);
Step 2: Create Sequences and Triggers
ORDERS Sequence and Trigger
CREATE SEQUENCE ORDERS_SEQ NOCACHE;
CREATE TRIGGER ORDERS_TRG
BEFORE INSERT ON ORDERS
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL THEN
SELECT ORDERS_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END IF;
END;
/
CUSTOMER Sequence and Trigger
CREATE SEQUENCE CUSTOMER_SEQ NOCACHE;
CREATE TRIGGER CUSTOMER_TRG
BEFORE INSERT ON CUSTOMER
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL THEN
SELECT CUSTOMER_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END IF;
END;
/
Step 3: Define the Address Embeddable Class
@Embeddable
public class Address {
@Column(name = "STREET1")
private String street1;
@Column(name = "STREET2")
private String street2;
@Column(name = "ZIPCODE")
private String zipcode;
@Column(name = "STATE")
private String state;
@Column(name = "COUNTRY")
private String country;
@Column(name = "CITY")
private String city;
// Getters, Setters, toString(), hashCode(), equals()
}
Step 4: Define Entity Classes
Orders Entity
@Entity
@Table(name = "ORDERS")
public class Orders implements Serializable {
@Id
@Column(name = "ID")
private Integer id;
@Column(name = "ORDER_DATE")
@Temporal(TemporalType.DATE)
private Date orderDate;
@Column(name = "BENF_NAME")
private String benfName;
@Embedded
private Address address;
// Getters, Setters, toString(), hashCode(), equals()
}
Customer Entity
@Entity
@Table(name = "CUSTOMER")
public class Customer implements Serializable {
@Id
@Column(name = "ID")
private Integer id;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "PHONE_NUMBER")
private String phoneNumber;
@Column(name = "EMAIL")
private String email;
@Embedded
private Address address;
// Getters, Setters, toString(), hashCode(), equals()
}
Step 5: JUnit Test Case
The following test case covers insert, select, update, and delete operations for embeddable objects:
public class EmbeddableJUnitTest {
static EntityManagerFactory emf;
static EntityManager em;
@BeforeClass
public static void setup() {
emf = Persistence.createEntityManagerFactory("JPAUnit");
em = emf.createEntityManager();
}
@Test
public void testInsert() {
Address address = new Address();
address.setCity("City");
address.setCountry("Country");
address.setState("State");
address.setStreet1("Street 1");
address.setZipcode("123456");
Customer customer = new Customer();
customer.setId(1);
customer.setFirstName("John");
customer.setLastName("Doe");
customer.setAddress(address);
em.getTransaction().begin();
em.persist(customer);
em.getTransaction().commit();
}
@Test
public void testSelect() {
Customer customer = em.find(Customer.class, 1);
assertNotNull(customer);
System.out.println(customer);
}
@Test
public void testUpdate() {
em.getTransaction().begin();
Customer customer = em.find(Customer.class, 1);
customer.setEmail("newemail@example.com");
em.merge(customer);
em.getTransaction().commit();
}
@Test
public void testDelete() {
em.getTransaction().begin();
Customer customer = em.find(Customer.class, 1);
em.remove(customer);
em.getTransaction().commit();
}
}
Conclusion
Using the @Embeddable
annotation in JPA simplifies managing shared object structures like addresses. The demonstrated approach ensures consistency across multiple entities while reducing repetitive mappings.
Would you like further assistance with advanced JPA features or related queries? 😊