Close

JPA - Persisting java.util.Map

[Last Updated: May 31, 2017]
A quick overview of persisting Map of basic types in JPA
  • To persist a java.util.Map having keys/values of basic Java types, the annotation @ElementCollection is used. This annotation is placed on the map reference in the entity class. This usage of @ElementCollection is very similar to java.util.Collection mapping.
  • The Entity and the map are persisted to two separate foreign/primary-key tables. One for the entity and other for the map. The keys and values of the map are persisted to two separate columns in the map table. Also there is a foreign key column in the map table, pointing to the primary key of the entity.
  • By default, JPA specific naming conventions are used for the mapping. To customize that, we can use @MapKeyColumn, @CollectionTable and @Column annotations (next tutorial) on the map field/property.

Example

@Entity
public class Customer {
  @Id
  @GeneratedValue
  private int id;
  private String name;
  @ElementCollection
  private Map<String, Integer> itemQtyMap;
    .............
}
public class ExampleMain {

  public static void main(String[] args) {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
      try {
          EntityManager em = emf.createEntityManager();
          nativeQuery(em, "SHOW TABLES");
          nativeQuery(em, "SHOW COLUMNS from Customer");
          nativeQuery(em, "SHOW COLUMNS from Customer_ItemQtyMap");
      } finally {
          emf.close();
      }
  }

  public static void nativeQuery(EntityManager em, String s) {
      System.out.printf("'%s'%n", s);
      Query query = em.createNativeQuery(s);
      List list = query.getResultList();
      for (Object o : list) {
          if (o instanceof Object[]) {
              System.out.println(Arrays.toString((Object[]) o));
          } else {
              System.out.println(o);
          }
      }
  }
}

Output

'SHOW TABLES'
[CUSTOMER, PUBLIC]
[CUSTOMER_ITEMQTYMAP, PUBLIC]
'SHOW COLUMNS from Customer'
[ID, INTEGER(10), NO, PRI, NULL]
[NAME, VARCHAR(255), YES, , NULL]
'SHOW COLUMNS from Customer_ItemQtyMap'
[CUSTOMER_ID, INTEGER(10), NO, PRI, NULL]
[ITEMQTYMAP, INTEGER(10), YES, , NULL]
[ITEMQTYMAP_KEY, VARCHAR(255), NO, PRI, NULL]

An overview of the mapping:

Persisting and loading data

public class ExampleMain2 {

  public static void main(String[] args) {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
      try {
          persistEntity(emf);
          runNativeQueries(emf);
          loadEntity(emf);
      } finally {
          emf.close();
      }
  }

  private static void persistEntity(EntityManagerFactory emf) {
      System.out.println("-- Persisting entities --");
      EntityManager em = emf.createEntityManager();

      Customer c1 = new Customer();
      c1.setName("Lindsey Craft");
      Map<String, Integer> itemPurchased = new HashMap<>();
      itemPurchased.put("XYZ Blender", 1);
      itemPurchased.put("ZZZ Beer Glass", 4);
      c1.setItemQtyMap(itemPurchased);
      System.out.println(c1);

      Customer c2 = new Customer();
      c2.setName("Morgan Philips");
      Map<String, Integer> orderMap2 = new HashMap<>();
      orderMap2.put("AA Glass Cleaner",3);
      c2.setItemQtyMap(orderMap2);
      System.out.println(c2);

      em.getTransaction().begin();
      em.persist(c1);
      em.persist(c2);
      em.getTransaction().commit();
      em.close();
  }

  private static void runNativeQueries(EntityManagerFactory emf) {
      System.out.println("-- Native queries --");
      EntityManager em = emf.createEntityManager();
      ExampleMain.nativeQuery(em, "Select * from Customer");
      ExampleMain.nativeQuery(em, "Select * from Customer_ItemQtyMap");
  }

  private static void loadEntity(EntityManagerFactory emf) {
      System.out.println("-- Loading Customer --");
      EntityManager em = emf.createEntityManager();
      List<Customer> entityAList = em.createQuery("Select t from Customer t")
                                     .getResultList();
      entityAList.forEach(System.out::println);
      em.close();
  }
}

Output

-- Persisting entities --
Customer{id=0, name='Lindsey Craft', itemQtyMap={XYZ Blender=1, ZZZ Beer Glass=4}}
Customer{id=0, name='Morgan Philips', itemQtyMap={AA Glass Cleaner=3}}
-- Native queries --
'Select * from Customer'
[1, Lindsey Craft]
[2, Morgan Philips]
'Select * from Customer_ItemQtyMap'
[1, 1, XYZ Blender]
[1, 4, ZZZ Beer Glass]
[2, 3, AA Glass Cleaner]
-- Loading Customer --
Customer{id=1, name='Lindsey Craft', itemQtyMap={XYZ Blender=1, ZZZ Beer Glass=4}}
Customer{id=2, name='Morgan Philips', itemQtyMap={AA Glass Cleaner=3}}

Example Project

Dependencies and Technologies Used:

  • h2 1.4.193: H2 Database Engine.
  • hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • JDK 1.8
  • Maven 3.3.9

Java Util Map Example Select All Download
  • mapping-java-util-map
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • Customer.java
          • resources
            • META-INF

    See Also