Hibernate-reactive: Prise en charge des types d'utilisateurs personnalisés

Créé le 9 juil. 2020  ·  30Commentaires  ·  Source: hibernate/hibernate-reactive

Bonjour à tous. Hibernate Reactive prend-il en charge les UserTypes personnalisés ? Je souhaite utiliser Postgres JSONB Type et pour cela, j'utilisais la bibliothèque suivante https://github.com/vladmihalcea/hibernate-types qui construit ses types personnalisés basés sur AbstractSingleColumnStandardBasicType d'Hibernate. Malheureusement, juste en passant d'Hibernate à Hibernate Reactive, les colonnes qui utilisent ces types sont toujours nulles dans les entités. Comme alternative, j'ai trouvé cet article qui construit son support JSONB Postgres sur le UserType d'Hibernate. Existe-t-il actuellement une limitation connue concernant la définition de types personnalisés et l'utilisation d'Hibernate Reactive ?

design

Tous les 30 commentaires

Bonjour, je n'ai pas testé UserType car cette interface est plutôt liée à JDBC. (Bien qu'en principe, cela pourrait peut-être fonctionner pour la plupart.)

Au lieu de cela, mon idée était que les gens pourraient utiliser des convertisseurs JPA. J'ai testé ça et AFAIK ça marche. Avez-vous essayé cela?

J'ai essayé avec un test rapide en utilisant UserType et cela ne semble pas fonctionner car le PgClient lève une exception lors de l'exécution de la requête.

J'ai essayé avec un test rapide en utilisant UserType et cela ne semble pas fonctionner car le PgClient lève une exception lors de l'exécution de la requête.

Mais c'est peut-être simplement parce que notre fausse couche JDBC est incomplète. (Certaines méthodes non implémentées.)

Pour clarifier, j'ai essayé l'exemple en utilisant la bibliothèque 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;

C'est l'erreur :

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.

Il semble que le client pg réactif utilise un type différent pour convertir en JSON.

@gavinking Devrions-nous prendre en charge une sorte de mappage pour les types 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)

Je pense que le client attend un objet de type io.reactiverse.pgclient.data.Json . Il semble que nous gérons correctement UserType

C'est bien ce que je voulais dire dans mon commentaire ci-dessus. Nos adaptateurs JDBC ne sont même pas proches d'une implémentation complète de JDBC, et je pense qu'il est fort probable qu'ils ne le seront jamais. En particulier, pour les types JDBC plus « exotiques », il peut être assez difficile de les mapper vers/depuis l'API Vert.x.

Devrions-nous prendre en charge une sorte de mappage pour les types pg-client ?

Eh bien, bien sûr, si c'est raisonnablement facile à faire.

Mais sinon, nous devrions considérer que peut-être UserType n'est tout simplement pas la bonne abstraction ici, et chercher une approche différente.

Je veux dire, dans la mesure où les UserType existants peuvent fonctionner sans rien faire d'horrible, alors bien sûr, faisons-les fonctionner. Cela facilitera la migration. Mais je pense qu'il est possible que nous rencontrions rapidement des limites quant à ce qui est vraiment possible là-bas.

J'irais regarder

J'irais regarder

Dans un premier temps, nous devrions ajouter un test pour un UserType totalement simple qui n'utilise aucun type de base de données fantaisiste, juste pour vérifier que le concept de base fonctionne (je ne vois pas pourquoi cela ne devrait pas ).

@gavinking Non, je n'ai pas encore testé les convertisseurs car j'utilise Hibernate avec la bibliothèque Hibernate Types. Mais la suggestion d'utiliser des convertisseurs signifierait que je mettrai à la fin un simple Postgres Text/Varchar dans la base de données et non un type Postgres JSONB.

@gavinking Non, je n'ai pas encore testé les convertisseurs car j'utilise Hibernate avec la bibliothèque Hibernate Types. Mais la suggestion d'utiliser des convertisseurs signifierait que je mettrai à la fin un simple Postgres Text/Varchar dans la base de données et non un type Postgres JSONB.

Pour clarifier : êtes-vous préoccupé par le type que vous avez en Java ou dans la base de données ? Il y a deux choses différentes ici.

  • L'une consiste à utiliser JSONB comme type de colonne, mais en principe, j'aurais pensé que les pilotes peuvent convertir de manière transparente les chaînes vers ce type. (Je ne sais pas, je n'ai jamais essayé.)
  • La seconde consiste à utiliser io.reactiverse.pgclient.data.Json comme type Java dans votre modèle. C'est un tout autre problème et cela nécessiterait en effet quelque chose de plus comme un UserType .

@gavinking
Je souhaite utiliser le type Postgres JSONB . Je pense qu'il n'est pas pris en charge directement par Hibernate. C'est pourquoi je me suis appuyé sur ce https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/ . Ou par exemple ce https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/ où le guide utilise UserType .

Bien, je comprends cela, mais avez-vous essayé de faire quelque chose de très simple, comme mapper un Java String à une colonne de type JSONB ? Cela suffirait-il si cela fonctionnait ?

@gavinking Non, je n'ai pas encore essayé. Oui ce serait assez bien. J'aurais juste besoin de convertir les objets JSON en chaîne JSON avant d'essayer d'insérer mes entités dans la base de données.

OK, alors il se peut que le client Vert.x prenne déjà en charge cette conversion de type, nous aurions besoin de l'essayer, mais même si ce n'est pas le cas, je suppose que je pense que cela devrait probablement le faire.

@DavideD quel est le statut ici ? Voulez-vous que je regarde celui-ci de plus près?

Je me suis distrait. N'hésitez pas à vous en occuper si vous avez le temps.

Dans #301, j'ai ajouté un test démontrant que les UserType fonctionnent dans les RH, du moins dans la mesure où nos adaptateurs PreparedStatement et ResultSet sont une implémentation fidèle de JDBC ( ce qui n'est pas particulièrement important).

@gavinking Devrions-nous prendre en charge une sorte de mappage pour les types 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)

La question devient donc maintenant : pouvons-nous faire en sorte que getObject() et setObject() dans nos adaptateurs JDBC prennent en charge ces types sans créer de dépendance stricte au client PostgreSQL ?

Serait-il possible d'avoir quelque chose comme :

@Type(type="passthrough")
Circle circle

Cela ne fait aucune conversion mais transmet simplement la valeur telle quelle ?

La question devient donc maintenant : pouvons-nous faire en sorte que getObject() et setObject() dans nos adaptateurs JDBC prennent en charge ces types sans créer de dépendance stricte au client PostgreSQL ?

Eh bien, j'ai essayé cela, et apparemment nous n'avons pas besoin de faire quoi que ce soit de spécial pour gérer io.vertx.core.json.JsonObject sur Postgres ou MySQL. Vous pouvez simplement utiliser getObject() / setObject() de votre UserType .

Cela marche:

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

    ...
}

Serait-il possible d'avoir quelque chose comme :

@Type(type="passthrough")
Circle circle

Cela ne fait aucune conversion mais transmet simplement la valeur telle quelle ?

Oui, cela fonctionnerait aussi.

Voir 54434c94b3ff57261fd905abaeb25961b2ed285c.

Je dirais que nous pouvons clore cette question.

Qu'en est-il des autres types, comme io.reactiverse.pgclient.data.Circle par exemple ?

@akoufa maintenant pour vous apporter des réponses concrètes à vos questions initiales :

Hibernate Reactive prend-il en charge les UserTypes ?

La réponse est oui!

Cependant, vous devez savoir que même si nous exposons quelque chose qui ressemble beaucoup à JDBC à votre UserType , sous les couvertures, il n'y a pas de connexion JDBC, mais un tout autre client de base de données non bloquant. Donc, certaines choses ne fonctionneront tout simplement pas.

J'utilisais la bibliothèque suivante https://github.com/vladmihalcea/hibernate-types

Je pense donc que vous devrez être assez réaliste à ce sujet. La bibliothèque ci-dessus est écrite pour fonctionner avec JDBC, donc même si certains de ses UserType peuvent fonctionner, d'autres non.

Comme alternative, j'ai trouvé cet article qui construit son support JSONB Postgres sur le UserType Hibernate.

Jetez un œil à la façon dont j'ai implémenté cela dans la suite de tests. L'idée de base est que vous devez passer un Vert.x JsonObject au client Vert.x PostgreSQL ou MySQL en appelant simplement setObject() .

Qu'en est-il des autres types, comme io.reactiverse.pgclient.data.Circle par exemple ?

Ça devrait être la même affaire, même si je n'ai pas testé.

Au fait, io.reactiverse.pgclient.data est mort. C'est pour une version précédente du client. Ce n'est pas ce que vous devriez regarder.

Voici la liste actuelle des types :

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

Je comprends cela, mais avez-vous essayé de faire quelque chose de très simple, comme simplement mapper une chaîne Java sur une colonne de type JSONB ?

...

OK, alors il se peut que le client Vert.x prenne déjà en charge cette conversion de type, nous aurions besoin de l'essayer, mais même si ce n'est pas le cas, je suppose que je pense que cela devrait probablement le faire.

D' après les documents que je Linked ci - dessus, cela fonctionne. J'ai même testé l'écriture d'un entier directement dans une colonne JSONB -types et cela a fonctionné.

Donc, en principe, vous n'avez même pas besoin de vous embêter avec JsonObject si vous ne le souhaitez pas. (C'est probablement plus propre cependant.)

Bien sûr, pourriez-vous ajouter un test pour certains des autres types spécifiques ? Comme une ligne ou un cercle. Pour que nous puissions montrer à quoi ressemble la cartographie

Salut!

Avez-vous vu une bibliothèque comme https://github.com/vladmihalcea/hibernate-types à utiliser avec hibernate-reactive ?

Si cela n'existe pas encore, j'aimerais construire quelque chose pour mon projet (en utilisant quarkus). J'utilise beaucoup de colonnes JSON dans postgres.

Mais je ne sais pas si je me trompe, mais hibernate-reactive n'autorise le type personnalisé qu'en implémentant à partir UserType interface

@AlexandreGuidin , je pense que @gavinking a déjà répondu à vos questions dans l'un des commentaires précédents : https://github.com/hibernate/hibernate-reactive/issues/279#issuecomment -666289449

Mais si quelque chose me manque, n'hésitez pas à poser d'autres questions.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

tsegismont picture tsegismont  ·  9Commentaires

hantsy picture hantsy  ·  7Commentaires

gavinking picture gavinking  ·  6Commentaires

gavinking picture gavinking  ·  16Commentaires

markusdlugi picture markusdlugi  ·  30Commentaires