/* * Copyright (c) 2001-2007, Inversoft Inc., All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the License. */ package org.primeframework.mvc.util; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.Map; import org.primeframework.mvc.parameter.el.CollectionExpressionException; /** * This is a toolkit that assists with generics. * * @author Brian Pontarelli */ public class TypeTools { /** * Determines the component type. Lists is the first type, Map is the second type, etc. * * @param type The parametrized type. * @param path The path to the type, used in exception message. * @return The component type. */ public static Type componentType(Type type, String path) { if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Class<?> rawType = (Class<?>) parameterizedType.getRawType(); if (Map.class.isAssignableFrom(rawType)) { return parameterizedType.getActualTypeArguments()[1]; } else if (Collection.class.isAssignableFrom(rawType)) { return parameterizedType.getActualTypeArguments()[0]; } else { throw new CollectionExpressionException("Unknown collection type [" + type + "]"); } } else if (type instanceof GenericArrayType) { return ((GenericArrayType) type).getGenericComponentType(); } Class<?> rawType = (Class<?>) type; if (Map.class == type || Collection.class == type) { throw new CollectionExpressionException("The method or member [" + path + "] returns a simple " + "Map or Collection. Unable to determine the type of the Map or Collection. " + "Please make this method generic so that the correct type can be determined."); } else if (rawType.isArray()) { return rawType.getComponentType(); } return rawType; } /** * Determines the key type for a Map. * * @param type The parametrized type. * @param path The path to the type, used in exception message. * @return The key type. */ public static Type[] mapTypes(Type type, String path) { if (type instanceof Class) { Class c = (Class) type; type = c.getGenericSuperclass(); if (!(isGenericMap(type))) { Type[] types = c.getGenericInterfaces(); if (types != null && types.length > 0) { for (Type t : types) { if (isGenericMap(t)) { type = t; break; } } } } } if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Class<?> rawType = (Class<?>) parameterizedType.getRawType(); if (Map.class.isAssignableFrom(rawType)) { return parameterizedType.getActualTypeArguments(); } } throw new CollectionExpressionException("The method or member [" + path + "] returns a simple Map. Unable to determine the " + "types of the Map. Please make this method or member generic so that the correct type can be determined."); } /** * Returns true if the given type is a Parameterized type with a raw type of Map. * * @param t The type. * @return True or false. */ public static boolean isGenericMap(Type t) { return t instanceof ParameterizedType && Map.class.isAssignableFrom((Class) ((ParameterizedType) t).getRawType()); } /** * Determines the final component type. This continues to loop over Collections until it hits a non-parameterized * type. * * @param type The parametrized type. * @param path The path to the type, used in exception message. * @return The final component type. */ public static Class<?> componentFinalType(Type type, String path) { while (!(type instanceof Class)) { type = componentType(type, path); } return (Class<?>) type; } /** * Determines the raw type of the type given. * * @param type The type. * @return The raw type. */ public static Class<?> rawType(Type type) { if (type instanceof ParameterizedType) { type = ((ParameterizedType) type).getRawType(); } else if (type instanceof GenericArrayType) { Class<?> componentType = (Class<?>) ((GenericArrayType) type).getGenericComponentType(); type = Array.newInstance(componentType, 0).getClass(); } return (Class<?>) type; } }