    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> componentAdapterType) {
    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    }