Skip to content

Commit 16486e0

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 ecf78fb commit 16486e0

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
@@ -64,7 +64,8 @@ void before() {
6464

6565
R2dbcCustomConversions conversions = new R2dbcCustomConversions(
6666
Arrays.asList(StringToMapConverter.INSTANCE, MapToStringConverter.INSTANCE,
67-
CustomConversionPersonToOutboundRowConverter.INSTANCE, RowToCustomConversionPerson.INSTANCE));
67+
CustomConversionPersonToOutboundRowConverter.INSTANCE, RowToCustomConversionPerson.INSTANCE,
68+
StringToSimplePersonConverter.INSTANCE));
6869

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

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

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

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

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

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

0 commit comments

Comments
 (0)