Persistir um objeto JSON usando o Hibernate

Persistir um objeto JSON usando o Hibernate

1. Visão geral

Alguns projetos podem exigir que os objetos JSON sejam persistidos em um banco de dados relacional.

Neste tutorial, veremos comotake a JSON object and persist it in a relational database.

Existem várias estruturas disponíveis que fornecem essa funcionalidade, mas veremos algumas opções simples e genéricas usando apenasHibernateeJackson.

2. Dependências

Usaremosbasic Hibernate Core dependency para este tutorial:


    org.hibernate
    hibernate-core
    5.4.0.Final

Também usaremosJackson como nossa biblioteca JSON:


    com.fasterxml.jackson.core
    jackson-databind
    2.9.8

Note that these techniques are not limited to these two libraries. Podemos substituir nosso provedor JPA favorito e biblioteca JSON.

3. Métodos de serialização e desserialização

A maneira mais básica de persistir um objeto JSON em um banco de dados relacional éconvert the object into a String antes de persisti-lo. Então, nósconvert it back into an object quando o recuperamos do banco de dados.

Podemos fazer isso de algumas maneiras diferentes.

O primeiro que veremos é usarcustom serialize and deserialize methods.

Começaremos com uma entidadeCustomer simples que armazena o nome e o sobrenome do cliente, bem como alguns atributos sobre esse cliente.

Um objeto JSON padrão representaria esses atributos comoHashMap, então é isso que usaremos aqui:

@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;
}

Em vez de salvar os atributos em uma tabela separada, vamos parastore them as JSON in a column in the Customers table. Isso pode ajudar a reduzir a complexidade do esquema e melhorar o desempenho das consultas.

Primeiro,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);
}

Podemos chamar esse método manualmente antes de persistir, ou podemos chamá-lo do métodosetCustomerAttributes para que cada vez que os atributos forem atualizados, a string JSON também seja atualizada. 

A seguir,we’ll create a method to deserialize the JSON string back into a HashMap object quando recuperamosCustomer do banco de dados:

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

Mais uma vez, existem alguns lugares diferentes de onde podemos chamar esse método, mas, neste exemplo, vamos chamá-lo manualmente. 

Portanto, persistir e recuperar nosso objetoCustomer seria mais ou menos assim:

@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. Conversor de Atributos

If we are using JPA 2.1 or higher, podemos fazer uso deAttributeConverters para agilizar este processo.

Primeiro, vamos criar uma implementação deAttributeConverter. Reutilizaremos nosso código anterior:

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;
    }

}

Em seguida, dizemos ao Hibernate para usar nosso novoAttributeConverter para o campocustomerAttributes, e pronto:

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

With this approach, we no longer have to manually call the serialize and deserialize methods s desde que o Hibernate cuidará disso para nós. Podemos simplesmente salvar e recuperar o objetoCustomer normalmente.

5. Conclusão

Neste artigo, vimos vários exemplos de como persistir objetos JSON usando Hibernate e Jackson.

Nosso primeiro exemplo analisou um método simples e compatível, usando métodos personalizados de serialização e desserialização. Em segundo lugar, introduzimosAttributeConverters como uma forma poderosa de simplificar nosso código.

Como sempre, certifique-se de verificar o código-fonte deste tutorialover on Github.