Skip to content

Commit

Permalink
Fix id value conversion when projecting result types.
Browse files Browse the repository at this point in the history
Contextual information required for converting values are now passed on correctly when projecting id properties.

Closes: #4524
Original pull request: #4525
  • Loading branch information
christophstrobl authored and mp911de committed Oct 11, 2023
1 parent 5c06261 commit eae5c60
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ private Object readIdValue(ConversionContext context, SpELExpressionEvaluator ev
String expression = idProperty.getSpelExpression();
Object resolvedValue = expression != null ? evaluator.evaluate(expression) : rawId;

return resolvedValue != null ? readValue(context, resolvedValue, idProperty.getTypeInformation()) : null;
return resolvedValue != null ? readValue(context.forProperty(idProperty), resolvedValue, idProperty.getTypeInformation()) : null;
}

private void readProperties(ConversionContext context, MongoPersistentEntity<?> entity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
Expand Down Expand Up @@ -83,6 +85,7 @@
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
Expand Down Expand Up @@ -2866,7 +2869,7 @@ public org.bson.Document write(@Nullable String domainValue, MongoConversionCont

@Test // GH-4371
void shouldConvertTypesToStringTargetType() {

org.bson.Document source = org.bson.Document.parse("""
{
city : ["Gotham", "Metropolis"]
Expand All @@ -2876,6 +2879,35 @@ void shouldConvertTypesToStringTargetType() {
assertThat(converter.read(Address.class, source).city).isEqualTo("Gotham,Metropolis");
}

@ValueSource(classes = { ComplexIdAndNoAnnotation.class, ComplexIdAndIdAnnotation.class,
ComplexIdAndMongoIdAnnotation.class, ComplexIdAndFieldAnnotation.class })
@ParameterizedTest // GH-4524
void projectShouldReadComplexIdType(Class<?> projectionTargetType) {

EntityProjectionIntrospector introspector = EntityProjectionIntrospector.create(converter.getProjectionFactory(),
EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy()
.and((target, underlyingType) -> !converter.conversions.isSimpleType(target)),
mappingContext);

ComplexId idValue = ComplexId.of(101L);
org.bson.Document source = new org.bson.Document("_id", new org.bson.Document("innerId", idValue.innerId))
.append("value", "abc").append("_class", ComplexIdAndNoAnnotation.class.getName());

EntityProjection<?, ComplexIdAndNoAnnotation> projection = introspector.introspect(projectionTargetType,
ComplexIdAndNoAnnotation.class);

assertThat(converter.project(projection, source)) //
.isInstanceOf(projectionTargetType) //
.extracting("id").isEqualTo(idValue);
}

org.bson.Document write(Object source) {

org.bson.Document target = new org.bson.Document();
converter.write(source, target);
return target;
}

static class GenericType<T> {
T content;
}
Expand Down Expand Up @@ -3092,7 +3124,33 @@ static class ClassWithComplexId {
}

static class ComplexId {

Long innerId;

static ComplexId of(Long value) {

ComplexId id = new ComplexId();
id.innerId = value;
return id;
}

@Override
public boolean equals(Object o) {

if (o == this) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ComplexId complexId = (ComplexId) o;
return Objects.equals(innerId, complexId.innerId);
}

@Override
public int hashCode() {
return Objects.hash(innerId);
}
}

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

@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
@org.springframework.data.mongodb.core.mapping.DBRef
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;

@org.springframework.data.mongodb.core.mapping.DBRef @org.springframework.data.mongodb.core.mapping.Field(
@org.springframework.data.mongodb.core.mapping.DBRef
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;

}
Expand Down Expand Up @@ -3728,12 +3788,79 @@ static class Author {

}

@Data
static class Cyclic {

@Id String id;
String value;
Cyclic cycle;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public Cyclic getCycle() {
return cycle;
}

public void setCycle(Cyclic cycle) {
this.cycle = cycle;
}

@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Cyclic cyclic = (Cyclic) o;
return Objects.equals(id, cyclic.id) && Objects.equals(value, cyclic.value)
&& Objects.equals(cycle, cyclic.cycle);
}

@Override
public int hashCode() {
return Objects.hash(id, value, cycle);
}
}

static class ComplexIdAndFieldAnnotation {

@Field("_id") //
ComplexId id;
String value;
}

static class ComplexIdAndMongoIdAnnotation {

@MongoId //
ComplexId id;
String value;
}

static class ComplexIdAndIdAnnotation {

@Id //
ComplexId id;
String value;
}

static class ComplexIdAndNoAnnotation {

ComplexId id;
String value;
}
}

0 comments on commit eae5c60

Please sign in to comment.