Hibernate-reactive: Soporte para UserTypes personalizados

Creado en 9 jul. 2020  ·  30Comentarios  ·  Fuente: hibernate/hibernate-reactive

Hola a todos. ¿Hibernate Reactive admite tipos de usuario personalizados? Quiero usar Postgres JSONB Type y para eso estaba usando la siguiente biblioteca https://github.com/vladmihalcea/hibernate-types que construye sus tipos personalizados basados ​​en AbstractSingleColumnStandardBasicType de Hibernate. Desafortunadamente, con solo pasar de Hibernate a Hibernate Reactive, las columnas que usan estos tipos siempre son nulas en las entidades. Como alternativa, encontré este artículo que construye su soporte JSONB Postgres en el UserType de Hibernate. ¿Existe alguna limitación conocida sobre la definición de tipos personalizados y el uso de Hibernate Reactive en este momento?

design

Todos 30 comentarios

Hola, no probé UserType ya que esa interfaz está bastante ligada a JDBC. (Aunque, en principio, tal vez se podría hacer que funcione principalmente).

En cambio, mi idea era que la gente pudiera usar convertidores JPA. Lo probé y AFAIK funciona. ¿Has probado eso?

Intenté con una prueba rápida usando UserType y no parece funcionar porque PgClient lanza una excepción al ejecutar la consulta.

Intenté con una prueba rápida usando UserType y no parece funcionar porque PgClient lanza una excepción al ejecutar la consulta.

Pero eso podría deberse a que nuestra capa JDBC falsa está incompleta. (Algunos métodos no implementados).

Para aclarar, probé el ejemplo usando la 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 es el error:

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 el cliente pg reactivo usa un tipo diferente para convertir a JSON.

@gavinking ¿Deberíamos admitir algún tipo de mapeo para los tipos de cliente pg ?

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)

Creo que el cliente espera un objeto de tipo io.reactiverse.pgclient.data.Json . Sin embargo, parece que manejamos UserType correctamente

Bien, eso es lo que quise decir en mi comentario anterior. Nuestros adaptadores JDBC ni siquiera están cerca de una implementación completa de JDBC, y creo que es muy probable que nunca lo estén. En particular, para los tipos de JDBC más "exóticos", puede resultar bastante difícil asignarlos a / desde la API Vert.x.

¿Deberíamos admitir algún tipo de mapeo para los tipos de cliente pg?

Bueno, claro, si es razonablemente fácil de hacer.

Pero si no, deberíamos considerar que quizás UserType no sea la abstracción correcta aquí, y buscar un enfoque diferente.

Quiero decir, en la medida en que los UserType s existentes puedan funcionar sin hacer nada horrible, entonces claro, hagámoslos funcionar. Facilitará la migración. Pero creo que es posible que rápidamente nos encontremos con limitaciones en cuanto a lo que es realmente posible allí.

Echaré un vistazo

Echaré un vistazo

Como primer paso, debemos agregar una prueba para un UserType totalmente simple que no use ningún tipo de base de datos elegante, solo para verificar que el concepto básico funciona (no veo por qué no debería ).

@gavinking No, probé los convertidores porque estoy usando Hibernate junto con la biblioteca de tipos de Hibernate. Pero la sugerencia de usar convertidores significaría que al final pondré un Postgres Text / Varchar simple en la base de datos y no un tipo Postgres JSONB.

@gavinking No, probé los convertidores porque estoy usando Hibernate junto con la biblioteca de tipos de Hibernate. Pero la sugerencia de usar convertidores significaría que al final pondré un Postgres Text / Varchar simple en la base de datos y no un tipo Postgres JSONB.

Para aclarar: ¿le preocupa qué tipo tiene en Java o en la base de datos? Aquí hay dos cosas diferentes.

  • Una es usar JSONB como tipo de columna, pero en principio habría pensado que los controladores pueden convertir cadenas de forma transparente a ese tipo. (No estoy seguro, nunca lo intenté).
  • El segundo es usar io.reactiverse.pgclient.data.Json como el tipo de Java en su modelo. Ese es un problema completamente diferente y de hecho requeriría algo más como UserType .

@gavinking
Quiero usar el tipo Postgres JSONB . Creo que no es compatible directamente con Hibernate. Por eso confié en este https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/ . O, por ejemplo, este https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/ donde la guía usa UserType.

Bien, lo entiendo, pero ¿ha intentado hacer algo realmente simple como simplemente mapear un Java String a una columna de tipo JSONB ? ¿Sería suficientemente bueno si funcionara?

@gavinking No, no lo intenté todavía. Sí, sería lo suficientemente bueno. Solo necesitaría convertir los objetos JSON a una cadena JSON antes de intentar insertar mis Entidades en la base de datos.

Bien, entonces puede ser que el cliente Vert.x ya sea compatible con ese tipo de conversión, tendríamos que probarlo, pero incluso si no lo hace, creo que probablemente debería hacerlo.

@DavideD ¿cuál es el estado aquí? ¿Quieres que le dé un vistazo más de cerca a este?

Me desvié. Siéntase libre de abordar esto si tiene tiempo.

En el # 301, agregué una prueba que demuestra que UserType s funcionan en RR.HH., al menos en la medida en que nuestros adaptadores PreparedStatement y ResultSet son una implementación fiel de JDBC ( que no es una medida particularmente grande).

@gavinking ¿Deberíamos admitir algún tipo de mapeo para los tipos de cliente pg ?

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)

Entonces, la pregunta ahora es: ¿podemos hacer que getObject() y setObject() en nuestros adaptadores JDBC admitan estos tipos sin crear una dependencia estricta con el cliente PostgreSQL?

¿Sería posible tener algo como:

@Type(type="passthrough")
Circle circle

¿Eso no realiza ninguna conversión, sino que simplemente pasa el valor tal como está?

Entonces, la pregunta ahora es: ¿podemos hacer que getObject() y setObject() en nuestros adaptadores JDBC admitan estos tipos sin crear una dependencia estricta con el cliente PostgreSQL?

Bueno, lo intenté y aparentemente no necesitamos hacer nada especial para manejar io.vertx.core.json.JsonObject en Postgres o MySQL. Puede usar getObject() / setObject() de su UserType .

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

    ...
}

¿Sería posible tener algo como:

@Type(type="passthrough")
Circle circle

¿Eso no realiza ninguna conversión, sino que simplemente pasa el valor tal como está?

Sí, eso también funcionaría.

Consulte 54434c94b3ff57261fd905abaeb25961b2ed285c.

Diría que podemos cerrar este tema.

¿Qué pasa con los otros tipos, como io.reactiverse.pgclient.data.Circle por ejemplo?

@akoufa ahora para darte respuestas concretas a tus preguntas originales:

¿Hibernate Reactive admite UserTypes ?

¡La respuesta es sí!

Sin embargo, debe tener en cuenta que, aunque exponemos algo que se parece mucho a JDBC en su UserType , debajo de las cubiertas no hay conexión JDBC, sino un cliente de base de datos sin bloqueo completamente diferente. Entonces, algunas cosas simplemente no van a funcionar.

Estaba usando la siguiente biblioteca https://github.com/vladmihalcea/hibernate-types

Así que creo que tendrás que ser bastante realista al respecto. La biblioteca anterior está escrita para funcionar con JDBC, por lo que aunque algunos de sus UserType s pueden funcionar, otros no.

Como alternativa, encontré este artículo que construye su soporte JSONB Postgres en UserType Hibernate.

Eche un vistazo a cómo he implementado esto en el conjunto de pruebas. La idea básica es que necesita pasar un Vert.x JsonObject al cliente Vert.x PostgreSQL o MySQL simplemente llamando a setObject() .

¿Qué pasa con los otros tipos, como io.reactiverse.pgclient.data.Circle por ejemplo?

Debería ser el mismo trato, aunque no lo probé.

Por cierto, io.reactiverse.pgclient.data está muerto. Es para una versión anterior del cliente. Eso no es lo que deberías estar mirando.

Aquí está la lista actual de tipos:

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

Lo entiendo, pero ¿ha intentado hacer algo realmente simple como simplemente mapear una cadena de Java a una columna de tipo JSONB?

...

Bien, entonces puede ser que el cliente Vert.x ya sea compatible con ese tipo de conversión, tendríamos que probarlo, pero incluso si no lo hace, creo que probablemente debería hacerlo.

De acuerdo con la documentación que he vinculado anteriormente, esto funciona. Incluso probé escribir un número entero directamente en una columna JSONB -types y funcionó.

Entonces, en principio, ni siquiera necesita meterse con JsonObject si no quiere. (Aunque probablemente esté más limpio).

Seguro, ¿podría agregar una prueba para algunos de los otros tipos específicos? Como línea o círculo. Para que podamos mostrar cómo se ve el mapeo

¡Hola!

¿Han visto alguna biblioteca como https://github.com/vladmihalcea/hibernate-types para usar con hibernate-reactivo?

Si eso aún no existe, me gustaría construir algo para mi proyecto (usando quarkus). Utilizo muchas columnas JSON en postgres.

Pero no sé si me equivoco, pero hibernate-reactive solo permite el tipo personalizado implementando desde UserType interfaz? (http://hibernate.org/reactive/documentation/1.0/reference/html_single/#_custom_types)

@AlexandreGuidin , creo que @gavinking ya respondió tus preguntas en uno de los comentarios anteriores: https://github.com/hibernate/hibernate-reactive/issues/279#issuecomment -666289449

Pero si me falta algo, no dudes en continuar con algunas preguntas más.

¿Fue útil esta página
0 / 5 - 0 calificaciones