Skip to content

Commit fc513c2

Browse files
committed
fix #928 problem with JsonType converter
1 parent b370be4 commit fc513c2

File tree

5 files changed

+244
-52
lines changed

5 files changed

+244
-52
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.adaptor.impl;
7+
8+
import io.vertx.sqlclient.data.NullValue;
9+
10+
import java.sql.Types;
11+
12+
public class JdbcNull {
13+
private final int jdbcTypeCode;
14+
JdbcNull(int jdbcTypeCode) {
15+
this.jdbcTypeCode = jdbcTypeCode;
16+
}
17+
18+
public NullValue toNullValue() {
19+
switch ( jdbcTypeCode ) {
20+
case Types.BOOLEAN:
21+
case Types.BIT: //we misuse BIT in H5
22+
return NullValue.Boolean;
23+
case Types.VARCHAR:
24+
case Types.NVARCHAR:
25+
case Types.CHAR:
26+
case Types.NCHAR:
27+
case Types.CLOB:
28+
case Types.NCLOB:
29+
case Types.LONGVARCHAR:
30+
case Types.LONGNVARCHAR:
31+
return NullValue.String;
32+
case Types.FLOAT:
33+
case Types.DOUBLE:
34+
case Types.REAL:
35+
return NullValue.Double;
36+
case Types.BIGINT:
37+
return NullValue.Long;
38+
case Types.INTEGER:
39+
return NullValue.Integer;
40+
case Types.SMALLINT:
41+
case Types.TINYINT: //should really map to Byte
42+
return NullValue.Short;
43+
case Types.DECIMAL:
44+
return NullValue.BigDecimal;
45+
case Types.VARBINARY:
46+
case Types.BINARY:
47+
case Types.BLOB:
48+
case Types.LONGVARBINARY:
49+
return NullValue.Buffer;
50+
case Types.TIMESTAMP:
51+
return NullValue.LocalDateTime;
52+
case Types.DATE:
53+
return NullValue.LocalDate;
54+
case Types.TIME:
55+
return NullValue.LocalTime;
56+
case Types.TIMESTAMP_WITH_TIMEZONE:
57+
return NullValue.OffsetDateTime;
58+
case Types.TIME_WITH_TIMEZONE:
59+
return NullValue.OffsetTime;
60+
default: return null;
61+
}
62+
}
63+
64+
public int getJdbcTypeCode() {
65+
return jdbcTypeCode;
66+
}
67+
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/adaptor/impl/PreparedStatementAdaptor.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.sql.Clob;
2222
import java.sql.Connection;
2323
import java.sql.Date;
24-
import java.sql.JDBCType;
2524
import java.sql.NClob;
2625
import java.sql.ParameterMetaData;
2726
import java.sql.PreparedStatement;
@@ -94,7 +93,7 @@ public int executeUpdate() {
9493

9594
@Override
9695
public void setNull(int parameterIndex, int sqlType) {
97-
put( parameterIndex, JDBCType.valueOf(sqlType) );
96+
put( parameterIndex, new JdbcNull(sqlType) );
9897
}
9998

10099
@Override

hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/SqlClientConnection.java

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66
package org.hibernate.reactive.pool.impl;
77

88
import java.lang.invoke.MethodHandles;
9-
import java.sql.JDBCType;
109
import java.sql.ResultSet;
11-
import java.sql.Types;
1210
import java.util.ArrayList;
1311
import java.util.List;
1412
import java.util.Objects;
1513
import java.util.concurrent.CompletionStage;
1614

17-
import io.vertx.sqlclient.data.NullValue;
1815
import org.hibernate.engine.jdbc.internal.FormatStyle;
1916
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
17+
import org.hibernate.reactive.adaptor.impl.JdbcNull;
2018
import org.hibernate.reactive.adaptor.impl.ResultSetAdaptor;
2119
import org.hibernate.reactive.logging.impl.Log;
2220
import org.hibernate.reactive.logging.impl.LoggerFactory;
@@ -286,55 +284,10 @@ public CompletionStage<Void> executeBatch() {
286284
private static void translateNulls(Object[] paramValues) {
287285
for (int i = 0; i < paramValues.length; i++) {
288286
Object arg = paramValues[i];
289-
if (arg instanceof JDBCType) {
290-
paramValues[i] = toNullValue( (JDBCType) arg );
287+
if (arg instanceof JdbcNull) {
288+
paramValues[i] = ((JdbcNull) arg).toNullValue();
291289
}
292290
}
293291
}
294292

295-
private static NullValue toNullValue(JDBCType jdbcType) {
296-
switch ( jdbcType.getVendorTypeNumber() ) {
297-
case Types.BOOLEAN:
298-
case Types.BIT: //we misuse BIT in H5
299-
return NullValue.Boolean;
300-
case Types.VARCHAR:
301-
case Types.NVARCHAR:
302-
case Types.CHAR:
303-
case Types.NCHAR:
304-
case Types.CLOB:
305-
case Types.NCLOB:
306-
case Types.LONGVARCHAR:
307-
case Types.LONGNVARCHAR:
308-
return NullValue.String;
309-
case Types.FLOAT:
310-
case Types.DOUBLE:
311-
case Types.REAL:
312-
return NullValue.Double;
313-
case Types.BIGINT:
314-
return NullValue.Long;
315-
case Types.INTEGER:
316-
return NullValue.Integer;
317-
case Types.SMALLINT:
318-
case Types.TINYINT: //should really map to Byte
319-
return NullValue.Short;
320-
case Types.DECIMAL:
321-
return NullValue.BigDecimal;
322-
case Types.VARBINARY:
323-
case Types.BINARY:
324-
case Types.BLOB:
325-
case Types.LONGVARBINARY:
326-
return NullValue.Buffer;
327-
case Types.TIMESTAMP:
328-
return NullValue.LocalDateTime;
329-
case Types.DATE:
330-
return NullValue.LocalDate;
331-
case Types.TIME:
332-
return NullValue.LocalTime;
333-
case Types.TIMESTAMP_WITH_TIMEZONE:
334-
return NullValue.OffsetDateTime;
335-
case Types.TIME_WITH_TIMEZONE:
336-
return NullValue.OffsetTime;
337-
default: return null;
338-
}
339-
}
340293
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.types;
7+
8+
import io.vertx.core.json.JsonObject;
9+
10+
import javax.persistence.AttributeConverter;
11+
import javax.persistence.Converter;
12+
13+
@Converter
14+
public class StringToJson implements AttributeConverter<String, JsonObject> {
15+
16+
@Override
17+
public JsonObject convertToDatabaseColumn(String string) {
18+
if (string == null) {
19+
return null;
20+
}
21+
return new JsonObject(string);
22+
}
23+
24+
@Override
25+
public String convertToEntityAttribute(JsonObject dbData) {
26+
27+
if (dbData == null) {
28+
return null;
29+
}
30+
return dbData.encodePrettily();
31+
}
32+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.types;
7+
8+
import io.vertx.core.json.JsonObject;
9+
import io.vertx.ext.unit.TestContext;
10+
import org.hibernate.cfg.Configuration;
11+
import org.hibernate.reactive.BaseReactiveTest;
12+
import org.hibernate.reactive.testing.DatabaseSelectionRule;
13+
import org.junit.After;
14+
import org.junit.Rule;
15+
import org.junit.Test;
16+
17+
import javax.persistence.Column;
18+
import javax.persistence.Convert;
19+
import javax.persistence.Entity;
20+
import javax.persistence.GeneratedValue;
21+
import javax.persistence.Id;
22+
import javax.persistence.Table;
23+
import javax.persistence.Version;
24+
import java.util.Objects;
25+
import java.util.function.Consumer;
26+
27+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2;
28+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.SQLSERVER;
29+
30+
/**
31+
* Test types that we expect to work only on selected DBs.
32+
*/
33+
public class StringToJsonTypeTest extends BaseReactiveTest {
34+
35+
@Rule
36+
public DatabaseSelectionRule selectionRule = DatabaseSelectionRule.skipTestsFor( DB2, SQLSERVER );
37+
38+
@Override
39+
protected Configuration constructConfiguration() {
40+
Configuration configuration = super.constructConfiguration();
41+
configuration.addAnnotatedClass( Basic.class );
42+
return configuration;
43+
}
44+
45+
@After
46+
public void deleteTable(TestContext context) {
47+
test( context,
48+
getSessionFactory().withSession(
49+
session -> session.createQuery( "delete from JsonEntity" ).executeUpdate()
50+
)
51+
);
52+
}
53+
54+
@Test
55+
public void testJsonType(TestContext context) {
56+
Basic basic = new Basic();
57+
basic.json = new JsonObject().put("int", 123).put("str", "hello").encodePrettily();
58+
59+
testField( context, basic, found -> context.assertEquals( basic.json, found.json) );
60+
}
61+
62+
@Test
63+
public void testNullJsonType(TestContext context) {
64+
Basic basic = new Basic();
65+
basic.json = null;
66+
67+
testField( context, basic, found -> context.assertEquals(basic.json, found.json) );
68+
}
69+
70+
/**
71+
* Persist the entity, find it and execute the assertions
72+
*/
73+
private void testField(TestContext context, Basic original, Consumer<Basic> consumer) {
74+
test(
75+
context,
76+
getSessionFactory().withTransaction( (s, t) -> s.persist( original ) )
77+
.thenCompose( v -> openSession() )
78+
.thenCompose( s2 -> s2.find( Basic.class, original.id )
79+
.thenAccept( found -> {
80+
context.assertNotNull( found );
81+
context.assertEquals( original, found );
82+
consumer.accept( found );
83+
} ) )
84+
);
85+
}
86+
87+
@Entity(name="JsonEntity")
88+
@Table(name="JsonEntity")
89+
private static class Basic {
90+
91+
@Id @GeneratedValue Integer id;
92+
@Version Integer version;
93+
String string;
94+
95+
@Column(columnDefinition = "json")
96+
@Convert(converter = StringToJson.class)
97+
private String json;
98+
99+
public Basic() {
100+
}
101+
102+
public Basic(String string) {
103+
this.string = string;
104+
}
105+
106+
public Basic(Integer id, String string) {
107+
this.id = id;
108+
this.string = string;
109+
}
110+
111+
public Integer getId() {
112+
return id;
113+
}
114+
115+
public void setId(Integer id) {
116+
this.id = id;
117+
}
118+
119+
@Override
120+
public String toString() {
121+
return id + ": " + string;
122+
}
123+
124+
@Override
125+
public boolean equals(Object o) {
126+
if ( this == o ) {
127+
return true;
128+
}
129+
if ( o == null || getClass() != o.getClass() ) {
130+
return false;
131+
}
132+
Basic basic = (Basic) o;
133+
return Objects.equals(string, basic.string);
134+
}
135+
136+
@Override
137+
public int hashCode() {
138+
return Objects.hash(string);
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)