JPA 2.1 Type Converter
Bir JPA Entity sınıfına ait alanlar, tip bilgisine göre bir veritabanı kolon tipine dönüştürülürken, önceden tanımlı kurallara göre bu dönüşüm gerçekleştirilmektedir. Fakat varsayılan bu kurallar zaman zaman ihtiyacı karşılayamamaktaydı.
Java EE 7 stardartlar kümesi altında bulunan JPA 2.1 belirtimi ise, tip dönüşümlerinde yazılım geliştiriciyi özgürleştirecek Type Conversion yapısını getirdi. Type Conversion ile, Java programlama dilinde tanımlanan herhangi bir veri tipi, veritabanı tipine dönüştürülürken ne biçimde saklanacağı artık geliştirici tarafından karar verilebiliyor.
Geliştiriciye bağlı dönüştürüm işlemi için JPA 2.1 içerisinde AttributeConverter<X,Y> jenerik arayüzü bulunmaktadır. X dönüştürülmesini istediğimiz Java tipini temsil ederken, Y ise, veritabanına haritalanacak Java tipini temsil etmektedir.
public interface AttributeConverter<X,Y> {
// Java to DB
public Y convertToDatabaseColumn (X attribute);
// DB to Java
public X convertToEntityAttribute (Y dbData);
}
Örnek Uygulama
Elimizde Programmer adında bir Java @Entity sınıfı olsun diyelim. Bu sınıf içerisinde Long tipinde id, String tipinde name ve title ayrıca javax.json.JsonArray tipinde skills adında alanlar bulunsun. Long ve String tipleri JPA tarafından zaten veritabanı tip karşılıklarına olağan şekilde dönüştürülebilmektedir. Fakat javax.json.JsonArray tipi, JPA standardında veritabanı tip dönüşümünde varsayılan olarak dönüştürülebilecek bir tip değildir. İşte tam da bu noktada JsonArray tipinin veritabanında nasıl temsil edileceği Type Conversion yapısıyla sağlanabilirdir. Bu özel dönüştürüm mekanizması tüm Java veri tipleri için de ayrıca geçerli olabilmektedir. Çünkü dönüşüm mekanizmasını geliştirici kurabilmektedir.
JsonArray veri tipi, bir JSON dizisinin Java taraflı nesnel karşılığıdır. Örnek olarak [“Java”,”Android”,”C”,”Mysql”] şeklinde tanımlanan bir Json dizisi, javax.json.JsonArray tipiyle Java ortamında nesnel olarak temsil edilebilirdir.
Şimdi skills alanı için tip dönüştürüm sınıfımızı oluşturalım.
@Converter(autoApply = true)
public class SkillConverter
implements AttributeConverter<JsonArray, String> {
@Override // Java to DB
public String convertToDatabaseColumn(JsonArray attribute) {
// null ise boş bir Json dizisi hazırlanır;
if (attribute == null)
return "[]";
// null değilse, Json verisi String olarak döndürülür.
return attribute.toString();
}
@Override // DB to Java
public JsonArray convertToEntityAttribute(String dbData) {
// null ise içerisinde veri barınmayan JsonArray nesnesi döner.
if (dbData == null)
return Json.createArrayBuilder().build();
// null değilse, String –> JsonArray tipine dönüştürülür.
JsonArray jsonArray=null;
try(StringReader stringReader=new StringReader(dbData);
JsonReader jsonReader = Json.createReader(stringReader))
{
jsonArray=jsonReader.readArray();
}
return jsonArray;
}
}
AttributeConverter türünden bir sınıf, convertToDatabaseColumn ve convertToEntityAttribute metodlarının içerisini doldurmalıdır (implementation). SkillConverter sınıfına bakıldığında X yerine JsonArray, Y yerine ise String tiplerinin tanımlandığı görülebilir. JsonArray tipi Java taraflı tipi temsil ederken, String tipi veritabanı tipine dönüşümde kullanılacak veri tipidir.
AttributeConverter tipinden olan SkillConverter sınıfı, JPA ortamında tip dönüşümü açısından kullanılabilmesi için sınıf başına @Converter notasyonu uygulanmalıdır. @Converter notasyonunun autoApply türünde bir alanı bulunur ve varsayılan değeri false’ dir. Eğer autoApply alanı true olarak yapılandırılırsa, JsonArray türüne sahip tüm JPA Entity sınıfları, SkillConverter dönüştürücüsünü otomatik olarak kullanabilecektir.
Programmer @Entity sınıfı
@Entity
public class Programmer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String title;
// @Convert(converter = SkillConverter.class)
private JsonArray skills;
// getters, setters
}
JsonArray tipindeki skills alanı Entity <=> DB dönüştürümünde kullanılırken @Convert notasyonu kullanılabilmektedir. Fakat, eğer @Converter notasyonunda autoApply alanı true olarak yapılandırıldıysa @Convert notasyonunu kullanmak zorunlu değildir. Ama eğer autoApply alanı false olarak yapılandırıldıysa, dönüştürüm isteniyorsa @Convert notasyonunu alanın başına eklemek zorunludur ve @Convert notasyonunun converter alanı, dönüştürümde kullanılacak sınıfın sınıf tipini barındırmalıdır. Yine @Convert notasyonu ile dönüştürüm işlemini devre dışı bırakmak için disableConversion alanı kullanılabilmektedir.
Uygulamanın çalıştırılması
Uygulamanın çalıştırılması kısmında JPA 2.1 Type Conversion yapısına özgü bir gereklilik yoktur. Olağan yöntemle Programmer nesnesi oluşturulur ve veritabanına kazınır.
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("type-conversion-pu");
EntityManager em = emf.createEntityManager();
EntityTransaction trx = em.getTransaction();
JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
arrayBuilder
.add("Java")
.add("Linux")
.add("Json")
.add("JPA"); // Yetenekler diziye ekleniyor.
Programmer programmer=new Programmer();
programmer.setName("Meherrem Mehmedov");
programmer.setTitle("Java Developer");
// JsonArray set ediliyor.
programmer.setSkills(arrayBuilder.build());
trx.begin();
em.persist(programmer); // DB'ye kazınıyor.
trx.commit();
Veritabanı çıktısı
Bu haliyle veritabanı çıktısı kontrol edildiğinde, JsonArray tipinin String tipi üzerinden Mysql ortamında VARCHAR tipinde Json dizisi olarak temsil edildiği görülür.
Uygulamanın kaynak kodlarına kodedu.com’a üye olarak erişebilirsiniz.
Tekrar görüşmek dileğiyle..