GEDOPLAN

Java Persistence Trap: Embeddable bleibt null, wenn seine Komponenten null sind

Alle

Java Persistence erlaubt den Einsatz von Embeddables als persistente Eigenschaften von Entities, z. B. so:

@Embeddable
public class Adresse
{
  private String strasse;
  private String hausNummer;
  private String plz;
  private String ort;
  ...
}

@Entity
public class Person
{
  ...
  private Adresse   adresse;
  ...
}

Leider definiert die Spezifikation JPA 2.0 nicht eindeutig, wie beim Laden von Objekten verfahren werden soll, bei denen sämtliche Attribute des Embeddables null sind: Soll im Beispiel trotz leerer Adresse ein Adress-Objekt instanziert werden oder bleibt das Attribut
Person.adresse selbst null?

Eclipselink und Hibernate tun letzteres, d. h. vollständig leere eingebettete Objekte werden nicht instanziert.

Das Verfahren mag bei Betrachtung des Persistenzanteils einer Anwendung so in Ordnung sein, erzeugt aber für GUI-Frameworks Probleme, die ein Data Binding benutzen, also bspw. Eingabefelder direkt mit den entsprechenden Bean-Attribute verknüpfen. So könnte bspw. in einer JSF-View der folgende Ausdruck für die Eingabe der Postleitzahl – also eines Teils der eingebetteten Adresse – einer Person verwendet werden:

<h:inputText value="#{personModel.person.adresse.plz}" />

Für den oben skizzierten Fall einer bislang noch komplett leeren Adresse erzeugt der JSF-EL-Ausdruck eine NullPoinerException, da person.adresse noch null ist.
Nun könnte man auf die Idee kommen, das betroffene Attribut in einer Lifecycle-Methode nach dem Laden bei Bedarf zu instanzieren:

@Embeddable
public class Adresse
{
  ...
  @PostLoad
  private void postLoad()
  {
  if (this.adresse == null)
    this.adresse = new Adresse();
  }
}

Dadurch würde aber beim Speichern des Objektes stets ein unnötiger Update ausgelöst, da es aus Sicht des Persistenzproviders ‚dirty‘ ist. Würde man zur Behebung dieser Situation auch die umgekehrte Lifecycle-Methode vor dem Speichern so programmieren, dass das Attribut – soweit immer noch leer – wieder auf null gesetzt wird, käme man danach wieder in das Problem der NullPointerExceptions.

Eine funktionierende Lösung ist daher ein Late Initializing des Attributs in seiner Getter-Methode – nun allerdings threadsafe mittels Double Check Lock Idiom nach Joshua Bloch:

@Entity(name = "Person")
public class Person
{
  ...
  private volatile Adresse adresse;
  ...
  public Adresse getAdresse()
  {
    Adresse tmp = this.adresse;
    if (tmp == null)
    {
      synchronized (this)
      {
        tmp = this.adresse;
        if (tmp == null)
        {
          tmp = new Adresse();
          this.adresse = tmp;
        }
      }
    }
  return tmp;
  }

  ...

  @PrePersist
  @PreUpdate
  private void preSave()
  {
    if (this.adresse != null && this.adresse.isNull()) // Prüfen, ob Adresse komplett null
      this.adresse = null;
  }

Wichtig dafür: Das Attribut adresse muss volatile sein, sonst funktioniert das DCL-Idiom nicht zuverlässig!

Man sieht: Ziemlich vel Aufwand für so eine einfache Angelegenheit. Es wäre also schön, wenn JPA-Provider sind bei Embeddables anders verhalten würden. Man könnte ja bspw. in die entsprechende Annotation noch einen Parameter aufnehmen, der den Lademodus bestimmt:

@Embedded(loadIfNull=true)

EclipseLink bietet über sein Feature @Customizer eine ähnliche wirkende Konfigurationsmöglichkeit an (http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Entities/Embeddable).

Dirk

Autor

Diesen Artikel teilen

LinkedIn
Xing

Gibt es noch Fragen?

Fragen beantworten wir sehr gerne! Schreibe uns einfach per Kontaktformular.

Schulungen mit der selben Kategorie:

Blogkategorie: Alle
Es wurden keine Ergebnisse gefunden.

weitere Artikel

Kontakt

Brauchen Sie eine individuelle IT-Schulung, eine fundierte Beratung oder eine individuelle Softwareentwicklung? Dann sind Sie hier genau richtig!

Tim Neumann

Geschäftsleitung

GEDOPLAN GmbH
Stieghorster Straße 60
33605 Bielefeld

GEDOPLAN GmbH
Kantstraße 164
10623 Berlin

    Kontakt

    Tim Neumann

    Geschäftsleitung

    GEDOPLAN GmbH
    Stieghorster Straße 60
    33605 Bielefeld

    GEDOPLAN GmbH
    Kantstraße 164
    10623 Berlin

    Brauchen Sie eine individuelle IT-Schulung, eine fundierte Beratung oder eine individuelle Softwareentwicklung? Dann sind Sie hier genau richtig!