View Javadoc
1   package com.github.mygreen.supercsv.builder;
2   
3   import java.util.Objects;
4   
5   import org.springframework.beans.BeansException;
6   import org.springframework.beans.factory.InitializingBean;
7   import org.springframework.beans.factory.annotation.Autowired;
8   import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
9   import org.springframework.context.ApplicationContext;
10  import org.springframework.context.ApplicationContextAware;
11  import org.springframework.stereotype.Component;
12  import org.springframework.stereotype.Controller;
13  import org.springframework.stereotype.Repository;
14  import org.springframework.stereotype.Service;
15  
16  /**
17   * Springのコンテナからインタンスを作成するためのクラスです。
18   * <p>利用するには、このクラスをSpringのコンテナに登録しておく必要があります。</p>
19   * <p>Springのコンテナに登録されていないクラスは、通常のクラスとしてインスタンスを作成します。
20   *  <br>ただし、コンテナ管理外のクラスに対しても、アノテーション{@link Autowired}によるインジェクションが可能です。
21   * </p>
22   *
23   * @version 2.2
24   * @since 2.0
25   * @author T.TSUCHIE
26   *
27   */
28  public class SpringBeanFactory implements BeanFactory<Class<?>, Object>, ApplicationContextAware, InitializingBean {
29  
30      private AutowireCapableBeanFactory beanFactory;
31  
32      private ApplicationContext applicationContext;
33  
34      private BeanFactory<Class<?>, Object> defaultBeanFactory = new DefaultBeanFactory();
35  
36      @Override
37      public Object create(final Class<?> clazz) {
38          Objects.requireNonNull(clazz, "clazz should not be null.");
39  
40          final String beanName = getBeanName(clazz);
41          if(beanFactory.containsBean(beanName)) {
42              // Spring管理のクラスの場合
43              return beanFactory.getBean(beanName, clazz);
44  
45          } else {
46              // 通常のBeanクラスの場合
47              Object obj = defaultBeanFactory.create(clazz);
48  
49              // Springコンテナ管理外でもインジェクションする。
50              beanFactory.autowireBean(obj);
51  
52              return obj;
53          }
54      }
55  
56      private String getBeanName(final Class<?> clazz) {
57  
58          final Component componentAnno = clazz.getAnnotation(Component.class);
59          if(componentAnno != null && !componentAnno.value().isEmpty()) {
60              return componentAnno.value();
61          }
62  
63          final Service serviceAnno = clazz.getAnnotation(Service.class);
64          if(serviceAnno != null && !serviceAnno.value().isEmpty()) {
65              return serviceAnno.value();
66          }
67  
68          final Repository repositoryAnno = clazz.getAnnotation(Repository.class);
69          if(repositoryAnno != null && !repositoryAnno.value().isEmpty()) {
70              return repositoryAnno.value();
71          }
72  
73          final Controller controllerAnno = clazz.getAnnotation(Controller.class);
74          if(controllerAnno != null && !controllerAnno.value().isEmpty()) {
75              return controllerAnno.value();
76          }
77  
78          // ステレオタイプのアノテーションでBean名の指定がない場合は、クラス名の先頭を小文字にした名称とする。
79          String simpleName = uncapitalize(clazz.getSimpleName());
80  
81          String[] names = applicationContext.getBeanNamesForType(clazz);
82          if(names.length == 0) {
83              return simpleName;
84          }
85  
86          // 複数存在する場合、候補の中から一番シンプルな形式の名前で一致するものを選択する
87          for(String name : names) {
88              if(name.equals(simpleName)) {
89                  return name;
90              }
91          }
92  
93          // 見つからない場合は、候補の先頭のものにする。
94          return names[0];
95      }
96  
97      /**
98       * 先頭の文字を小文字にする。
99       * @param str 変換対象の文字列
100      * @return 引数がnull、空文字の場合、そのまま返す。
101      */
102     private static String uncapitalize(final String str) {
103         final int strLen;
104         if(str == null || (strLen = str.length()) == 0) {
105             return str;
106         }
107 
108         return new StringBuilder(strLen)
109             .append(String.valueOf(str.charAt(0)).toLowerCase())
110             .append(str.substring(1))
111             .toString();
112     }
113 
114     @Override
115     public void afterPropertiesSet() throws Exception {
116 
117         if(applicationContext != null && beanFactory == null) {
118             this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
119         }
120 
121     }
122 
123     public ApplicationContext getApplicationContext() {
124         return applicationContext;
125     }
126 
127     @Override
128     public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
129         this.applicationContext = applicationContext;
130     }
131 
132 }