Persister un objet JSON en utilisant Hibernate

Persister un objet JSON en utilisant Hibernate

1. Vue d'ensemble

Certains projets peuvent nécessiter la persistance d'objets JSON dans une base de données relationnelle.

Dans ce tutoriel, nous allons voir commenttake a JSON object and persist it in a relational database.

Il existe plusieurs frameworks disponibles qui fournissent cette fonctionnalité, mais nous examinerons quelques options simples et génériques en utilisant uniquementHibernate etJackson.

2. Les dépendances

Nous utiliserons lesbasic Hibernate Core dependency pour ce didacticiel:


    org.hibernate
    hibernate-core
    5.4.0.Final

Nous utiliserons égalementJackson comme bibliothèque JSON:


    com.fasterxml.jackson.core
    jackson-databind
    2.9.8

Note that these techniques are not limited to these two libraries. Nous pouvons remplacer notre fournisseur JPA préféré et la bibliothèque JSON.

3. Sérialiser et désérialiser les méthodes

Le moyen le plus simple de conserver un objet JSON dans une base de données relationnelle est deconvert the object into a String avant de le conserver. Ensuite, nousconvert it back into an object lorsque nous le récupérons de la base de données.

Nous pouvons le faire de différentes manières.

Le premier que nous allons examiner utilisecustom serialize and deserialize methods.

Nous allons commencer par une simple entitéCustomer qui stocke le prénom et le nom du client, ainsi que certains attributs concernant ce client.

Un objet JSON standard représenterait ces attributs sous forme deHashMap, c'est donc ce que nous allons utiliser ici:

@Entity
@Table(name = "Customers")
public class Customer {

    @Id
    private int id;

    private String firstName;

    private String lastName;

    private String customerAttributeJSON;

    @Convert(converter = HashMapConverter.class)
    private Map customerAttributes;
}

Plutôt que de sauvegarder les attributs dans une table séparée, nous allons versstore them as JSON in a column in the Customers table. Cela peut aider à réduire la complexité du schéma et à améliorer les performances des requêtes.

Tout d'abord,we’ll create a serialize method that will take our customerAttributes and convert it to a JSON string:

public void serializeCustomerAttributes() throws JsonProcessingException {
    this.customerAttributeJSON = objectMapper.writeValueAsString(customerAttributes);
}

Nous pouvons appeler cette méthode manuellement avant de persister, ou nous pouvons l'appeler à partir de la méthodesetCustomerAttributes afin que chaque fois que les attributs sont mis à jour, la chaîne JSON soit également mise à jour. 

Ensuite,we’ll create a method to deserialize the JSON string back into a HashMap object lorsque nous récupérons lesCustomer de la base de données:

public void deserializeCustomerAttributes() throws IOException {
    this.customerAttributes = objectMapper.readValue(customerAttributeJSON, HashMap.class);
}

Une fois de plus, il existe différents endroits à partir desquels nous pouvons appeler cette méthode, mais, dans cet exemple, nous l'appellerons manuellement. 

Ainsi, persister et récupérer notre objetCustomer ressemblerait à ceci:

@Test
public void whenStoringAJsonColumn_thenDeserializedVersionMatches() {
    Customer customer = new Customer();
    customer.setFirstName("first name");
    customer.setLastName("last name");

    Map attributes = new HashMap<>();
    attributes.put("address", "123 Main Street");
    attributes.put("zipcode", 12345);

    customer.setCustomerAttributes(attributes);
    customer.serializeCustomerAttributes();

    String serialized = customer.getCustomerAttributeJSON();

    customer.setCustomerAttributeJSON(serialized);
    customer.deserializeCustomerAttributes();

    assertEquals(attributes, customer.getCustomerAttributes());
}

4. Convertisseur d'attributs

If we are using JPA 2.1 or higher, nous pouvons utiliserAttributeConverters pour rationaliser ce processus.

Tout d'abord, nous allons créer une implémentation deAttributeConverter. Nous réutiliserons notre code antérieur:

public class HashMapConverter implements AttributeConverter, String> {

    @Override
    public String convertToDatabaseColumn(Map customerInfo) {

        String customerInfoJson = null;
        try {
            customerInfoJson = objectMapper.writeValueAsString(customerInfo);
        } catch (final JsonProcessingException e) {
            logger.error("JSON writing error", e);
        }

        return customerInfoJson;
    }

    @Override
    public Map convertToEntityAttribute(String customerInfoJSON) {

        Map customerInfo = null;
        try {
            customerInfo = objectMapper.readValue(customerInfoJSON, Map.class);
        } catch (final IOException e) {
            logger.error("JSON reading error", e);
        }

        return customerInfo;
    }

}

Ensuite, nous disons à Hibernate d'utiliser nos nouveauxAttributeConverter pour le champcustomerAttributes, et nous avons terminé:

@Convert(converter = HashMapConverter.class)
private Map customerAttributes;

With this approach, we no longer have to manually call the serialize and deserialize methods since Hibernate s'en chargera pour nous. Nous pouvons simplement sauvegarder et récupérer l'objetCustomer normalement.

5. Conclusion

Dans cet article, nous avons vu plusieurs exemples sur la façon de conserver des objets JSON à l'aide d'Hibernate et Jackson.

Notre premier exemple portait sur une méthode simple et compatible utilisant des méthodes personnalisées de sérialisation et de désérialisation. Et deuxièmement, nous avons introduitAttributeConverters comme un moyen puissant de simplifier notre code.

Comme toujours, assurez-vous de consulter le code source de ce tutorielover on Github.