Skip to content

Commit 4d65223

Browse files
committed
Avoid nested entity creation if column value is null.
We now no longer attempt to create instances of nested entities if the column value is null. Previously the null check happened after checking registered custom conversions which has lead to potential object creation for columns containing null values. Closes #670
1 parent 7f3bc97 commit 4d65223

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,18 @@ private Object readFrom(Row row, @Nullable RowMetadata metadata, RelationalPersi
167167
value = row.get(identifier);
168168
}
169169

170-
if (value != null && getConversions().hasCustomReadTarget(value.getClass(), property.getType())) {
170+
if (value == null) {
171+
return null;
172+
}
173+
174+
if (getConversions().hasCustomReadTarget(value.getClass(), property.getType())) {
171175
return readValue(value, property.getTypeInformation());
172176
}
173177

174178
if (property.isEntity()) {
175179
return readEntityFrom(row, metadata, property);
176180
}
177181

178-
if (value == null) {
179-
return null;
180-
}
181-
182182
return readValue(value, property.getTypeInformation());
183183

184184
} catch (Exception o_O) {
@@ -613,8 +613,8 @@ public <T> BiFunction<Row, RowMetadata, T> populateIdIfNecessary(T object) {
613613

614614
if (idPropertyUpdateNeeded) {
615615
return potentiallySetId(row, metadata, propertyAccessor, idProperty) //
616-
? (T) propertyAccessor.getBean() //
617-
: object;
616+
? (T) propertyAccessor.getBean() //
617+
: object;
618618
}
619619

620620
return object;

src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ void before() {
6565

6666
R2dbcCustomConversions conversions = R2dbcCustomConversions.of(PostgresDialect.INSTANCE,
6767
Arrays.asList(StringToMapConverter.INSTANCE, MapToStringConverter.INSTANCE,
68-
CustomConversionPersonToOutboundRowConverter.INSTANCE, RowToCustomConversionPerson.INSTANCE));
68+
CustomConversionPersonToOutboundRowConverter.INSTANCE, RowToCustomConversionPerson.INSTANCE,
69+
StringToSimplePersonConverter.INSTANCE));
6970

7071
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
7172

@@ -82,8 +83,7 @@ void shouldIncludeAllPropertiesInOutboundRow() {
8283
converter.write(new Person("id", "Walter", "White", instant, localDateTime), row);
8384

8485
assertThat(row).containsEntry(SqlIdentifier.unquoted("id"), Parameter.fromOrEmpty("id", String.class));
85-
assertThat(row).containsEntry(SqlIdentifier.unquoted("firstname"),
86-
Parameter.fromOrEmpty("Walter", String.class));
86+
assertThat(row).containsEntry(SqlIdentifier.unquoted("firstname"), Parameter.fromOrEmpty("Walter", String.class));
8787
assertThat(row).containsEntry(SqlIdentifier.unquoted("lastname"), Parameter.fromOrEmpty("White", String.class));
8888
assertThat(row).containsEntry(SqlIdentifier.unquoted("instant"), Parameter.from(instant));
8989
assertThat(row).containsEntry(SqlIdentifier.unquoted("local_date_time"), Parameter.from(localDateTime));
@@ -237,6 +237,19 @@ void shouldEvaluateSpelExpression() {
237237
assertThat(result.world).isEqualTo("No, universe");
238238
}
239239

240+
@Test // GH-670
241+
void considersConverterBeforeEntityConstruction() {
242+
243+
MockRow row = MockRow.builder().identified("id", Object.class, 42).identified("person", Object.class, null).build();
244+
MockRowMetadata metadata = MockRowMetadata.builder().columnMetadata(MockColumnMetadata.builder().name("id").build())
245+
.columnMetadata(MockColumnMetadata.builder().name("person").build()).build();
246+
247+
WithSimplePersonConstructor result = converter.read(WithSimplePersonConstructor.class, row, metadata);
248+
249+
assertThat(result.id).isEqualTo(42);
250+
assertThat(result.person).isNull();
251+
}
252+
240253
@AllArgsConstructor
241254
static class Person {
242255
@Id String id;
@@ -350,6 +363,17 @@ public CustomConversionPerson convert(Row source) {
350363
}
351364
}
352365

366+
@ReadingConverter
367+
enum StringToSimplePersonConverter implements Converter<String, SimplePerson> {
368+
369+
INSTANCE;
370+
371+
@Override
372+
public SimplePerson convert(String source) {
373+
return new SimplePerson(source);
374+
}
375+
}
376+
353377
static class WithSpelExpression {
354378

355379
private final long id;
@@ -362,4 +386,24 @@ public WithSpelExpression(long id, @Value("null") String hello, @Value("#root.wo
362386
this.world = world;
363387
}
364388
}
389+
390+
static class WithSimplePersonConstructor {
391+
392+
private final long id;
393+
private final SimplePerson person;
394+
395+
public WithSimplePersonConstructor(long id, SimplePerson person) {
396+
this.id = id;
397+
this.person = person;
398+
}
399+
}
400+
401+
static class SimplePerson {
402+
403+
private final String name;
404+
405+
SimplePerson(String name) {
406+
this.name = name;
407+
}
408+
}
365409
}

0 commit comments

Comments
 (0)