Skip to content

Commit 5b6cb19

Browse files
GH-2684 - Make Neo4j templates safer to use outside an application context.
While still not recommended to use outside an application context, this allows basic usage. Closes #2684.
1 parent 233421c commit 5b6cb19

File tree

2 files changed

+37
-22
lines changed

2 files changed

+37
-22
lines changed

src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java

+19-12
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public final class Neo4jTemplate implements
124124

125125
private EventSupport eventSupport;
126126

127-
private ProjectionFactory projectionFactory;
127+
private ProjectionFactory projectionFactoryf;
128128

129129
private Renderer renderer;
130130

@@ -146,6 +146,11 @@ public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingCo
146146
this.neo4jMappingContext = neo4jMappingContext;
147147
this.cypherGenerator = CypherGenerator.INSTANCE;
148148
this.eventSupport = EventSupport.useExistingCallbacks(neo4jMappingContext, entityCallbacks);
149+
this.renderer = Renderer.getDefaultRenderer();
150+
}
151+
152+
ProjectionFactory getProjectionFactory() {
153+
return Objects.requireNonNull(this.projectionFactoryf, "Projection support for the Neo4j template is only available when the template is a proper and fully initialized Spring bean.");
149154
}
150155

151156
@Override
@@ -256,7 +261,7 @@ <T, R> List<R> doFind(@Nullable String cypherQuery, @Nullable Map<String, Object
256261

257262
if (resultType.isInterface()) {
258263
return intermediaResults.stream()
259-
.map(instance -> projectionFactory.createProjection(resultType, instance))
264+
.map(instance -> getProjectionFactory().createProjection(resultType, instance))
260265
.collect(Collectors.toList());
261266
}
262267

@@ -342,23 +347,24 @@ public <T, R> R saveAs(T instance, Class<R> resultType) {
342347
return resultType.cast(save(instance));
343348
}
344349

345-
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
350+
ProjectionFactory localProjectionFactory = getProjectionFactory();
351+
ProjectionInformation projectionInformation = localProjectionFactory.getProjectionInformation(resultType);
346352
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(instance.getClass(), resultType,
347-
projectionFactory, neo4jMappingContext);
353+
localProjectionFactory, neo4jMappingContext);
348354

349355
T savedInstance = saveImpl(instance, pps, null);
350356
if (!resultType.isInterface()) {
351357
@SuppressWarnings("unchecked") R result = (R) new DtoInstantiatingConverter(resultType, neo4jMappingContext).convertDirectly(savedInstance);
352358
return result;
353359
}
354360
if (projectionInformation.isClosed()) {
355-
return projectionFactory.createProjection(resultType, savedInstance);
361+
return localProjectionFactory.createProjection(resultType, savedInstance);
356362
}
357363

358364
Neo4jPersistentEntity<?> entityMetaData = neo4jMappingContext.getRequiredPersistentEntity(savedInstance.getClass());
359365
Neo4jPersistentProperty idProperty = entityMetaData.getIdProperty();
360366
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(savedInstance);
361-
return projectionFactory.createProjection(resultType,
367+
return localProjectionFactory.createProjection(resultType,
362368
this.findById(propertyAccessor.getProperty(idProperty), savedInstance.getClass()).get());
363369
}
364370

@@ -542,15 +548,16 @@ public <T, R> List<R> saveAllAs(Iterable<T> instances, Class<R> resultType) {
542548
return saveElements;
543549
}
544550

545-
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
551+
ProjectionFactory localProjectionFactory = getProjectionFactory();
552+
ProjectionInformation projectionInformation = localProjectionFactory.getProjectionInformation(resultType);
546553

547554
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(commonElementType, resultType,
548-
projectionFactory, neo4jMappingContext);
555+
localProjectionFactory, neo4jMappingContext);
549556

550557
List<T> savedInstances = saveAllImpl(instances, pps, null);
551558

552559
if (projectionInformation.isClosed()) {
553-
return savedInstances.stream().map(instance -> projectionFactory.createProjection(resultType, instance))
560+
return savedInstances.stream().map(instance -> localProjectionFactory.createProjection(resultType, instance))
554561
.collect(Collectors.toList());
555562
}
556563

@@ -563,7 +570,7 @@ public <T, R> List<R> saveAllAs(Iterable<T> instances, Class<R> resultType) {
563570
}).collect(Collectors.toList());
564571

565572
return findAllById(ids, commonElementType)
566-
.stream().map(instance -> projectionFactory.createProjection(resultType, instance))
573+
.stream().map(instance -> localProjectionFactory.createProjection(resultType, instance))
567574
.collect(Collectors.toList());
568575
}
569576

@@ -1000,7 +1007,7 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
10001007
SpelAwareProxyProjectionFactory spelAwareProxyProjectionFactory = new SpelAwareProxyProjectionFactory();
10011008
spelAwareProxyProjectionFactory.setBeanClassLoader(beanClassLoader);
10021009
spelAwareProxyProjectionFactory.setBeanFactory(beanFactory);
1003-
this.projectionFactory = spelAwareProxyProjectionFactory;
1010+
this.projectionFactoryf = spelAwareProxyProjectionFactory;
10041011

10051012
Configuration cypherDslConfiguration = beanFactory
10061013
.getBeanProvider(Configuration.class)
@@ -1054,7 +1061,7 @@ <T, R> List<R> doSave(Iterable<R> instances, Class<T> domainType) {
10541061
Class<?> resultType = TemplateSupport.findCommonElementType(instances);
10551062

10561063
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(domainType, resultType,
1057-
projectionFactory, neo4jMappingContext);
1064+
getProjectionFactory(), neo4jMappingContext);
10581065

10591066
NestedRelationshipProcessingStateMachine stateMachine = new NestedRelationshipProcessingStateMachine(neo4jMappingContext);
10601067
List<R> results = new ArrayList<>();

src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java

+18-10
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.LinkedHashSet;
3535
import java.util.List;
3636
import java.util.Map;
37+
import java.util.Objects;
3738
import java.util.Set;
3839
import java.util.concurrent.ConcurrentHashMap;
3940
import java.util.concurrent.atomic.AtomicReference;
@@ -140,6 +141,11 @@ public ReactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContex
140141
this.neo4jMappingContext = neo4jMappingContext;
141142
this.cypherGenerator = CypherGenerator.INSTANCE;
142143
this.eventSupport = ReactiveEventSupport.useExistingCallbacks(neo4jMappingContext, ReactiveEntityCallbacks.create());
144+
this.renderer = Renderer.getDefaultRenderer();
145+
}
146+
147+
ProjectionFactory getProjectionFactory() {
148+
return Objects.requireNonNull(this.projectionFactory, "Projection support for the Neo4j template is only available when the template is a proper and fully initialized Spring bean.");
143149
}
144150

145151
@Override
@@ -250,7 +256,7 @@ <T, R> Flux<R> doFind(@Nullable String cypherQuery, @Nullable Map<String, Object
250256
}
251257

252258
if (resultType.isInterface()) {
253-
return intermediaResults.map(instance -> projectionFactory.createProjection(resultType, instance));
259+
return intermediaResults.map(instance -> getProjectionFactory().createProjection(resultType, instance));
254260
}
255261

256262
DtoInstantiatingConverter converter = new DtoInstantiatingConverter(resultType, neo4jMappingContext);
@@ -341,9 +347,10 @@ public <T, R> Mono<R> saveAs(T instance, Class<R> resultType) {
341347
return save(instance).map(resultType::cast);
342348
}
343349

344-
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
350+
ProjectionFactory localProjectionFactory = getProjectionFactory();
351+
ProjectionInformation projectionInformation = localProjectionFactory.getProjectionInformation(resultType);
345352
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(instance.getClass(), resultType,
346-
projectionFactory, neo4jMappingContext);
353+
localProjectionFactory, neo4jMappingContext);
347354

348355
Mono<T> savingPublisher = saveImpl(instance, pps, null);
349356

@@ -355,7 +362,7 @@ public <T, R> Mono<R> saveAs(T instance, Class<R> resultType) {
355362
});
356363
}
357364
if (projectionInformation.isClosed()) {
358-
return savingPublisher.map(savedInstance -> projectionFactory.createProjection(resultType, savedInstance));
365+
return savingPublisher.map(savedInstance -> localProjectionFactory.createProjection(resultType, savedInstance));
359366
}
360367

361368
return savingPublisher.flatMap(savedInstance -> {
@@ -364,7 +371,7 @@ public <T, R> Mono<R> saveAs(T instance, Class<R> resultType) {
364371
Neo4jPersistentProperty idProperty = entityMetaData.getIdProperty();
365372
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(savedInstance);
366373
return this.findById(propertyAccessor.getProperty(idProperty), savedInstance.getClass())
367-
.map(loadedValue -> projectionFactory.createProjection(resultType, loadedValue));
374+
.map(loadedValue -> localProjectionFactory.createProjection(resultType, loadedValue));
368375
});
369376
}
370377

@@ -377,7 +384,7 @@ <T, R> Flux<R> doSave(Iterable<R> instances, Class<T> domainType) {
377384
Class<?> resultType = TemplateSupport.findCommonElementType(instances);
378385

379386
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(domainType, resultType,
380-
projectionFactory, neo4jMappingContext);
387+
getProjectionFactory(), neo4jMappingContext);
381388

382389
NestedRelationshipProcessingStateMachine stateMachine = new NestedRelationshipProcessingStateMachine(neo4jMappingContext);
383390
EntityFromDtoInstantiatingConverter<T> converter = new EntityFromDtoInstantiatingConverter<>(domainType, neo4jMappingContext);
@@ -499,13 +506,14 @@ public <T, R> Flux<R> saveAllAs(Iterable<T> instances, Class<R> resultType) {
499506
return saveAll(instances).map(resultType::cast);
500507
}
501508

502-
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
509+
ProjectionFactory localProjectionFactory = getProjectionFactory();
510+
ProjectionInformation projectionInformation = localProjectionFactory.getProjectionInformation(resultType);
503511
Collection<PropertyFilter.ProjectedPath> pps = PropertyFilterSupport.addPropertiesFrom(commonElementType, resultType,
504-
projectionFactory, neo4jMappingContext);
512+
localProjectionFactory, neo4jMappingContext);
505513

506514
Flux<T> savedInstances = saveAllImpl(instances, pps, null);
507515
if (projectionInformation.isClosed()) {
508-
return savedInstances.map(instance -> projectionFactory.createProjection(resultType, instance));
516+
return savedInstances.map(instance -> localProjectionFactory.createProjection(resultType, instance));
509517
}
510518

511519
Neo4jPersistentEntity<?> entityMetaData = neo4jMappingContext.getRequiredPersistentEntity(commonElementType);
@@ -514,7 +522,7 @@ public <T, R> Flux<R> saveAllAs(Iterable<T> instances, Class<R> resultType) {
514522
return savedInstances.flatMap(savedInstance -> {
515523
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(savedInstance);
516524
return findById(propertyAccessor.getProperty(idProperty), commonElementType);
517-
}).map(instance -> projectionFactory.createProjection(resultType, instance));
525+
}).map(instance -> localProjectionFactory.createProjection(resultType, instance));
518526
}
519527

520528
private <T> Flux<T> saveAllImpl(Iterable<T> instances, @Nullable Collection<PropertyFilter.ProjectedPath> includedProperties, @Nullable BiPredicate<PropertyPath, Neo4jPersistentProperty> includeProperty) {

0 commit comments

Comments
 (0)