DATACOUCH-533 - Promote id field if no annotation id.
Promote id field if no annotation id. Note that there is no longer any Couchbase @Id annotation - only the Spring @id annotation.
This commit is contained in:
@@ -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<T> extends BasicPersistentEntity<T,
|
||||
}
|
||||
|
||||
// check existing ID vs new candidate
|
||||
boolean currentCbId = this.getIdProperty().isAnnotationPresent(Id.class);
|
||||
boolean currentSpringId = this.getIdProperty().isAnnotationPresent(org.springframework.data.annotation.Id.class);
|
||||
boolean candidateCbId = property.isAnnotationPresent(Id.class);
|
||||
boolean candidateSpringId = property.isAnnotationPresent(org.springframework.data.annotation.Id.class);
|
||||
|
||||
if (currentCbId && candidateSpringId) {
|
||||
// spring IDs will have priority over SDK IDs
|
||||
if (candidateSpringId && !currentSpringId) {
|
||||
// spring IDs will have priority over fields named id
|
||||
return property;
|
||||
} else if (currentSpringId && candidateCbId) {
|
||||
// ignore SDK's IDs if current is a Spring ID
|
||||
} else if (currentSpringId && !candidateSpringId) {
|
||||
// spring IDs will have priority over fields named id
|
||||
return null;
|
||||
} else {
|
||||
// do not allow two @Id fields or two fields named id (possible via @Field)
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add id property %s but already have property %s registered as id. Check your mapping configuration!",
|
||||
property.getField(), getIdProperty().getField()));
|
||||
}
|
||||
/* any of the following will throw:
|
||||
- current is a spring ID and the candidate bears another spring ID
|
||||
- current is a SDK ID and the candidate bears another SDK ID
|
||||
- any other combination involving something else than a SDK or Spring ID
|
||||
*/
|
||||
return super.returnPropertyIfBetterIdPropertyCandidateOrNull(property);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import com.couchbase.client.core.deps.com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Implements annotated property representations of a given {@link Field} instance.
|
||||
* <p/>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TestIdField> 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<TestIdField> 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<TestIdField> 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<TestIdField> 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<TestIdField> 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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user