Motivation
Auch in der heutigen Zeit, in der Speicher vergleichsweise günstig ist, kann es trotzdem sinnvoll sein, eben diesen nicht zu verschwenden. Wir haben innerhalb unseres Projekts nach einer vergleichsweise günstigen Alternative gesucht, einem Datensatz zusätzliche Informationen mitzugeben, welche wir innerhalb des Frontends Anzeigen, sprich wir müssen diese nicht in der Datenbank für Menschen leserlich ablegen. Da ein Datensatz allerdings mehrere zusätzlich Informationen haben kann, ist einfaches Enum hier nicht das Mittel der Wahl. Somit sind wir auf das EnumSet gestoßen und wie wir das Ganze umgesetzt haben und wie du es auch umsetzen kannst, erfährst du im nachfolgenden Beitrag.
Exkurs Enum
Enums (Abkürzung für “Enumerationen”) sind eine spezielle Klasse in Programmiersprachen wie Java, die eine Gruppe von konstanten Werten definiert. Enums helfen dabei, eine Sammlung verwandter Konstanten wie z.B. Tage der Woche, Farben oder Statuswerte sicherer und lesbarer zu verwalten. Sie sorgen für typsichere Konstruktionen und verbessern die Codequalität durch die Einschränkung auf vordefinierte Werte.
Beispiel in Java:
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
In diesem Fall repräsentiert das Enum Day
die sieben Tage der Woche. Enums verbessern die Lesbarkeit und Wartbarkeit
des Codes, indem sie eine saubere und typsichere Möglichkeit bieten, mit vordefinierten konstanten Werten zu arbeiten.
Noch etwas Theorie
In der Beispiel Implementierung benutzen wir ein Byte
als Grundlage für unser EnumSet. Du kannst das Ganze auch
Short
oder Integer
umsetzen, dies hängt davon ab, wie viele Ausprägungen des Enums du benötigst. Da ein Byte
maximal 8 Ausprägungen haben kann.
Um uns das Ganze noch etwas besser Vorstellen zu können, versuche ich dies einmal in folgender Skizze darzustellen:
Die Implementierung
Um ein EnumSet
als BitSet
mit einem JPA Converter in einer JPA Entity zu speichern, kannst du den Ansatz aus dem
genannten Beispiel verwenden. Der Prozess umfasst die Erstellung eines AttributeConverter
sowie die Umwandlung des
EnumSet
in ein numerisches Format. Hier ist ein vollständiges Beispiel, das zeigt, wie das geht:
Schritt 1: Enum definieren
public enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Schritt 2: EnumSetConverter erstellen
Du erstellst den Converter, der zwischen EnumSet
und einer numerischen Darstellung konvertiert:
import javax.persistence.AttributeConverter;
import java.util.BitSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public abstract class EnumSetConverter<E extends Enum<E>, N extends Number> implements AttributeConverter<Set<E>, N> {
private final E[] values;
public EnumSetConverter(Class<E> enumType) {
values = enumType.getEnumConstants();
}
@Override
public Set<E> convertToEntityAttribute(N dbData) {
if (dbData == null) {
return null;
}
BitSet bitSet = map(dbData);
return bitSet.stream().mapToObj(i -> values[i]).collect(Collectors.toSet());
}
@Override
public N convertToDatabaseColumn(Set<E> attribute) {
if (attribute == null) {
return null;
}
BitSet bitSet = attribute.stream().collect(Collectors.toCollection(
() -> {
BitSet bs = new BitSet();
attribute.forEach(e -> bs.set(e.ordinal()));
return bs;
}));
return map(bitSet);
}
protected abstract N map(BitSet bitSet);
protected abstract BitSet map(N value);
}
Schritt 3: ToByteConverter implementieren
Da unser Enum
nur sieben Werte hat, reicht ein Byte
als numerischer Typ:
import java.time.DayOfWeek;
import java.util.BitSet;
public class DayOfWeekConverter extends EnumSetConverter<DayOfWeek, Byte> {
public DayOfWeekConverter() {
super(DayOfWeek.class);
}
@Override
protected Byte map(BitSet bitSet) {
return (byte) bitSet.toLongArray()[0];
}
@Override
protected BitSet map(Byte value) {
return BitSet.valueOf(new long[]{value});
}
}
Schritt 4: JPA Entity definieren
Definiere die JPA Entity und verwende den Converter:
import javax.persistence.*;
import java.util.EnumSet;
import java.util.Set;
@Entity
public class Alarm {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Convert(converter = DayOfWeekConverter.class)
private Set<DayOfWeek> recurringDays = EnumSet.noneOf(DayOfWeek.class);
// Standard-Konstruktor
public Alarm() {
}
// Getter und Setter
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Set<DayOfWeek> getRecurringDaysDays() {
return recurringDays;
}
public void setRecurringDaysDays(Set<DayOfWeek> days) {
this.recurringDays = days;
}
}
Erklärung:
EnumSetConverter
: Eine abstrakte Klasse, die den allgemeinen Konvertierungsvorgang bereitstellt.DayOfWeekConverter
: Eine spezifische Implementierung des Konverters für dasDayOfWeek
-Enum, die einBitSet
in einByte
umwandelt und umgekehrt.@Convert
: Auf der JPA Entity wird der Konverter angewendet, um dieEnumSet
in der Datenbank alsByte
zu speichern.
Mit diesem Setup kannst du EnumSet
als BitSet
in der Datenbank speichern, was sowohl Speicherplatz spart als auch
die Effizienz verbessert.