Est-il possible de déclarer les champs finaux pour les objets gérés par Hibernate?

StackOverflow https://stackoverflow.com/questions/912093

  •  06-09-2019
  •  | 
  •  

Question

Je viens juste de commencer avec Hibernate, et tous les exemples que je vois l'air si loin à peu près comme le tutoriel dans la documentation Hibernate:

package org.hibernate.tutorial.domain;
import java.util.Date;

public class Event {

    private Long id;
    private String title;
    private Date date;

    public Event() {}

    /* Accessor methods... */
}

Plus précisément: aucun des champs sont déclarés comme final, et il doit y avoir un constructeur sans argument pour que le cadre Hibernate peut instancier la classe et définir ses champs

.

Mais voici la chose - I vraiment n'aime pas faire mes cours mutable de quelque façon que chaque fois que je peux l'éviter (Java pratiques: objets Immuable font un argument assez fort pour le faire). Alors est-il possible de se Hibernate pour même si je devais déclarer chacun des champs « finale »

Je comprends que Hibernate utilise la réflexion pour instancier ses classes et doit donc être en mesure d'invoquer un constructeur de quelque sorte sans prendre le risque qu'il choisirait le mauvais constructeur ou passer la mauvaise valeur à l'un de ses paramètres, il est donc probablement plus sûr d'invoquer le constructeur sans arg et définir chaque champ un à la fois. Cependant, il ne devrait pas être possible de fournir les informations nécessaires à Hibernate afin qu'il puisse en toute sécurité instancier des objets immuables?

public class Event {

    private final Long id;
    private final String title;
    private final Date date;

    public Event(@SetsProperty("id") Long id,
        @SetsProperty("title") String title,
        @SetsProperty("date") Date date) {

        this.id = id;
        this.title = title;
        this.date = new Date(date.getTime());
    }

    /* Accessor methods... */
}

L'annotation @SetsProperty est évidemment fictive, mais ne semble pas comme il devrait être hors de portée.

Était-ce utile?

La solution

Cela sonne comme il n'est pas un cas d'utilisation pour Hibernate, car de nombreuses opérations qu'il effectue concernent l'état mutable:

  • objets fusion
  • sale état de vérification
  • changements de rinçage

Cela étant dit, si vous êtes préoccupé par l'immuabilité vous pouvez choisir de fournir des emballages autour de vos objets, avec copie-constructeurs:

public class FinalEvent {
    private final Integer id;

    public FinalEvent(Event event) {
        id = event.id;
    }
}

Il ne signifie du travail supplémentaire bien.


Maintenant que je pense à lui, séances hiverne sont généralement liées fil et ce vides au moins un des avantages des champs finaux -. Publication en toute sécurité

Quels sont les autres avantages des champs finaux recherchez-vous?

Autres conseils

objet immuable: un objet sans méthodes qui modifient son état (à savoir ses domaines). Les champs ne doivent pas être définitive. Ainsi, vous pouvez supprimer tous les mutateurs et configurer Hibernate d'utiliser des champs d'accès au lieu de accesseurs ou vous pouvez simplement marquer sans arg constructeur et mutateurs comme dépréciée. Il est une solution de peu, mais mieux que que rien.

En fait, dans JDK 1.5+ mise en veille prolongée peut traiter (par réflexion) en modifiant les champs finaux. Créer un constructeur par défaut protégé () qui définit les champs à certains paramètres par défaut / null etc ... Mise en veille prolongée peut et remplacer ces valeurs quand il instancie l'objet.

Ceci est possible grâce à des changements de Java 1.5 modèle de mémoire - les changements d'intérêt (ce qui permet finale d'être pas définitive), lorsqu'il est fait pour permettre sérialisation / désérialisation

.
public class Event {

private final Long id;
private final String title;
private final Date date;

// Purely for serialization/deserialization
protected Event() {
    id = null;
    title = null;
    date = null;
}

public Event(Long id, String title, Data date) {
    this.id = id;
    this.title = title;
    this.date = date;
}

/* Accessor methods... */

}

Celui-ci a été mise sur écoute moi depuis longtemps aussi. Une idée que j'ai essayer est récemment ce - définir les interfaces en lecture seule pour vos classes de modèle et que vos OTI et les usines retournent les place sur l'objet. Cela signifie que même si la mise en œuvre est mutable, une fois qu'il a quitté l'objet DAO / usine, il ne peut plus être modifié.

comme ceci:

public interface Grape {
  public Color getColor();
}

public class HibernateGrapeDao {
  public Grape findGrape(int grapeId) {
    HibernateGrape grape = hibernate.find(...
    return grape;
  }
}

class HibernateGrape implements Grape {
 ....
}

Peut même vouloir conserver le paquet-privé les classes de mise en œuvre du paquet dao, donc personne ne peut jouer avec eux directement. Un peu plus de travail, mais contribue probablement à garder les choses propres à long terme. Et, de toute évidence, être prudent avec l'entreprise toute l'égalité / identité.

Vous pouvez être en mesure d'obtenir le résultat souhaité en utilisant un motif Builder. Je lis un affichage il y a un moment sur les forums Hibernate discussion l'idée (si je ne me ... implémenté)

annoter votre classe avec @access (AccessType.FIELD), vous pouvez faire vos champs final. Comme ceci:

@Access(AccessType.FIELD)
public final class Event {

    private final Long id;
    private final String title;
    private final Date date;

    private Event() {
        id = null;
        title = null;
        date = null;
    }

    public Event(Long id, String title, Date date) {
        this.id = id;
        this.title = title;
        this.date = date;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top