Java tutorial
/* * Copyright 2007-2012 Jiemamy Project and the Others. * * This file is part of Jiemamy. * * 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.jiemamy.utils.reflect; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.Maps; import org.apache.commons.lang.Validate; /** * Generics???? * * @version $Id$ * @author j5ik2o */ public final class GenericUtil { /** * {@code type}???? * <ul> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type * @param map ????????{@link Map} * @return {@code type}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualClass(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (Class.class.isInstance(type)) { return Class.class.cast(type); } if (ParameterizedType.class.isInstance(type)) { return getActualClass(ParameterizedType.class.cast(type).getRawType(), map); } if (WildcardType.class.isInstance(type)) { return getActualClass(WildcardType.class.cast(type).getUpperBounds()[0], map); } if (TypeVariable.class.isInstance(type)) { return getActualClass(map.get(TypeVariable.class.cast(type)), map); } if (GenericArrayType.class.isInstance(type)) { GenericArrayType genericArrayType = GenericArrayType.class.cast(type); Class<?> componentClass = getActualClass(genericArrayType.getGenericComponentType(), map); return Array.newInstance(componentClass, 0).getClass(); } return null; } /** * ??????????? * <ul> * <li>{@code type}??????????{@code null}??</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ?????? * @param map ????????{@link Map} * @return ????????? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualElementClassOfArray(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (GenericArrayType.class.isInstance(type) == false) { return null; } return getActualClass(GenericArrayType.class.cast(type).getGenericComponentType(), map); } /** * ??{@link Collection}???? * <ul> * <li>{@code type}???{@link Collection}?????{@code null} * ?</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ??{@link Collection} * @param map ????????{@link Map} * @return ??{@link Collection}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualElementClassOfCollection(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (isTypeOf(type, Collection.class) == false) { return null; } return getActualClass(getGenericParameter(type, 0), map); } /** * ??{@link List}????? * <ul> * <li>{@code type}???{@link List}?????{@code null}?</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ??{@link List} * @param map ????????{@link Map} * @return ??{@link List}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualElementClassOfList(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (isTypeOf(type, List.class) == false) { return null; } return getActualClass(getGenericParameter(type, 0), map); } /** * ??{@link Set}????? * <ul> * <li>{@code type}???{@link Set}?????{@code null}?</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ??{@link Set} * @param map ????????{@link Map} * @return ??{@link Set}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualElementClassOfSet(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (isTypeOf(type, Set.class) == false) { return null; } return getActualClass(getGenericParameter(type, 0), map); } /** * ??{@link Map}????? * <ul> * <li>???{@link Map}?????{@code null}?</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ??{@link Map} * @param map ????????{@link Map} * @return ??{@link Map}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualKeyClassOfMap(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (isTypeOf(type, Map.class) == false) { return null; } return getActualClass(getGenericParameter(type, 0), map); } /** * ??{@link Map}????? * <ul> * <li>{@code type}???{@link Map}?????{@code null}?</li> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type ??{@link Map} * @param map ????????{@link Map} * @return ??{@link Map}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getActualValueClassOfMap(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (isTypeOf(type, Map.class) == false) { return null; } return getActualClass(getGenericParameter(type, 1), map); } /** * ?????????? * <p> * {@code type}??????????{@code null}? * </p> * * @param type ?????? * @return ???????? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getElementTypeOfArray(Type type) { Validate.notNull(type); if (GenericArrayType.class.isInstance(type) == false) { return null; } return GenericArrayType.class.cast(type).getGenericComponentType(); } /** * ??{@link Collection}???? * <p> * {@code type}???{@link List}?????{@code null}? * </p> * * @param type ??{@link List} * @return ??{@link List}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getElementTypeOfCollection(Type type) { Validate.notNull(type); if (isTypeOf(type, Collection.class) == false) { return null; } return getGenericParameter(type, 0); } /** * ??{@link List}???? * <p> * {@code type}???{@link List}?????{@code null}? * </p> * * @param type ??{@link List} * @return ??{@link List}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getElementTypeOfList(Type type) { Validate.notNull(type); if (isTypeOf(type, List.class) == false) { return null; } return getGenericParameter(type, 0); } /** * ??{@link Set}???? * <p> * {@code type}???{@link Set}?????{@code null}? * </p> * * @param type ??{@link Set} * @return ??{@link Set}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getElementTypeOfSet(Type type) { Validate.notNull(type); if (isTypeOf(type, Set.class) == false) { return null; } return getGenericParameter(type, 0); } /** * {@code type}????? * <p> * {@code type}????????{@code null}? * </p> * * @param type * @return {@code type}??? * @throws IllegalArgumentException ?{@code null}??? */ public static Type[] getGenericParameter(Type type) { Validate.notNull(type); if (ParameterizedType.class.isInstance(type)) { return ParameterizedType.class.cast(type).getActualTypeArguments(); } if (GenericArrayType.class.isInstance(type)) { return getGenericParameter(GenericArrayType.class.cast(type).getGenericComponentType()); } return new Type[0]; } /** * ????{@code type}??? * <p> * {@code type}????????{@code null}? * </p> * * @param type * @param index ? * @return ????{@code type}? * @throws IllegalArgumentException ?{@code null}??? * @throws ArrayIndexOutOfBoundsException {@code index}???? */ public static Type getGenericParameter(Type type, int index) { Validate.notNull(type); if (ParameterizedType.class.isInstance(type) == false) { return null; } Type[] genericParameter = getGenericParameter(type); if (genericParameter == null) { return null; } return genericParameter[index]; } /** * ??{@link Map}???? * <p> * {@code type}???{@link Map}?????{@code null}? * </p> * * @param type ??{@link Map} * @return ??{@link Map}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getKeyTypeOfMap(Type type) { Validate.notNull(type); if (isTypeOf(type, Map.class) == false) { return null; } return getGenericParameter(type, 0); } /** * {@code type}??? * <ul> * <li>{@code type}?{@code Class}?????????</li> * <li>{@code type}??????????</li> * <li>{@code type}????(??)??</li> * <li>{@code type}??????????????</li> * <li>??????{@code null}?</li> * </ul> * * @param type * @return {@code type}? * @throws IllegalArgumentException ?{@code null}??? */ public static Class<?> getRawClass(Type type) { Validate.notNull(type); if (Class.class.isInstance(type)) { return Class.class.cast(type); } if (ParameterizedType.class.isInstance(type)) { ParameterizedType parameterizedType = ParameterizedType.class.cast(type); return getRawClass(parameterizedType.getRawType()); } if (WildcardType.class.isInstance(type)) { WildcardType wildcardType = WildcardType.class.cast(type); Type[] types = wildcardType.getUpperBounds(); return getRawClass(types[0]); } if (GenericArrayType.class.isInstance(type)) { GenericArrayType genericArrayType = GenericArrayType.class.cast(type); Class<?> rawClass = getRawClass(genericArrayType.getGenericComponentType()); return Array.newInstance(rawClass, 0).getClass(); } return null; } /** * ??(???)??????{@link Map}?? * * @param clazz ??(???) * @return ????????{@link Map} * @throws IllegalArgumentException ?{@code null}??? */ public static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> clazz) { Validate.notNull(clazz); Map<TypeVariable<?>, Type> map = Maps.newLinkedHashMap(); Class<?> superClass = clazz.getSuperclass(); Type superClassType = clazz.getGenericSuperclass(); if (superClass != null) { gatherTypeVariables(superClass, superClassType, map); } Class<?>[] interfaces = clazz.getInterfaces(); Type[] interfaceTypes = clazz.getGenericInterfaces(); for (int i = 0; i < interfaces.length; ++i) { gatherTypeVariables(interfaces[i], interfaceTypes[i], map); } return map; } /** * ??{@link Map}???? * <p> * {@code type}???{@link Map}?????{@code null}? * </p> * * @param type ??{@link Map} * @return ??{@link Map}?? * @throws IllegalArgumentException ?{@code null}??? */ public static Type getValueTypeOfMap(Type type) { Validate.notNull(type); if (isTypeOf(type, Map.class) == false) { return null; } return getGenericParameter(type, 1); } /** * {@code type}??{@code clazz}?????{@code true}? * ?????{@code false}?? * * @param type * @param clazz * @return {@code type}??{@code clazz}?????{@code true} * @throws IllegalArgumentException ?{@code null}??? */ public static boolean isTypeOf(Type type, Class<?> clazz) { Validate.notNull(clazz); if (Class.class.isInstance(type)) { return clazz.isAssignableFrom(Class.class.cast(type)); } if (ParameterizedType.class.isInstance(type)) { ParameterizedType parameterizedType = ParameterizedType.class.cast(type); return isTypeOf(parameterizedType.getRawType(), clazz); } return false; } /** * ??(???)???????{@code map}?? * * @param clazz * @param type * @param map ????????{@link Map} */ protected static void gatherTypeVariables(Class<?> clazz, Type type, Map<TypeVariable<?>, Type> map) { if (clazz == null) { return; } gatherTypeVariables(type, map); Class<?> superClass = clazz.getSuperclass(); Type superClassType = clazz.getGenericSuperclass(); if (superClass != null) { gatherTypeVariables(superClass, superClassType, map); } Class<?>[] interfaces = clazz.getInterfaces(); Type[] interfaceTypes = clazz.getGenericInterfaces(); for (int i = 0; i < interfaces.length; ++i) { gatherTypeVariables(interfaces[i], interfaceTypes[i], map); } } /** * ??(???)??????? {@code map}?? * * @param type * @param map ????????{@link Map} * @throws IllegalArgumentException ?{@code null}??? */ protected static void gatherTypeVariables(Type type, Map<TypeVariable<?>, Type> map) { Validate.notNull(type); Validate.notNull(map); if (ParameterizedType.class.isInstance(type)) { ParameterizedType parameterizedType = ParameterizedType.class.cast(type); TypeVariable<?>[] typeVariables = GenericDeclaration.class.cast(parameterizedType.getRawType()) .getTypeParameters(); Type[] actualTypes = parameterizedType.getActualTypeArguments(); for (int i = 0; i < actualTypes.length; ++i) { map.put(typeVariables[i], actualTypes[i]); } } } private GenericUtil() { } }