#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:
Mark Paluch
2020-09-10 09:21:15 +02:00
parent b720249dac
commit 4506fb67ca
2 changed files with 85 additions and 9 deletions

View File

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

View File

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