001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.google.inject.spring;
016:
017: import static com.google.inject.util.Objects.nonNull;
018: import com.google.inject.Provider;
019: import com.google.inject.Inject;
020: import com.google.inject.Binder;
021: import com.google.inject.name.Names;
022: import com.google.inject.spi.SourceProviders;
023: import com.google.inject.util.Objects;
024: import org.springframework.beans.factory.BeanFactory;
025: import org.springframework.beans.factory.ListableBeanFactory;
026:
027: /**
028: * Integrates Guice with Spring.
029: *
030: * @author crazybob@google.com (Bob Lee)
031: */
032: public class SpringIntegration {
033:
034: static {
035: SourceProviders.skip(SpringIntegration.class);
036: }
037:
038: private SpringIntegration() {
039: }
040:
041: /**
042: * Creates a provider which looks up objects from Spring using the given name.
043: * Expects a binding to {@link
044: * org.springframework.beans.factory.BeanFactory}. Example usage:
045: *
046: * <pre>
047: * bind(DataSource.class)
048: * .toProvider(fromSpring(DataSource.class, "dataSource"));
049: * </pre>
050: */
051: public static <T> Provider<T> fromSpring(Class<T> type, String name) {
052: return new InjectableSpringProvider<T>(type, name);
053: }
054:
055: /**
056: * Binds all Spring beans from the given factory by name. For a Spring bean
057: * named "foo", this method creates a binding to the bean's type and
058: * {@code @Named("foo")}.
059: *
060: * @see com.google.inject.name.Named
061: * @see com.google.inject.name.Names#named(String)
062: */
063: public static void bindAll(Binder binder,
064: ListableBeanFactory beanFactory) {
065: for (String name : beanFactory.getBeanDefinitionNames()) {
066: Class<?> type = beanFactory.getType(name);
067: bindBean(binder, beanFactory, name, type);
068: }
069: }
070:
071: static <T> void bindBean(Binder binder,
072: ListableBeanFactory beanFactory, String name, Class<T> type) {
073: SpringProvider<T> provider = SpringProvider.newInstance(type,
074: name);
075: try {
076: provider.initialize(beanFactory);
077: } catch (Exception e) {
078: binder.addError(e);
079: return;
080: }
081:
082: binder.bind(type).annotatedWith(Names.named(name)).toProvider(
083: provider);
084: }
085:
086: static class SpringProvider<T> implements Provider<T> {
087:
088: BeanFactory beanFactory;
089: boolean singleton;
090: final Class<T> type;
091: final String name;
092:
093: public SpringProvider(Class<T> type, String name) {
094: this .type = nonNull(type, "type");
095: this .name = nonNull(name, "name");
096: }
097:
098: static <T> SpringProvider<T> newInstance(Class<T> type,
099: String name) {
100: return new SpringProvider<T>(type, name);
101: }
102:
103: void initialize(BeanFactory beanFactory) {
104: this .beanFactory = beanFactory;
105: if (!beanFactory.isTypeMatch(name, type)) {
106: throw new ClassCastException("Spring bean named '"
107: + name + "' does not implement "
108: + type.getName() + ".");
109: }
110: singleton = beanFactory.isSingleton(name);
111: }
112:
113: public T get() {
114: return singleton ? getSingleton() : type.cast(beanFactory
115: .getBean(name));
116: }
117:
118: volatile T instance;
119:
120: private T getSingleton() {
121: if (instance == null) {
122: instance = type.cast(beanFactory.getBean(name));
123: }
124: return instance;
125: }
126: }
127:
128: static class InjectableSpringProvider<T> extends SpringProvider<T> {
129:
130: InjectableSpringProvider(Class<T> type, String name) {
131: super (type, name);
132: }
133:
134: @Inject
135: @Override
136: void initialize(BeanFactory beanFactory) {
137: super.initialize(beanFactory);
138: }
139: }
140: }
|