Java tutorial
/* * Copyright (c) 2013. Alexander Herwix * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * You can also obtain a commercial license. Contact: alex@herwix.com for further details. */ package com.iterranux.droolsjbpmCore.internal; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import javax.annotation.PostConstruct; import java.lang.reflect.*; import java.util.*; /** * Abstract Generic Factory that can be easily extended with new manufacturables. * The implementing generic factory needs to provide the class of manufacturables * as well as the specific production logic itself. Beans implementing the manufacturable * class are then automatically registered on init and can be used in the production logic. * * @param <T> */ public abstract class AbstractGenericFactory<T extends GenericFactoryManufacturable> implements ApplicationContextAware { protected ApplicationContext applicationContext; protected Map<String, T> manufacturableBeans; @PostConstruct @SuppressWarnings("unchecked") public void init() { Map<String, T> beanMap = new HashMap<String, T>(); for (T bean : (Collection<T>) applicationContext.getBeansOfType(getManufacturableClass()).values()) { beanMap.put(bean.getManufacturableTypeName(), bean); } setManufacturableBeans(beanMap); } public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } public Map<String, T> getManufacturableBeans() { return this.manufacturableBeans; } public void setManufacturableBeans(Map<String, T> manufacturableBeans) { this.manufacturableBeans = manufacturableBeans; } public T getManufacturableBean(String manufacturableName) throws InstantiationException, IllegalAccessException { return manufacturableBeans.get(manufacturableName); } /** * Reflection technique to determine the actual class of the generic at runtime. * http://www.artima.com/weblogs/viewpost.jsp?thread=208860 */ public Class getManufacturableClass() { return getTypeArguments(AbstractGenericFactory.class, getClass()).get(0); } /** * Get the underlying class for a type, or null if the type is a variable type. * @param type the type * @return the underlying class */ public static Class<?> getClass(Type type) { if (type instanceof Class) { return (Class) type; } else if (type instanceof ParameterizedType) { return getClass(((ParameterizedType) type).getRawType()); } else if (type instanceof GenericArrayType) { Type componentType = ((GenericArrayType) type).getGenericComponentType(); Class<?> componentClass = getClass(componentType); if (componentClass != null) { return Array.newInstance(componentClass, 0).getClass(); } else { return null; } } else { return null; } } /** * Get the actual type arguments a child class has used to extend a generic base class. * * @param baseClass the base class * @param childClass the child class * @return a list of the raw classes for the actual type arguments. */ @SuppressWarnings("all") public static <T> List<Class<?>> getTypeArguments(Class<T> baseClass, Class<? extends T> childClass) { Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); Type type = childClass; // start walking up the inheritance hierarchy until we hit baseClass while (!getClass(type).equals(baseClass)) { if (type instanceof Class) { // there is no useful information for us in raw types, so just keep going. type = ((Class) type).getGenericSuperclass(); } else { ParameterizedType parameterizedType = (ParameterizedType) type; Class<?> rawType = (Class) parameterizedType.getRawType(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); for (int i = 0; i < actualTypeArguments.length; i++) { resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); } if (!rawType.equals(baseClass)) { type = rawType.getGenericSuperclass(); } } } // finally, for each actual type argument provided to baseClass, determine (if possible) // the raw class for that type argument. Type[] actualTypeArguments; if (type instanceof Class) { actualTypeArguments = ((Class) type).getTypeParameters(); } else { actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); } List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); // resolve types by chasing down type variables. for (Type baseType : actualTypeArguments) { while (resolvedTypes.containsKey(baseType)) { baseType = resolvedTypes.get(baseType); } typeArgumentsAsClasses.add(getClass(baseType)); } return typeArgumentsAsClasses; } }