JPA Attribute Converter

Konvertierung von Java Datentypen zu ORM-Datentypen


Die JPA (Java Persistence API) ist eine Spezifikation aus dem Java Enterprise Bereich. Wie der Name schon sagt geht es um eine Schnittstelle für die Speicherung von Daten mit Java. Die Spezifikation wird von verschiedenen Anbietern implementiert. Die bekanntesten sind Hibernate und EclipseLink.

Hibernate ist bekannter und weiter verbreitet. EclipseLink ist mehr standardkonform und bietet ein sehr nettes Feature out of the box. Dieses ist das Verfolgen von Änderungen an den Daten. Eine ganz gute Anleitung dazu findet sich hier.
Hibernate kann sowas auch, jedoch muss man Hibernate Envers zu seinem Projekt hinzufügen. Ist allerdings auch vergleichsweise einfach wie hier beschrieben.

Bei der Verwendung von JPA bzw. der darunter liegenden Implementierung findet eine Konvertierung zwischen Java Klassen und Datentypen der Datenbank statt. Für einige Java Klassen ist dies bereits implementiert. Klar sonst könnte man damit nicht arbeiten. Für die meisten jedoch nicht und für komplett eigene Klassen natürlich auch nicht. Seit der Java Persistence API 2.1 kann man Konverter hierfür schreiben. Mit diesen Konvertern kann man nahezu jede Klasse in einen Datentyp konvertieren, den der ORM-Layer bereits kennt. Somit können die Daten ohne weitere Schritte gespeichert werden. Natürlich muss auch der Weg zurück implementiert werden, also von der Datenbank zum Java Datentyp.

Nachfolgend werden zwei Beispiele aufgeführt. Mit dem einen kann man Java Listen ganz bequem als kommaseparierte Liste in der Datenbank ablegen und wieder auslesen. Und mit dem anderen Java Locale als Strings speichern und wieder auslesen. Letzteres wurde bei der Erstellung des generischen Datenlayers verwendet.

Konverter für Listen


package de.finait.start.app.converter;

import java.util.Arrays;
import java.util.List;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class StringListToStringConverter implements AttributeConverter<List<String>, String> {
    private static final String SPLIT_CHAR = ";";

    @Override
    public String convertToDatabaseColumn(List<String> stringList) {
        return String.join(SPLIT_CHAR, stringList);
    }

    @Override
    public List<String> convertToEntityAttribute(String string) {
        return Arrays.asList(string.split(SPLIT_CHAR));
    }
}

Es muss nur das Interface AttributeConverter mit den beiden Methoden convertToDatabaseColumn und convertToEntityAttribute implementiert werden. Wie die Namen schon sagen dient eine zur Konvertierung zur Datenbankspalte und die andere zum Java Datentyp.

Konverter für Locale


package de.finait.start.app.converter;

import java.util.Locale;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class LocaleToStringConverter implements AttributeConverter<Locale, String> {

    @Override
    public String convertToDatabaseColumn(Locale locale) {
        return locale.toLanguageTag();
    }

    @Override
    public Locale convertToEntityAttribute(String localeString) {
        return Locale.forLanguageTag(localeString);
    }
}

Hier wurde ebenfalls die Implementierung des Interfaces vorgenommen. Um den Konverter nutzen zu können, muss man nur noch die entsprechende Annotation zur Entity hinzufügen.

Verwendung der @Convert Annotation


package de.finait.start.app.model.base;

import java.util.Locale;
import javax.persistence.Convert;
//...

@Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PUBLIC)
@MappedSuperclass
public abstract class AbstractI18nEntity extends AbstractEntity {

    @NotBlank
    @Size(min = 5, max = 5)
    @Column(name = "locale", nullable = false, length = 5)
    @Convert(converter = LocaleToStringConverter.class)
    private Locale locale;

//...
}

Somit ist man ziemlich frei in der Wahl der Datentypen für die Attribute in seinen Entitäten.

Zurück zur Kategorie: Java EE
Zurück nach oben