diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java index 78e4f3a6..cb82d214 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java @@ -23,6 +23,8 @@ import java.util.concurrent.TimeUnit; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.data.annotation.Id; +import org.springframework.data.mapping.MappingException; +import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; @@ -76,24 +78,22 @@ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity @@ -97,6 +99,7 @@ public class BasicCouchbasePersistentProperty extends AnnotationBasedPersistentP // DATACOUCH-145: allows SDK's @Id annotation to be used @Override public boolean isIdProperty() { - return isAnnotationPresent(Id.class) || super.isIdProperty(); + return isAnnotationPresent(Id.class) || super.isIdProperty() + || this.getFieldName().toLowerCase(Locale.ROOT).equals("id"); } } diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java index 6d728eab..19bf8dbe 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java @@ -23,6 +23,7 @@ import java.lang.reflect.Field; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.annotation.Id; +import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; @@ -82,6 +83,98 @@ public class BasicCouchbasePersistentPropertyTests { assertThat(test.getIdProperty()).isEqualTo(springIdProperty); } + @Test + void testAnnotationIdFieldOnly() { // only has @springId + class TestIdField { + @org.springframework.data.couchbase.core.mapping.Field String name; + String description; + @Id private String springId; + } + BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity<>( + ClassTypeInformation.from(TestIdField.class)); + Field springIdField = ReflectionUtils.findField(TestIdField.class, "springId"); + CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField); + test.addPersistentProperty(springIdProperty); + assertThat(test.getIdProperty()).isEqualTo(springIdProperty); + } + + @Test + void testIdFieldOnly() { // only has id + class TestIdField { + @org.springframework.data.couchbase.core.mapping.Field String name; + String description; + private String id; + } + Field idField = ReflectionUtils.findField(TestIdField.class, "id"); + CouchbasePersistentProperty idProperty = getPropertyFor(idField); + BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity<>( + ClassTypeInformation.from(TestIdField.class)); + test.addPersistentProperty(idProperty); + assertThat(test.getIdProperty()).isEqualTo(idProperty); + } + + @Test + void testIdFieldAndAnnotationIdField() { // has @springId and id + class TestIdField { + @org.springframework.data.couchbase.core.mapping.Field String name; + String description; + @Id private String springId; + private String id; + } + BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity<>( + ClassTypeInformation.from(TestIdField.class)); + Field springIdField = ReflectionUtils.findField(TestIdField.class, "springId"); + Field idField = ReflectionUtils.findField(TestIdField.class, "id"); + CouchbasePersistentProperty idProperty = getPropertyFor(idField); + CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField); + // here this simulates the order in which the annotations would be found + // when "overriding" Spring @Id with SDK's @Id... + test.addPersistentProperty(idProperty); + // replace id with springId + test.addPersistentProperty(springIdProperty); + assertThat(test.getIdProperty()).isEqualTo(springIdProperty); + } + + @Test + void testTwoAnnotationIdFields() { // has @Id springId and @Id id + class TestIdField { + @org.springframework.data.couchbase.core.mapping.Field String name; + String description; + @Id private String springId; + @Id private String id; + } + Field springIdField = ReflectionUtils.findField(TestIdField.class, "springId"); + Field idField = ReflectionUtils.findField(TestIdField.class, "id"); + CouchbasePersistentProperty idProperty = getPropertyFor(idField); + CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField); + BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity<>( + ClassTypeInformation.from(TestIdField.class)); + test.addPersistentProperty(springIdProperty); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + test.addPersistentProperty(idProperty); + }); + } + + @Test + void testTwoIdFields() { // has @Field("id") springId and id + class TestIdField { + @org.springframework.data.couchbase.core.mapping.Field String name; + String description; + @org.springframework.data.couchbase.core.mapping.Field("id") private String springId; + private String id; + } + Field springIdField = ReflectionUtils.findField(TestIdField.class, "springId"); + Field idField = ReflectionUtils.findField(TestIdField.class, "id"); + CouchbasePersistentProperty idProperty = getPropertyFor(idField); + CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField); + BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity<>( + ClassTypeInformation.from(TestIdField.class)); + test.addPersistentProperty(springIdProperty); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + test.addPersistentProperty(idProperty); + }); + } + /** * Helper method to create a property out of the field. * diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java index 33069392..b754514d 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java @@ -955,4 +955,104 @@ public class MappingCouchbaseConverterTests { assertThat(converted.getId()).isEqualTo(entity.id); assertThat(converted.getId()).isEqualTo(entity.prefix1 + '.' + entity.someId + '.' + entity.suffix); } + + @Test + void idHasIdFieldOnly() { + class Entity { + public String id = "123"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(entity, converted); + assertThat(converted.getId()).isEqualTo(entity.id); + } + + @Test + void idHasIdFieldAndAnnotatedId() { + class Entity { + public String id = "123"; + @Id public String otherId = "456"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(entity, converted); + assertThat(converted.getId()).isEqualTo(entity.otherId); + } + + @Test + void idHasIdFieldAndAnnotatedIdReverse() { + class Entity { + @Id public String otherId = "456"; + public String id = "123"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(entity, converted); + assertThat(converted.getId()).isEqualTo(entity.otherId); + } + + @Test + void idHasTwoAnnotatedIdFields() { + class Entity { + @Id public String id = "123"; + @Id public String otherId = "456"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + converter.write(entity, converted); + }); + } + + @Test + void idHasTwoIdFields() { + class Entity { + public String id = "123"; + @Field("id") public String otherId = "456"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + converter.write(entity, converted); + }); + } + + @Test + void idHasAnnotatedIdAndMultipleIdFields() { + class Entity { // @Id has precedence, multiple 'id' fields is irrelevant + @Id public String annotatedId = "123"; + @Field("id") public String otherId0 = "456"; + @Field("id") public String otherId1 = "789"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(entity, converted); + assertThat(converted.getId()).isEqualTo(entity.annotatedId); + } + + @Test + void idHasAnnotatedIdAndMultipleIdFieldsReverse() { + class Entity { // exception will be thrown at otherId1 as it is the second 'id' before @Id has been processed + @Field("id") public String otherId0 = "456"; + @Field("id") public String otherId1 = "789"; + @Id public String annotatedId = "123"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + converter.write(entity, converted); + }); + } + + @Test + void idHasNoId() { + class Entity { + public String notId = "123"; + } + Entity entity = new Entity(); + CouchbaseDocument converted = new CouchbaseDocument(); + assertThatExceptionOfType(MappingException.class).isThrownBy(() -> { + converter.write(entity, converted); + }); + } }