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 }