Coverage Report - org.apache.commons.inject.impl.Introspector
 
Classes in this File Line Coverage Branch Coverage Complexity
Introspector
90%
69/76
85%
29/34
0
Introspector$1
50%
2/4
N/A
0
Introspector$1$1
100%
2/2
N/A
0
Introspector$2
50%
1/2
N/A
0
 
 1  
 /**
 2  
  Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  contributor license agreements.  See the NOTICE file distributed with
 4  
  this work for additional information regarding copyright ownership.
 5  
  The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  (the "License"); you may not use this file except in compliance with
 7  
  the License.  You may obtain a copy of the License at
 8  
 
 9  
       http://www.apache.org/licenses/LICENSE-2.0
 10  
 
 11  
  Unless required by applicable law or agreed to in writing, software
 12  
  distributed under the License is distributed on an "AS IS" BASIS,
 13  
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  See the License for the specific language governing permissions and
 15  
  limitations under the License.
 16  
 */
 17  
 package org.apache.commons.inject.impl;
 18  
 
 19  
 import java.lang.annotation.Annotation;
 20  
 import java.lang.reflect.Array;
 21  
 import java.lang.reflect.Constructor;
 22  
 import java.lang.reflect.Field;
 23  
 import java.lang.reflect.Method;
 24  
 import java.lang.reflect.Modifier;
 25  
 import java.lang.reflect.ParameterizedType;
 26  
 import java.lang.reflect.Type;
 27  
 import java.util.ArrayList;
 28  
 import java.util.List;
 29  
 
 30  
 import javax.inject.Inject;
 31  
 import javax.inject.Named;
 32  
 import javax.inject.Provider;
 33  
 
 34  
 import org.apache.commons.inject.api.IBinding;
 35  
 import org.apache.commons.inject.api.IInjector;
 36  
 import org.apache.commons.inject.api.IKey;
 37  
 import org.apache.commons.inject.api.IPoint;
 38  
 import org.apache.commons.inject.api.IProvider;
 39  
 import org.apache.commons.inject.api.Key;
 40  
 import org.apache.commons.inject.impl.bind.DefaultBinding;
 41  
 import org.apache.commons.inject.util.Generics;
 42  
 
 43  
 public class Introspector {
 44  1
         private static final Introspector introspector = new Introspector();
 45  1
         private static final Class<Object> PROVIDER_CLASS = Generics.cast(Provider.class);
 46  
 
 47  
         // Private constructor, to avoid accidental instantiation.
 48  1
         private Introspector() {
 49  1
         }
 50  
 
 51  
         public static Introspector getInstance() {
 52  64
                 return introspector;
 53  
         }
 54  
 
 55  
         public <T> AbstractBaseProvider<T> getProvider(Class<T> pType, IPoint<T> pPoint, IMutableBindingSource pBindings) {
 56  
                 @SuppressWarnings("unchecked")
 57  28
                 final Constructor<T>[] constructors = (Constructor<T>[]) pType.getDeclaredConstructors();
 58  52
                 for (Constructor<T> constructor : constructors) {
 59  36
                         if (constructor.isAnnotationPresent(Inject.class)) {
 60  12
                                 return getProvider(constructor, pBindings);
 61  
                         }
 62  
                 }
 63  16
                 return new DefaultProvider<T>(pType, pPoint);
 64  
         }
 65  
 
 66  
         public <T> AbstractBaseProvider<T> getProvider(Constructor<? extends T> pConstructor, IMutableBindingSource pBindings) {
 67  
                 @SuppressWarnings("unchecked")
 68  12
                 final Class<Object>[] parameterClasses = (Class<Object>[]) pConstructor.getParameterTypes();
 69  12
                 final Type[] parameterTypes = pConstructor.getGenericParameterTypes();
 70  12
                 final Annotation[][] parameterAnnotations = pConstructor.getParameterAnnotations();
 71  12
                 final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes,
 72  
                                 parameterAnnotations, pBindings,
 73  
                                 "Required to invoke the constructor " + pConstructor);
 74  
                 @SuppressWarnings("unchecked")
 75  12
                 final Constructor<T> constructor = (Constructor<T>) pConstructor;
 76  12
                 return new FactoryMethodProvider<T>(constructor,
 77  
                                                                                         getPoint(constructor.getDeclaringClass(), pBindings),
 78  
                                                                                         parameterBindings);
 79  
         }
 80  
 
 81  
         public <T> AbstractBaseProvider<T> getProvider(Method pMethod, IMutableBindingSource pBindings) {
 82  
                 @SuppressWarnings("unchecked")
 83  0
                 final Class<Object>[] parameterClasses = (Class<Object>[]) pMethod.getParameterTypes();
 84  0
                 final Type[] parameterTypes = pMethod.getGenericParameterTypes();
 85  0
                 final Annotation[][] parameterAnnotations = pMethod.getParameterAnnotations();
 86  0
                 final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes, parameterAnnotations, pBindings,
 87  
                         "Required to invoke the method " + pMethod);
 88  
                 @SuppressWarnings("unchecked")
 89  0
                 final Class<T> cl = (Class<T>) pMethod.getReturnType();
 90  0
                 final IPoint<T> point = getPoint(cl, pBindings);
 91  0
                 return new FactoryMethodProvider<T>(pMethod, parameterBindings, point);
 92  
         }
 93  
 
 94  
         private IBinding<Object>[] getBindings(Class<Object>[] pParameterClasses, Type[] pParameterTypes, Annotation[][] pParameterAnnotations, IMutableBindingSource pBindings,
 95  
                         String pCause) {
 96  
                 @SuppressWarnings("unchecked")
 97  120
                 final IBinding<Object>[] bindings = (IBinding<Object>[]) Array.newInstance(IBinding.class, pParameterTypes.length);
 98  194
                 for (int i = 0;  i < bindings.length;  i++) {
 99  74
                         final Class<Object> cl = pParameterClasses[i];
 100  74
                         final Annotation[] annotations = pParameterAnnotations[i];
 101  74
                         bindings[i] = getBinding(cl, pParameterTypes[i], annotations, pBindings, pCause);
 102  
                 }
 103  120
                 return bindings;
 104  
         }
 105  
 
 106  
         private IBinding<Object> getBinding(Class<Object> pClass, Type pType, Annotation[] pAnnotations, IMutableBindingSource pBindings, String pCause) {
 107  138
                 String name = Key.NO_NAME;
 108  230
                 for (Annotation annotation : pAnnotations) {
 109  112
                         if (annotation instanceof Named) {
 110  20
                                 name = ((Named) annotation).value();
 111  20
                                 break;
 112  
                         }
 113  
                 }
 114  138
                 if (pClass == PROVIDER_CLASS  &&  pType != null  &&  pType instanceof ParameterizedType) {
 115  46
                         final ParameterizedType ptype = (ParameterizedType) pType;
 116  46
                         final Type[] typeArgs = ptype.getActualTypeArguments();
 117  46
                         if (typeArgs != null  &&  typeArgs.length == 1) {
 118  46
                                 final Type typeArg = typeArgs[0];
 119  46
                                 if (typeArg instanceof Class<?>) {
 120  
                                         @SuppressWarnings("unchecked")
 121  46
                                         final Class<Object> cl = (Class<Object>) typeArg;
 122  46
                                         final IKey<Object> key = new Key<Object>(cl, name);
 123  46
                                         final IBinding<Object> binding1 = pBindings.requireBinding(key, pCause);
 124  46
                                         final IProvider<Object> provider = new IProvider<Object>(){
 125  
                                                 @Override
 126  
                                                 public Object get() {
 127  44
                                                         return new Provider<Object>(){
 128  
                                                                 @Override
 129  
                                                                 public Object get() {
 130  100
                                                                         return binding1.getProvider().get();
 131  
                                                                 }
 132  
                                                         };
 133  
                                                 }
 134  
 
 135  
                                                 @Override
 136  
                                                 public Class<? extends Object> getType() {
 137  0
                                                         return Provider.class;
 138  
                                                 }
 139  
 
 140  
                                                 @Override
 141  
                                                 public Object get(IInjector pInjector) {
 142  0
                                                         return get();
 143  
                                                 }
 144  
                                         };
 145  46
                                         final IPoint<Object> point = new IPoint<Object>(){
 146  
                                                 @Override
 147  
                                                 public void injectTo(Object pInstance,
 148  
                                                                 IInjector pInjector) {
 149  
                                                         // Does nothing.
 150  0
                                                 }
 151  
                                         };
 152  46
                                         final IBinding<Object> binding2 = new DefaultBinding<Object>(provider, point);
 153  46
                                         return binding2;
 154  
                                 }
 155  
                         }
 156  
                 }
 157  92
                 final IKey<Object> key = new Key<Object>(pClass, name);
 158  92
                 return pBindings.requireBinding(key, pCause);
 159  
         }
 160  
 
 161  
         public <T> ListPoint<T> getPoint(Class<T> pType, IMutableBindingSource pBindings) {
 162  48
                 final List<IPoint<T>> points = new ArrayList<IPoint<T>>();
 163  48
                 final Field[] fields = pType.getDeclaredFields();
 164  501
                 for (final Field f : fields) {
 165  453
                         if (Modifier.isStatic(f.getModifiers())) {
 166  127
                                 continue;
 167  
                         }
 168  326
                         if (!f.isAnnotationPresent(Inject.class)) {
 169  262
                                 continue;
 170  
                         }
 171  
                         @SuppressWarnings("unchecked")
 172  64
                         Class<Object> type = (Class<Object>) f.getType();
 173  64
                         Type genericType = f.getGenericType();
 174  64
                         IBinding<Object> binding = null;
 175  64
                         Annotation[] annotations = f.getAnnotations();
 176  64
                         binding = getBinding(type, genericType, annotations, pBindings,
 177  
                                         "Required to inject to an instance of " + pType.getName());
 178  64
                         final IPoint<T> point = new FieldPoint<T>(binding, f);
 179  64
                         points.add(point);
 180  
                 }
 181  48
                 final Method[] methods = pType.getDeclaredMethods();
 182  638
                 for (final Method m : methods) {
 183  590
                         if (Modifier.isStatic(m.getModifiers())) {
 184  152
                                 continue;
 185  
                         }
 186  438
                         if (!m.isAnnotationPresent(Inject.class)) {
 187  330
                                 continue;
 188  
                         }
 189  
                         @SuppressWarnings("unchecked")
 190  108
                         Class<Object>[] parameterClasses = (Class<Object>[]) m.getParameterTypes();
 191  108
                         Type[] parameterTypes = m.getGenericParameterTypes();
 192  108
                         Annotation[][] annotations = m.getParameterAnnotations();
 193  108
                         final IBinding<Object>[] bindings = getBindings(parameterClasses, parameterTypes, annotations, pBindings,
 194  
                                         "Required to inject to an instance of " + pType.getName());
 195  108
                         final IPoint<T> point = new MethodPoint<T>(bindings, m);
 196  108
                         points.add(point);
 197  
                 }
 198  48
                 return new ListPoint<T>(points);
 199  
         }
 200  
 }