Home | History | Annotate | Download | only in spring
      1 /**
      2  * Copyright (C) 2006 Google Inc.
      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 com.google.inject.spring;
     18 
     19 import static com.google.common.base.Preconditions.checkNotNull;
     20 
     21 import com.google.inject.Binder;
     22 import com.google.inject.Inject;
     23 import com.google.inject.Provider;
     24 import com.google.inject.name.Names;
     25 
     26 import org.springframework.beans.factory.BeanFactory;
     27 import org.springframework.beans.factory.ListableBeanFactory;
     28 
     29 /**
     30  * Integrates Guice with Spring.
     31  *
     32  * @author crazybob (at) google.com (Bob Lee)
     33  */
     34 public class SpringIntegration {
     35   private SpringIntegration() {}
     36 
     37   /**
     38    * Creates a provider which looks up objects from Spring using the given name.
     39    * Expects a binding to {@link
     40    * org.springframework.beans.factory.BeanFactory}. Example usage:
     41    *
     42    * <pre>
     43    * bind(DataSource.class)
     44    *   .toProvider(fromSpring(DataSource.class, "dataSource"));
     45    * </pre>
     46    */
     47   public static <T> Provider<T> fromSpring(Class<T> type, String name) {
     48     return new InjectableSpringProvider<T>(type, name);
     49   }
     50 
     51   /**
     52    * Binds all Spring beans from the given factory by name. For a Spring bean
     53    * named "foo", this method creates a binding to the bean's type and
     54    * {@code @Named("foo")}.
     55    *
     56    * @see com.google.inject.name.Named
     57    * @see com.google.inject.name.Names#named(String)
     58    */
     59   public static void bindAll(Binder binder, ListableBeanFactory beanFactory) {
     60     binder = binder.skipSources(SpringIntegration.class);
     61 
     62     for (String name : beanFactory.getBeanDefinitionNames()) {
     63       Class<?> type = beanFactory.getType(name);
     64       bindBean(binder, beanFactory, name, type);
     65     }
     66   }
     67 
     68   static <T> void bindBean(Binder binder, ListableBeanFactory beanFactory,
     69       String name, Class<T> type) {
     70     SpringProvider<T> provider
     71         = SpringProvider.newInstance(type, name);
     72     try {
     73       provider.initialize(beanFactory);
     74     }
     75     catch (Exception e) {
     76       binder.addError(e);
     77       return;
     78     }
     79 
     80     binder.bind(type)
     81         .annotatedWith(Names.named(name))
     82         .toProvider(provider);
     83   }
     84 
     85   static class SpringProvider<T> implements Provider<T> {
     86 
     87     BeanFactory beanFactory;
     88     boolean singleton;
     89     final Class<T> type;
     90     final String name;
     91 
     92     public SpringProvider(Class<T> type, String name) {
     93       this.type = checkNotNull(type, "type");
     94       this.name = checkNotNull(name, "name");
     95     }
     96 
     97     static <T> SpringProvider<T> newInstance(Class<T> type, String name) {
     98       return new SpringProvider<T>(type, name);
     99     }
    100 
    101     void initialize(BeanFactory beanFactory) {
    102       this.beanFactory = beanFactory;
    103       if (!beanFactory.isTypeMatch(name, type)) {
    104         throw new ClassCastException("Spring bean named '" + name
    105             + "' does not implement " + type.getName() + ".");
    106       }
    107       singleton = beanFactory.isSingleton(name);
    108     }
    109 
    110     public T get() {
    111       return singleton ? getSingleton() : type.cast(beanFactory.getBean(name));
    112     }
    113 
    114     volatile T instance;
    115 
    116     private T getSingleton() {
    117       if (instance == null) {
    118         instance = type.cast(beanFactory.getBean(name));
    119       }
    120       return instance;
    121     }
    122   }
    123 
    124   static class InjectableSpringProvider<T> extends SpringProvider<T> {
    125 
    126     InjectableSpringProvider(Class<T> type, String name) {
    127       super(type, name);
    128     }
    129 
    130     @Inject
    131     @Override
    132     void initialize(BeanFactory beanFactory) {
    133       super.initialize(beanFactory);
    134     }
    135   }
    136 }
    137