1
16 package org.springframework.data.repository.core.support;
17
18 import java.util.List;
19 import java.util.Optional;
20
21 import javax.annotation.Nonnull;
22
23 import org.springframework.beans.BeansException;
24 import org.springframework.beans.factory.BeanClassLoaderAware;
25 import org.springframework.beans.factory.BeanFactory;
26 import org.springframework.beans.factory.BeanFactoryAware;
27 import org.springframework.beans.factory.FactoryBean;
28 import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.beans.factory.ListableBeanFactory;
30 import org.springframework.context.ApplicationEventPublisher;
31 import org.springframework.context.ApplicationEventPublisherAware;
32 import org.springframework.data.mapping.PersistentEntity;
33 import org.springframework.data.mapping.context.MappingContext;
34 import org.springframework.data.repository.Repository;
35 import org.springframework.data.repository.core.EntityInformation;
36 import org.springframework.data.repository.core.NamedQueries;
37 import org.springframework.data.repository.core.RepositoryInformation;
38 import org.springframework.data.repository.core.RepositoryMetadata;
39 import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
40 import org.springframework.data.repository.query.ExtensionAwareQueryMethodEvaluationContextProvider;
41 import org.springframework.data.repository.query.QueryLookupStrategy;
42 import org.springframework.data.repository.query.QueryLookupStrategy.Key;
43 import org.springframework.data.repository.query.QueryMethod;
44 import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
45 import org.springframework.data.util.Lazy;
46 import org.springframework.util.Assert;
47
48
57 public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID>
58 implements InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T>, BeanClassLoaderAware,
59 BeanFactoryAware, ApplicationEventPublisherAware {
60
61 private final Class<? extends T> repositoryInterface;
62
63 private RepositoryFactorySupport factory;
64 private Key queryLookupStrategyKey;
65 private Optional<Class<?>> repositoryBaseClass = Optional.empty();
66 private Optional<Object> customImplementation = Optional.empty();
67 private Optional<RepositoryFragments> repositoryFragments = Optional.empty();
68 private NamedQueries namedQueries;
69 private Optional<MappingContext<?, ?>> mappingContext = Optional.empty();
70 private ClassLoader classLoader;
71 private BeanFactory beanFactory;
72 private boolean lazyInit = false;
73 private Optional<QueryMethodEvaluationContextProvider> evaluationContextProvider = Optional.empty();
74 private ApplicationEventPublisher publisher;
75
76 private Lazy<T> repository;
77
78 private RepositoryMetadata repositoryMetadata;
79
80
85 protected RepositoryFactoryBeanSupport(Class<? extends T> repositoryInterface) {
86
87 Assert.notNull(repositoryInterface, "Repository interface must not be null!");
88 this.repositoryInterface = repositoryInterface;
89 }
90
91
97 public void setRepositoryBaseClass(Class<?> repositoryBaseClass) {
98 this.repositoryBaseClass = Optional.ofNullable(repositoryBaseClass);
99 }
100
101
106 public void setQueryLookupStrategyKey(Key queryLookupStrategyKey) {
107 this.queryLookupStrategyKey = queryLookupStrategyKey;
108 }
109
110
115 public void setCustomImplementation(Object customImplementation) {
116 this.customImplementation = Optional.of(customImplementation);
117 }
118
119
124 public void setRepositoryFragments(RepositoryFragments repositoryFragments) {
125 this.repositoryFragments = Optional.of(repositoryFragments);
126 }
127
128
133 public void setNamedQueries(NamedQueries namedQueries) {
134 this.namedQueries = namedQueries;
135 }
136
137
143 protected void setMappingContext(MappingContext<?, ?> mappingContext) {
144 this.mappingContext = Optional.of(mappingContext);
145 }
146
147
153 public void setEvaluationContextProvider(QueryMethodEvaluationContextProvider evaluationContextProvider) {
154 this.evaluationContextProvider = Optional.of(evaluationContextProvider);
155 }
156
157
162 public void setLazyInit(boolean lazy) {
163 this.lazyInit = lazy;
164 }
165
166
170 @Override
171 public void setBeanClassLoader(ClassLoader classLoader) {
172 this.classLoader = classLoader;
173 }
174
175
179 @Override
180 public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
181
182 this.beanFactory = beanFactory;
183
184 if (!this.evaluationContextProvider.isPresent() && ListableBeanFactory.class.isInstance(beanFactory)) {
185 this.evaluationContextProvider = Optional
186 .of(new ExtensionAwareQueryMethodEvaluationContextProvider((ListableBeanFactory) beanFactory));
187 }
188 }
189
190
194 @Override
195 public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
196 this.publisher = publisher;
197 }
198
199
203 @SuppressWarnings("unchecked")
204 public EntityInformation<S, ID> getEntityInformation() {
205 return (EntityInformation<S, ID>) factory.getEntityInformation(repositoryMetadata.getDomainType());
206 }
207
208
212 public RepositoryInformation getRepositoryInformation() {
213
214 RepositoryFragments fragments = customImplementation.map(RepositoryFragments::just)
215 .orElse(RepositoryFragments.empty());
216
217 return factory.getRepositoryInformation(repositoryMetadata, fragments);
218 }
219
220
224 public PersistentEntity<?, ?> getPersistentEntity() {
225
226 return mappingContext.orElseThrow(() -> new IllegalStateException("No MappingContext available!"))
227 .getRequiredPersistentEntity(repositoryMetadata.getDomainType());
228 }
229
230
234 public List<QueryMethod> getQueryMethods() {
235 return factory.getQueryMethods();
236 }
237
238
242 @Nonnull
243 public T getObject() {
244 return this.repository.get();
245 }
246
247
251 @Nonnull
252 public Class<? extends T> getObjectType() {
253 return repositoryInterface;
254 }
255
256
260 public boolean isSingleton() {
261 return true;
262 }
263
264
268 public void afterPropertiesSet() {
269
270 this.factory = createRepositoryFactory();
271 this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
272 this.factory.setNamedQueries(namedQueries);
273 this.factory.setEvaluationContextProvider(
274 evaluationContextProvider.orElseGet(() -> QueryMethodEvaluationContextProvider.DEFAULT));
275 this.factory.setBeanClassLoader(classLoader);
276 this.factory.setBeanFactory(beanFactory);
277
278 if (publisher != null) {
279 this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher));
280 }
281
282 repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass);
283
284 RepositoryFragments customImplementationFragment = customImplementation
285 .map(RepositoryFragments::just)
286 .orElseGet(RepositoryFragments::empty);
287
288 RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments
289 .orElseGet(RepositoryFragments::empty)
290 .append(customImplementationFragment);
291
292 this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
293
294
295 this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));
296
297 this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
298
299 if (!lazyInit) {
300 this.repository.get();
301 }
302 }
303
304
309 protected abstract RepositoryFactorySupport createRepositoryFactory();
310 }
311