Skip to content

Commit eae5c60

Browse files
christophstroblmp911de
authored andcommitted
Fix id value conversion when projecting result types.
Contextual information required for converting values are now passed on correctly when projecting id properties. Closes: #4524 Original pull request: #4525
1 parent 5c06261 commit eae5c60

File tree

2 files changed

+132
-5
lines changed

2 files changed

+132
-5
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ private Object readIdValue(ConversionContext context, SpELExpressionEvaluator ev
569569
String expression = idProperty.getSpelExpression();
570570
Object resolvedValue = expression != null ? evaluator.evaluate(expression) : rawId;
571571

572-
return resolvedValue != null ? readValue(context, resolvedValue, idProperty.getTypeInformation()) : null;
572+
return resolvedValue != null ? readValue(context.forProperty(idProperty), resolvedValue, idProperty.getTypeInformation()) : null;
573573
}
574574

575575
private void readProperties(ConversionContext context, MongoPersistentEntity<?> entity,

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

+131-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import org.junit.jupiter.api.Disabled;
4343
import org.junit.jupiter.api.Test;
4444
import org.junit.jupiter.api.extension.ExtendWith;
45+
import org.junit.jupiter.params.ParameterizedTest;
46+
import org.junit.jupiter.params.provider.ValueSource;
4547
import org.mockito.Mock;
4648
import org.mockito.Mockito;
4749
import org.mockito.junit.jupiter.MockitoExtension;
@@ -83,6 +85,7 @@
8385
import org.springframework.data.mongodb.core.mapping.Document;
8486
import org.springframework.data.mongodb.core.mapping.Field;
8587
import org.springframework.data.mongodb.core.mapping.FieldType;
88+
import org.springframework.data.mongodb.core.mapping.MongoId;
8689
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
8790
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
8891
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
@@ -2866,7 +2869,7 @@ public org.bson.Document write(@Nullable String domainValue, MongoConversionCont
28662869

28672870
@Test // GH-4371
28682871
void shouldConvertTypesToStringTargetType() {
2869-
2872+
28702873
org.bson.Document source = org.bson.Document.parse("""
28712874
{
28722875
city : ["Gotham", "Metropolis"]
@@ -2876,6 +2879,35 @@ void shouldConvertTypesToStringTargetType() {
28762879
assertThat(converter.read(Address.class, source).city).isEqualTo("Gotham,Metropolis");
28772880
}
28782881

2882+
@ValueSource(classes = { ComplexIdAndNoAnnotation.class, ComplexIdAndIdAnnotation.class,
2883+
ComplexIdAndMongoIdAnnotation.class, ComplexIdAndFieldAnnotation.class })
2884+
@ParameterizedTest // GH-4524
2885+
void projectShouldReadComplexIdType(Class<?> projectionTargetType) {
2886+
2887+
EntityProjectionIntrospector introspector = EntityProjectionIntrospector.create(converter.getProjectionFactory(),
2888+
EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy()
2889+
.and((target, underlyingType) -> !converter.conversions.isSimpleType(target)),
2890+
mappingContext);
2891+
2892+
ComplexId idValue = ComplexId.of(101L);
2893+
org.bson.Document source = new org.bson.Document("_id", new org.bson.Document("innerId", idValue.innerId))
2894+
.append("value", "abc").append("_class", ComplexIdAndNoAnnotation.class.getName());
2895+
2896+
EntityProjection<?, ComplexIdAndNoAnnotation> projection = introspector.introspect(projectionTargetType,
2897+
ComplexIdAndNoAnnotation.class);
2898+
2899+
assertThat(converter.project(projection, source)) //
2900+
.isInstanceOf(projectionTargetType) //
2901+
.extracting("id").isEqualTo(idValue);
2902+
}
2903+
2904+
org.bson.Document write(Object source) {
2905+
2906+
org.bson.Document target = new org.bson.Document();
2907+
converter.write(source, target);
2908+
return target;
2909+
}
2910+
28792911
static class GenericType<T> {
28802912
T content;
28812913
}
@@ -3092,7 +3124,33 @@ static class ClassWithComplexId {
30923124
}
30933125

30943126
static class ComplexId {
3127+
30953128
Long innerId;
3129+
3130+
static ComplexId of(Long value) {
3131+
3132+
ComplexId id = new ComplexId();
3133+
id.innerId = value;
3134+
return id;
3135+
}
3136+
3137+
@Override
3138+
public boolean equals(Object o) {
3139+
3140+
if (o == this) {
3141+
return true;
3142+
}
3143+
if (o == null || getClass() != o.getClass()) {
3144+
return false;
3145+
}
3146+
ComplexId complexId = (ComplexId) o;
3147+
return Objects.equals(innerId, complexId.innerId);
3148+
}
3149+
3150+
@Override
3151+
public int hashCode() {
3152+
return Objects.hash(innerId);
3153+
}
30963154
}
30973155

30983156
static class TypWithCollectionConstructor {
@@ -3611,10 +3669,12 @@ static class WithFieldWrite {
36113669
@org.springframework.data.mongodb.core.mapping.Field(
36123670
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Integer writeAlways;
36133671

3614-
@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
3672+
@org.springframework.data.mongodb.core.mapping.DBRef
3673+
@org.springframework.data.mongodb.core.mapping.Field(
36153674
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;
36163675

3617-
@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
3676+
@org.springframework.data.mongodb.core.mapping.DBRef
3677+
@org.springframework.data.mongodb.core.mapping.Field(
36183678
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
36193679

36203680
}
@@ -3728,12 +3788,79 @@ static class Author {
37283788

37293789
}
37303790

3731-
@Data
37323791
static class Cyclic {
37333792

37343793
@Id String id;
37353794
String value;
37363795
Cyclic cycle;
3796+
3797+
public String getId() {
3798+
return id;
3799+
}
3800+
3801+
public void setId(String id) {
3802+
this.id = id;
3803+
}
3804+
3805+
public String getValue() {
3806+
return value;
3807+
}
3808+
3809+
public void setValue(String value) {
3810+
this.value = value;
3811+
}
3812+
3813+
public Cyclic getCycle() {
3814+
return cycle;
3815+
}
3816+
3817+
public void setCycle(Cyclic cycle) {
3818+
this.cycle = cycle;
3819+
}
3820+
3821+
@Override
3822+
public boolean equals(Object o) {
3823+
if (o == this) {
3824+
return true;
3825+
}
3826+
if (o == null || getClass() != o.getClass()) {
3827+
return false;
3828+
}
3829+
Cyclic cyclic = (Cyclic) o;
3830+
return Objects.equals(id, cyclic.id) && Objects.equals(value, cyclic.value)
3831+
&& Objects.equals(cycle, cyclic.cycle);
3832+
}
3833+
3834+
@Override
3835+
public int hashCode() {
3836+
return Objects.hash(id, value, cycle);
3837+
}
3838+
}
3839+
3840+
static class ComplexIdAndFieldAnnotation {
3841+
3842+
@Field("_id") //
3843+
ComplexId id;
3844+
String value;
3845+
}
3846+
3847+
static class ComplexIdAndMongoIdAnnotation {
3848+
3849+
@MongoId //
3850+
ComplexId id;
3851+
String value;
37373852
}
37383853

3854+
static class ComplexIdAndIdAnnotation {
3855+
3856+
@Id //
3857+
ComplexId id;
3858+
String value;
3859+
}
3860+
3861+
static class ComplexIdAndNoAnnotation {
3862+
3863+
ComplexId id;
3864+
String value;
3865+
}
37393866
}

0 commit comments

Comments
 (0)