Fix id conversion when storing document reference.

This commit makes sure that the string to ObjectId conversion when storing document references follows the general conversion rules.

Closes #3847
Original pull request: #3848.
This commit is contained in:
Christoph Strobl
2021-09-29 14:37:58 +02:00
committed by Mark Paluch
parent c350be1f52
commit eed9b2470a
2 changed files with 81 additions and 1 deletions

View File

@@ -23,6 +23,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.annotation.Reference;
@@ -90,6 +91,8 @@ class DocumentPointerFactory {
if (idProperty.hasExplicitWriteTarget()
&& conversionService.canConvert(idValue.getClass(), idProperty.getFieldType())) {
return () -> conversionService.convert(idValue, idProperty.getFieldType());
} else if (idValue instanceof String && ObjectId.isValid((String)idValue)) {
return () -> new ObjectId((String)idValue);
}
return () -> idValue;

View File

@@ -1180,6 +1180,73 @@ public class MongoTemplateDocumentReferenceTests {
assertThat(target.books).containsExactlyInAnyOrder(book1, book3);
}
@Test // GH-3847
void writeReferenceWithIdStringThatIsAnObjectId() {
String rootCollectionName = template.getCollectionName(SingleRefRoot.class);
ObjectId id = new ObjectId();
SingleRefRoot source = new SingleRefRoot();
source.id = "root-1";
source.simpleValueRef = new SimpleObjectRef(id.toHexString(), "me-the-referenced-object");
template.save(source);
Document target = template.execute(db -> {
return db.getCollection(rootCollectionName).find(Filters.eq("_id", "root-1")).first();
});
assertThat(target.get("simpleValueRef")).isEqualTo(id);
}
@Test // GH-3847
void readWithIdStringThatIsAnObjectId() {
ObjectId id = new ObjectId();
String rootCollectionName = template.getCollectionName(SingleRefRoot.class);
String refCollectionName = template.getCollectionName(SimpleObjectRef.class);
Document refSource = new Document("_id", id).append("value", "me-the-referenced-object");
Document source = new Document("_id", "id-1").append("value", "v1").append("simpleValueRef", id);
template.execute(db -> {
db.getCollection(refCollectionName).insertOne(refSource);
db.getCollection(rootCollectionName).insertOne(source);
return null;
});
SingleRefRoot result = template.findOne(query(where("id").is("id-1")), SingleRefRoot.class);
assertThat(result.getSimpleValueRef()).isEqualTo(new SimpleObjectRef(id.toHexString(), "me-the-referenced-object"));
}
@Test // GH-3847
void readWriteTypeReferenceHavingFixedStringIdTargetType() {
ObjectId id = new ObjectId();
String rootCollectionName = template.getCollectionName(SingleRefRoot.class);
ObjectRefHavingStringIdTargetType customStringIdTargetRef = new ObjectRefHavingStringIdTargetType(id.toHexString(),
"me-the-referenced-object");
template.save(customStringIdTargetRef);
SingleRefRoot source = new SingleRefRoot();
source.id = "root-1";
source.customStringIdTargetRef = customStringIdTargetRef;
template.save(source);
Document target = template.execute(db -> {
return db.getCollection(rootCollectionName).find(Filters.eq("_id", "root-1")).first();
});
assertThat(target.get("customStringIdTargetRef")).isEqualTo(id.toHexString());
SingleRefRoot result = template.findOne(query(where("id").is("root-1")), SingleRefRoot.class);
assertThat(result.getCustomStringIdTargetRef())
.isEqualTo(new ObjectRefHavingStringIdTargetType(id.toHexString(), "me-the-referenced-object"));
}
@Data
static class SingleRefRoot {
@@ -1188,7 +1255,7 @@ public class MongoTemplateDocumentReferenceTests {
@DocumentReference SimpleObjectRefWithReadingConverter withReadingConverter;
@DocumentReference(lookup = "{ '_id' : '?#{#target}' }") //
@DocumentReference(lookup = "{ '_id' : ?#{#target} }") //
SimpleObjectRef simpleValueRef;
@DocumentReference(lookup = "{ '_id' : '?#{#target}' }", lazy = true) //
@@ -1211,6 +1278,8 @@ public class MongoTemplateDocumentReferenceTests {
ObjectRefOnNonIdField lazyObjectValueRefOnNonIdFields;
@DocumentReference ObjectRefHavingCustomizedIdTargetType customIdTargetRef;
@DocumentReference ObjectRefHavingStringIdTargetType customStringIdTargetRef;
}
@Data
@@ -1325,6 +1394,14 @@ public class MongoTemplateDocumentReferenceTests {
String name;
}
@Data
@AllArgsConstructor
static class ObjectRefHavingStringIdTargetType {
@MongoId(targetType = FieldType.STRING) String id;
String name;
}
static class ReferencableConverter implements Converter<ReferenceAble, DocumentPointer<Object>> {
@Nullable