1.What
i want to get generic class method return type and method parameters and parameters class type by dynamic java reflect.
For example code:
now, i have one UserService instance, and have it's selectOne method of java.lang.reflect.Method, by rpc proxy, i have the T result json string. how i unmarsher it to UserDomain?
2. how
Thanks google search one reference result, i have GenericClassHelper(make small change from GenericClass):
How to used it:
Last:
Thanks for your readed
Reference:
A wrapper around reflection to resolve generics. : Generic « Reflection « Java
i want to get generic class method return type and method parameters and parameters class type by dynamic java reflect.
For example code:
////////////////////////////////////////////////////////////class UserDomain {}public interface BaseService<T> {T selectOne(T record);}public interface UserService extends BaseService<UserDomain> { }public interface MyMapper<T> { }public interface UserDomainMapper extends MyMapper<UserDomain> { }public abstract class BaseServiceImpl<MAP extends MyMapper<T>,T extends Object> implements BaseService<T> {@Overridepublic T selectOne(T record){return ...;}}@Service("userService")public class UserServiceImpl extends BaseServiceImpl<UserDomainMapper,UserDomain> implements UserService { }////////////////////////////////////////////////////////////
now, i have one UserService instance, and have it's selectOne method of java.lang.reflect.Method, by rpc proxy, i have the T result json string. how i unmarsher it to UserDomain?
2. how
Thanks google search one reference result, i have GenericClassHelper(make small change from GenericClass):
package com.myzc98.server.helper;
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 GenericClassHelper {
private Class<?> myclass = null;
private Map<String, Class<?>> genericMap = new HashMap<String, Class<?>>();
private Map<String, String> reverseIntermediate = new HashMap<String, String>();
private static void warnMsg(String msg) {
// String msg = "Impossible situation, it's a bug : {0} generic is both {1} and bound to {2}" + target + genericMap.get(target) + search;
// System.out.println(msg);
// throw new RuntimeException(msg);
}
public static GenericClassHelper forClass(Class<?> concrete) {
return new GenericClassHelper(concrete);
}
public static GenericClassHelper forField(Field field) {
return forGenericType(field.getGenericType());
}
public static GenericClassHelper forReturnType(Method method) {
return forGenericType(method.getGenericReturnType());
}
public static GenericClassHelper forParameter(Method method, int index) {
return forGenericType(method.getGenericParameterTypes()[index]);
}
public static GenericClassHelper forGenericType(Type type) {
if (type instanceof Class) {
return forClass((Class<?>) type);
} else if (type instanceof ParameterizedType) {
return new GenericClassHelper((ParameterizedType) type);
} else {
return forClass(Object.class);
// throw new MagmaException("Dont know how to build a GenericClassHelper out of
// {0}", type.getClass());
}
}
private GenericClassHelper(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 GenericClassHelper(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))
warnMsg("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))
warnMsg("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) {
String target = clazz.getName() + "--" + simplesup.getName() + "--" + parameters[i].getName();
if (genericMap.containsKey(target))
warnMsg("Impossible situation, it's a bug : {0} generic is both {1}"+ target+ genericMap.get(target));
genericMap.put(target, (Class<?>) typeArguments[i]);
} else if (typeArguments[i] instanceof TypeVariable) {
String target = clazz.getName() + "--" + ((TypeVariable<?>) typeArguments[i]).getName();
if (reverseIntermediate.containsKey(target))
warnMsg("Impossible situation, it's a bug : {0} generic is both {1}"+ target+ reverseIntermediate.get(target));
reverseIntermediate.put(target, simplesup.getName() + "--"
+ parameters[i].getName());
}
}
recurse(simplesup);
}
private void recurse(Class<?> clazz) {
recurse(clazz, null);
}
private void recurse(Class<?> clazz, Class<?> parent) {
if(parent == null) {
parent = clazz;
}
Type[] types = clazz.getGenericInterfaces();
for(Type t : types) {
if(t instanceof ParameterizedType ) {
recurse(clazz, (Class<?>)((ParameterizedType) t).getRawType(), (ParameterizedType) t);
if(!parent.equals(clazz))
recurse(parent, (Class<?>)((ParameterizedType) t).getRawType(), (ParameterizedType) t);
}else if(t instanceof TypeVariable ) {
recurse(clazz, (Class<?>)t, (ParameterizedType) t);
if(!parent.equals(clazz))
recurse(parent, (Class<?>)t, (ParameterizedType) t);
}else {
recurse((Class<?>)t, clazz);
}
}
Type supclass = clazz.getGenericSuperclass();
Class<?> simplesup = clazz.getSuperclass();
if (supclass == null)
return;
if (supclass instanceof ParameterizedType) {
recurse(clazz, simplesup, (ParameterizedType) supclass);
if(!parent.equals(clazz))
recurse(parent, simplesup, (ParameterizedType) supclass);
} else {
recurse(parent, simplesup);
if(!parent.equals(simplesup))
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 GenericClassHelper[] getParameterTypes(Method method) {
Class<?> declaring = method.getDeclaringClass();
String declname = declaring.getName();
Type[] parameterTypes = method.getGenericParameterTypes();
GenericClassHelper[] ret = new GenericClassHelper[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 GenericClassHelper resolveType(Class<?> cls, 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();
Class<?> objClass = genericMap.get(cls.getName() + "--" + acclass.getName() + "--" + name);
if(objClass != null)
return forClass(objClass);
objClass = genericMap.get(cls.getName() + "--" + name);
if(objClass != null)
return forClass(objClass);
objClass = genericMap.get(acclass.getName() + "--" + name);
return forClass(objClass);
} 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>();
findMethods(founds, myclass, name, parameterTypes);
return founds;
}
private void findMethods(List<MethodDef> founds, Class<?> current, String name, Class<?>... parameterTypes) {
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) {
GenericClassHelper[] GenericClassHelperes = getParameterTypes(method);
Class<?>[] classes = toRawClasses(GenericClassHelperes);
boolean good = true;
for (int i = 0; i < types.length; i++) {
if (parameterTypes[i] != null) {
if (!classes[i].equals(parameterTypes[i])) {
if (!Object.class.equals(parameterTypes[i])) {
good = false;
break;
}
}
}
}
if (good) {
MethodDef def = new MethodDef(method, GenericClassHelperes);
if (!founds.contains(def))
founds.add(def);
}
}
}
}
Class<?>[] classes = current.getInterfaces();
for(Class<?> cls : classes) {
findMethods(founds, cls, name, parameterTypes);
}
current = current.getSuperclass();
}
}
public static Class<?>[] toRawClasses(GenericClassHelper[] 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>();
findAllMethods(founds, myclass, name);
return founds;
}
private void findAllMethods(List<MethodDef> founds, Class<?> current, String name) {
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);
}
}
Class<?>[] classes = current.getInterfaces();
for(Class<?> cls : classes) {
findAllMethods(founds, cls, name);
}
current = current.getSuperclass();
}
}
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 GenericClassHelper))
return false;
GenericClassHelper oth = (GenericClassHelper) obj;
return this.getBaseClass().equals(oth.getBaseClass());
}
public class MethodDef {
private Method method = null;
private GenericClassHelper[] params = null;
MethodDef(Method m) {
this.method = m;
}
MethodDef(Method m, GenericClassHelper[] params) {
this.method = m;
this.params = params;
}
public String getName() {
return this.method.getName();
}
public Method getBaseMethod() {
return this.method;
}
public GenericClassHelper[] getParameterTypes() {
if (this.params == null) {
this.params = GenericClassHelper.this.getParameterTypes(method);
}
return this.params;
}
public GenericClassHelper getReturnType() {
return getReturnType(myclass);
}
public GenericClassHelper getReturnType(Class<?> instanceClass) {
return resolveType(instanceClass, 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();
}
}
}
How to used it:
static void testGeneric(Class<?> beanCls, String methodName) {
GenericClassHelper v1 = GenericClassHelper.forClass(beanCls);
java.util.List<GenericClassHelper.MethodDef> methods = v1.findAllMethods(methodName);
GenericClassHelper.MethodDef method = methods.get(0);
GenericClassHelper ret = method.getReturnType();
Class<?> cls = ret.getBaseClass();
System.out.println(beanCls.getName() + " " + methodName);
System.out.println(" ret:" + cls);
GenericClassHelper[] params = method.getParameterTypes();
for(int i=0,c=params.length;i<c;++i) {
System.out.println(" p" + (i+1) + ":" + params[i].getBaseClass() + "\n");
}
}
testGeneric(UserServiceImpl.class, "selectOne");
testGeneric(UserService.class, "selectOne");
Last:
Thanks for your readed
Reference:
A wrapper around reflection to resolve generics. : Generic « Reflection « Java
No comments:
Post a Comment