
org.springframework.guice.module.SpringModule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-guice Show documentation
Show all versions of spring-guice Show documentation
Utilities for using Spring with Guice and vice versa
The newest version!
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.guice.module;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.ProvisionException;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.Annotations;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.util.Types;
import jakarta.inject.Provider;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ClassUtils;
/**
* A Guice module that wraps a Spring {@link ApplicationContext}.
*
* @author Dave Syer
*
*/
public class SpringModule extends AbstractModule {
/**
* Identifier for bindings provided by this module.
*/
public static final String SPRING_GUICE_SOURCE = "spring-guice";
private BindingTypeMatcher matcher = new GuiceModuleMetadata();
private Map> bound = new HashMap>();
private ConfigurableListableBeanFactory beanFactory;
private Provider beanFactoryProvider;
private boolean enableJustInTimeBinding = true;
private Provider injector;
public SpringModule(ApplicationContext context) {
this(context, true);
}
public SpringModule(ApplicationContext context, boolean enableJustInTimeBinding) {
this((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory(), enableJustInTimeBinding);
}
public SpringModule(ConfigurableListableBeanFactory beanFactory) {
this(beanFactory, true);
}
public SpringModule(ConfigurableListableBeanFactory beanFactory, boolean enableJustInTimeBinding) {
this.beanFactory = beanFactory;
this.enableJustInTimeBinding = enableJustInTimeBinding;
}
public SpringModule(Provider beanFactoryProvider) {
this.beanFactoryProvider = beanFactoryProvider;
}
@Override
public void configure() {
if (this.beanFactory == null) {
this.beanFactory = this.beanFactoryProvider.get();
}
this.injector = binder().getProvider(Injector.class);
if (this.beanFactory.getBeanNamesForType(ProvisionListener.class).length > 0) {
binder().bindListener(Matchers.any(), this.beanFactory.getBeansOfType(ProvisionListener.class).values()
.toArray(new ProvisionListener[0]));
}
if (this.enableJustInTimeBinding) {
if (this.beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) this.beanFactory)
.setAutowireCandidateResolver(new GuiceAutowireCandidateResolver(this.injector));
}
}
if (this.beanFactory.getBeanNamesForType(GuiceModuleMetadata.class).length > 0) {
this.matcher = new CompositeTypeMatcher(
this.beanFactory.getBeansOfType(GuiceModuleMetadata.class).values());
}
bind(this.beanFactory);
}
public Provider getInjector() {
return this.injector;
}
private void bind(ConfigurableListableBeanFactory beanFactory) {
for (String name : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(name);
if (definition.hasAttribute(SPRING_GUICE_SOURCE)) {
continue;
}
Optional bindingAnnotation = getAnnotationForBeanDefinition(definition);
if (definition.isAutowireCandidate() && definition.getRole() == AbstractBeanDefinition.ROLE_APPLICATION) {
Type type;
Class> clazz = beanFactory.getType(name);
if (clazz == null) {
continue;
}
if (clazz.getTypeParameters().length > 0) {
RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanFactory
.getMergedBeanDefinition(name);
if (rootBeanDefinition.getFactoryBeanName() != null
&& rootBeanDefinition.getResolvedFactoryMethod() != null) {
type = rootBeanDefinition.getResolvedFactoryMethod().getGenericReturnType();
}
else {
type = rootBeanDefinition.getResolvableType().getType();
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() instanceof Class
&& FactoryBean.class.isAssignableFrom((Class>) parameterizedType.getRawType())) {
type = Types.newParameterizedTypeWithOwner(parameterizedType.getOwnerType(), clazz,
parameterizedType.getActualTypeArguments());
}
}
}
else {
type = clazz;
}
Provider> typeProvider = BeanFactoryProvider.typed(beanFactory, type, bindingAnnotation);
Provider> namedProvider = BeanFactoryProvider.named(beanFactory, name, type, bindingAnnotation);
if (!clazz.isInterface() && !clazz.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
bindConditionally(binder(), name, clazz, typeProvider, namedProvider, bindingAnnotation);
}
for (Type superType : getAllSuperTypes(type, clazz)) {
if (!superType.getTypeName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)
&& !superType.equals(Object.class)) {
bindConditionally(binder(), name, superType, typeProvider, namedProvider, bindingAnnotation);
}
}
for (Type iface : clazz.getGenericInterfaces()) {
bindConditionally(binder(), name, iface, typeProvider, namedProvider, bindingAnnotation);
}
}
}
}
private static String getNameFromBindingAnnotation(Optional bindingAnnotation) {
if (bindingAnnotation.isPresent()) {
Annotation annotation = bindingAnnotation.get();
if (annotation instanceof Named) {
return ((Named) annotation).value();
}
else if (annotation instanceof jakarta.inject.Named) {
return ((jakarta.inject.Named) annotation).value();
}
else {
return null;
}
}
else {
return null;
}
}
private static Optional getAnnotationForBeanDefinition(BeanDefinition definition) {
if (definition instanceof AnnotatedBeanDefinition) {
MethodMetadata methodMetadata = ((AnnotatedBeanDefinition) definition).getFactoryMethodMetadata();
if (methodMetadata != null) {
return methodMetadata.getAnnotations().stream().filter(MergedAnnotation::isDirectlyPresent)
.filter((mergedAnnotation) -> Annotations.isBindingAnnotation(mergedAnnotation.getType()))
.map(MergedAnnotation::synthesize).findFirst();
}
else {
return Optional.empty();
}
}
else {
return Optional.empty();
}
}
private static Set getAllSuperTypes(Type originalType, Class> clazz) {
Set allInterfaces = new HashSet<>();
TypeLiteral> typeToken = TypeLiteral.get(originalType);
Queue queue = new LinkedList<>();
queue.add(clazz);
if (originalType != clazz) {
queue.add(originalType);
}
while (!queue.isEmpty()) {
Type type = queue.poll();
allInterfaces.add(type);
if (type instanceof Class) {
for (Type i : ((Class>) type).getInterfaces()) {
if (i instanceof Class && ((Class>) i).isAssignableFrom(typeToken.getRawType())) {
Type superInterface = typeToken.getSupertype((Class>) i).getType();
queue.add(superInterface);
if (!(superInterface instanceof Class)) {
queue.add(i);
}
}
}
if (((Class>) type).getSuperclass() != null
&& ((Class>) type).isAssignableFrom(typeToken.getRawType())) {
Type superClass = typeToken.getSupertype(((Class>) type).getSuperclass()).getType();
queue.add(superClass);
}
}
}
return allInterfaces;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void bindConditionally(Binder binder, String name, Type type, Provider typeProvider, Provider namedProvider,
Optional bindingAnnotation) {
if (!this.matcher.matches(name, type)) {
return;
}
String typeName = type.getTypeName();
if (typeName.startsWith("com.google.inject") || typeName.startsWith("jakarta.inject.Provider")) {
return;
}
if (type instanceof ParameterizedType) {
ParameterizedType param = (ParameterizedType) type;
for (Type t : param.getActualTypeArguments()) {
if (!ClassUtils.isPresent(t.getTypeName(), null)) {
return;
}
}
}
Key> key = bindingAnnotation.map((a) -> (Key
© 2015 - 2025 Weber Informatics LLC | Privacy Policy