Close

Type Conversion involving Map with embeddable key or value

[Last Updated: Mar 2, 2018]

Following example shows how to use JPA type conversion of attributes involving embeddable key or value of a Map.

When the @Convert annotation is used on a map containing instances of embeddable classes, the attributeName element must be specified, and "key." or "value." must be used to prefix the name of the attribute that is to be converted. Let's understand that with an example.

Example

The Converter

@Converter
public class FileConverter implements AttributeConverter<File, String> {

  @Override
  public String convertToDatabaseColumn(File attribute) {
      return attribute.getAbsolutePath();
  }

  @Override
  public File convertToEntityAttribute(String dbData) {
      return new File(dbData);
  }
}

The Entity

@Entity
public class Journal {
  @Id
  @GeneratedValue
  private long id;
  @ElementCollection
  @Convert(converter = FileConverter.class, attributeName = "value.file")
  private Map<String, Report> reportMap;
    .............
  public void addReport(String reportName, String description, File file) {
      if (reportMap == null) {
          reportMap = new HashMap<>();
      }
      Report report = new Report();
      report.setDescription(description);
      report.setFile(file);
      reportMap.put(reportName, report);
  }
    .............
}
@Embeddable
public class Report {
  private String description;
  private File file;
    .............
}

The main class

When persisting a Map with @ElementCollection, the entity and the map are persisted to two separate foreign/primary-key tables (check out the related tutorial here).

public class ExampleMain {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          nativeQuery("Show Columns from Journal");
          nativeQuery("Show Columns from Journal_ReportMap");
          persistEntity();
          nativeQuery("Select * from Journal");
          nativeQuery("Select * from Journal_ReportMap");
          loadEntity();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistEntity() {
      Journal journal = new Journal();
      journal.addReport("name1", "test report 1", new File("c:/temp/report-1.txt"));
      journal.addReport("name2", "test report 2", new File("c:/temp/report-2.txt"));
      System.out.println("Persisting journal: " + journal);
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      em.persist(journal);
      em.getTransaction().commit();
      em.close();
  }

  private static void loadEntity() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Journal journal = em.find(Journal.class, 1L);
      System.out.println("Journal loaded: " + journal);
      em.close();
  }

  public static void nativeQuery(String s) {
      EntityManager em = entityManagerFactory.createEntityManager();
      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);
          }
      }
      em.close();
  }
}
'Show Columns from Journal'
[ID, BIGINT(19), NO, PRI, NULL]
'Show Columns from Journal_ReportMap'
[JOURNAL_ID, BIGINT(19), NO, PRI, NULL]
[DESCRIPTION, VARCHAR(255), YES, , NULL]
[FILE, VARCHAR(255), YES, , NULL]
[REPORTMAP_KEY, VARCHAR(255), NO, PRI, NULL]
Persisting journal: Journal{id=0, reportMap={name2=Report{, description='test report 2', file=c:\temp\report-2.txt}, name1=Report{, description='test report 1', file=c:\temp\report-1.txt}}}
'Select * from Journal'
1
'Select * from Journal_ReportMap'
[1, test report 2, c:\temp\report-2.txt, name2]
[1, test report 1, c:\temp\report-1.txt, name1]
Journal loaded: Journal{id=1, reportMap={name2=Report{, description='test report 2', file=c:\temp\report-2.txt}, name1=Report{, description='test report 1', file=c:\temp\report-1.txt}}}

Example Project

Dependencies and Technologies Used:

  • h2 1.4.196: H2 Database Engine.
  • hibernate-core 5.2.12.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

Type Conversion involving Map with Embeddable Example Select All Download
  • jpa-converter-map-with-embeddable-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • Journal.java
          • resources
            • META-INF

    See Also