001 /***************************************************************************** 002 * Copyright (C) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 *****************************************************************************/ 009 package org.picocontainer.injectors; 010 011 import java.lang.reflect.ParameterizedType; 012 import java.lang.reflect.Type; 013 import java.lang.reflect.Array; 014 import java.lang.reflect.GenericArrayType; 015 import java.lang.reflect.TypeVariable; 016 import java.util.List; 017 import java.util.ArrayList; 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.picocontainer.ComponentAdapter; 022 import org.picocontainer.Injector; 023 import org.picocontainer.PicoCompositionException; 024 import org.picocontainer.PicoContainer; 025 import org.picocontainer.PicoVisitor; 026 027 /** 028 * <p> 029 * A Injector which provides an custom instance in a factory style 030 * </p> 031 * 032 * @author Paul Hammant 033 */ 034 public abstract class FactoryInjector<T> implements Injector<T> { 035 private Class key; 036 037 public FactoryInjector() throws PicoCompositionException { 038 key = getTypeArguments(FactoryInjector.class, getClass()).get(0); 039 if (key == null) { 040 key = CantWorkItOut.class; 041 } 042 } 043 044 public FactoryInjector(Class<T> key) { 045 this.key = key; 046 } 047 048 // from http://www.artima.com/weblogs/viewpost.jsp?thread=208860 049 public static Class<?> getClass(Type type) { 050 if (type instanceof Class) { 051 return (Class) type; 052 } else if (type instanceof ParameterizedType) { 053 return getClass(((ParameterizedType) type).getRawType()); 054 } else if (type instanceof GenericArrayType) { 055 Type componentType = ((GenericArrayType) type).getGenericComponentType(); 056 Class<?> componentClass = getClass(componentType); 057 if (componentClass != null) { 058 return Array.newInstance(componentClass, 0).getClass(); 059 } else { 060 return null; 061 } 062 } else { 063 return null; 064 } 065 } 066 067 /** 068 * Get the actual type arguments a child class has used to extend a generic base class. 069 * 070 * @param class1 the base class 071 * @param class2 the child class 072 * @return a list of the raw classes for the actual type arguments. 073 */ 074 public static <T> List<Class<?>> getTypeArguments( 075 Class<FactoryInjector> class1, Class<? extends Object> class2) { 076 Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); 077 Type type = class2; 078 // start walking up the inheritance hierarchy until we hit baseClass 079 while (! getClass(type).equals(class1)) { 080 if (type instanceof Class) { 081 // there is no useful information for us in raw types, so just keep going. 082 type = ((Class) type).getGenericSuperclass(); 083 } 084 else { 085 ParameterizedType parameterizedType = (ParameterizedType) type; 086 Class<?> rawType = (Class) parameterizedType.getRawType(); 087 088 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 089 TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); 090 for (int i = 0; i < actualTypeArguments.length; i++) { 091 resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); 092 } 093 094 if (!rawType.equals(class1)) { 095 type = rawType.getGenericSuperclass(); 096 } 097 } 098 } 099 100 // finally, for each actual type argument provided to baseClass, determine (if possible) 101 // the raw class for that type argument. 102 Type[] actualTypeArguments; 103 if (type instanceof Class) { 104 actualTypeArguments = ((Class) type).getTypeParameters(); 105 } 106 else { 107 actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); 108 } 109 List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); 110 // resolve types by chasing down type variables. 111 for (Type baseType: actualTypeArguments) { 112 while (resolvedTypes.containsKey(baseType)) { 113 baseType = resolvedTypes.get(baseType); 114 } 115 typeArgumentsAsClasses.add(getClass(baseType)); 116 } 117 return typeArgumentsAsClasses; 118 } 119 120 public Object getComponentKey() { 121 return key; 122 } 123 124 public Class<T> getComponentImplementation() { 125 return key; 126 } 127 128 public void accept(PicoVisitor visitor) { 129 visitor.visitComponentAdapter(this); 130 } 131 132 public ComponentAdapter<T> getDelegate() { 133 return null; 134 } 135 136 public <U extends ComponentAdapter> U findAdapterOfType(Class<U> componentAdapterType) { 137 return null; 138 } 139 140 public T getComponentInstance(PicoContainer container) { 141 throw new UnsupportedOperationException(); 142 } 143 144 public abstract T getComponentInstance(PicoContainer container, Type clazz); 145 146 public void decorateComponentInstance(PicoContainer container, Type into, T instance) { 147 } 148 149 150 public void verify(PicoContainer container) { 151 } 152 153 public String getDescriptor() { 154 return "FactoryInjector-"; 155 } 156 157 public void start(PicoContainer container) { 158 } 159 160 public void stop(PicoContainer container) { 161 } 162 163 public void dispose(PicoContainer container) { 164 } 165 166 public boolean componentHasLifecycle() { 167 return false; 168 } 169 170 public static class CantWorkItOut {} 171 172 }