Skip to content

Commit 6b9ee32

Browse files
committed
Merge pull request #14568 from michael-simons
* pr/14568: Polish Neo4J BookmarkManager auto-configuration Auto-configure Neo4J BookmarkManager when possible
2 parents 94b366b + 2add65f commit 6b9ee32

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.neo4j;
18+
19+
import com.github.benmanes.caffeine.cache.Caffeine;
20+
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
26+
import org.springframework.cache.caffeine.CaffeineCacheManager;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.context.annotation.Scope;
30+
import org.springframework.context.annotation.ScopedProxyMode;
31+
import org.springframework.data.neo4j.bookmark.BeanFactoryBookmarkOperationAdvisor;
32+
import org.springframework.data.neo4j.bookmark.BookmarkInterceptor;
33+
import org.springframework.data.neo4j.bookmark.BookmarkManager;
34+
import org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager;
35+
import org.springframework.web.context.WebApplicationContext;
36+
37+
/**
38+
* Provides a {@link BookmarkManager} for Neo4j's bookmark support based on Caffeine if
39+
* available. Depending on the applications kind (web or not) the bookmark manager will be
40+
* bound to the application or the request, as recommend by Spring Data Neo4j.
41+
*
42+
* @author Michael Simons
43+
* @since 2.1.0
44+
*/
45+
@Configuration
46+
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
47+
@ConditionalOnMissingBean(BookmarkManager.class)
48+
@ConditionalOnBean({ BeanFactoryBookmarkOperationAdvisor.class,
49+
BookmarkInterceptor.class })
50+
class Neo4jBookmarkManagementConfiguration {
51+
52+
private static final String BOOKMARK_MANAGER_BEAN_NAME = "bookmarkManager";
53+
54+
@Bean(BOOKMARK_MANAGER_BEAN_NAME)
55+
@ConditionalOnWebApplication
56+
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
57+
public BookmarkManager requestScopedBookmarkManager() {
58+
return new CaffeineBookmarkManager();
59+
}
60+
61+
@Bean(BOOKMARK_MANAGER_BEAN_NAME)
62+
@ConditionalOnNotWebApplication
63+
public BookmarkManager singletonScopedBookmarkManager() {
64+
return new CaffeineBookmarkManager();
65+
}
66+
67+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.context.ApplicationContext;
3838
import org.springframework.context.annotation.Bean;
3939
import org.springframework.context.annotation.Configuration;
40+
import org.springframework.context.annotation.Import;
4041
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
4142
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
4243
import org.springframework.transaction.PlatformTransactionManager;
@@ -59,6 +60,7 @@
5960
PlatformTransactionManager.class })
6061
@ConditionalOnMissingBean(SessionFactory.class)
6162
@EnableConfigurationProperties(Neo4jProperties.class)
63+
@Import(Neo4jBookmarkManagementConfiguration.class)
6264
public class Neo4jDataAutoConfiguration {
6365

6466
@Bean

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,26 +16,33 @@
1616

1717
package org.springframework.boot.autoconfigure.data.neo4j;
1818

19+
import com.github.benmanes.caffeine.cache.Caffeine;
1920
import org.junit.Test;
2021
import org.neo4j.ogm.session.Session;
2122
import org.neo4j.ogm.session.SessionFactory;
2223
import org.neo4j.ogm.session.event.Event;
2324
import org.neo4j.ogm.session.event.EventListener;
2425
import org.neo4j.ogm.session.event.PersistenceEvent;
2526

27+
import org.springframework.beans.factory.config.BeanDefinition;
2628
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
2729
import org.springframework.boot.autoconfigure.AutoConfigurations;
2830
import org.springframework.boot.autoconfigure.data.neo4j.city.City;
2931
import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
3032
import org.springframework.boot.autoconfigure.domain.EntityScan;
3133
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
34+
import org.springframework.boot.test.context.FilteredClassLoader;
35+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3236
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
3337
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3438
import org.springframework.context.annotation.Bean;
3539
import org.springframework.context.annotation.Configuration;
40+
import org.springframework.data.neo4j.annotation.EnableBookmarkManagement;
41+
import org.springframework.data.neo4j.bookmark.BookmarkManager;
3642
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
3743
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
3844
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
45+
import org.springframework.web.context.WebApplicationContext;
3946

4047
import static org.assertj.core.api.Assertions.assertThat;
4148
import static org.mockito.ArgumentMatchers.any;
@@ -51,6 +58,7 @@
5158
* @author Vince Bickers
5259
* @author Andy Wilkinson
5360
* @author Kazuki Shimizu
61+
* @author Michael Simons
5462
*/
5563
public class Neo4jDataAutoConfigurationTests {
5664

@@ -69,6 +77,7 @@ public void defaultConfiguration() {
6977
assertThat(context).hasSingleBean(SessionFactory.class);
7078
assertThat(context).hasSingleBean(Neo4jTransactionManager.class);
7179
assertThat(context).hasSingleBean(OpenSessionInViewInterceptor.class);
80+
assertThat(context).doesNotHaveBean(BookmarkManager.class);
7281
});
7382
}
7483

@@ -146,6 +155,40 @@ public void eventListenersAreAutoRegistered() {
146155
});
147156
}
148157

158+
@Test
159+
public void providesARequestScopedBookmarkManangerIfNecessaryAndPossible() {
160+
this.contextRunner
161+
.withUserConfiguration(BookmarkManagementEnabledConfiguration.class)
162+
.run((context) -> {
163+
BeanDefinition bookmarkManagerBean = context.getBeanFactory()
164+
.getBeanDefinition("scopedTarget.bookmarkManager");
165+
assertThat(bookmarkManagerBean.getScope())
166+
.isEqualTo(WebApplicationContext.SCOPE_REQUEST);
167+
});
168+
}
169+
170+
@Test
171+
public void providesASingletonScopedBookmarkManangerIfNecessaryAndPossible() {
172+
new ApplicationContextRunner()
173+
.withUserConfiguration(TestConfiguration.class,
174+
BookmarkManagementEnabledConfiguration.class)
175+
.withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
176+
TransactionAutoConfiguration.class))
177+
.run((context) -> {
178+
assertThat(context).hasSingleBean(BookmarkManager.class);
179+
assertThat(context.getBeanDefinitionNames())
180+
.doesNotContain("scopedTarget.bookmarkManager");
181+
});
182+
}
183+
184+
@Test
185+
public void doesNotProvideABookmarkManagerIfNotPossible() {
186+
this.contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class))
187+
.withUserConfiguration(BookmarkManagementEnabledConfiguration.class)
188+
.run((context) -> assertThat(context)
189+
.doesNotHaveBean(BookmarkManager.class));
190+
}
191+
149192
private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext,
150193
Class<?>... types) {
151194
for (Class<?> type : types) {
@@ -180,6 +223,12 @@ public org.neo4j.ogm.config.Configuration myConfiguration() {
180223

181224
}
182225

226+
@Configuration
227+
@EnableBookmarkManagement
228+
static class BookmarkManagementEnabledConfiguration {
229+
230+
}
231+
183232
@Configuration
184233
static class EventListenerConfiguration {
185234

0 commit comments

Comments
 (0)