1
1
/*
2
- * Copyright 2011-2013 the original author or authors.
2
+ * Copyright 2011-2014 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
28
28
import javax .enterprise .context .spi .CreationalContext ;
29
29
import javax .enterprise .inject .Alternative ;
30
30
import javax .enterprise .inject .Stereotype ;
31
+ import javax .enterprise .inject .UnsatisfiedResolutionException ;
31
32
import javax .enterprise .inject .spi .Bean ;
32
33
import javax .enterprise .inject .spi .BeanManager ;
33
34
import javax .enterprise .inject .spi .InjectionPoint ;
34
35
import javax .enterprise .inject .spi .PassivationCapable ;
35
36
36
37
import org .slf4j .Logger ;
37
38
import org .slf4j .LoggerFactory ;
39
+ import org .springframework .beans .factory .support .AbstractBeanDefinition ;
40
+ import org .springframework .data .repository .config .CustomRepositoryImplementationDetector ;
41
+ import org .springframework .data .repository .config .DefaultRepositoryConfiguration ;
38
42
import org .springframework .util .Assert ;
43
+ import org .springframework .util .ClassUtils ;
39
44
import org .springframework .util .StringUtils ;
40
45
41
46
/**
48
53
public abstract class CdiRepositoryBean <T > implements Bean <T >, PassivationCapable {
49
54
50
55
private static final Logger LOGGER = LoggerFactory .getLogger (CdiRepositoryBean .class );
56
+ private static final CdiRepositoryConfiguration DEFAULT_CONFIGURATION = DefaultCdiRepositoryConfiguration .INSTANCE ;
51
57
52
58
private final Set <Annotation > qualifiers ;
53
59
private final Class <T > repositoryType ;
54
- private final Bean <?> customImplementationBean ;
60
+ private final CustomRepositoryImplementationDetector detector ;
55
61
private final BeanManager beanManager ;
56
62
private final String passivationId ;
57
63
@@ -74,11 +80,11 @@ public CdiRepositoryBean(Set<Annotation> qualifiers, Class<T> repositoryType, Be
74
80
* @param qualifiers must not be {@literal null}.
75
81
* @param repositoryType has to be an interface must not be {@literal null}.
76
82
* @param beanManager the CDI {@link BeanManager}, must not be {@literal null}.
77
- * @param customImplementationBean the bean for the custom implementation of the
78
- * {@link org.springframework.data.repository.Repository}, can be {@literal null}.
83
+ * @param detector detector for the custom repository implementations {@link CustomRepositoryImplementationDetector},
84
+ * can be {@literal null}.
79
85
*/
80
86
public CdiRepositoryBean (Set <Annotation > qualifiers , Class <T > repositoryType , BeanManager beanManager ,
81
- Bean <?> customImplementationBean ) {
87
+ CustomRepositoryImplementationDetector detector ) {
82
88
83
89
Assert .notNull (qualifiers );
84
90
Assert .notNull (beanManager );
@@ -88,7 +94,7 @@ public CdiRepositoryBean(Set<Annotation> qualifiers, Class<T> repositoryType, Be
88
94
this .qualifiers = qualifiers ;
89
95
this .repositoryType = repositoryType ;
90
96
this .beanManager = beanManager ;
91
- this .customImplementationBean = customImplementationBean ;
97
+ this .detector = detector ;
92
98
this .passivationId = createPassivationId (qualifiers , repositoryType );
93
99
}
94
100
@@ -179,7 +185,93 @@ public void destroy(T instance, CreationalContext<T> creationalContext) {
179
185
creationalContext .release ();
180
186
}
181
187
182
- /*
188
+ /**
189
+ * Looks up an instance of a {@link CdiRepositoryConfiguration}. In case the instance cannot be found within the CDI
190
+ * scope, a default configuration is used.
191
+ *
192
+ * @return an available CdiRepositoryConfiguration instance or a default configuration.
193
+ */
194
+ @ SuppressWarnings ("unchecked" )
195
+ protected CdiRepositoryConfiguration lookupConfiguration (BeanManager beanManager , Set <Annotation > qualifiers ) {
196
+
197
+ Set <Bean <?>> beans = beanManager .getBeans (CdiRepositoryConfiguration .class , getQualifiersArray (qualifiers ));
198
+
199
+ if (beans .isEmpty ()) {
200
+ return DEFAULT_CONFIGURATION ;
201
+ }
202
+
203
+ Bean <CdiRepositoryConfiguration > bean = (Bean <CdiRepositoryConfiguration >) beans .iterator ().next ();
204
+ return getDependencyInstance (bean , (Class <CdiRepositoryConfiguration >) bean .getBeanClass ());
205
+ }
206
+
207
+ /**
208
+ * Try to lookup a custom implementation for a {@link org.springframework.data.repository.Repository}. Can only be
209
+ * used when a {@code CustomRepositoryImplementationDetector} is provided.
210
+ *
211
+ * @param repositoryType
212
+ * @param beanManager
213
+ * @param qualifiers
214
+ * @return the custom implementation instance or null
215
+ */
216
+ private Bean <?> getCustomImplementationBean (Class <?> repositoryType , BeanManager beanManager ,
217
+ Set <Annotation > qualifiers ) {
218
+
219
+ if (detector == null ) {
220
+ return null ;
221
+ }
222
+
223
+ CdiRepositoryConfiguration cdiRepositoryConfiguration = lookupConfiguration (beanManager , qualifiers );
224
+ Class <?> customImplementationClass = getCustomImplementationClass (repositoryType , cdiRepositoryConfiguration );
225
+
226
+ if (customImplementationClass == null ) {
227
+ return null ;
228
+ }
229
+
230
+ Set <Bean <?>> beans = beanManager .getBeans (customImplementationClass , getQualifiersArray (qualifiers ));
231
+ return beans .isEmpty () ? null : beans .iterator ().next ();
232
+ }
233
+
234
+ /**
235
+ * Retrieves a custom repository interfaces from a repository type. This works for the whole class hierarchy and can
236
+ * find also a custom repo which is inherieted over many levels.
237
+ *
238
+ * @param repositoryType The class representing the repository.
239
+ * @param cdiRepositoryConfiguration The configuration for CDI usage.
240
+ * @return the interface class or {@literal null}.
241
+ */
242
+ private Class <?> getCustomImplementationClass (Class <?> repositoryType ,
243
+ CdiRepositoryConfiguration cdiRepositoryConfiguration ) {
244
+
245
+ String className = getCustomImplementationClassName (repositoryType , cdiRepositoryConfiguration );
246
+ AbstractBeanDefinition beanDefinition = detector .detectCustomImplementation (className ,
247
+ Collections .singleton (repositoryType .getPackage ().getName ()));
248
+
249
+ if (beanDefinition == null ) {
250
+ return null ;
251
+ }
252
+
253
+ try {
254
+ return Class .forName (beanDefinition .getBeanClassName ());
255
+ } catch (ClassNotFoundException e ) {
256
+ throw new UnsatisfiedResolutionException (String .format ("Unable to resolve class for '%s'" ,
257
+ beanDefinition .getBeanClassName ()), e );
258
+ }
259
+ }
260
+
261
+ private String getCustomImplementationClassName (Class <?> repositoryType ,
262
+ CdiRepositoryConfiguration cdiRepositoryConfiguration ) {
263
+
264
+ String configuredPostfix = cdiRepositoryConfiguration .getRepositoryImplementationPostfix ();
265
+ Assert .hasText (configuredPostfix , "Configured repository postfix must not be null or empty!" );
266
+
267
+ return ClassUtils .getShortName (repositoryType ) + configuredPostfix ;
268
+ }
269
+
270
+ private Annotation [] getQualifiersArray (Set <Annotation > qualifiers ) {
271
+ return qualifiers .toArray (new Annotation [qualifiers .size ()]);
272
+ }
273
+
274
+ /*
183
275
* (non-Javadoc)
184
276
* @see javax.enterprise.inject.spi.Bean#getQualifiers()
185
277
*/
@@ -253,7 +345,7 @@ public Class<? extends Annotation> getScope() {
253
345
return ApplicationScoped .class ;
254
346
}
255
347
256
- /*
348
+ /*
257
349
* (non-Javadoc)
258
350
* @see javax.enterprise.inject.spi.PassivationCapable#getId()
259
351
*/
@@ -272,6 +364,7 @@ public String getId() {
272
364
@ Deprecated
273
365
protected T create (CreationalContext <T > creationalContext , Class <T > repositoryType ) {
274
366
367
+ Bean <?> customImplementationBean = getCustomImplementationBean (repositoryType , beanManager , qualifiers );
275
368
Object customImplementation = customImplementationBean == null ? null : beanManager .getReference (
276
369
customImplementationBean , customImplementationBean .getBeanClass (),
277
370
beanManager .createCreationalContext (customImplementationBean ));
@@ -292,13 +385,27 @@ protected T create(CreationalContext<T> creationalContext, Class<T> repositoryTy
292
385
+ "in order to use custom repository implementations" );
293
386
}
294
387
295
- /*
388
+ /*
296
389
* (non-Javadoc)
297
390
* @see java.lang.Object#toString()
298
391
*/
299
392
@ Override
300
393
public String toString () {
301
394
return String
302
- .format ("JpaRepositoryBean: type='%s', qualifiers=%s" , repositoryType .getName (), qualifiers .toString ());
395
+ .format ("CdiRepositoryBean: type='%s', qualifiers=%s" , repositoryType .getName (), qualifiers .toString ());
396
+ }
397
+
398
+ static enum DefaultCdiRepositoryConfiguration implements CdiRepositoryConfiguration {
399
+
400
+ INSTANCE ;
401
+
402
+ /*
403
+ * (non-Javadoc)
404
+ * @see org.springframework.data.repository.cdi.CdiRepositoryConfiguration#getRepositoryImplementationPostfix()
405
+ */
406
+ @ Override
407
+ public String getRepositoryImplementationPostfix () {
408
+ return DefaultRepositoryConfiguration .DEFAULT_REPOSITORY_IMPLEMENTATION_POSTFIX ;
409
+ }
303
410
}
304
411
}
0 commit comments