A H M A D G O H A R

Please Wait For Loading

Java Persistence API (JPA) Embeddables: Addressing Shared Object Mappings

August 19, 2013 Ahmad Gohar 0 Comments

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.

image

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? 😊

author avatar
Ahmad Gohar
With over 18 years of experience in software architecture, Java technologies, and leadership, I specialize in crafting scalable, future-proof solutions for global organizations. Whether it’s transforming legacy systems, building cutting-edge cloud-native applications, or mentoring teams to excel, I’m committed to delivering value-driven results.

Leave A Comment