Convertisseurs d’attributs JPA

Convertisseurs d'attributs JPA

1. introduction

Dans cet article rapide, nous allons couvrir l'utilisation des convertisseurs d'attributs disponibles dans JPA 2.1 - qui, en termes simples, nous permettent de mapper les types JDBC aux classes Java.

Nous utiliserons Hibernate 5 comme implémentation JPA ici.

2. Création d'un convertisseur

Nous allons montrer comment implémenter un convertisseur d'attributs pour une classe Java personnalisée.

Commençons par créer une classePersonName - qui sera convertie plus tard:

public class PersonName implements Serializable {

    private String name;
    private String surname;

    // getters and setters
}

Ensuite, nous ajouterons un attribut de typePersonName à une classe@Entity:

@Entity(name = "PersonTable")
public class Person {

    private PersonName personName;

    //...
}

Nous devons maintenant créer un convertisseur qui transforme l'attributPersonName en colonne de base de données et vice-versa. Dans notre cas, nous convertirons l'attribut en une valeurString contenant à la fois les champs nom et prénom.

Pour ce fairewe have to annotate our converter class with @Converter and implement the AttributeConverter interface. Nous paramétrerons l'interface avec les types de la classe et de la colonne de base de données, dans cet ordre:

@Converter
public class PersonNameConverter implements
  AttributeConverter {

    private static final String SEPARATOR = ", ";

    @Override
    public String convertToDatabaseColumn(PersonName personName) {
        if (personName == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        if (personName.getSurname() != null && !personName.getSurname()
            .isEmpty()) {
            sb.append(personName.getSurname());
            sb.append(SEPARATOR);
        }

        if (personName.getName() != null
          && !personName.getName().isEmpty()) {
            sb.append(personName.getName());
        }

        return sb.toString();
    }

    @Override
    public PersonName convertToEntityAttribute(String dbPersonName) {
        if (dbPersonName == null || dbPersonName.isEmpty()) {
            return null;
        }

        String[] pieces = dbPersonName.split(SEPARATOR);

        if (pieces == null || pieces.length == 0) {
            return null;
        }

        PersonName personName = new PersonName();
        String firstPiece = !pieces[0].isEmpty() ? pieces[0] : null;
        if (dbPersonName.contains(SEPARATOR)) {
            personName.setSurname(firstPiece);

            if (pieces.length >= 2 && pieces[1] != null
              && !pieces[1].isEmpty()) {
                personName.setName(pieces[1]);
            }
        } else {
            personName.setName(firstPiece);
        }

        return personName;
    }
}

Notez que nous avons dû implémenter 2 méthodes:convertToDatabaseColumn() etconvertToEntityAttribute().

Les deux méthodes sont utilisées pour convertir l'attribut en une colonne de base de données et inversement.

3. Utilisation du convertisseur

To use our converter, we just need to add the @Convert annotation to the attribute and specify the converter class we want to use:

@Entity(name = "PersonTable")
public class Person {

    @Convert(converter = PersonNameConverter.class)
    private PersonName personName;

    // ...
}

Enfin, créons un test unitaire pour voir qu'il fonctionne vraiment.

Pour ce faire, nous allons d'abord stocker un objetPerson dans notre base de données:

@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
    String name = "name";
    String surname = "surname";

    PersonName personName = new PersonName();
    personName.setName(name);
    personName.setSurname(surname);

    Person person = new Person();
    person.setPersonName(personName);

    Long id = (Long) session.save(person);

    session.flush();
    session.clear();
}

Ensuite, nous allons tester que lePersonName a été stocké tel que nous l'avons défini dans le convertisseur - en récupérant ce champ de la table de base de données:

@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
    // ...

    String dbPersonName = (String) session.createNativeQuery(
      "select p.personName from PersonTable p where p.id = :id")
      .setParameter("id", id)
      .getSingleResult();

    assertEquals(surname + ", " + name, dbPersonName);
}

Testons également que la conversion de la valeur stockée dans la base de données vers la classePersonName fonctionne comme défini dans le convertisseur en écrivant une requête qui récupère toute la classePerson:

@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
    // ...

    Person dbPerson = session.createNativeQuery(
      "select * from PersonTable p where p.id = :id", Person.class)
        .setParameter("id", id)
        .getSingleResult();

    assertEquals(dbPerson.getPersonName()
      .getName(), name);
    assertEquals(dbPerson.getPersonName()
      .getSurname(), surname);
}

4. Conclusion

Dans ce bref tutoriel, nous avons montré comment utiliser les convertisseurs d'attributs récemment introduits dans JPA 2.1.

Comme toujours, le code source complet des exemples est disponibleover on GitHub.