1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
package org.apache.shiro.guice; |
20 | |
|
21 | |
import com.google.common.primitives.Primitives; |
22 | |
import com.google.inject.*; |
23 | |
import com.google.inject.matcher.Matcher; |
24 | |
import com.google.inject.matcher.Matchers; |
25 | |
import com.google.inject.multibindings.MapBinder; |
26 | |
import com.google.inject.name.Names; |
27 | |
import com.google.inject.spi.TypeEncounter; |
28 | |
import com.google.inject.spi.TypeListener; |
29 | |
import com.google.inject.util.Types; |
30 | |
import org.apache.commons.beanutils.PropertyUtils; |
31 | |
import org.apache.shiro.SecurityUtils; |
32 | |
|
33 | |
import java.beans.PropertyDescriptor; |
34 | |
import java.lang.reflect.InvocationTargetException; |
35 | |
import java.lang.reflect.Modifier; |
36 | |
import java.lang.reflect.Type; |
37 | |
import java.util.HashMap; |
38 | |
import java.util.Map; |
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | 170 | class BeanTypeListener implements TypeListener { |
44 | 1 | public static final Package SHIRO_GUICE_PACKAGE = ShiroModule.class.getPackage(); |
45 | 1 | public static final Package SHIRO_PACKAGE = SecurityUtils.class.getPackage(); |
46 | |
|
47 | 1 | private static Matcher<Class> shiroMatcher = Matchers.inSubpackage(SHIRO_PACKAGE.getName()); |
48 | 1 | private static Matcher<Class> shiroGuiceMatcher = Matchers.inSubpackage(SHIRO_GUICE_PACKAGE.getName()); |
49 | |
|
50 | 1 | private static Matcher<Class> classMatcher = ShiroMatchers.ANY_PACKAGE.and(shiroMatcher.and(Matchers.not(shiroGuiceMatcher))); |
51 | |
|
52 | 1 | public static final Matcher<TypeLiteral> MATCHER = ShiroMatchers.typeLiteral(classMatcher); |
53 | |
|
54 | |
private static final String BEAN_TYPE_MAP_NAME = "__SHIRO_BEAN_TYPES__"; |
55 | 1 | static final Key<?> MAP_KEY = Key.get(Types.mapOf(TypeLiteral.class, BeanTypeKey.class), Names.named(BEAN_TYPE_MAP_NAME)); |
56 | |
|
57 | |
public <I> void hear(TypeLiteral<I> type, final TypeEncounter<I> encounter) { |
58 | 14 | PropertyDescriptor propertyDescriptors[] = PropertyUtils.getPropertyDescriptors(type.getRawType()); |
59 | 14 | final Map<PropertyDescriptor, Key<?>> propertyDependencies = new HashMap<PropertyDescriptor, Key<?>>(propertyDescriptors.length); |
60 | 14 | final Provider<Injector> injectorProvider = encounter.getProvider(Injector.class); |
61 | 150 | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { |
62 | 136 | if (propertyDescriptor.getWriteMethod() != null && Modifier.isPublic(propertyDescriptor.getWriteMethod().getModifiers())) { |
63 | 118 | Type propertyType = propertyDescriptor.getWriteMethod().getGenericParameterTypes()[0]; |
64 | 118 | propertyDependencies.put(propertyDescriptor, createDependencyKey(propertyDescriptor, propertyType)); |
65 | |
} |
66 | |
} |
67 | 14 | encounter.register(new MembersInjector<I>() { |
68 | |
public void injectMembers(I instance) { |
69 | 18 | for (Map.Entry<PropertyDescriptor, Key<?>> dependency : propertyDependencies.entrySet()) { |
70 | |
try { |
71 | 158 | final Injector injector = injectorProvider.get(); |
72 | |
|
73 | 158 | Object value = injector.getInstance(getMappedKey(injector, dependency.getValue())); |
74 | 32 | dependency.getKey().getWriteMethod().invoke(instance, value); |
75 | |
|
76 | 126 | } catch (ConfigurationException e) { |
77 | |
|
78 | |
|
79 | 0 | } catch (InvocationTargetException e) { |
80 | 0 | throw new RuntimeException("Couldn't set property " + dependency.getKey().getDisplayName(), e); |
81 | 0 | } catch (IllegalAccessException e) { |
82 | 0 | throw new RuntimeException("We shouldn't have ever reached this point, we don't try to inject to non-accessible methods.", e); |
83 | 158 | } |
84 | |
} |
85 | |
|
86 | 18 | } |
87 | |
}); |
88 | 14 | } |
89 | |
|
90 | |
private static Key<?> getMappedKey(Injector injector, Key<?> key) { |
91 | 158 | Map<TypeLiteral, BeanTypeKey> beanTypeMap = getBeanTypeMap(injector); |
92 | 158 | if(key.getAnnotation() == null && beanTypeMap.containsKey(key.getTypeLiteral())) { |
93 | 4 | return beanTypeMap.get(key.getTypeLiteral()).key; |
94 | |
} else { |
95 | 154 | return key; |
96 | |
} |
97 | |
} |
98 | |
|
99 | |
@SuppressWarnings({"unchecked"}) |
100 | |
private static Map<TypeLiteral, BeanTypeKey> getBeanTypeMap(Injector injector) { |
101 | 158 | return (Map<TypeLiteral, BeanTypeKey>) injector.getInstance(MAP_KEY); |
102 | |
} |
103 | |
|
104 | |
private static Key<?> createDependencyKey(PropertyDescriptor propertyDescriptor, Type propertyType) { |
105 | 118 | if(requiresName(propertyType)) { |
106 | 28 | return Key.get(propertyType, Names.named("shiro." + propertyDescriptor.getName())); |
107 | |
} else { |
108 | 90 | return Key.get(propertyType); |
109 | |
} |
110 | |
} |
111 | |
|
112 | |
private static boolean requiresName(Type propertyType) { |
113 | 118 | if (propertyType instanceof Class) { |
114 | 109 | Class<?> aClass = (Class<?>) propertyType; |
115 | 109 | return aClass.isPrimitive() || aClass.isEnum() || Primitives.isWrapperType(aClass) || CharSequence.class.isAssignableFrom(aClass); |
116 | |
} else { |
117 | 9 | return false; |
118 | |
} |
119 | |
} |
120 | |
|
121 | |
static void ensureBeanTypeMapExists(Binder binder) { |
122 | 11 | beanTypeMapBinding(binder).addBinding(TypeLiteral.get(BeanTypeKey.class)).toInstance(new BeanTypeKey(null)); |
123 | 11 | } |
124 | |
|
125 | |
static <T> void bindBeanType(Binder binder, TypeLiteral<T> typeLiteral, Key<? extends T> key) { |
126 | 5 | beanTypeMapBinding(binder).addBinding(typeLiteral).toInstance(new BeanTypeKey(key)); |
127 | 5 | } |
128 | |
|
129 | |
private static MapBinder<TypeLiteral, BeanTypeKey> beanTypeMapBinding(Binder binder) { |
130 | 16 | return MapBinder.newMapBinder(binder, TypeLiteral.class, BeanTypeKey.class, Names.named(BEAN_TYPE_MAP_NAME)); |
131 | |
} |
132 | |
|
133 | 16 | private static class BeanTypeKey { |
134 | |
Key<?> key; |
135 | |
|
136 | 16 | private BeanTypeKey(Key<?> key) { |
137 | 16 | this.key = key; |
138 | 16 | } |
139 | |
} |
140 | |
} |