Hibernate-reactive: Suporte para UserTypes personalizados

Criado em 9 jul. 2020  ·  30Comentários  ·  Fonte: hibernate/hibernate-reactive

Olá a todos. O Hibernate Reactive oferece suporte a UserTypes personalizados? Eu quero usar o tipo JSONB Postgres e para isso eu estava usando a seguinte biblioteca https://github.com/vladmihalcea/hibernate-types que cria seus tipos personalizados com base no AbstractSingleColumnStandardBasicType do Hibernate. Infelizmente, apenas mudando do Hibernate para o Hibernate Reactive, as colunas que usam esses tipos são sempre nulas nas entidades. Como alternativa, encontrei este artigo que constrói seu suporte a JSONB Postgres no UserType do Hibernate. Existe alguma limitação conhecida em torno da definição de tipos personalizados e do uso do Hibernate Reactive no momento?

design

Todos 30 comentários

Olá, não testei UserType porque essa interface está bastante ligada ao JDBC. (Embora, em princípio, talvez pudesse funcionar principalmente.)

Em vez disso, minha ideia era que as pessoas pudessem usar conversores JPA. Eu testei isso e AFAIK funciona. Você já tentou isso?

Eu tentei com um teste rápido usando UserType e não parece funcionar porque o PgClient lança uma exceção ao executar a consulta.

Eu tentei com um teste rápido usando UserType e não parece funcionar porque o PgClient lança uma exceção ao executar a consulta.

Mas isso pode ser apenas porque nossa camada JDBC falsa está incompleta. (Alguns métodos não implementados.)

Para esclarecer, tentei o exemplo usando a biblioteca vlad:

    @TypeDefs({
            @TypeDef(name = "json", typeClass = JsonStringType.class),
            @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
    })
    @Entity(name="GuineaPig")
    @Table(name="Pig")
    public static class GuineaPig {
        <strong i="6">@Id</strong>
        private Integer id;
        private String name;

        @Type(type = "jsonb")
        @Column(columnDefinition = "jsonb")
        private  Location location;

Este é o erro:

Caused by: io.vertx.core.impl.NoStackTraceThrowable: Parameter at position[0] with class = [com.fasterxml.jackson.databind.node.ObjectNode] and value = [{"country":"UK","city":"Gotham"}] can not be coerced to the expected class = [java.lang.Object] for encoding.

Parece que o cliente pg reativo usa um tipo diferente para converter para JSON.

@gavinking Devemos oferecer suporte a algum tipo de mapeamento para os tipos pg-client ?

JSON (io.reactiverse.pgclient.data.Json)
JSONB (io.reactiverse.pgclient.data.Json)
POINT (io.reactiverse.pgclient.data.Point)
LINE (io.reactiverse.pgclient.data.Line)
LSEG (io.reactiverse.pgclient.data.LineSegment)
BOX (io.reactiverse.pgclient.data.Box)
PATH (io.reactiverse.pgclient.data.Path)
POLYGON (io.reactiverse.pgclient.data.Polygon)
CIRCLE (io.reactiverse.pgclient.data.Circle)

Acho que o cliente está esperando um objeto do tipo io.reactiverse.pgclient.data.Json . Parece que lidamos com UserType corretamente, no entanto

Certo, é isso que eu quis dizer no meu comentário acima. Nossos adaptadores JDBC não estão nem perto de uma implementação completa do JDBC, e eu vejo como bem provável que nunca estarão. Em particular, para tipos JDBC mais “exóticos”, pode ser bastante difícil mapeá-los de / para a API Vert.x.

Devemos oferecer suporte a algum tipo de mapeamento para os tipos pg-client?

Bem, claro, se for razoavelmente fácil de fazer.

Mas se não, devemos considerar que talvez UserType simplesmente não seja a abstração certa aqui e procurar uma abordagem diferente.

Quero dizer, na medida em que UserType s existentes podem funcionar sem fazer nada horrível, então com certeza, vamos fazê-los funcionar. Isso tornará a migração mais fácil. Mas eu acho que é possível que rapidamente encontremos limitações quanto ao que é realmente possível lá.

vou dar uma olhada

vou dar uma olhada

Como primeiro passo, devemos adicionar um teste para um totalmente simples UserType que não usa nenhum tipo de banco de dados extravagante, apenas para verificar se o conceito básico funciona (não vejo por que não deveria )

@gavinking Não, eu não testei os conversores ainda porque estou usando o Hibernate junto com a biblioteca de tipos do Hibernate. Mas a sugestão de usar conversores significaria que no final irei colocar um Postgres Text / Varchar simples no banco de dados e não um tipo Postgres JSONB.

@gavinking Não, eu não testei os conversores ainda porque estou usando o Hibernate junto com a biblioteca de tipos do Hibernate. Mas a sugestão de usar conversores significaria que no final irei colocar um Postgres Text / Varchar simples no banco de dados e não um tipo Postgres JSONB.

Para esclarecer: você está preocupado com o tipo que você tem no Java ou no banco de dados? Existem duas coisas diferentes aqui.

  • Uma é usar JSONB como o tipo de coluna, mas, em princípio, eu pensaria que os drivers podem converter strings para esse tipo de forma transparente. (Não tenho certeza, nunca tentei.)
  • A segunda é usar io.reactiverse.pgclient.data.Json como o tipo Java em seu modelo. Esse é um problema totalmente diferente e, de fato, exigiria algo mais como UserType .

@gavinking
Quero usar o tipo Postgres JSONB . Acho que não é suportado diretamente pelo Hibernate. É por isso que confiei neste https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/ . Ou, por exemplo, este https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/ onde o guia usa UserType.

Certo, eu entendo isso, mas você já tentou fazer algo realmente simples, como mapear um Java String para uma coluna do tipo JSONB ? Isso seria bom o suficiente se funcionasse?

@gavinking Não, eu não tentei ainda. Sim, seria bom o suficiente. Eu só precisaria converter os objetos JSON em string JSON antes de tentar inserir minhas entidades no banco de dados.

OK, então pode ser que o cliente Vert.x já suporte essa conversão de tipo, precisaríamos tentar, mas mesmo que não, acho que provavelmente deveria.

@DavideD qual é o status aqui? Você quer que eu dê uma olhada mais de perto neste?

Eu fui desviado. Sinta-se à vontade para resolver isso se tiver tempo.

Em # 301, adicionei um teste demonstrando que UserType s trabalham em RH, pelo menos até o ponto em que nossos adaptadores PreparedStatement e ResultSet são implementações fiéis de JDBC ( o que não é particularmente grande).

@gavinking Devemos oferecer suporte a algum tipo de mapeamento para os tipos pg-client ?

JSON (io.reactiverse.pgclient.data.Json)
JSONB (io.reactiverse.pgclient.data.Json)
POINT (io.reactiverse.pgclient.data.Point)
LINE (io.reactiverse.pgclient.data.Line)
LSEG (io.reactiverse.pgclient.data.LineSegment)
BOX (io.reactiverse.pgclient.data.Box)
PATH (io.reactiverse.pgclient.data.Path)
POLYGON (io.reactiverse.pgclient.data.Polygon)
CIRCLE (io.reactiverse.pgclient.data.Circle)

Portanto, a questão agora é: podemos fazer com que getObject() e setObject() em nossos adaptadores JDBC suportem esses tipos sem criar uma dependência rígida para o cliente PostgreSQL?

Seria possível ter algo como:

@Type(type="passthrough")
Circle circle

Isso não faz nenhuma conversão, mas apenas passa o valor como está?

Portanto, a questão agora é: podemos fazer com que getObject() e setObject() em nossos adaptadores JDBC suportem esses tipos sem criar uma dependência rígida para o cliente PostgreSQL?

Bem, eu tentei isso e aparentemente não precisamos fazer nada de especial para lidar com io.vertx.core.json.JsonObject no Postgres ou MySQL. Você pode simplesmente usar getObject() / setObject() do seu UserType .

Isso funciona:

public class Json implements UserType {

    <strong i="15">@Override</strong>
    public int[] sqlTypes() {
        return new int[] {Types.OTHER};
    }

    <strong i="16">@Override</strong>
    public Class returnedClass() {
        return JsonObject.class;
    }

    <strong i="17">@Override</strong>
    public boolean equals(Object x, Object y) throws HibernateException {
        return Objects.equals(x,y);
    }

    <strong i="18">@Override</strong>
    public int hashCode(Object x) throws HibernateException {
        return Objects.hashCode(x);
    }

    <strong i="19">@Override</strong>
    public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
        return rs.getObject(names[0]);
    }

    <strong i="20">@Override</strong>
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
        if (value==null) {
            st.setNull(index, Types.OTHER);
        }
        else {
            st.setObject(index, value);
        }
    }

    ...
}

Seria possível ter algo como:

@Type(type="passthrough")
Circle circle

Isso não faz nenhuma conversão, mas apenas passa o valor como está?

Sim, isso também funcionaria.

Consulte 54434c94b3ff57261fd905abaeb25961b2ed285c.

Eu diria que podemos encerrar esse problema.

E quanto aos outros tipos, como io.reactiverse.pgclient.data.Circle por exemplo?

@akoufa agora para dar respostas concretas às suas perguntas originais:

O Hibernate Reactive suporta UserTypes customizado?

A resposta é sim!

No entanto, você precisa estar ciente de que, embora exponhamos algo que se parece muito com JDBC para seu UserType , nos bastidores não há conexão JDBC, mas um cliente de banco de dados totalmente diferente, sem bloqueio. Portanto, algumas coisas simplesmente não vão funcionar.

Eu estava usando a seguinte biblioteca https://github.com/vladmihalcea/hibernate-types

Então, acho que você precisa ser bem realista sobre isso. A biblioteca acima foi escrita para funcionar com JDBC, então enquanto algumas de suas UserType s podem funcionar, outras não.

Como alternativa, encontrei este artigo que constrói seu suporte JSONB Postgres no Hibernate UserType .

Dê uma olhada em como implementei isso no conjunto de testes. A ideia básica é que você precisa passar um Vert.x JsonObject para o cliente Vert.x PostgreSQL ou MySQL apenas chamando setObject() .

E quanto aos outros tipos, como io.reactiverse.pgclient.data.Circle por exemplo?

Deve ser o mesmo negócio, embora eu não teste.

A propósito, io.reactiverse.pgclient.data está morto. É para uma versão anterior do cliente. Não é para isso que você deveria estar olhando.

Aqui está a lista atual de tipos:

https://vertx.io/docs/vertx-pg-client/java/#_postgresql_type_mapping

Eu entendo isso, mas você já tentou fazer algo realmente simples, como apenas mapear uma string Java para uma coluna do tipo JSONB?

...

OK, então pode ser que o cliente Vert.x já suporte essa conversão de tipo, precisaríamos tentar, mas mesmo que não, acho que provavelmente deveria.

De acordo com os documentos que eu ligadas acima, isso não funciona. Eu até testei escrever um inteiro diretamente em uma coluna JSONB -types e funcionou.

Portanto, em princípio, você nem precisa mexer em JsonObject se não quiser. (Provavelmente, é mais limpo.)

Claro, você poderia adicionar um teste para alguns dos outros tipos específicos? Como linha ou círculo. Para que possamos mostrar a aparência do mapeamento

Oi!

Vocês viram alguma biblioteca como https://github.com/vladmihalcea/hibernate-types para usar com hibernate-reativo?

Se isso ainda não existir, gostaria de construir algo para o meu projeto (usando quarkus). Eu uso muitas colunas JSON no postgres.

Mas eu não sei se entendi errado, mas hibernate-reactive só permite o tipo personalizado implementando a partir da interface UserType ? (http://hibernate.org/reactive/documentation/1.0/reference/html_single/#_custom_types)

@AlexandreGuidin , acho que @gavinking já respondeu suas perguntas em um dos comentários anteriores: https://github.com/hibernate/hibernate-reactive/issues/279#issuecomment -666289449

Mas se eu estiver faltando alguma coisa, fique à vontade para fazer mais algumas perguntas.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Xset-s picture Xset-s  ·  3Comentários

tsegismont picture tsegismont  ·  9Comentários

gavinking picture gavinking  ·  6Comentários

markusdlugi picture markusdlugi  ·  30Comentários

arifpratama398 picture arifpratama398  ·  10Comentários