001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.util.reflection; 031 032import java.lang.reflect.Array; 033import java.lang.reflect.GenericArrayType; 034import java.lang.reflect.Method; 035import java.lang.reflect.Modifier; 036import java.lang.reflect.ParameterizedType; 037import java.lang.reflect.Type; 038import java.lang.reflect.TypeVariable; 039import java.util.ArrayList; 040import java.util.HashMap; 041import java.util.List; 042import java.util.Map; 043 044/** 045 * Utility methods for java reflection 046 * 047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 048 * 049 */ 050public class ReflectionUtils { 051 /** 052 * Test if a class has a "public static main(String [] args)" method 053 * @param clz the class 054 * @return true if main method exists; false otherwise 055 */ 056 public static boolean hasMain(Class<?> clz) { 057 return getMain(clz) != null; 058 } 059 060 /** 061 * Get the "public static main(String [] args)" method of the class, 062 * or null if it doesn't have one. 063 * 064 * @param clz the class 065 * @return the main method, or null if it doesn't exist 066 */ 067 public static Method getMain(Class<?> clz) { 068 try { 069 Method m = clz.getMethod("main", String[].class); 070 071 if (Modifier.isPublic(m.getModifiers()) && 072 Modifier.isStatic(m.getModifiers())) 073 return m; 074 } catch (NoSuchMethodException e1) { 075 //do nothing 076 } 077 return null; 078 } 079 080 /** 081 * Get the underlying class for a type, or null if the type is a variable 082 * type. 083 * 084 * @param type 085 * the type 086 * @return the underlying class 087 */ 088 public static Class<?> getClass(Type type) { 089 if (type instanceof Class) { 090 return (Class<?>) type; 091 } else if (type instanceof ParameterizedType) { 092 return getClass(((ParameterizedType) type).getRawType()); 093 } else if (type instanceof GenericArrayType) { 094 Type componentType = ((GenericArrayType) type) 095 .getGenericComponentType(); 096 Class<?> componentClass = getClass(componentType); 097 if (componentClass != null) { 098 return Array.newInstance(componentClass, 0).getClass(); 099 } else { 100 return null; 101 } 102 } else { 103 return null; 104 } 105 } 106 107 /** 108 * Get the actual type arguments a child class has used to extend a generic 109 * base class. An implementation kindly described in this blog post: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 110 * by 111 * @param <T> The type of the base class 112 * 113 * @param baseClass 114 * the base class 115 * @param childClass 116 * the child class 117 * @return a list of the raw classes for the actual type arguments. 118 */ 119 public static <T> List<Class<?>> getTypeArguments(Class<T> baseClass, Class<? extends T> childClass) { 120 Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); 121 Type type = childClass; 122 // start walking up the inheritance hierarchy until we hit baseClass 123 while (!getClass(type).equals(baseClass)) { 124 if (type instanceof Class) { 125 // there is no useful information for us in raw types, so just 126 // keep going. 127 type = ((Class<?>) type).getGenericSuperclass(); 128 } else { 129 ParameterizedType parameterizedType = (ParameterizedType) type; 130 Class<?> rawType = (Class<?>) parameterizedType.getRawType(); 131 132 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 133 TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); 134 for (int i = 0; i < actualTypeArguments.length; i++) { 135 resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); 136 } 137 138 if (!rawType.equals(baseClass)) { 139 type = rawType.getGenericSuperclass(); 140 } 141 } 142 } 143 144 // finally, for each actual type argument provided to baseClass, 145 // determine (if possible) 146 // the raw class for that type argument. 147 Type[] actualTypeArguments; 148 if (type instanceof Class) { 149 actualTypeArguments = ((Class<?>) type).getTypeParameters(); 150 } else { 151 actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); 152 } 153 List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); 154 // resolve types by chasing down type variables. 155 for (Type baseType : actualTypeArguments) { 156 while (resolvedTypes.containsKey(baseType)) { 157 baseType = resolvedTypes.get(baseType); 158 } 159 typeArgumentsAsClasses.add(getClass(baseType)); 160 } 161 return typeArgumentsAsClasses; 162 } 163}