Skip to content

Commit ba32d32

Browse files
committed
Fix embedded path ColumnInfo access for composite IDs (GH-2201)
Signed-off-by: 62hoon99 <ske06008@gmail.com>
1 parent 08c86dc commit ba32d32

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
*
5858
* @author Mark Paluch
5959
* @author Jens Schauder
60+
* @author Ki Hoon You
6061
*/
6162
class MappingJdbcConverterUnitTests {
6263

@@ -187,6 +188,38 @@ void readByteArrayToNestedUuidWithCustomConverter() {
187188

188189
}
189190

191+
@Test // GH-2201
192+
void shouldReadEntityWithClassBasedCompositeIdUsingReadAndResolve() {
193+
194+
// This test verifies that ResolvingRelationalPropertyValueProvider.potentiallyAppendIdentifier
195+
// correctly handles embedded composite IDs without throwing "Cannot obtain ColumnInfo for embedded path"
196+
RowDocument rowdocument = new RowDocument(Map.of("UID", "1", "TID", "2", "ALIAS", "test-alias"));
197+
198+
TenantUserWithClassId result = converter.readAndResolve(TenantUserWithClassId.class, rowdocument);
199+
200+
assertThat(result).isNotNull();
201+
assertThat(result.id).isNotNull();
202+
assertThat(result.id.uid).isEqualTo("1");
203+
assertThat(result.id.tid).isEqualTo("2");
204+
assertThat(result.alias).isEqualTo("test-alias");
205+
}
206+
207+
@Test // GH-2201
208+
void shouldReadEntityWithRecordBasedCompositeIdUsingReadAndResolve() {
209+
210+
// This test verifies that ResolvingRelationalPropertyValueProvider.potentiallyAppendIdentifier
211+
// correctly handles embedded composite IDs without throwing "Cannot obtain ColumnInfo for embedded path"
212+
RowDocument rowdocument = new RowDocument(Map.of("UID", "1", "TID", "2", "ALIAS", "test-alias"));
213+
214+
TenantUserWithRecordId result = converter.readAndResolve(TenantUserWithRecordId.class, rowdocument);
215+
216+
assertThat(result).isNotNull();
217+
assertThat(result.id()).isNotNull();
218+
assertThat(result.id().uid()).isEqualTo("1");
219+
assertThat(result.id().tid()).isEqualTo("2");
220+
assertThat(result.alias()).isEqualTo("test-alias");
221+
}
222+
190223
private static void checkReadConversion(SoftAssertions softly, MappingJdbcConverter converter, String propertyName,
191224
Object expected) {
192225

@@ -279,6 +312,19 @@ private record Referenced(@Id Long id) {
279312
private record ReferencedByUuid(@Id UUID id) {
280313
}
281314

315+
// GH-2201: Test entities for composite ID issue
316+
static class TenantUserWithClassId {
317+
@Id
318+
TenantUserID id;
319+
String alias;
320+
}
321+
322+
record TenantUserID(String uid, String tid) {
323+
}
324+
325+
record TenantUserWithRecordId(@Id TenantUserID id, String alias) {
326+
}
327+
282328
static class ByteArrayToUuid implements Converter<byte[], UUID> {
283329
@Override
284330
public UUID convert(byte[] source) {

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

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,14 +1214,33 @@ public boolean hasNonEmptyValue(RelationalPersistentProperty property) {
12141214
@Override
12151215
public Object getValue(AggregatePath path) {
12161216

1217-
Object value = document.get(path.getColumnInfo().alias().getReference());
1217+
// Embedded paths (e.g., composite ids) cannot have a single ColumnInfo
1218+
// Return null as embedded values are handled through their individual properties
1219+
if (path.isEmbedded()) {
1220+
return null;
1221+
}
12181222

1219-
return value;
1223+
return document.get(path.getColumnInfo().alias().getReference());
12201224
}
12211225

12221226
@Override
12231227
public boolean hasValue(AggregatePath path) {
12241228

1229+
// Embedded paths (e.g., composite ids) cannot have a single ColumnInfo
1230+
// Check if any of the embedded properties have values
1231+
if (path.isEmbedded()) {
1232+
RelationalPersistentEntity<?> leafEntity = path.getLeafEntity();
1233+
if (leafEntity != null) {
1234+
for (RelationalPersistentProperty property : leafEntity) {
1235+
AggregatePath propertyPath = path.append(property);
1236+
if (hasValue(propertyPath)) {
1237+
return true;
1238+
}
1239+
}
1240+
}
1241+
return false;
1242+
}
1243+
12251244
Object value = document.get(path.getColumnInfo().alias().getReference());
12261245

12271246
if (value == null) {
@@ -1238,6 +1257,21 @@ public boolean hasValue(AggregatePath path) {
12381257
@Override
12391258
public boolean hasNonEmptyValue(AggregatePath path) {
12401259

1260+
// Embedded paths (e.g., composite ids) cannot have a single ColumnInfo
1261+
// Check if any of the embedded properties have non-empty values
1262+
if (path.isEmbedded()) {
1263+
RelationalPersistentEntity<?> leafEntity = path.getLeafEntity();
1264+
if (leafEntity != null) {
1265+
for (RelationalPersistentProperty property : leafEntity) {
1266+
AggregatePath propertyPath = path.append(property);
1267+
if (hasNonEmptyValue(propertyPath)) {
1268+
return true;
1269+
}
1270+
}
1271+
}
1272+
return false;
1273+
}
1274+
12411275
if (!hasValue(path)) {
12421276
return false;
12431277
}

0 commit comments

Comments
 (0)