001 /** 002 Licensed to the Apache Software Foundation (ASF) under one or more 003 contributor license agreements. See the NOTICE file distributed with 004 this work for additional information regarding copyright ownership. 005 The ASF licenses this file to You under the Apache License, Version 2.0 006 (the "License"); you may not use this file except in compliance with 007 the License. You may obtain a copy of the License at 008 009 http://www.apache.org/licenses/LICENSE-2.0 010 011 Unless required by applicable law or agreed to in writing, software 012 distributed under the License is distributed on an "AS IS" BASIS, 013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 See the License for the specific language governing permissions and 015 limitations under the License. 016 */ 017 package org.apache.commons.inject.impl; 018 019 import java.lang.annotation.Annotation; 020 import java.lang.reflect.Array; 021 import java.lang.reflect.Constructor; 022 import java.lang.reflect.Field; 023 import java.lang.reflect.Method; 024 import java.lang.reflect.Modifier; 025 import java.lang.reflect.ParameterizedType; 026 import java.lang.reflect.Type; 027 import java.util.ArrayList; 028 import java.util.List; 029 030 import javax.inject.Inject; 031 import javax.inject.Named; 032 import javax.inject.Provider; 033 034 import org.apache.commons.inject.api.IBinding; 035 import org.apache.commons.inject.api.IInjector; 036 import org.apache.commons.inject.api.IKey; 037 import org.apache.commons.inject.api.IPoint; 038 import org.apache.commons.inject.api.IProvider; 039 import org.apache.commons.inject.api.Key; 040 import org.apache.commons.inject.impl.bind.DefaultBinding; 041 import org.apache.commons.inject.util.Generics; 042 043 public class Introspector { 044 private static final Introspector introspector = new Introspector(); 045 private static final Class<Object> PROVIDER_CLASS = Generics.cast(Provider.class); 046 047 // Private constructor, to avoid accidental instantiation. 048 private Introspector() { 049 } 050 051 public static Introspector getInstance() { 052 return introspector; 053 } 054 055 public <T> AbstractBaseProvider<T> getProvider(Class<T> pType, IPoint<T> pPoint, IMutableBindingSource pBindings) { 056 @SuppressWarnings("unchecked") 057 final Constructor<T>[] constructors = (Constructor<T>[]) pType.getDeclaredConstructors(); 058 for (Constructor<T> constructor : constructors) { 059 if (constructor.isAnnotationPresent(Inject.class)) { 060 return getProvider(constructor, pBindings); 061 } 062 } 063 return new DefaultProvider<T>(pType, pPoint); 064 } 065 066 public <T> AbstractBaseProvider<T> getProvider(Constructor<? extends T> pConstructor, IMutableBindingSource pBindings) { 067 @SuppressWarnings("unchecked") 068 final Class<Object>[] parameterClasses = (Class<Object>[]) pConstructor.getParameterTypes(); 069 final Type[] parameterTypes = pConstructor.getGenericParameterTypes(); 070 final Annotation[][] parameterAnnotations = pConstructor.getParameterAnnotations(); 071 final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes, 072 parameterAnnotations, pBindings, 073 "Required to invoke the constructor " + pConstructor); 074 @SuppressWarnings("unchecked") 075 final Constructor<T> constructor = (Constructor<T>) pConstructor; 076 return new FactoryMethodProvider<T>(constructor, 077 getPoint(constructor.getDeclaringClass(), pBindings), 078 parameterBindings); 079 } 080 081 public <T> AbstractBaseProvider<T> getProvider(Method pMethod, IMutableBindingSource pBindings) { 082 @SuppressWarnings("unchecked") 083 final Class<Object>[] parameterClasses = (Class<Object>[]) pMethod.getParameterTypes(); 084 final Type[] parameterTypes = pMethod.getGenericParameterTypes(); 085 final Annotation[][] parameterAnnotations = pMethod.getParameterAnnotations(); 086 final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes, parameterAnnotations, pBindings, 087 "Required to invoke the method " + pMethod); 088 @SuppressWarnings("unchecked") 089 final Class<T> cl = (Class<T>) pMethod.getReturnType(); 090 final IPoint<T> point = getPoint(cl, pBindings); 091 return new FactoryMethodProvider<T>(pMethod, parameterBindings, point); 092 } 093 094 private IBinding<Object>[] getBindings(Class<Object>[] pParameterClasses, Type[] pParameterTypes, Annotation[][] pParameterAnnotations, IMutableBindingSource pBindings, 095 String pCause) { 096 @SuppressWarnings("unchecked") 097 final IBinding<Object>[] bindings = (IBinding<Object>[]) Array.newInstance(IBinding.class, pParameterTypes.length); 098 for (int i = 0; i < bindings.length; i++) { 099 final Class<Object> cl = pParameterClasses[i]; 100 final Annotation[] annotations = pParameterAnnotations[i]; 101 bindings[i] = getBinding(cl, pParameterTypes[i], annotations, pBindings, pCause); 102 } 103 return bindings; 104 } 105 106 private IBinding<Object> getBinding(Class<Object> pClass, Type pType, Annotation[] pAnnotations, IMutableBindingSource pBindings, String pCause) { 107 String name = Key.NO_NAME; 108 for (Annotation annotation : pAnnotations) { 109 if (annotation instanceof Named) { 110 name = ((Named) annotation).value(); 111 break; 112 } 113 } 114 if (pClass == PROVIDER_CLASS && pType != null && pType instanceof ParameterizedType) { 115 final ParameterizedType ptype = (ParameterizedType) pType; 116 final Type[] typeArgs = ptype.getActualTypeArguments(); 117 if (typeArgs != null && typeArgs.length == 1) { 118 final Type typeArg = typeArgs[0]; 119 if (typeArg instanceof Class<?>) { 120 @SuppressWarnings("unchecked") 121 final Class<Object> cl = (Class<Object>) typeArg; 122 final IKey<Object> key = new Key<Object>(cl, name); 123 final IBinding<Object> binding1 = pBindings.requireBinding(key, pCause); 124 final IProvider<Object> provider = new IProvider<Object>(){ 125 @Override 126 public Object get() { 127 return new Provider<Object>(){ 128 @Override 129 public Object get() { 130 return binding1.getProvider().get(); 131 } 132 }; 133 } 134 135 @Override 136 public Class<? extends Object> getType() { 137 return Provider.class; 138 } 139 140 @Override 141 public Object get(IInjector pInjector) { 142 return get(); 143 } 144 }; 145 final IPoint<Object> point = new IPoint<Object>(){ 146 @Override 147 public void injectTo(Object pInstance, 148 IInjector pInjector) { 149 // Does nothing. 150 } 151 }; 152 final IBinding<Object> binding2 = new DefaultBinding<Object>(provider, point); 153 return binding2; 154 } 155 } 156 } 157 final IKey<Object> key = new Key<Object>(pClass, name); 158 return pBindings.requireBinding(key, pCause); 159 } 160 161 public <T> ListPoint<T> getPoint(Class<T> pType, IMutableBindingSource pBindings) { 162 final List<IPoint<T>> points = new ArrayList<IPoint<T>>(); 163 final Field[] fields = pType.getDeclaredFields(); 164 for (final Field f : fields) { 165 if (Modifier.isStatic(f.getModifiers())) { 166 continue; 167 } 168 if (!f.isAnnotationPresent(Inject.class)) { 169 continue; 170 } 171 @SuppressWarnings("unchecked") 172 Class<Object> type = (Class<Object>) f.getType(); 173 Type genericType = f.getGenericType(); 174 IBinding<Object> binding = null; 175 Annotation[] annotations = f.getAnnotations(); 176 binding = getBinding(type, genericType, annotations, pBindings, 177 "Required to inject to an instance of " + pType.getName()); 178 final IPoint<T> point = new FieldPoint<T>(binding, f); 179 points.add(point); 180 } 181 final Method[] methods = pType.getDeclaredMethods(); 182 for (final Method m : methods) { 183 if (Modifier.isStatic(m.getModifiers())) { 184 continue; 185 } 186 if (!m.isAnnotationPresent(Inject.class)) { 187 continue; 188 } 189 @SuppressWarnings("unchecked") 190 Class<Object>[] parameterClasses = (Class<Object>[]) m.getParameterTypes(); 191 Type[] parameterTypes = m.getGenericParameterTypes(); 192 Annotation[][] annotations = m.getParameterAnnotations(); 193 final IBinding<Object>[] bindings = getBindings(parameterClasses, parameterTypes, annotations, pBindings, 194 "Required to inject to an instance of " + pType.getName()); 195 final IPoint<T> point = new MethodPoint<T>(bindings, m); 196 points.add(point); 197 } 198 return new ListPoint<T>(points); 199 } 200 }