diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java index f47474a87..16e80b991 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java @@ -465,7 +465,7 @@ protected T updateIndexedObject(T entity, IndexedObjectInformation indexedOb ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty(); // Only deal with text because ES generated Ids are strings! - if (indexedObjectInformation.getId() != null && idProperty != null + if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable() && idProperty.getType().isAssignableFrom(String.class)) { propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId()); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractReactiveElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractReactiveElasticsearchTemplate.java index a13d18454..6fd9e58c2 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractReactiveElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractReactiveElasticsearchTemplate.java @@ -259,7 +259,7 @@ protected T updateIndexedObject(T entity, IndexedObjectInformation indexedOb ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty(); // Only deal with text because ES generated Ids are strings! - if (indexedObjectInformation.getId() != null && idProperty != null + if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable() && idProperty.getType().isAssignableFrom(String.class)) { propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId()); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java index 9d625ee5d..dbadf090b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java @@ -342,7 +342,7 @@ private R readEntity(ElasticsearchPersistentEntity entity, Map propertyAccessor = new ConvertingPropertyAccessor<>( targetEntity.getPropertyAccessor(result), conversionService); // Only deal with String because ES generated Ids are strings ! - if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) { + if (idProperty != null && idProperty.isWritable() && idProperty.getType().isAssignableFrom(String.class)) { propertyAccessor.setProperty(idProperty, document.getId()); } } @@ -406,7 +406,7 @@ protected R readProperties(ElasticsearchPersistentEntity entity, R instan for (ElasticsearchPersistentProperty prop : entity) { - if (entity.isCreatorArgument(prop) || !prop.isReadable()) { + if (entity.isCreatorArgument(prop) || !prop.isReadable() || !prop.isWritable()) { continue; } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java index 4b89139f6..5981a4530 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java @@ -54,7 +54,9 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.annotation.AccessType; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.annotation.Version; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -3705,6 +3707,21 @@ public int hashCode() { } } + @Test // #2230 + @DisplayName("should work with readonly id") + void shouldWorkWithReadonlyId() { + + ReadonlyIdEntity entity = new ReadonlyIdEntity(); + entity.setPart1("foo"); + entity.setPart2("bar"); + operations.save(entity); + + ReadonlyIdEntity readEntity = operations.get(entity.getId(), ReadonlyIdEntity.class); + + assertThat(readEntity.getPart1()).isEqualTo(entity.getPart1()); + assertThat(readEntity.getPart2()).isEqualTo(entity.getPart2()); + } + @Document(indexName = "#{@indexNameProvider.indexName()}") private static class SampleEntityUUIDKeyed { @Nullable @@ -4450,5 +4467,36 @@ public String toString() { + '}'; } } + + @Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id") + static class ReadonlyIdEntity { + @Field(type = FieldType.Keyword) private String part1; + + @Field(type = FieldType.Keyword) private String part2; + + @Id + @ReadOnlyProperty + @AccessType(AccessType.Type.PROPERTY) + public String getId() { + return part1 + '-' + part2; + } + + public String getPart1() { + return part1; + } + + public void setPart1(String part1) { + this.part1 = part1; + } + + public String getPart2() { + return part2; + } + + public void setPart2(String part2) { + this.part2 = part2; + } + } + // endregion } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchIntegrationTests.java index ec263871c..2be396bc0 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchIntegrationTests.java @@ -50,7 +50,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.annotation.AccessType; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.annotation.Version; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -1161,6 +1163,23 @@ void shouldReturnMonoOfReactiveSearchHits() { .verifyComplete(); } + @Test // #2230 + @DisplayName("should work with readonly id") + void shouldWorkWithReadonlyId() { + + ReadonlyIdEntity entity = new ReadonlyIdEntity(); + entity.setPart1("foo"); + entity.setPart2("bar"); + + operations.save(entity).block(); + + operations.get(entity.getId(), ReadonlyIdEntity.class) // + .as(StepVerifier::create) // + .assertNext(readEntity -> { // + assertThat(readEntity.getPart1()).isEqualTo(entity.getPart1()); // + assertThat(readEntity.getPart2()).isEqualTo(entity.getPart2()); // + }).verifyComplete(); + } // endregion // region Helper functions @@ -1494,5 +1513,35 @@ public String toString() { + seqNoPrimaryTerm + '}'; } } + + @Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id") + static class ReadonlyIdEntity { + @Field(type = FieldType.Keyword) private String part1; + + @Field(type = FieldType.Keyword) private String part2; + + @Id + @ReadOnlyProperty + @AccessType(AccessType.Type.PROPERTY) + public String getId() { + return part1 + '-' + part2; + } + + public String getPart1() { + return part1; + } + + public void setPart1(String part1) { + this.part1 = part1; + } + + public String getPart2() { + return part2; + } + + public void setPart2(String part2) { + this.part2 = part2; + } + } // endregion } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/event/CallbackIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/event/CallbackIntegrationTests.java index b2db76fca..8d7faedcb 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/event/CallbackIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/event/CallbackIntegrationTests.java @@ -241,7 +241,7 @@ static class SampleEntity { @Id private String id; @Nullable private String text; - @ReadOnlyProperty +// @ReadOnlyProperty @Nullable private String className; @Nullable diff --git a/src/test/java/org/springframework/data/elasticsearch/core/event/ReactiveCallbackIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/event/ReactiveCallbackIntegrationTests.java index 21502ac3a..45d62bd4c 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/event/ReactiveCallbackIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/event/ReactiveCallbackIntegrationTests.java @@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; @@ -119,7 +118,6 @@ static class SampleEntity { @Id private String id; private String text; - @ReadOnlyProperty @Nullable private String className; public SampleEntity(String id, String text) {