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 * An 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 036 private Class key; 037 038 public FactoryInjector() throws PicoCompositionException { 039 key = getTypeArguments(FactoryInjector.class, getClass()).get(0); 040 if (key == null) { 041 key = CantWorkItOut.class; 042 } 043 } 044 045 public FactoryInjector(Class<T> key) { 046 this.key = key; 047 } 048 049 // from http://www.artima.com/weblogs/viewpost.jsp?thread=208860 050 public static Class<?> getClass(Type type) { 051 if (type instanceof Class) { 052 return (Class) type; 053 } else if (type instanceof ParameterizedType) { 054 return getClass(((ParameterizedType) type).getRawType()); 055 } else if (type instanceof GenericArrayType) { 056 Type componentType = ((GenericArrayType) type).getGenericComponentType(); 057 Class<?> componentClass = getClass(componentType); 058 if (componentClass != null) { 059 return Array.newInstance(componentClass, 0).getClass(); 060 } else { 061 return null; 062 } 063 } else { 064 return null; 065 } 066 } 067 068 /** 069 * Get the actual type arguments a child class has used to extend a generic base class. 070 * 071 * @param class1 the base class 072 * @param class2 the child class 073 * @return a list of the raw classes for the actual type arguments. 074 */ 075 public static <T> List<Class<?>> getTypeArguments( 076 Class<FactoryInjector> class1, Class<? extends Object> class2) { 077 Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); 078 Type type = class2; 079 // start walking up the inheritance hierarchy until we hit baseClass 080 while (! getClass(type).equals(class1)) { 081 if (type instanceof Class) { 082 // there is no useful information for us in raw types, so just keep going. 083 type = ((Class) type).getGenericSuperclass(); 084 } 085 else { 086 ParameterizedType parameterizedType = (ParameterizedType) type; 087 Class<?> rawType = (Class) parameterizedType.getRawType(); 088 089 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 090 TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); 091 for (int i = 0; i < actualTypeArguments.length; i++) { 092 resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); 093 } 094 095 if (!rawType.equals(class1)) { 096 type = rawType.getGenericSuperclass(); 097 } 098 } 099 } 100 101 // finally, for each actual type argument provided to baseClass, determine (if possible) 102 // the raw class for that type argument. 103 Type[] actualTypeArguments; 104 if (type instanceof Class) { 105 actualTypeArguments = ((Class) type).getTypeParameters(); 106 } 107 else { 108 actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); 109 } 110 List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); 111 // resolve types by chasing down type variables. 112 for (Type baseType: actualTypeArguments) { 113 while (resolvedTypes.containsKey(baseType)) { 114 baseType = resolvedTypes.get(baseType); 115 } 116 typeArgumentsAsClasses.add(getClass(baseType)); 117 } 118 return typeArgumentsAsClasses; 119 } 120 121 public Object getComponentKey() { 122 return key; 123 } 124 125 public Class<T> getComponentImplementation() { 126 return key; 127 } 128 129 public void accept(PicoVisitor visitor) { 130 visitor.visitComponentAdapter(this); 131 } 132 133 public ComponentAdapter<T> getDelegate() { 134 return null; 135 } 136 137 public <U extends ComponentAdapter> U findAdapterOfType(Class<U> adapterType) { 138 return null; 139 } 140 141 public T getComponentInstance(PicoContainer container) { 142 throw new UnsupportedOperationException(); 143 } 144 145 public abstract T getComponentInstance(PicoContainer container, Type into); 146 147 public Object decorateComponentInstance(PicoContainer container, Type into, T instance) { 148 return null; 149 } 150 151 public void verify(PicoContainer container) { 152 } 153 154 public String getDescriptor() { 155 return "FactoryInjector-"; 156 } 157 158 public void start(PicoContainer container) { 159 } 160 161 public void stop(PicoContainer container) { 162 } 163 164 public void dispose(PicoContainer container) { 165 } 166 167 public boolean componentHasLifecycle() { 168 return false; 169 } 170 171 public static class CantWorkItOut { 172 private CantWorkItOut() { 173 } 174 } 175 176 }