Skip to content

Commit 159687e

Browse files
authored
Improve handling of immutable classes.
Original Pull Request #1801 Closes #1800
1 parent 502ce0b commit 159687e

12 files changed

+255
-82
lines changed

src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java

+32-10
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ public <T> T save(T entity, IndexCoordinates index) {
188188
IndexQuery query = getIndexQuery(entityAfterBeforeConvert);
189189
doIndex(query, index);
190190

191-
T entityAfterAfterSave = maybeCallbackAfterSave(entityAfterBeforeConvert, index);
191+
T entityAfterAfterSave = (T) maybeCallbackAfterSave(query.getObject(), index);
192192

193193
return entityAfterAfterSave;
194194
}
@@ -215,13 +215,18 @@ public <T> Iterable<T> save(Iterable<T> entities, IndexCoordinates index) {
215215
List<IndexQuery> indexQueries = Streamable.of(entities).stream().map(this::getIndexQuery)
216216
.collect(Collectors.toList());
217217

218-
if (!indexQueries.isEmpty()) {
219-
List<IndexedObjectInformation> indexedObjectInformations = bulkIndex(indexQueries, index);
220-
Iterator<IndexedObjectInformation> iterator = indexedObjectInformations.iterator();
221-
entities.forEach(entity -> updateIndexedObject(entity, iterator.next()));
218+
if (indexQueries.isEmpty()) {
219+
return Collections.emptyList();
222220
}
223221

224-
return indexQueries.stream().map(IndexQuery::getObject).map(entity -> (T) entity).collect(Collectors.toList());
222+
List<IndexedObjectInformation> indexedObjectInformations = bulkIndex(indexQueries, index);
223+
Iterator<IndexedObjectInformation> iterator = indexedObjectInformations.iterator();
224+
225+
// noinspection unchecked
226+
return indexQueries.stream() //
227+
.map(IndexQuery::getObject) //
228+
.map(entity -> (T) updateIndexedObject(entity, iterator.next())) //
229+
.collect(Collectors.toList()); //
225230
}
226231

227232
@Override
@@ -419,7 +424,9 @@ public <T> SearchHits<T> search(MoreLikeThisQuery query, Class<T> clazz, IndexCo
419424
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
420425

421426
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = requestFactory.moreLikeThisQueryBuilder(query, index);
422-
return search(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).withPageable(query.getPageable()).build(), clazz, index);
427+
return search(
428+
new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).withPageable(query.getPageable()).build(),
429+
clazz, index);
423430
}
424431

425432
@Override
@@ -611,7 +618,7 @@ protected List<IndexedObjectInformation> checkForBulkOperationFailure(BulkRespon
611618
}).collect(Collectors.toList());
612619
}
613620

614-
protected void updateIndexedObject(Object entity, IndexedObjectInformation indexedObjectInformation) {
621+
protected <T> T updateIndexedObject(T entity, IndexedObjectInformation indexedObjectInformation) {
615622

616623
ElasticsearchPersistentEntity<?> persistentEntity = elasticsearchConverter.getMappingContext()
617624
.getPersistentEntity(entity.getClass());
@@ -621,22 +628,30 @@ protected void updateIndexedObject(Object entity, IndexedObjectInformation index
621628
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
622629

623630
// Only deal with text because ES generated Ids are strings!
624-
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
631+
if (indexedObjectInformation.getId() != null && idProperty != null
632+
&& idProperty.getType().isAssignableFrom(String.class)) {
625633
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
626634
}
627635

628636
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
629637
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
630638
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
639+
// noinspection ConstantConditions
631640
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
632641
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
633642
}
634643

635644
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
636645
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
646+
// noinspection ConstantConditions
637647
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
638648
}
649+
650+
// noinspection unchecked
651+
T updatedEntity = (T) propertyAccessor.getBean();
652+
return updatedEntity;
639653
}
654+
return entity;
640655
}
641656

642657
ElasticsearchPersistentEntity<?> getRequiredPersistentEntity(Class<?> clazz) {
@@ -807,13 +822,16 @@ protected <T> T maybeCallbackAfterConvert(T entity, Document document, IndexCoor
807822

808823
protected void updateIndexedObjectsWithQueries(List<?> queries,
809824
List<IndexedObjectInformation> indexedObjectInformations) {
825+
810826
for (int i = 0; i < queries.size(); i++) {
811827
Object query = queries.get(i);
828+
812829
if (query instanceof IndexQuery) {
813830
IndexQuery indexQuery = (IndexQuery) query;
814831
Object queryObject = indexQuery.getObject();
832+
815833
if (queryObject != null) {
816-
updateIndexedObject(queryObject, indexedObjectInformations.get(i));
834+
indexQuery.setObject(updateIndexedObject(queryObject, indexedObjectInformations.get(i)));
817835
}
818836
}
819837
}
@@ -848,6 +866,10 @@ public T doWith(@Nullable Document document) {
848866
}
849867

850868
T entity = reader.read(type, document);
869+
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of(
870+
document.hasId() ? document.getId() : null, document.getSeqNo(), document.getPrimaryTerm(),
871+
document.getVersion());
872+
entity = updateIndexedObject(entity, indexedObjectInformation);
851873
return maybeCallbackAfterConvert(entity, document, index);
852874
}
853875
}

src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,10 @@ public String doIndex(IndexQuery query, IndexCoordinates index) {
157157
IndexResponse indexResponse = execute(client -> client.index(request, RequestOptions.DEFAULT));
158158

159159
Object queryObject = query.getObject();
160+
160161
if (queryObject != null) {
161-
updateIndexedObject(queryObject, IndexedObjectInformation.of(indexResponse.getId(), indexResponse.getSeqNo(),
162-
indexResponse.getPrimaryTerm(), indexResponse.getVersion()));
162+
query.setObject(updateIndexedObject(queryObject, IndexedObjectInformation.of(indexResponse.getId(),
163+
indexResponse.getSeqNo(), indexResponse.getPrimaryTerm(), indexResponse.getVersion())));
163164
}
164165

165166
return indexResponse.getId();
@@ -168,6 +169,7 @@ public String doIndex(IndexQuery query, IndexCoordinates index) {
168169
@Override
169170
@Nullable
170171
public <T> T get(String id, Class<T> clazz, IndexCoordinates index) {
172+
171173
GetRequest request = requestFactory.getRequest(id, routingResolver.getRouting(), index);
172174
GetResponse response = execute(client -> client.get(request, RequestOptions.DEFAULT));
173175

src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ public String doIndex(IndexQuery query, IndexCoordinates index) {
177177

178178
Object queryObject = query.getObject();
179179
if (queryObject != null) {
180-
updateIndexedObject(queryObject, IndexedObjectInformation.of(documentId, response.getSeqNo(),
181-
response.getPrimaryTerm(), response.getVersion()));
180+
query.setObject(updateIndexedObject(queryObject, IndexedObjectInformation.of(documentId, response.getSeqNo(),
181+
response.getPrimaryTerm(), response.getVersion())));
182182
}
183183

184184
return documentId;

src/main/java/org/springframework/data/elasticsearch/core/EntityOperations.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,6 @@ public ElasticsearchPersistentEntity<?> getPersistentEntity() {
477477
*/
478478
private static class AdaptibleMappedEntity<T> extends MappedEntity<T> implements AdaptibleEntity<T> {
479479

480-
private final T bean;
481480
private final ElasticsearchPersistentEntity<?> entity;
482481
private final ConvertingPropertyAccessor<T> propertyAccessor;
483482
private final IdentifierAccessor identifierAccessor;
@@ -490,7 +489,6 @@ private AdaptibleMappedEntity(T bean, ElasticsearchPersistentEntity<?> entity,
490489

491490
super(entity, identifierAccessor, propertyAccessor);
492491

493-
this.bean = bean;
494492
this.entity = entity;
495493
this.propertyAccessor = propertyAccessor;
496494
this.identifierAccessor = identifierAccessor;
@@ -510,6 +508,11 @@ static <T> AdaptibleEntity<T> of(T bean,
510508
new ConvertingPropertyAccessor<>(propertyAccessor, conversionService), conversionService, routingResolver);
511509
}
512510

511+
@Override
512+
public T getBean() {
513+
return propertyAccessor.getBean();
514+
}
515+
513516
@Nullable
514517
@Override
515518
public T populateIdIfNecessary(@Nullable Object id) {
@@ -584,7 +587,7 @@ public T incrementVersion() {
584587
@Override
585588
public String getRouting() {
586589

587-
String routing = routingResolver.getRouting(bean);
590+
String routing = routingResolver.getRouting(propertyAccessor.getBean());
588591

589592
if (routing != null) {
590593
return routing;

src/main/java/org/springframework/data/elasticsearch/core/IndexedObjectInformation.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,25 @@
2525
* @since 4.1
2626
*/
2727
public class IndexedObjectInformation {
28-
private final String id;
28+
@Nullable private final String id;
2929
@Nullable private final Long seqNo;
3030
@Nullable private final Long primaryTerm;
3131
@Nullable private final Long version;
3232

33-
private IndexedObjectInformation(String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
33+
private IndexedObjectInformation(@Nullable String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
3434
@Nullable Long version) {
3535
this.id = id;
3636
this.seqNo = seqNo;
3737
this.primaryTerm = primaryTerm;
3838
this.version = version;
3939
}
4040

41-
public static IndexedObjectInformation of(String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
41+
public static IndexedObjectInformation of(@Nullable String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
4242
@Nullable Long version) {
4343
return new IndexedObjectInformation(id, seqNo, primaryTerm, version);
4444
}
4545

46+
@Nullable
4647
public String getId() {
4748
return id;
4849
}

src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java

+25-6
Original file line numberDiff line numberDiff line change
@@ -275,27 +275,42 @@ public <T> Flux<T> saveAll(Mono<? extends Collection<? extends T>> entitiesPubli
275275
}
276276

277277
private <T> T updateIndexedObject(T entity, IndexedObjectInformation indexedObjectInformation) {
278-
AdaptibleEntity<T> adaptibleEntity = operations.forEntity(entity, converter.getConversionService(),
279-
routingResolver);
280-
adaptibleEntity.populateIdIfNecessary(indexedObjectInformation.getId());
281278

282-
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntityFor(entity.getClass());
279+
ElasticsearchPersistentEntity<?> persistentEntity = converter.getMappingContext()
280+
.getPersistentEntity(entity.getClass());
281+
283282
if (persistentEntity != null) {
284283
PersistentPropertyAccessor<Object> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
284+
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
285+
286+
// Only deal with text because ES generated Ids are strings!
287+
if (indexedObjectInformation.getId() != null && idProperty != null
288+
&& idProperty.getType().isAssignableFrom(String.class)) {
289+
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
290+
}
285291

286292
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
287293
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
288294
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
295+
// noinspection ConstantConditions
289296
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
290297
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
291298
}
292299

293300
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
294301
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
302+
// noinspection ConstantConditions
295303
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
296304
}
297-
}
298305

306+
// noinspection unchecked
307+
T updatedEntity = (T) propertyAccessor.getBean();
308+
return updatedEntity;
309+
} else {
310+
AdaptibleEntity<T> adaptibleEntity = operations.forEntity(entity, converter.getConversionService(),
311+
routingResolver);
312+
adaptibleEntity.populateIdIfNecessary(indexedObjectInformation.getId());
313+
}
299314
return entity;
300315
}
301316

@@ -457,7 +472,7 @@ public <T> Mono<T> get(String id, Class<T> entityType, IndexCoordinates index) {
457472

458473
DocumentCallback<T> callback = new ReadDocumentCallback<>(converter, entityType, index);
459474

460-
return doGet(id, index).flatMap(it -> callback.toEntity(DocumentAdapters.from(it)));
475+
return doGet(id, index).flatMap(response -> callback.toEntity(DocumentAdapters.from(response)));
461476
}
462477

463478
private Mono<GetResult> doGet(String id, IndexCoordinates index) {
@@ -1097,6 +1112,10 @@ public Mono<T> toEntity(@Nullable Document document) {
10971112
}
10981113

10991114
T entity = reader.read(type, document);
1115+
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of(
1116+
document.hasId() ? document.getId() : null, document.getSeqNo(), document.getPrimaryTerm(),
1117+
document.getVersion());
1118+
entity = updateIndexedObject(entity, indexedObjectInformation);
11001119
return maybeCallAfterConvert(entity, document, index);
11011120
}
11021121
}

src/main/java/org/springframework/data/elasticsearch/core/join/JoinField.java

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.join;
1717

18+
import org.springframework.data.annotation.PersistenceConstructor;
1819
import org.springframework.lang.Nullable;
1920

2021
/**
@@ -35,6 +36,7 @@ public JoinField(String name) {
3536
this(name, null);
3637
}
3738

39+
@PersistenceConstructor
3840
public JoinField(String name, @Nullable ID parent) {
3941
this.name = name;
4042
this.parent = parent;

src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java

-14
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.springframework.data.mapping.PropertyHandler;
3636
import org.springframework.data.mapping.model.BasicPersistentEntity;
3737
import org.springframework.data.mapping.model.FieldNamingStrategy;
38-
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
3938
import org.springframework.data.spel.ExpressionDependencies;
4039
import org.springframework.data.util.Lazy;
4140
import org.springframework.data.util.TypeInformation;
@@ -238,19 +237,6 @@ private void warnAboutBothSeqNoPrimaryTermAndVersionProperties() {
238237
getType());
239238
}
240239

241-
/*
242-
* (non-Javadoc)
243-
* @see org.springframework.data.mapping.model.BasicPersistentEntity#setPersistentPropertyAccessorFactory(org.springframework.data.mapping.model.PersistentPropertyAccessorFactory)
244-
*/
245-
@SuppressWarnings("SpellCheckingInspection")
246-
@Override
247-
public void setPersistentPropertyAccessorFactory(PersistentPropertyAccessorFactory factory) {
248-
249-
// Do nothing to avoid the usage of ClassGeneratingPropertyAccessorFactory for now
250-
// DATACMNS-1322 switches to proper immutability behavior which Spring Data Elasticsearch
251-
// cannot yet implement
252-
}
253-
254240
@Nullable
255241
@Override
256242
public ElasticsearchPersistentProperty getPersistentPropertyWithFieldName(String fieldName) {

src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java

-5
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,6 @@ protected Association<ElasticsearchPersistentProperty> createAssociation() {
279279
throw new UnsupportedOperationException();
280280
}
281281

282-
@Override
283-
public boolean isImmutable() {
284-
return false;
285-
}
286-
287282
@Override
288283
public boolean isSeqNoPrimaryTermProperty() {
289284
return isSeqNoPrimaryTerm;

0 commit comments

Comments
 (0)