Close

Type Conversion involving Embeddable

[Updated: Mar 1, 2018, Created: Feb 28, 2018]

Following example shows how to use a type converter involving a collection of Embeddable.

If @Convert annotation is used on complex types, for example on a map or a collection of simple or embeddable types, then we can use its attributeName to specify on what type the converter should be applied.

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);
  }
}

An embeddable

@Embeddable
public class Report {
  private String description;
  //@Convert(converter = FileConverter.class)
  private File file;
    .............
}

The Entity

@Entity
public class Journal {
  @Id
  @GeneratedValue
  private long id;
  @ElementCollection
  @Convert(converter = FileConverter.class, attributeName = "file")
  private List<Report> reports;
    .............
}

Note that we could have used @Convert annotation directly on file field of Report embeddable, in that case we don't have to use attributeName element. This example scenario assumes that doing that is not feasible (may be we would want to use multiple embeddable of same type with different converters in the same entity).

The main class

In case of the embeddable collection, the entity and the collection are mapped to two separate foreign/primary-key tables. One for the entity and other for embeddable fields/properties values (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_Reports");
          persistEntity();
          nativeQuery("Select * from Journal");
          nativeQuery("Select * from Journal_Reports");
          loadEntity();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistEntity() {
      Journal journal = new Journal();
      journal.addReport("test report 1", new File("c:/temp/report-1.txt"));
      journal.addReport("test report 2", new File("c:/temp/report-1.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_Reports'
[JOURNAL_ID, BIGINT(19), NO, , NULL]
[DESCRIPTION, VARCHAR(255), YES, , NULL]
[FILE, VARCHAR(255), YES, , NULL]
Persisting journal: Journal{id=0, reports=[Report{, description='test report 1', file=c:\temp\report-1.txt}, Report{, description='test report 2', file=c:\temp\report-1.txt}]}
'Select * from Journal'
1
'Select * from Journal_Reports'
[1, test report 1, c:\temp\report-1.txt]
[1, test report 2, c:\temp\report-1.txt]
Journal loaded: Journal{id=1, reports=[Report{, description='test report 1', file=c:\temp\report-1.txt}, Report{, description='test report 2', file=c:\temp\report-1.txt}]}

In above example, if we don't use @Convert on the collection attribute then File instance will be persisted as a binary form. All Serializable types which are not Java Basic types (String, primitives etc) can be persisted into VARBINARY SQL type, check out this tutorial for details.

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.
  • JDK 1.8
  • Maven 3.3.9

Type Conversion involving Embeddable Example Select All Download
  • jpa-converter-on-element-collection-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF

See Also