Est-il possible d'écrire un générique enum convertisseur pour JPA?
Je voulais écrire un Convertisseur de JPA qui stocke toutes les enum, en MAJUSCULES. Certaines énumérations que nous rencontrons ne suivent pas encore la convention à utiliser uniquement des lettres Majuscules donc, jusqu'à ce qu'ils sont refait j'ai toujours stocker la valeur future.
Ce que j'ai obtenu jusqu'à présent:
package student;
public enum StudentState {
Started,
Mentoring,
Repeating,
STUPID,
GENIUS;
}
Je veux "Commencé" à être stockées sous forme de "commencer" et ainsi de suite.
package student;
import jpa.EnumUppercaseConverter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "STUDENTS")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long mId;
@Column(name = "LAST_NAME", length = 35)
private String mLastName;
@Column(name = "FIRST_NAME", nullable = false, length = 35)
private String mFirstName;
@Column(name = "BIRTH_DATE", nullable = false)
@Temporal(TemporalType.DATE)
private Date mBirthDate;
@Column(name = "STUDENT_STATE")
@Enumerated(EnumType.STRING)
@Convert(converter = EnumUppercaseConverter.class)
private StudentState studentState;
}
le convertisseur actuellement ressemble à ceci:
package jpa;
import javax.persistence.AttributeConverter;
import java.util.EnumSet;
public class EnumUppercaseConverter<E extends Enum<E>> implements AttributeConverter<E, String> {
private Class<E> enumClass;
@Override
public String convertToDatabaseColumn(E e) {
return e.name().toUpperCase();
}
@Override
public E convertToEntityAttribute(String s) {
//which enum is it?
for (E en : EnumSet.allOf(enumClass)) {
if (en.name().equalsIgnoreCase(s)) {
return en;
}
}
return null;
}
}
ce qui ne va pas, c'est que je ne sais pas ce que enumClass sera au moment de l'exécution. Et je ne pouvais pas trouver un moyen de transmettre cette information à l'convertisseur dans le @Convertisseur annotation.
Donc est-il possible d'ajouter des paramètres à la converter ou tricher un peu? Ou est-il un autre moyen?
Je suis en utilisant EclipseLink 2.4.2
Merci!
- Attention, c'est fragile, surtout parce qu'il est parfaitement légal pour un enum pour avoir des valeurs
AVALUE
etAValue
. - oui c'est vrai, mais je définir comme completement interdite 😀
Vous devez vous connecter pour publier un commentaire.
Ce que vous devez faire est d'écrire une classe générique de base, puis d'étendre que pour chaque type enum vous souhaitez persister. Ensuite, utilisez le type étendu dans le
@Converter
annotation:où
Foo
est l'enum vous souhaitez gérer.L'alternative consisterait à définir un d'annotations personnalisées, le patch, la JPA fournisseur de reconnaître cette annotation. De cette façon, vous pouvez examiner le type de champ que vous construire la cartographie de l'information et de nourrir le nécessaire d'un type enum uniquement un convertisseur générique.
Connexes:
implements AttributeConverter <Foo, String>
à la déclaration de votre bétonFooConverter
classe, grâce à ce bug: hibernate.atlassian.net/browse/HHH-8854Basé sur @scottb solution, j'ai fait cette, testés contre hibernate 4.3: (pas de hibernate classes, devrait fonctionner sur JPA très bien)
Interface enum doit mettre en œuvre:
De Base abstraite converter:
Vous devez créer un convertisseur de classe pour chaque enum, je trouve plus facile de créer statique de la classe à l'intérieur de l'enum: (jpa/hibernate pourrait fournir de l'interface pour les enum, eh bien...)
Et de la cartographie exemple avec l'annotation:
Avec quelques modifications, vous pouvez créer un IntegerEnum interface et generify pour que.
@Converter
de laAbstractEnumConverter
parce que le Printemps essaie automatiquement d'enregistrer le convertisseur dans le Hibernate, qui ne fonctionne pas comme leAbstractEnumConverter
n'a pas de défaut noarg constructeur. Sinon, cela fonctionne comme un charme.@Converter
d'annotation à partir d'AbstractEnumConverter
et@Convert(converter = IndOrientation.Converter.class)
deIndOrientation
champ et au lieu de cela, j'ai ajouté@Converter(autoApply = true)
à la mise en œuvre concrèteConverter
.Ma solution à ce problème ressemble et permet également l'utilisation de la JPA 2.1 Convertisseur de facilité. Hélas, les types génériques en Java 8 ne sont pas réifiée, et donc il ne semble pas être un moyen facile d'éviter d'écrire une catégorie distincte pour chaque enum de Java que vous voulez être en mesure de convertir vers/à partir d'un format de base de données.
Vous pouvez toutefois réduire le processus de rédaction d'un enum classe de convertisseur pur passe-partout. Les composants de cette solution sont:
Encodeable
de l'interface; le contrat pour un enum classe qui donne accès à uneString
jeton pour chaque constante enum (également une usine pour obtenir la constante enum correspondant jeton)AbstractEnumConverter
classe; fournit le code pour traduire les jetons vers/à partir de enum constantesEncodeable
interfaceAbstractEnumConverter
classeLa
Encodeable
interface est simple et contient statique méthode de fabrique,forToken()
, pour l'obtention d'enum constantes:La
AbstractEnumConverter
classe est une classe générique est aussi simple. Il met en œuvre la JPA 2.1 AttributeConverter interface, mais ne fournit aucune implémentations pour ses méthodes (parce que cette classe ne peut pas connaître les types de béton nécessaire pour obtenir les enum constantes). Au lieu de cela, il définit les méthodes d'aide que le béton convertisseur classes de la chaîne d':Un exemple concret enum class que l'on pourrait maintenant être conservées dans une base de données avec JPA 2.1 Convertisseur installation est indiqué ci-dessous (notez qu'il met en œuvre
Encodeable
, et que le jeton pour chaque enum constante est définie comme un champ privé):Le passe-partout pour tous les JPA 2.1 Convertisseur de classe devrait maintenant ressembler à ceci (notez que chaque convertisseur devra étendre
AbstractEnumConverter
et de fournir des implémentations pour les méthodes de la JPA AttributeConverter interface):