Skip to content

Commit 46bc937

Browse files
committed
Consider embedded entities with empty non entity collections empty.
Embedded entities which contain a empty collection of values that aren't entities are now considered empty, if this collection is empty. Closes #1737
1 parent 37c0c20 commit 46bc937

File tree

3 files changed

+88
-25
lines changed

3 files changed

+88
-25
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ public <T> T getPropertyValue(RelationalPersistentProperty property) {
421421
@Override
422422
public boolean hasValue(RelationalPersistentProperty property) {
423423

424-
if (property.isCollectionLike() || property.isMap()) {
424+
if ((property.isCollectionLike() && property.isEntity())|| property.isMap()) {
425425
// attempt relation fetch
426426
return true;
427427
}

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java

+49-13
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,8 @@
2222
import static org.springframework.data.jdbc.testing.TestDatabaseFeatures.Feature.*;
2323

2424
import java.time.LocalDateTime;
25+
import java.util.*;
2526
import java.util.ArrayList;
26-
import java.util.Collections;
27-
import java.util.HashMap;
28-
import java.util.HashSet;
29-
import java.util.Iterator;
30-
import java.util.List;
31-
import java.util.Map;
32-
import java.util.Objects;
33-
import java.util.Optional;
34-
import java.util.Set;
3527
import java.util.function.Function;
3628
import java.util.stream.IntStream;
3729

@@ -61,6 +53,7 @@
6153
import org.springframework.data.mapping.context.InvalidPersistentPropertyPath;
6254
import org.springframework.data.relational.core.conversion.DbActionExecutionException;
6355
import org.springframework.data.relational.core.mapping.Column;
56+
import org.springframework.data.relational.core.mapping.Embedded;
6457
import org.springframework.data.relational.core.mapping.InsertOnlyProperty;
6558
import org.springframework.data.relational.core.mapping.MappedCollection;
6659
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
@@ -778,6 +771,36 @@ void saveAndLoadAnEntityWithSet() {
778771
assertThat(reloaded.digits).isEqualTo(new HashSet<>(asList("one", "two", "three")));
779772
}
780773

774+
@Test //GH-1737
775+
@EnabledOnFeature(SUPPORTS_ARRAYS)
776+
void saveAndLoadEmbeddedArray() {
777+
778+
EmbeddedStringListOwner embeddedStringListOwner = new EmbeddedStringListOwner();
779+
embeddedStringListOwner.embeddedStringList = new EmbeddedStringList();
780+
embeddedStringListOwner.embeddedStringList.digits = List.of("one", "two", "three");
781+
782+
EmbeddedStringListOwner saved = template.save(embeddedStringListOwner);
783+
784+
EmbeddedStringListOwner reloaded = template.findById(saved.id, EmbeddedStringListOwner.class);
785+
786+
assertThat(reloaded.embeddedStringList.digits).containsExactly("one", "two", "three");
787+
}
788+
789+
@Test //GH-1737
790+
@EnabledOnFeature(SUPPORTS_ARRAYS)
791+
void saveAndLoadEmptyEmbeddedArray() {
792+
793+
EmbeddedStringListOwner embeddedStringListOwner = new EmbeddedStringListOwner();
794+
embeddedStringListOwner.embeddedStringList = new EmbeddedStringList();
795+
embeddedStringListOwner.embeddedStringList.digits = emptyList();
796+
797+
EmbeddedStringListOwner saved = template.save(embeddedStringListOwner);
798+
799+
EmbeddedStringListOwner reloaded = template.findById(saved.id, EmbeddedStringListOwner.class);
800+
801+
assertThat(reloaded.embeddedStringList).isNull();
802+
}
803+
781804
@Test
782805
// DATAJDBC-327
783806
void saveAndLoadAnEntityWithByteArray() {
@@ -919,7 +942,7 @@ void readOnlyGetsLoadedButNotWritten() {
919942

920943
assertThat(
921944
jdbcTemplate.queryForObject("SELECT read_only FROM with_read_only", Collections.emptyMap(), String.class))
922-
.isEqualTo("from-db");
945+
.isEqualTo("from-db");
923946
}
924947

925948
@Test
@@ -1258,15 +1281,16 @@ void recordOfSet() {
12581281
@Test // GH-1656
12591282
void mapWithEnumKey() {
12601283

1261-
EnumMapOwner enumMapOwner = template.save(new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element"))));
1284+
EnumMapOwner enumMapOwner = template
1285+
.save(new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element"))));
12621286

12631287
Iterable<EnumMapOwner> enumMapOwners = template.findAll(EnumMapOwner.class);
12641288

12651289
assertThat(enumMapOwners).containsExactly(enumMapOwner);
12661290
}
12671291

12681292
@Test // GH-1684
1269-
void oneToOneWithIdenticalIdColumnName(){
1293+
void oneToOneWithIdenticalIdColumnName() {
12701294

12711295
WithOneToOne saved = template.insert(new WithOneToOne("one", new Referenced(23L)));
12721296

@@ -1369,6 +1393,17 @@ private static class FloatListOwner {
13691393
List<Float> digits = new ArrayList<>();
13701394
}
13711395

1396+
@Table("ARRAY_OWNER")
1397+
private static class EmbeddedStringListOwner {
1398+
@Id Long id;
1399+
1400+
@Embedded(onEmpty = Embedded.OnEmpty.USE_NULL, prefix = "") EmbeddedStringList embeddedStringList;
1401+
}
1402+
1403+
private static class EmbeddedStringList {
1404+
List<String> digits = new ArrayList<>();
1405+
}
1406+
13721407
static class LegoSet {
13731408

13741409
@Column("id1")
@@ -2096,7 +2131,8 @@ record Book(String name) {
20962131
record EnumMapOwner(@Id Long id, String name, Map<Color, MapElement> map) {
20972132
}
20982133

2099-
record WithOneToOne(@Id String id,@MappedCollection(idColumn = "renamed") Referenced referenced){}
2134+
record WithOneToOne(@Id String id, @MappedCollection(idColumn = "renamed") Referenced referenced) {
2135+
}
21002136

21012137
record Referenced(@Id Long id) {
21022138
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java

+38-11
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,7 @@
4444
import org.springframework.data.mapping.PersistentPropertyAccessor;
4545
import org.springframework.data.mapping.PersistentPropertyPathAccessor;
4646
import org.springframework.data.mapping.context.MappingContext;
47-
import org.springframework.data.mapping.model.CachingValueExpressionEvaluatorFactory;
48-
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
49-
import org.springframework.data.mapping.model.EntityInstantiator;
50-
import org.springframework.data.mapping.model.ParameterValueProvider;
51-
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
52-
import org.springframework.data.mapping.model.PropertyValueProvider;
53-
import org.springframework.data.mapping.model.SimpleTypeHolder;
54-
import org.springframework.data.mapping.model.SpELContext;
55-
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
56-
import org.springframework.data.mapping.model.ValueExpressionParameterValueProvider;
47+
import org.springframework.data.mapping.model.*;
5748
import org.springframework.data.projection.EntityProjection;
5849
import org.springframework.data.projection.EntityProjectionIntrospector;
5950
import org.springframework.data.projection.EntityProjectionIntrospector.ProjectionPredicate;
@@ -1168,7 +1159,43 @@ public Object getValue(AggregatePath path) {
11681159

11691160
@Override
11701161
public boolean hasValue(AggregatePath path) {
1171-
return document.get(path.getColumnInfo().alias().getReference()) != null;
1162+
Object value = document.get(path.getColumnInfo().alias().getReference());
1163+
1164+
if (value == null) {
1165+
return false;
1166+
}
1167+
if (!path.isCollectionLike()) {
1168+
return true;
1169+
}
1170+
1171+
if (value instanceof char[] ar) {
1172+
return ar.length != 0;
1173+
}
1174+
if (value instanceof byte[] ar) {
1175+
return ar.length != 0;
1176+
}
1177+
if (value instanceof short[] ar) {
1178+
return ar.length != 0;
1179+
}
1180+
if (value instanceof int[] ar) {
1181+
return ar.length != 0;
1182+
}
1183+
if (value instanceof long[] ar) {
1184+
return ar.length != 0;
1185+
}
1186+
if (value instanceof float[] ar) {
1187+
return ar.length != 0;
1188+
}
1189+
if (value instanceof double[] ar) {
1190+
return ar.length != 0;
1191+
}
1192+
if (value instanceof Object[] ar) {
1193+
return ar.length != 0;
1194+
}
1195+
if (value instanceof Collection<?> col) {
1196+
return !col.isEmpty();
1197+
}
1198+
return true;
11721199
}
11731200

11741201
@Override

0 commit comments

Comments
 (0)