Java/Reflection/Generic
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 All information about a class
- 2 A wrapper around reflection to resolve generics.
- 3 Class Declaration Spy
- 4 Generic Class reflection
- 5 Generic method reflection
- 6 Get all implemented generic interfaces
- 7 Get all interface and object classes that are generalizations of the provided class
- 8 get Exception Types and get Generic Exception Types
- 9 Get field type and generic type by field name
- 10 get Generic Parameter Types from Constructor
- 11 Get Generic Super class
- 12 get Parameter Types and get Generic ParameterTypes
- 13 get Return Type and get Generic Return Type
- 14 If right-hand side type may be assigned to the left-hand side type following the Java generics rules.
All information about a class
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
enum ClassMember {
CONSTRUCTOR, FIELD, METHOD, CLASS, ALL
}
public class ClassSpy {
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
out.format("Class:%n %s%n%n", c.getCanonicalName());
Package p = c.getPackage();
out.format("Package:%n %s%n%n", (p != null ? p.getName()
: "-- No Package --"));
for (int i = 1; i < args.length; i++) {
switch (ClassMember.valueOf(args[i])) {
case CONSTRUCTOR:
printMembers(c.getConstructors(), "Constructor");
break;
case FIELD:
printMembers(c.getFields(), "Fields");
break;
case METHOD:
printMembers(c.getMethods(), "Methods");
break;
case CLASS:
printClasses(c);
break;
case ALL:
printMembers(c.getConstructors(), "Constuctors");
printMembers(c.getFields(), "Fields");
printMembers(c.getMethods(), "Methods");
printClasses(c);
break;
default:
assert false;
}
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
private static void printMembers(Member[] mbrs, String s) {
out.format("%s:%n", s);
for (Member mbr : mbrs) {
if (mbr instanceof Field)
out.format(" %s%n", ((Field) mbr).toGenericString());
else if (mbr instanceof Constructor)
out.format(" %s%n", ((Constructor) mbr).toGenericString());
else if (mbr instanceof Method)
out.format(" %s%n", ((Method) mbr).toGenericString());
}
if (mbrs.length == 0)
out.format(" -- No %s --%n", s);
out.format("%n");
}
private static void printClasses(Class<?> c) {
out.format("Classes:%n");
Class<?>[] clss = c.getClasses();
for (Class<?> cls : clss)
out.format(" %s%n", cls.getCanonicalName());
if (clss.length == 0)
out.format(" -- No member interfaces, classes, or enums --%n");
out.format("%n");
}
}
A wrapper around reflection to resolve generics.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A wrapper around reflection to resolve generics.
*
* @author Simone Gianni <simoneg@apache.org>
*/
// TODO there is vast space for caching and optimizations here!
public class GenericClass {
private Class<?> myclass = null;
private Map<String, Class<?>> genericMap = new HashMap<String, Class<?>>();
private Map<String, String> reverseIntermediate = new HashMap<String, String>();
public static GenericClass forClass(Class<?> concrete) {
return new GenericClass(concrete);
}
public static GenericClass forField(Field field) {
return forGenericType(field.getGenericType());
}
public static GenericClass forReturnType(Method method) {
return forGenericType(method.getGenericReturnType());
}
public static GenericClass forParameter(Method method, int index) {
return forGenericType(method.getGenericParameterTypes()[index]);
}
public static GenericClass forGenericType(Type type) {
if (type instanceof Class) {
return forClass((Class<?>) type);
} else if (type instanceof ParameterizedType) {
return new GenericClass((ParameterizedType) type);
} else {
return forClass(Object.class);
// throw new MagmaException("Dont know how to build a GenericClass out of
// {0}", type.getClass());
}
}
private GenericClass(Class<?> concrete) {
TypeVariable<?>[] parameters = concrete.getTypeParameters();
// if (parameters.length > 0) throw new MagmaException("Cannot parse {0}, it
// is a generic class, use a concrete class instead", concrete);
myclass = concrete;
recurse(concrete);
coalesceMap();
}
private GenericClass(ParameterizedType type) {
myclass = (Class<?>) type.getRawType();
recurse(myclass, myclass, type);
coalesceMap();
}
private void coalesceMap() {
int cnt = reverseIntermediate.size();
while (reverseIntermediate.size() > 0 && cnt > 0) {
for (Iterator<Map.Entry<String, String>> iterator = this.reverseIntermediate.entrySet()
.iterator(); iterator.hasNext();) {
Map.Entry<String, String> entry = iterator.next();
String target = entry.getValue();
String search = entry.getKey();
Class<?> clazz = genericMap.get(search);
if (clazz == null)
continue;
if (genericMap.containsKey(target))
throw new RuntimeException(
"Impossible situation, it"s a bug : {0} generic is both {1} and bound to {2}"
+ target + genericMap.get(target) + search);
genericMap.put(target, clazz);
iterator.remove();
}
cnt--;
}
if (reverseIntermediate.size() > 0) {
for (Iterator<Map.Entry<String, String>> iterator = this.reverseIntermediate.entrySet()
.iterator(); iterator.hasNext();) {
Map.Entry<String, String> entry = iterator.next();
String target = entry.getValue();
String search = entry.getKey();
Class<?> clazz = genericMap.get(search);
if (clazz == null)
clazz = Object.class;
if (genericMap.containsKey(target))
throw new RuntimeException(
"Impossible situation, it"s a bug : {0} generic is both {1} and bound to {2}"+
target+ genericMap.get(target)+ search);
genericMap.put(target, clazz);
}
}
}
public Class<?> getBaseClass() {
return this.myclass;
}
private void recurse(Class<?> clazz, Class<?> simplesup, ParameterizedType partype) {
Type[] typeArguments = partype.getActualTypeArguments();
TypeVariable<?>[] parameters = simplesup.getTypeParameters();
for (int i = 0; i < typeArguments.length; i++) {
if (typeArguments[i] instanceof Class) {
genericMap.put(simplesup.getName() + "--" + parameters[i].getName(),
(Class) typeArguments[i]);
} else if (typeArguments[i] instanceof TypeVariable) {
reverseIntermediate.put(clazz.getName() + "--"
+ ((TypeVariable<?>) typeArguments[i]).getName(), simplesup.getName() + "--"
+ parameters[i].getName());
}
}
recurse(simplesup);
}
private void recurse(Class<?> clazz) {
Type supclass = clazz.getGenericSuperclass();
Class simplesup = clazz.getSuperclass();
if (supclass == null)
return;
if (supclass instanceof ParameterizedType) {
recurse(clazz, simplesup, (ParameterizedType) supclass);
} else {
recurse(simplesup);
}
}
/**
* Return real, "generics dereferenced", parameter types for the given method.
*
* @param method
* The method to analyze
* @return The real classes, dereferencing generics
*/
public GenericClass[] getParameterTypes(Method method) {
Class<?> declaring = method.getDeclaringClass();
String declname = declaring.getName();
Type[] parameterTypes = method.getGenericParameterTypes();
GenericClass[] ret = new GenericClass[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Type type = parameterTypes[i];
if (type instanceof Class) {
ret[i] = forClass((Class<?>) type);
} else if (type instanceof TypeVariable) {
String name = ((TypeVariable<?>) type).getName();
Class<?> sub = genericMap.get(declname + "--" + name);
if (sub == null)
sub = Object.class;
ret[i] = forClass(sub);
} else {
ret[i] = forGenericType(type);
}
}
return ret;
}
public GenericClass resolveType(Type type) {
if (type instanceof Class) {
return forClass((Class<?>) type);
} else if (type instanceof TypeVariable) {
GenericDeclaration gd = ((TypeVariable<?>) type).getGenericDeclaration();
Class<?> acclass = null;
if (gd instanceof Class) {
acclass = (Class<?>) gd;
} else if (gd instanceof Method) {
acclass = ((Method) gd).getDeclaringClass();
} else if (gd instanceof Constructor) {
acclass = ((Constructor<?>) gd).getDeclaringClass();
}
String name = ((TypeVariable<?>) type).getName();
return forClass(genericMap.get(acclass.getName() + "--" + name));
} else {
return forGenericType(type);
}
}
/**
* Search for all occurrencies of a specific method.
* <p>
* The type parameters passed in may be Class or null. If they are null, that
* means that we don"t know which class they should be, if they are a class,
* that means we are searching for that class, and the comparison is made on
* dereferenced generics.
* </p>
* <p>
* Specifying no parameter types explicitly means "a method without
* parameters".
* </p>
*
* @param name
* The name of the method
* @param parameterTypes
* The types of the parameters
* @return A list of {@link MethodDef}, ordered with methods from current
* class first, then method from superclass and so on.
*/
public List<MethodDef> findMethods(String name, Class<?>... parameterTypes) {
List<MethodDef> founds = new ArrayList<MethodDef>();
Class<?> current = myclass;
while (current != null) {
Method[] methods = current.getDeclaredMethods();
for (Method method : methods) {
if (!method.isBridge() && !method.isSynthetic() && method.getName().equals(name)) {
Type[] types = method.getGenericParameterTypes();
if (types.length == parameterTypes.length) {
GenericClass[] genericClasses = getParameterTypes(method);
Class<?>[] classes = toRawClasses(genericClasses);
boolean good = true;
for (int i = 0; i < types.length; i++) {
if (parameterTypes[i] != null) {
if (!classes[i].equals(parameterTypes[i])) {
good = false;
break;
}
}
}
if (good) {
MethodDef def = new MethodDef(method, genericClasses);
if (!founds.contains(def))
founds.add(def);
}
}
}
}
current = current.getSuperclass();
}
return founds;
}
public static Class<?>[] toRawClasses(GenericClass[] genclasses) {
Class<?>[] ret = new Class<?>[genclasses.length];
for (int i = 0; i < genclasses.length; i++) {
ret[i] = genclasses[i].getBaseClass();
}
return ret;
}
/**
* Search for all methods having that name, no matter which parameter they
* take.
*
* @param name
* The name of the methods
* @return A list of {@link MethodDef}, ordered with methods from current
* class first, then method from superclass and so on.
*/
public List<MethodDef> findAllMethods(String name) {
List<MethodDef> founds = new ArrayList<MethodDef>();
Class<?> current = myclass;
while (current != null) {
Method[] methods = current.getDeclaredMethods();
for (Method method : methods) {
if (!method.isBridge() && !method.isSynthetic() && method.getName().equals(name)) {
MethodDef def = new MethodDef(method);
if (!founds.contains(def))
founds.add(def);
}
}
current = current.getSuperclass();
}
return founds;
}
public List<MethodDef> getMethods() {
List<MethodDef> founds = new ArrayList<MethodDef>();
Class<?> current = myclass;
while (current != null) {
Method[] methods = current.getDeclaredMethods();
for (Method method : methods) {
if (!method.isBridge() && !method.isSynthetic()) {
MethodDef def = new MethodDef(method);
if (!founds.contains(def))
founds.add(def);
}
}
current = current.getSuperclass();
}
return founds;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof GenericClass))
return false;
GenericClass oth = (GenericClass) obj;
return this.getBaseClass().equals(oth.getBaseClass());
}
public class MethodDef {
private Method method = null;
private GenericClass[] params = null;
MethodDef(Method m) {
this.method = m;
}
MethodDef(Method m, GenericClass[] params) {
this.method = m;
this.params = params;
}
public String getName() {
return this.method.getName();
}
public Method getBaseMethod() {
return this.method;
}
public GenericClass[] getParameterTypes() {
if (this.params == null) {
this.params = GenericClass.this.getParameterTypes(method);
}
return this.params;
}
public GenericClass getReturnType() {
return resolveType(method.getGenericReturnType());
}
@Override
public boolean equals(Object other) {
if (!(other instanceof MethodDef))
return false;
MethodDef oth = (MethodDef) other;
return (method.getName().equals(oth.method.getName()))
&& (Arrays.equals(getParameterTypes(), oth.getParameterTypes()));
}
public Class<?> getDeclaringClass() {
return this.method.getDeclaringClass();
}
}
}
Class Declaration Spy
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
public class ClassDeclarationSpy {
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
out.format("Class:%n %s%n%n", c.getCanonicalName());
out.format("Modifiers:%n %s%n%n", Modifier.toString(c.getModifiers()));
out.format("Type Parameters:%n");
TypeVariable[] tv = c.getTypeParameters();
if (tv.length != 0) {
out.format(" ");
for (TypeVariable t : tv)
out.format("%s ", t.getName());
out.format("%n%n");
} else {
out.format(" -- No Type Parameters --%n%n");
}
out.format("Implemented Interfaces:%n");
Type[] intfs = c.getGenericInterfaces();
if (intfs.length != 0) {
for (Type intf : intfs)
out.format(" %s%n", intf.toString());
out.format("%n");
} else {
out.format(" -- No Implemented Interfaces --%n%n");
}
out.format("Inheritance Path:%n");
List<Class> l = new ArrayList<Class>();
printAncestor(c, l);
if (l.size() != 0) {
for (Class<?> cl : l)
out.format(" %s%n", cl.getCanonicalName());
out.format("%n");
} else {
out.format(" -- No Super Classes --%n%n");
}
out.format("Annotations:%n");
Annotation[] ann = c.getAnnotations();
if (ann.length != 0) {
for (Annotation a : ann)
out.format(" %s%n", a.toString());
out.format("%n");
} else {
out.format(" -- No Annotations --%n%n");
}
// production code should handle this exception more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
private static void printAncestor(Class<?> c, List<Class> l) {
Class<?> ancestor = c.getSuperclass();
if (ancestor != null) {
l.add(ancestor);
printAncestor(ancestor, l);
}
}
}
Generic Class reflection
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class Cls {
private Cls() {
}
}
public class ClassTrouble {
public static void main(String... args) {
try {
Class<?> c = Class.forName("Cls");
c.newInstance(); // InstantiationException
// production code should handle these exceptions more gracefully
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
Generic method reflection
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.lang.reflect.Method;
public class MethodTrouble<T> {
public void lookup(T t) {
}
public void find(Integer i) {
}
public static void main(String... args) {
try {
String mName = args[0];
Class cArg = Class.forName(args[1]);
Class<?> c = (new MethodTrouble<Integer>()).getClass();
Method m = c.getMethod(mName, cArg);
System.out.format("Found:%n %s%n", m.toGenericString());
// production code should handle these exceptions more gracefully
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
Get all implemented generic interfaces
import java.lang.reflect.Type;
import javax.xml.transform.sax.SAXSource;
public class GetGenericInterfaces {
public static void main(String[] args) {
try {
Type[] ts = SAXSource.class.getGenericInterfaces();
for (int i = 0; i < ts.length; i++) {
System.out.println(ts[i]);
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
Get all interface and object classes that are generalizations of the provided class
/*
* The contents of this file are subject to the Sapient Public License
* Version 1.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://carbon.sf.net/License.html.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is The Carbon Component Framework.
*
* The Initial Developer of the Original Code is Sapient Corporation
*
* Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
*
* Copyright 2003 Sapient
* @since carbon 2.0
* @author Greg Hinkle, March 2003
* @version $Revision: 1.5 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)
*/
public class ClassUtil {
/**
* Retrieves all interfaces implemented by a specified interface
* including all recursively extended interfaces and the classes supplied
* int the parameter.
* @param childInterfaces a set of interfaces
* @return Class[] an array of interfaces that includes those specifed
* in childInterfaces plus all of those interfaces" super interfaces
*/
public static Class[] getSuperInterfaces(Class[] childInterfaces) {
List allInterfaces = new ArrayList();
for (int i = 0; i < childInterfaces.length; i++) {
allInterfaces.add(childInterfaces[i]);
allInterfaces.addAll(
Arrays.asList(
getSuperInterfaces(childInterfaces[i].getInterfaces())));
}
return (Class[]) allInterfaces.toArray(new Class[allInterfaces.size()]);
}
/**
* Builds an <b>unordered</b> set of all interface and object classes that
* are generalizations of the provided class.
* @param classObject the class to find generalization of.
* @return a Set of class objects.
*/
public static Set getGeneralizations(Class classObject) {
Set generalizations = new HashSet();
generalizations.add(classObject);
Class superClass = classObject.getSuperclass();
if (superClass != null) {
generalizations.addAll(getGeneralizations(superClass));
}
Class[] superInterfaces = classObject.getInterfaces();
for (int i = 0; i < superInterfaces.length; i++) {
Class superInterface = superInterfaces[i];
generalizations.addAll(getGeneralizations(superInterface));
}
return generalizations;
}
}
get Exception Types and get Generic Exception Types
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class MethodSpy {
private static final String fmt = "%24s: %s%n";
// for the morbidly curious
<E extends RuntimeException> void genericThrow() throws E {
}
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods) {
if (!m.getName().equals(args[1])) {
continue;
}
out.format("%s%n", m.toGenericString());
Class<?>[] xType = m.getExceptionTypes();
Type[] gxType = m.getGenericExceptionTypes();
for (int i = 0; i < xType.length; i++) {
out.format(fmt, "ExceptionType", xType[i]);
out.format(fmt, "GenericExceptionType", gxType[i]);
}
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
Get field type and generic type by field name
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.lang.reflect.Field;
import java.util.List;
public class FieldSpy<T> {
public boolean[][] b = { { false, false }, { true, true } };
public String name = "Alice";
public List<Integer> list;
public T val;
public static void main(String... args) {
try {
Class<?> c = Class.forName("FieldSpy");
Field f = c.getField("name");
System.out.format("Type: %s%n", f.getType());
System.out.format("GenericType: %s%n", f.getGenericType());
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
} catch (NoSuchFieldException x) {
x.printStackTrace();
}
}
}
get Generic Parameter Types from Constructor
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
public class ConstructorSift {
public static void main(String... args) {
try {
Class<?> cArg = Class.forName(args[1]);
Class<?> c = Class.forName(args[0]);
Constructor[] allConstructors = c.getDeclaredConstructors();
for (Constructor ctor : allConstructors) {
Class<?>[] pType = ctor.getParameterTypes();
for (int i = 0; i < pType.length; i++) {
if (pType[i].equals(cArg)) {
out.format("%s%n", ctor.toGenericString());
Type[] gpType = ctor.getGenericParameterTypes();
for (int j = 0; j < gpType.length; j++) {
char ch = (pType[j].equals(cArg) ? "*" : " ");
out.format("%7c%s[%d]: %s%n", ch, "GenericParameterType", j,
gpType[j]);
}
break;
}
}
}
// production code should handle this exception more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
Get Generic Super class
import java.lang.reflect.Type;
import java.util.ArrayList;
import javax.xml.transform.sax.SAXSource;
public class GetGenericSuperclass {
public static void main(String[] args) {
try {
Class< ? super SAXSource> ts = SAXSource.class.getSuperclass();
System.out.println(ts);
} catch (SecurityException e) {
e.printStackTrace();
}
try {
Type t = ArrayList.class.getGenericSuperclass();
System.out.println(t);
} catch (SecurityException e) {
e.printStackTrace();
}
try {
Class[] is = SAXSource.class.getInterfaces();
for(int i=0;i<is.length;i++){
System.out.println(is[i]);
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
get Parameter Types and get Generic ParameterTypes
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class MethodSpy {
private static final String fmt = "%24s: %s%n";
// for the morbidly curious
<E extends RuntimeException> void genericThrow() throws E {
}
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods) {
if (!m.getName().equals(args[1])) {
continue;
}
out.format("%s%n", m.toGenericString());
out.format(fmt, "ReturnType", m.getReturnType());
out.format(fmt, "GenericReturnType", m.getGenericReturnType());
Class<?>[] pType = m.getParameterTypes();
Type[] gpType = m.getGenericParameterTypes();
for (int i = 0; i < pType.length; i++) {
out.format(fmt, "ParameterType", pType[i]);
out.format(fmt, "GenericParameterType", gpType[i]);
}
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
get Return Type and get Generic Return Type
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import static java.lang.System.out;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class MethodSpy {
private static final String fmt = "%24s: %s%n";
// for the morbidly curious
<E extends RuntimeException> void genericThrow() throws E {
}
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods) {
if (!m.getName().equals(args[1])) {
continue;
}
out.format("%s%n", m.toGenericString());
out.format(fmt, "ReturnType", m.getReturnType());
out.format(fmt, "GenericReturnType", m.getGenericReturnType());
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
If right-hand side type may be assigned to the left-hand side type following the Java generics rules.
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
import java.beans.Introspector;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.Assert;
import sun.rmi.runtime.Log;
/**
* Utility to work with Java 5 generic type parameters.
* Mainly for internal use within the framework.
*
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @since 2.0.7
*/
public abstract class TypeUtils {
/**
* Check if the right-hand side type may be assigned to the left-hand side
* type following the Java generics rules.
* @param lhsType the target type
* @param rhsType the value type that should be assigned to the target type
* @return true if rhs is assignable to lhs
*/
public static boolean isAssignable(Type lhsType, Type rhsType) {
if (lhsType.equals(rhsType)) {
return true;
}
if (lhsType instanceof Class && rhsType instanceof Class) {
return ClassUtils.isAssignable((Class) lhsType, (Class) rhsType);
}
if (lhsType instanceof ParameterizedType && rhsType instanceof ParameterizedType) {
return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType);
}
if (lhsType instanceof WildcardType) {
return isAssignable((WildcardType) lhsType, rhsType);
}
return false;
}
private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) {
if (lhsType.equals(rhsType)) {
return true;
}
Type[] lhsTypeArguments = lhsType.getActualTypeArguments();
Type[] rhsTypeArguments = rhsType.getActualTypeArguments();
if (lhsTypeArguments.length != rhsTypeArguments.length) {
return false;
}
for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) {
Type lhsArg = lhsTypeArguments[i];
Type rhsArg = rhsTypeArguments[i];
if (!lhsArg.equals(rhsArg) &&
!(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) {
return false;
}
}
return true;
}
private static boolean isAssignable(WildcardType lhsType, Type rhsType) {
Type[] upperBounds = lhsType.getUpperBounds();
Type[] lowerBounds = lhsType.getLowerBounds();
for (int size = upperBounds.length, i = 0; i < size; ++i) {
if (!isAssignable(upperBounds[i], rhsType)) {
return false;
}
}
for (int size = lowerBounds.length, i = 0; i < size; ++i) {
if (!isAssignable(rhsType, lowerBounds[i])) {
return false;
}
}
return true;
}
}
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
/**
* Miscellaneous class utility methods. Mainly for internal use within the
* framework; consider Jakarta"s Commons Lang for a more comprehensive suite
* of class utilities.
*
* @author Keith Donald
* @author Rob Harrop
* @author Juergen Hoeller
* @since 1.1
* @see TypeUtils
* @see ReflectionUtils
*/
abstract class ClassUtils {
/** Suffix for array class names: "[]" */
public static final String ARRAY_SUFFIX = "[]";
/** Prefix for internal array class names: "[L" */
private static final String INTERNAL_ARRAY_PREFIX = "[L";
/** The package separator character "." */
private static final char PACKAGE_SEPARATOR = ".";
/** The inner class separator character "$" */
private static final char INNER_CLASS_SEPARATOR = "$";
/** The CGLIB class separator character "$$" */
public static final String CGLIB_CLASS_SEPARATOR = "$$";
/** The ".class" file suffix */
public static final String CLASS_FILE_SUFFIX = ".class";
/**
* Map with primitive wrapper type as key and corresponding primitive
* type as value, for example: Integer.class -> int.class.
*/
private static final Map primitiveWrapperTypeMap = new HashMap(8);
/**
* Map with primitive type name as key and corresponding primitive
* type as value, for example: "int" -> "int.class".
*/
private static final Map primitiveTypeNameMap = new HashMap(16);
static {
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
primitiveWrapperTypeMap.put(Byte.class, byte.class);
primitiveWrapperTypeMap.put(Character.class, char.class);
primitiveWrapperTypeMap.put(Double.class, double.class);
primitiveWrapperTypeMap.put(Float.class, float.class);
primitiveWrapperTypeMap.put(Integer.class, int.class);
primitiveWrapperTypeMap.put(Long.class, long.class);
primitiveWrapperTypeMap.put(Short.class, short.class);
Set primitiveTypeNames = new HashSet(16);
primitiveTypeNames.addAll(primitiveWrapperTypeMap.values());
primitiveTypeNames.addAll(Arrays.asList(new Class[] {
boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class}));
for (Iterator it = primitiveTypeNames.iterator(); it.hasNext();) {
Class primitiveClass = (Class) it.next();
primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass);
}
}
/**
* Check if the right-hand side type may be assigned to the left-hand side
* type, assuming setting by reflection. Considers primitive wrapper
* classes as assignable to the corresponding primitive types.
* @param lhsType the target type
* @param rhsType the value type that should be assigned to the target type
* @return if the target type is assignable from the value type
* @see TypeUtils#isAssignable
*/
public static boolean isAssignable(Class lhsType, Class rhsType) {
return (lhsType.isAssignableFrom(rhsType) ||
lhsType.equals(primitiveWrapperTypeMap.get(rhsType)));
}
}