Hello to all. Does Hibernate Reactive support custom UserTypes? I want to use Postgres JSONB Type and for that I was using the following library https://github.com/vladmihalcea/hibernate-types which builds it's custom types based on Hibernate'sAbstractSingleColumnStandardBasicType. Unfortunately just moving from Hibernate to Hibernate Reactive the columns that use these types are always null in the entities. As an alternative I found this article which builds it's JSONB Postgres support on the Hibernate's UserType. Is there any known limitation around defining custom types and using Hibernate Reactive at the moment ?
Hi, I didnât test UserType
since that interface is rather tied to JDBC. (Though in principle, perhaps it could be made to mostly work.)
Instead, my idea was that people could use JPA converters. I did test that and AFAIK it works. Have you tried that?
I tried with a quick test using UserType and it doesn't seem to work because the PgClient throw an exception when running the query.
I tried with a quick test using UserType and it doesn't seem to work because the PgClient throw an exception when running the query.
But that might just be because our fake JDBC layer is incomplete. (Some unimplemented methods.)
To clarify, I've tried the example using vlad library:
@TypeDefs({
@TypeDef(name = "json", typeClass = JsonStringType.class),
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
@Entity(name="GuineaPig")
@Table(name="Pig")
public static class GuineaPig {
@Id
private Integer id;
private String name;
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
private Location location;
This is the 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.
It seems that the reactive pg client uses a different type to convert to JSON.
@gavinking Should we support some kind of mapping for the pg-client types?
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)
I think the client is expecting an object of type io.reactiverse.pgclient.data.Json
. It seems we handle UserType
correctly though
Right so thatâs what I meant in my comment above. Our JDBC adaptors arenât even close to a complete implementation of JDBC, and I see it as quite likely that they never will be. In particular, for more âexoticâ JDBC types, it might be quite difficult to map them to/from the Vert.x API.
Should we support some kind of mapping for the pg-client types?
Well, sure, if itâs reasonably easy to do.
But if not, we should consider that perhaps UserType
is just not the right abstraction here, and look for a different approach.
I mean, to the extent that existing UserType
s can be made to work without doing anything horrible, then sure, letâs make âem work. It will make migration easier. But I think itâs possible that weâll quickly run into limitations as to whatâs really possible there.
I will have a look
I will have a look
As a first step we should add a test for a totally plain-vanilla UserType
that doesnât use any fancy database types, just to check that the basic concept works (I donât see why it shouldnât).
@gavinking No I did not test Converters yet because I am using Hibernate together with Hibernate Types library. But the suggestion to use converters would mean that I will in the end put a plain Postgres Text/Varchar to the DB and not a Postgres JSONB type.
@gavinking No I did not test Converters yet because I am using Hibernate together with Hibernate Types library. But the suggestion to use converters would mean that I will in the end put a plain Postgres Text/Varchar to the DB and not a Postgres JSONB type.
To clarify: are you concerned about what type you have in Java or in the database? Thereâs two different things here.
JSONB
as the column type, but in principle I would have thought that the drivers can transparently convert strings to that type. (Not sure, I never tried.)io.reactiverse.pgclient.data.Json
as the Java type in your model. Thatâs a whole different problem and would indeed require something more like a UserType
.@gavinking
I want to use the Postgres JSONB
type. I think it is not supported directly by Hibernate. That's why I relied on this https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/ . Or for example this https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/ where the guide uses UserType .
Right I understand that but have you tried doing something really simple like just mapping a Java String
to a column of type JSONB
? Would that be good enough if it worked?
@gavinking No I did not try that yet. Yes it would be good enough. I would just need to convert the JSON objects to JSON string prior to trying to insert my Entities in the DB.
OK then it may be that the Vert.x client already supports that type conversion, we would need to try it, but even if it doesn't, I guess I think it probably should.
@DavideD what's the status here? Do you want me to take a closer look at this one?
I got sidetracked. Feel free to tackle this if you have time.
In #301 I've added a test demonstrating that UserType
s work in HR, at least to the extent to which our PreparedStatement
and ResultSet
adaptors are faithful implementation of JDBC (which is not a particularly great extent).
@gavinking Should we support some kind of mapping for the pg-client types?
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)
So the question now becomes: can we make getObject()
and setObject()
in our JDBC adaptors support these types without creating a hard dependency to the PostgreSQL client?
Would it be possible to have something like:
@Type(type="passthrough")
Circle circle
That doesn't do any conversion but just pass the value as is?
So the question now becomes: can we make
getObject()
andsetObject()
in our JDBC adaptors support these types without creating a hard dependency to the PostgreSQL client?
Well, I've tried this, and apparently we don't actually need to do anything special in order to handle io.vertx.core.json.JsonObject
on Postgres or MySQL. You can just use getObject()
/setObject()
from your UserType
.
This works:
public class Json implements UserType {
@Override
public int[] sqlTypes() {
return new int[] {Types.OTHER};
}
@Override
public Class returnedClass() {
return JsonObject.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return Objects.equals(x,y);
}
@Override
public int hashCode(Object x) throws HibernateException {
return Objects.hashCode(x);
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
return rs.getObject(names[0]);
}
@Override
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);
}
}
...
}
Would it be possible to have something like:
@Type(type="passthrough") Circle circle
That doesn't do any conversion but just pass the value as is?
Yes, that would work too.
See 54434c94b3ff57261fd905abaeb25961b2ed285c.
I would say we can close this issue.
What about the other types, like io.reactiverse.pgclient.data.Circle
for example?
@akoufa now to give you concrete responses to your original questions:
Does Hibernate Reactive support custom
UserTypes
?
The answer is yes!
However, you need to be aware that even though we expose something that looks a lot like JDBC to your UserType
, under the covers there is no JDBC connection, but a whole different non-blocking database client. So some things simply aren't going to work.
I was using the following library https://github.com/vladmihalcea/hibernate-types
So I think you'll need to be pretty realistic about that. The above library is written to work with JDBC, so while some of it's UserType
s might work, others won't.
As an alternative I found this article which builds it's JSONB Postgres support on the Hibernate's
UserType
.
Take a look at how I've implemented this in the test suite. The basic idea is that you need to pass a Vert.x JsonObject
to the Vert.x PostgreSQL or MySQL client by just calling setObject()
.
What about the other types, like
io.reactiverse.pgclient.data.Circle
for example?
Should be the same deal, though I did not test.
By the way, io.reactiverse.pgclient.data
is dead. It's for a previous version of the client. That's not what you should be looking at.
Here is the current list of types:
https://vertx.io/docs/vertx-pg-client/java/#_postgresql_type_mapping
I understand that but have you tried doing something really simple like just mapping a Java String to a column of type JSONB?
...
OK then it may be that the Vert.x client already supports that type conversion, we would need to try it, but even if it doesn't, I guess I think it probably should.
According to the docs I linked above, this does work. I even tested writing an integer directly to a JSONB
-types column and it worked.
So in principle you don't even need to mess about with JsonObject
if you don't want to. (It's probably cleaner though.)
Sure, could you add a test for some of the other specific types? Like line or circle. So that we can show what the mapping looks like
Hi!
Have you guys saw some library like https://github.com/vladmihalcea/hibernate-types to use with hibernate-reactive ?
If that not exists yet, i would like to build something for my project (using quarkus). I use a lot of JSON columns in postgres.
But i dont know if i get it wrong, but hibernate-reactive
only allow custom type by implementing from UserType
interface? (http://hibernate.org/reactive/documentation/1.0/reference/html_single/#_custom_types)
@AlexandreGuidin, I think @gavinking already answered your questions in one of the previous comments: https://github.com/hibernate/hibernate-reactive/issues/279#issuecomment-666289449
But if I'm missing something feel free to follow up with some more questions.