#453 - Introduce converters to consume Postgres Json and convert these to String/byte[].
We now ship converters for Postgres' Json data type to map JSON to String and to byte[] for easier and safe consumption.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import io.r2dbc.postgresql.codec.Json;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
@@ -38,6 +40,9 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
|
||||
|
||||
private static final Set<Class<?>> SIMPLE_TYPES;
|
||||
|
||||
private static final boolean JSON_PRESENT = ClassUtils.isPresent("io.r2dbc.postgresql.codec.Json",
|
||||
PostgresDialect.class.getClassLoader());
|
||||
|
||||
private static final boolean GEO_TYPES_PRESENT = ClassUtils.isPresent("io.r2dbc.postgresql.codec.Polygon",
|
||||
PostgresDialect.class.getClassLoader());
|
||||
|
||||
@@ -45,9 +50,6 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
|
||||
|
||||
Set<Class<?>> simpleTypes = new HashSet<>(Arrays.asList(UUID.class, URL.class, URI.class, InetAddress.class));
|
||||
|
||||
// conditional Postgres JSON support.
|
||||
ifClassPresent("io.r2dbc.postgresql.codec.Json", simpleTypes::add);
|
||||
|
||||
// conditional Postgres Geo support.
|
||||
Stream.of("io.r2dbc.postgresql.codec.Box", //
|
||||
"io.r2dbc.postgresql.codec.Circle", //
|
||||
@@ -58,6 +60,9 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
|
||||
"io.r2dbc.postgresql.codec.Polygon") //
|
||||
.forEach(s -> ifClassPresent(s, simpleTypes::add));
|
||||
|
||||
// conditional Postgres JSON support.
|
||||
ifClassPresent("io.r2dbc.postgresql.codec.Json", simpleTypes::add);
|
||||
|
||||
SIMPLE_TYPES = simpleTypes;
|
||||
}
|
||||
|
||||
@@ -106,14 +111,24 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
|
||||
@Override
|
||||
public Collection<Object> getConverters() {
|
||||
|
||||
if (GEO_TYPES_PRESENT) {
|
||||
return Arrays.asList(FromPostgresPointConverter.INSTANCE, ToPostgresPointConverter.INSTANCE, //
|
||||
FromPostgresCircleConverter.INSTANCE, ToPostgresCircleConverter.INSTANCE, //
|
||||
FromPostgresBoxConverter.INSTANCE, ToPostgresBoxConverter.INSTANCE, //
|
||||
FromPostgresPolygonConverter.INSTANCE, ToPostgresPolygonConverter.INSTANCE);
|
||||
if (!GEO_TYPES_PRESENT && !JSON_PRESENT) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
List<Object> converters = new ArrayList<>();
|
||||
|
||||
if (GEO_TYPES_PRESENT) {
|
||||
converters.addAll(Arrays.asList(FromPostgresPointConverter.INSTANCE, ToPostgresPointConverter.INSTANCE, //
|
||||
FromPostgresCircleConverter.INSTANCE, ToPostgresCircleConverter.INSTANCE, //
|
||||
FromPostgresBoxConverter.INSTANCE, ToPostgresBoxConverter.INSTANCE, //
|
||||
FromPostgresPolygonConverter.INSTANCE, ToPostgresPolygonConverter.INSTANCE));
|
||||
}
|
||||
|
||||
if (JSON_PRESENT) {
|
||||
converters.addAll(Arrays.asList(JsonToByteArrayConverter.INSTANCE, JsonToStringConverter.INSTANCE));
|
||||
}
|
||||
|
||||
return converters;
|
||||
}
|
||||
|
||||
private static class R2dbcArrayColumns implements ArrayColumns {
|
||||
@@ -269,4 +284,28 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
private enum JsonToStringConverter implements Converter<Json, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String convert(Json source) {
|
||||
return source.asString();
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
private enum JsonToByteArrayConverter implements Converter<Json, byte[]> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public byte[] convert(Json source) {
|
||||
return source.asArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.data.r2dbc.convert;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.postgresql.codec.Json;
|
||||
import io.r2dbc.spi.test.MockColumnMetadata;
|
||||
import io.r2dbc.spi.test.MockRow;
|
||||
import io.r2dbc.spi.test.MockRowMetadata;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -72,6 +75,30 @@ public class PostgresMappingR2dbcConverterUnitTests {
|
||||
assertThat(row).containsEntry(SqlIdentifier.unquoted("json_value"), Parameter.from(person.jsonValue));
|
||||
}
|
||||
|
||||
@Test // gh-453
|
||||
public void shouldConvertJsonToString() {
|
||||
|
||||
MockRow row = MockRow.builder().identified("json_string", Object.class, Json.of("{\"hello\":\"world\"}")).build();
|
||||
|
||||
MockRowMetadata metadata = MockRowMetadata.builder()
|
||||
.columnMetadata(MockColumnMetadata.builder().name("json_string").build()).build();
|
||||
|
||||
ConvertedJson result = converter.read(ConvertedJson.class, row, metadata);
|
||||
assertThat(result.jsonString).isEqualTo("{\"hello\":\"world\"}");
|
||||
}
|
||||
|
||||
@Test // gh-453
|
||||
public void shouldConvertJsonToByteArray() {
|
||||
|
||||
MockRow row = MockRow.builder().identified("json_bytes", Object.class, Json.of("{\"hello\":\"world\"}")).build();
|
||||
|
||||
MockRowMetadata metadata = MockRowMetadata.builder()
|
||||
.columnMetadata(MockColumnMetadata.builder().name("json_bytes").build()).build();
|
||||
|
||||
ConvertedJson result = converter.read(ConvertedJson.class, row, metadata);
|
||||
assertThat(result.jsonBytes).isEqualTo("{\"hello\":\"world\"}".getBytes());
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
static class JsonPerson {
|
||||
|
||||
@@ -79,4 +106,14 @@ public class PostgresMappingR2dbcConverterUnitTests {
|
||||
|
||||
Json jsonValue;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
static class ConvertedJson {
|
||||
|
||||
@Id Long id;
|
||||
|
||||
String jsonString;
|
||||
|
||||
byte[] jsonBytes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user