11
votes

Fournisseur de persistance pour Java qui soutient les champs finaux

Je suis très nouveau à Java, mais je développe une habitude d'utiliser finale dans la mesure du possible, déclarant immuabilité que je pense est une bonne chose. (Considérer f #)

J'ai lu que JPA ne prend pas en charge les champs finaux. Hibernate, toplink? Je ne suis pas sûr de cela, mais je préfère JPA pour l'instant.

est-ce que même possible théoriquement - disons par réflexion - pour modifier les champs finaux après la création? Je suppose que ce serait ... non :)

Qu'est-ce qui serait certainement possible pour une solution de persistance consiste à prendre en charge les constructeurs avec des paramètres. Au moins je ne vois aucune raison qui rendrait cela impossible. La cartographie serait un peu délicate, je suppose. Ceci est une solution alternative.

suggestions?

edit: Je ne connais pas la définition exacte pour immuable, donc je l'ai utilisé dans ce post intuitivement. Déclarant immuabilité ici signifie déclarer qu'un champ ne peut pas être changé. Désolé pour le malentendu.


0 commentaires

5 Réponses :


-2
votes

C'est honnêtement une idée étrange.

En faisant des champs final , vous dites au compilateur qu'ils seront jamais changer après la création d'objets. En conséquence, c'est une hypothèse raisonnable de ne pas les persister, car ils ne changeront jamais. Eh bien, en écrivant cela, je suppose que vous avez la culture Java, mais la question que vous demandez raconte précisément le contraire.

En Java, les obéjcts persistés sont "toujours" supposés être pojo (en d'autres termes, haricots Java). Un haricot Java doit avoir (à considérer comme tel) un constructeur vide qui permettra aux cadres de persistance et donc de la construire à l'aide de son constructeur vide, en l'appelant indirectement à travers la classe.NewInstance () /.

Il existe des champs dans lesquels des constructeurs non vides sont utilisés (comme des conteneurs IOC - Guice, IOC de printemps et de tapisserie), mais il est hors de portée des haricots Java, qui doivent être considérés comme des objets de données.


8 commentaires

Qu'en est-il d'une base de données en lecture seule? BTW Je viens d'explorer des possibilités.


Autres cas d'utilisation: entité multiple pour une table. Ou créer ces entités via une méthode d'usine.


Désolé. Je ne comprends pas ça du tout. Si ce que vous dites, c'est que les cadres de persistance existants ne soutiennent que Javabeans, vous pouvez avoir raison. Mais si vous dites qu'il y a quelque chose d'intrinsèque à des objets immuables qui les rendent inappropriés à la persistance, je suis totalement en désaccord. On pourrait affirmer que la langue Java prend de travailler avec des objets immuables fastidieux, mais des cadres pouvaient facilement atténuer ces lacunes.


Dans le premier paragraphe de votre réponse, vous semblez supposer qu'un objet est extrait d'une base de données, modifiée, puis engagée, et donc l'objet doit être modifiable à la place afin d'être utile. Dans de nombreux cas (peut-être la plupart), le client de persistance est un serveur apatride où la mise à jour externalisée (page Web, quoi que ce soit) et un nouvel objet est réalisée, sur l'appel de validation (poste, placé). Dans ce cas, je préférerais préférer des objets immuables, car il applique une transparence référentielle, en particulier si des validations commerciales complexes sont effectuées avant de commettre.


Et même dans les cas où un scénario de processus fermé où une entité est récupérée, modifiée et engagée. Je favoriserais toujours des objets immuables car, même si vous ne pouvez pas effectuer une mise à jour en place, vous pouvez effectuer une mise à jour avec des objets immuables, puis commettre la copie mise à jour. Je ferais toujours favoriser les objets immuables dans ce cas car vous devrez peut-être toujours passer l'objet à de nombreux validateurs, pour lesquels une transparence référentielle serait idéale.


@ DSMITH Premièrement, le cadre de persistance existant est en effet construit avec JavaBeans. Pour être honnête, quand ils ont été conçus (il y a 15 ans), JavaBeans étaient censés être une bonne idée. De nos jours, les gens sautent dans la bande passante immuable et ces préoccupations de la création d'objets immuables commencent à avoir un sens.


@RiDuidel c'est vrai. Bien que je ne puisse pas savoir à quel point il serait difficile de moderniser les cadres de persistance existants à prendre conscience des autres mécanismes de construction tels que des constructeurs. Par exemple, le Cadre Jackson pour JSON.


Un événement est immuable mais il est logique de le persister.



7
votes

Immutabilité de l'objet (notez la différence entre un objet immuable et déclarant une finale de champ - un objet n'est immuable que si tous les champs sont finaux, l'état de l'objet ne peut donc pas changer après la création) est un sujet très sensible. Je les aime moi-même et l'hibernate les soutient par @Immutable.

Je ne sais pas de son statut dans JPA 2, mais de répondre à la question concernant les champs finaux: vous pouvez modifier leurs valeurs à l'aide de la réflexion - mais la réflexion est sévèrement limitée dans un environnement Java EE.

Pour éclairer le problème principal: si vos pojos sont immuables, comment une solution persistante recréerait-elle les objets? Disons que vous disposez de deux champs internationaux et d'un constructeur pour les initialiser. La couche de persistance ne peut avoir aucune information sur leur commande, ni que leurs noms (comme noms de champ et de paramètres sont effacés pendant la compilation).

Koshuke a posté un blog à ce sujet (par rapport à Jaxb supportant des haricots immuables), mais ne peut pas le trouver maintenant.


1 commentaires

Les noms de paramètres sont disponibles avec Java 8 et avec des versions plus anciennes, vous pouvez les obtenir en utilisant Paranamer pendant la construction.



4
votes

Cela peut ne pas être exactement ce que vous cherchez, mais le principe d'immutabilité peut facilement être pris en charge par des champs privés non finis ayant uniquement un getter. En fait, le compilateur reconnaît cela et génère un code qui est à peu près identique à ce que vous obtiendriez avec des champs déclarés en finale.

Cela nécessitera que vous soyez consciencieux et ne changez pas vos champs de la classe contenant (alors que final en ferait appliquer cela), mais je pense que ce n'est pas un gros prix à payer pour la flexibilité que vous Gain.


2 commentaires

Je mettrais cette réponse en avant comme le correct.


C'est une pitié cependant, avec le modificateur final, il est clair que vous avez conçu de cette manière. Supprimer le setter Ce n'est pas une bonne solution, vous pouvez toujours modifier l'état et que quelqu'un de l'équipe finira par le faire, car il est très tentant et que vous ne pouvez pas l'appliquer. Cadres (au moins des cadres de persistance) devrait soutenir cet IMHO, c'est un outil très utile



0
votes

Les champs finaux ne peuvent pas être modifiés après la création par design. Faire autrement est une très mauvaise idée, car quelqu'un peut compter sur un comportement standard.

En général, les cadres de persistance traitent de hiérarchies d'objets "normaux". Vous avez des objets, qui peuvent être créés et supprimés, non modifiés. C'est très étrange, car lorsque vous créez une entité, vous créez une sorte d'identifiant pour cela. Grâce à cet identifiant, vous connectez une entité aux autres. Lorsque vous retirez l'ancienne entité et créez un autre, vous (en général) obtenez une entité avec un autre identifiant. Ainsi, toutes les connexions (clés étrangères) sont cassées. Est-ce le comportement ciblé?


0 commentaires

2
votes

bonne question. En fait, il est une bonne idée de déclarer des champs en finale si elles ne changent pas (vous obtenez alors des garanties d'initialisation de la JMM).

La spécification JPA est claire concernant les champs finaux:

La classe d'entité ne doit pas être définitive. Aucune méthode ni variables d'instance persistante de la classe d'entité peut être définitive.

heavreon, toutes les implémentations ne suivent pas cette règle et gérer les champs finaux:

  • OpenJPA ne prend pas en charge les champs finaux, c'est-à-dire qu'ils sont traités comme transitoires. Lors du chargement des champs finaux d'une telle entité sont initialisés avec les valeurs comme défini dans le constructeur sans paramètre.

  • La mise en œuvre de l'hibernate prend toutefois en charge les champs finaux. Sur la construction des champs finaux qui ont été initialisés dans le constructeur sans paramètre sont remplacés par les valeurs stockées dans la base de données.

    afin de répondre à votre question: Oui, il existe des fournisseurs de persistance JPA qui soutiennent les champs finaux, Cependant, je recommande de ne pas utiliser de champs finaux dans vos classes d'entité car le comportement n'est pas défini. (et diffère effectivement du fournisseur au fournisseur). De plus, je pense que c'est une mauvaise idée qu'un Le fournisseur JPA modifie les champs finaux après la construction, car les garanties de visibilité peuvent être violées de cette manière.


0 commentaires