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 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 into);
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 }