Skip to content

Commit fc1013c

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 4dab1f6 commit fc1013c

File tree

2 files changed

+131
-4
lines changed

2 files changed

+131
-4
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ private Object readIdValue(ConversionContext context, SpELExpressionEvaluator ev
583583
String expression = idProperty.getSpelExpression();
584584
Object resolvedValue = expression != null ? evaluator.evaluate(expression) : rawId;
585585

586-
return resolvedValue != null ? readValue(context, resolvedValue, idProperty.getTypeInformation()) : null;
586+
return resolvedValue != null ? readValue(context.forProperty(idProperty), resolvedValue, idProperty.getTypeInformation()) : null;
587587
}
588588

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

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

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import org.junit.jupiter.api.Disabled;
4242
import org.junit.jupiter.api.Test;
4343
import org.junit.jupiter.api.extension.ExtendWith;
44+
import org.junit.jupiter.params.ParameterizedTest;
45+
import org.junit.jupiter.params.provider.ValueSource;
4446
import org.mockito.Mock;
4547
import org.mockito.Mockito;
4648
import org.mockito.junit.jupiter.MockitoExtension;
@@ -82,6 +84,7 @@
8284
import org.springframework.data.mongodb.core.mapping.Document;
8385
import org.springframework.data.mongodb.core.mapping.Field;
8486
import org.springframework.data.mongodb.core.mapping.FieldType;
87+
import org.springframework.data.mongodb.core.mapping.MongoId;
8588
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
8689
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
8790
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
@@ -2866,6 +2869,35 @@ void shouldConvertTypesToStringTargetType() {
28662869
assertThat(converter.read(Address.class, source).city).isEqualTo("Gotham,Metropolis");
28672870
}
28682871

2872+
@ValueSource(classes = { ComplexIdAndNoAnnotation.class, ComplexIdAndIdAnnotation.class,
2873+
ComplexIdAndMongoIdAnnotation.class, ComplexIdAndFieldAnnotation.class })
2874+
@ParameterizedTest // GH-4524
2875+
void projectShouldReadComplexIdType(Class<?> projectionTargetType) {
2876+
2877+
EntityProjectionIntrospector introspector = EntityProjectionIntrospector.create(converter.getProjectionFactory(),
2878+
EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy()
2879+
.and((target, underlyingType) -> !converter.conversions.isSimpleType(target)),
2880+
mappingContext);
2881+
2882+
ComplexId idValue = ComplexId.of(101L);
2883+
org.bson.Document source = new org.bson.Document("_id", new org.bson.Document("innerId", idValue.innerId))
2884+
.append("value", "abc").append("_class", ComplexIdAndNoAnnotation.class.getName());
2885+
2886+
EntityProjection<?, ComplexIdAndNoAnnotation> projection = introspector.introspect(projectionTargetType,
2887+
ComplexIdAndNoAnnotation.class);
2888+
2889+
assertThat(converter.project(projection, source)) //
2890+
.isInstanceOf(projectionTargetType) //
2891+
.extracting("id").isEqualTo(idValue);
2892+
}
2893+
2894+
org.bson.Document write(Object source) {
2895+
2896+
org.bson.Document target = new org.bson.Document();
2897+
converter.write(source, target);
2898+
return target;
2899+
}
2900+
28692901
static class GenericType<T> {
28702902
T content;
28712903
}
@@ -3082,7 +3114,33 @@ static class ClassWithComplexId {
30823114
}
30833115

30843116
static class ComplexId {
3117+
30853118
Long innerId;
3119+
3120+
static ComplexId of(Long value) {
3121+
3122+
ComplexId id = new ComplexId();
3123+
id.innerId = value;
3124+
return id;
3125+
}
3126+
3127+
@Override
3128+
public boolean equals(Object o) {
3129+
3130+
if (o == this) {
3131+
return true;
3132+
}
3133+
if (o == null || getClass() != o.getClass()) {
3134+
return false;
3135+
}
3136+
ComplexId complexId = (ComplexId) o;
3137+
return Objects.equals(innerId, complexId.innerId);
3138+
}
3139+
3140+
@Override
3141+
public int hashCode() {
3142+
return Objects.hash(innerId);
3143+
}
30863144
}
30873145

30883146
static class TypWithCollectionConstructor {
@@ -3589,10 +3647,12 @@ static class WithFieldWrite {
35893647
@org.springframework.data.mongodb.core.mapping.Field(
35903648
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Integer writeAlways;
35913649

3592-
@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
3650+
@org.springframework.data.mongodb.core.mapping.DBRef
3651+
@org.springframework.data.mongodb.core.mapping.Field(
35933652
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;
35943653

3595-
@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
3654+
@org.springframework.data.mongodb.core.mapping.DBRef
3655+
@org.springframework.data.mongodb.core.mapping.Field(
35963656
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
35973657

35983658
}
@@ -3706,12 +3766,79 @@ static class Author {
37063766

37073767
}
37083768

3709-
@Data
37103769
static class Cyclic {
37113770

37123771
@Id String id;
37133772
String value;
37143773
Cyclic cycle;
3774+
3775+
public String getId() {
3776+
return id;
3777+
}
3778+
3779+
public void setId(String id) {
3780+
this.id = id;
3781+
}
3782+
3783+
public String getValue() {
3784+
return value;
3785+
}
3786+
3787+
public void setValue(String value) {
3788+
this.value = value;
3789+
}
3790+
3791+
public Cyclic getCycle() {
3792+
return cycle;
3793+
}
3794+
3795+
public void setCycle(Cyclic cycle) {
3796+
this.cycle = cycle;
3797+
}
3798+
3799+
@Override
3800+
public boolean equals(Object o) {
3801+
if (o == this) {
3802+
return true;
3803+
}
3804+
if (o == null || getClass() != o.getClass()) {
3805+
return false;
3806+
}
3807+
Cyclic cyclic = (Cyclic) o;
3808+
return Objects.equals(id, cyclic.id) && Objects.equals(value, cyclic.value)
3809+
&& Objects.equals(cycle, cyclic.cycle);
3810+
}
3811+
3812+
@Override
3813+
public int hashCode() {
3814+
return Objects.hash(id, value, cycle);
3815+
}
37153816
}
37163817

3818+
static class ComplexIdAndFieldAnnotation {
3819+
3820+
@Field("_id") //
3821+
ComplexId id;
3822+
String value;
3823+
}
3824+
3825+
static class ComplexIdAndMongoIdAnnotation {
3826+
3827+
@MongoId //
3828+
ComplexId id;
3829+
String value;
3830+
}
3831+
3832+
static class ComplexIdAndIdAnnotation {
3833+
3834+
@Id //
3835+
ComplexId id;
3836+
String value;
3837+
}
3838+
3839+
static class ComplexIdAndNoAnnotation {
3840+
3841+
ComplexId id;
3842+
String value;
3843+
}
37173844
}

0 commit comments

Comments
 (0)