1 /*
2  * Copyright 2012-2020 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  *      https://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 package org.springframework.data.repository.config;
17
18 import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
19 import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
20 import org.springframework.beans.factory.config.BeanDefinition;
21 import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
22 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
23 import org.springframework.beans.factory.support.BeanNameGenerator;
24 import org.springframework.context.annotation.AnnotationBeanNameGenerator;
25 import org.springframework.util.Assert;
26 import org.springframework.util.ClassUtils;
27
28 /**
29  * Special {@link BeanNameGenerator} to create bean names for Spring Data repositories. Will delegate to an
30  * {@link AnnotationBeanNameGenerator} but let the delegate work with a customized {@link BeanDefinition} to make sure
31  * the repository interface is inspected and not the actual bean definition class.
32  *
33  * @author Oliver Gierke
34  * @author Jens Schauder
35  * @author Mark Paluch
36  */

37 class RepositoryBeanNameGenerator {
38
39     private final ClassLoader beanClassLoader;
40     private final BeanNameGenerator generator;
41     private final BeanDefinitionRegistry registry;
42
43     /**
44      * Creates a new {@link RepositoryBeanNameGenerator} for the given {@link ClassLoader}, {@link BeanNameGenerator}, and
45      * {@link BeanDefinitionRegistry}.
46      *
47      * @param beanClassLoader must not be {@literal null}.
48      * @param generator must not be {@literal null}.
49      * @param registry must not be {@literal null}.
50      */

51     public RepositoryBeanNameGenerator(ClassLoader beanClassLoader, BeanNameGenerator generator,
52             BeanDefinitionRegistry registry) {
53
54         Assert.notNull(beanClassLoader, "Bean ClassLoader must not be null!");
55         Assert.notNull(generator, "BeanNameGenerator must not be null!");
56         Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
57
58         this.beanClassLoader = beanClassLoader;
59         this.generator = generator;
60         this.registry = registry;
61     }
62
63     /**
64      * Generate a bean name for the given bean definition.
65      *
66      * @param definition the bean definition to generate a name for
67      * @return the generated bean name
68      * @since 2.0
69      */

70     public String generateBeanName(BeanDefinition definition) {
71
72         AnnotatedBeanDefinition beanDefinition = definition instanceof AnnotatedBeanDefinition //
73                 ? (AnnotatedBeanDefinition) definition //
74                 : new AnnotatedGenericBeanDefinition(getRepositoryInterfaceFrom(definition));
75
76         return generator.generateBeanName(beanDefinition, registry);
77     }
78
79     /**
80      * Returns the type configured for the {@code repositoryInterface} property of the given bean definition. Uses a
81      * potential {@link Class} being configured as is or tries to load a class with the given value's {@link #toString()}
82      * representation.
83      *
84      * @param beanDefinition
85      * @return
86      */

87     private Class<?> getRepositoryInterfaceFrom(BeanDefinition beanDefinition) {
88
89         ValueHolder argumentValue = beanDefinition.getConstructorArgumentValues().getArgumentValue(0, Class.class);
90
91         if (argumentValue == null) {
92             throw new IllegalStateException(
93                     String.format("Failed to obtain first constructor parameter value of BeanDefinition %s!", beanDefinition));
94         }
95
96         Object value = argumentValue.getValue();
97
98         if (value == null) {
99
100             throw new IllegalStateException(
101                     String.format("Value of first constructor parameter value of BeanDefinition %s is null!", beanDefinition));
102
103         } else if (value instanceof Class<?>) {
104
105             return (Class<?>) value;
106
107         } else {
108
109             try {
110                 return ClassUtils.forName(value.toString(), beanClassLoader);
111             } catch (Exception o_O) {
112                 throw new RuntimeException(o_O);
113             }
114         }
115     }
116 }
117