SNCP、REST支持部分含泛型继承的类
This commit is contained in:
@@ -79,7 +79,7 @@ public final class Rest {
|
||||
private Rest() {
|
||||
}
|
||||
|
||||
public static class MethodParamClassVisitor extends ClassVisitor {
|
||||
static class MethodParamClassVisitor extends ClassVisitor {
|
||||
|
||||
private final Map<String, List<String>> fieldmap;
|
||||
|
||||
@@ -92,7 +92,9 @@ public final class Rest {
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (java.lang.reflect.Modifier.isStatic(access)) return null;
|
||||
List<String> fieldnames = new ArrayList<>();
|
||||
fieldmap.put(name + ":" + desc, fieldnames);
|
||||
String key = name + ":" + desc;
|
||||
if (fieldmap.containsKey(key)) return null;
|
||||
fieldmap.put(key, fieldnames);
|
||||
return new MethodVisitor(Opcodes.ASM5) {
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
|
||||
@@ -111,16 +113,17 @@ public final class Rest {
|
||||
}
|
||||
|
||||
//返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多
|
||||
public static Map<String, List<String>> getMethodParamNames(Class clazz) {
|
||||
public static Map<String, List<String>> getMethodParamNames(Map<String, List<String>> map, Class clazz) {
|
||||
String n = clazz.getName();
|
||||
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
if (in == null) return map;
|
||||
try {
|
||||
new ClassReader(Utility.readBytesThenClose(in)).accept(new MethodParamClassVisitor(Opcodes.ASM5, map), 0);
|
||||
} catch (Exception e) { //无需理会
|
||||
} catch (Exception e) { //无需理会
|
||||
}
|
||||
return map;
|
||||
Class superClass = clazz.getSuperclass();
|
||||
if (superClass == Object.class) return map;
|
||||
return getMethodParamNames(map, superClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +187,7 @@ public final class Rest {
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends HttpServlet> T createRestWebSocketServlet(final ClassLoader classLoader, final Class<? extends WebSocket> webSocketType) {
|
||||
public static <T extends HttpServlet> T createRestWebSocketServlet(final ClassLoader classLoader, final Class<? extends WebSocket> webSocketType) {
|
||||
if (webSocketType == null) throw new RuntimeException("Rest WebSocket Class is null on createRestWebSocketServlet");
|
||||
if (Modifier.isAbstract(webSocketType.getModifiers())) throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") cannot abstract on createRestWebSocketServlet");
|
||||
if (Modifier.isFinal(webSocketType.getModifiers())) throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") cannot final on createRestWebSocketServlet");
|
||||
@@ -233,7 +236,7 @@ public final class Rest {
|
||||
final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString();
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(webSocketType);
|
||||
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), webSocketType);
|
||||
final Set<String> messageNames = new HashSet<>();
|
||||
final List<Method> messageMethods = new ArrayList<>();
|
||||
for (Method method : webSocketType.getMethods()) {
|
||||
@@ -640,7 +643,7 @@ public final class Rest {
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends HttpServlet> T createRestServlet(final ClassLoader classLoader, final Class userType0, final Class<T> baseServletType, final Class<? extends Service> serviceType) {
|
||||
public static <T extends HttpServlet> T createRestServlet(final ClassLoader classLoader, final Class userType0, final Class<T> baseServletType, final Class<? extends Service> serviceType) {
|
||||
if (baseServletType == null || serviceType == null) throw new RuntimeException(" Servlet or Service is null Class on createRestServlet");
|
||||
if (!HttpServlet.class.isAssignableFrom(baseServletType)) throw new RuntimeException(baseServletType + " is not HttpServlet Class on createRestServlet");
|
||||
int mod = baseServletType.getModifiers();
|
||||
@@ -782,7 +785,7 @@ public final class Rest {
|
||||
}
|
||||
}
|
||||
if (ignore) continue;
|
||||
paramtypes.add(method.getGenericParameterTypes());
|
||||
paramtypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType));
|
||||
if (mappings.length == 0) { //没有Mapping,设置一个默认值
|
||||
MappingEntry entry = new MappingEntry(methodidex, null, bigmodulename, method);
|
||||
if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
|
||||
@@ -798,7 +801,7 @@ public final class Rest {
|
||||
}
|
||||
if (entrys.isEmpty()) return null; //没有可HttpMapping的方法
|
||||
//将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法
|
||||
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(serviceType);
|
||||
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), serviceType);
|
||||
final Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>();
|
||||
|
||||
final List<RestConvert[]> restConverts = new ArrayList<>();
|
||||
@@ -986,7 +989,7 @@ public final class Rest {
|
||||
}
|
||||
av1.visitEnd();
|
||||
|
||||
java.lang.reflect.Type grt = method.getGenericReturnType();
|
||||
java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType);
|
||||
av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
|
||||
|
||||
av0.visitEnd();
|
||||
|
||||
@@ -99,7 +99,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
||||
for (Method method : this.getClass().getDeclaredMethods()) {
|
||||
if (!method.getName().equals("createWebSocket")) continue;
|
||||
if (method.getParameterCount() > 0) continue;
|
||||
Type rt = method.getGenericReturnType();
|
||||
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), this.getClass());
|
||||
if (rt instanceof ParameterizedType) {
|
||||
msgtype = ((ParameterizedType) rt).getActualTypeArguments()[1];
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ public final class SncpClient {
|
||||
|
||||
public SncpAction(final Class clazz, Method method, DLong actionid) {
|
||||
this.actionid = actionid == null ? Sncp.hash(method) : actionid;
|
||||
Type rt = method.getGenericReturnType();
|
||||
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), clazz);
|
||||
if (rt instanceof TypeVariable) {
|
||||
TypeVariable tv = (TypeVariable) rt;
|
||||
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
|
||||
@@ -558,7 +558,7 @@ public final class SncpClient {
|
||||
this.resultTypes = rt == void.class ? null : rt;
|
||||
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||
this.futureCreator = boolReturnTypeFuture ? Creator.create((Class<? extends CompletableFuture>) method.getReturnType()) : null;
|
||||
this.paramTypes = method.getGenericParameterTypes();
|
||||
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), clazz);
|
||||
this.paramClass = method.getParameterTypes();
|
||||
this.method = method;
|
||||
Annotation[][] anns = method.getParameterAnnotations();
|
||||
|
||||
@@ -588,9 +588,9 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
try {
|
||||
SncpServletAction instance = (SncpServletAction) newClazz.newInstance();
|
||||
instance.method = method;
|
||||
java.lang.reflect.Type[] ptypes = method.getGenericParameterTypes();
|
||||
java.lang.reflect.Type[] ptypes = TypeToken.getGenericType(method.getGenericParameterTypes(), newClazz);
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[ptypes.length + 1];
|
||||
java.lang.reflect.Type rt = method.getGenericReturnType();
|
||||
java.lang.reflect.Type rt = TypeToken.getGenericType(method.getGenericReturnType(), newClazz);
|
||||
if (rt instanceof TypeVariable) {
|
||||
TypeVariable tv = (TypeVariable) rt;
|
||||
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
|
||||
|
||||
@@ -56,6 +56,35 @@ public abstract class TypeToken<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Type[] getGenericType(final Type[] types, final Type declaringClass) {
|
||||
Type[] newTypes = new Type[types.length];
|
||||
for (int i = 0; i < newTypes.length; i++) {
|
||||
newTypes[i] = getGenericType(types[i], declaringClass);
|
||||
}
|
||||
return newTypes;
|
||||
}
|
||||
|
||||
public static Type getGenericType(final Type type, final Type declaringClass) {
|
||||
if (declaringClass == null) return type;
|
||||
if (type instanceof TypeVariable) {
|
||||
if (declaringClass instanceof Class) {
|
||||
final Class declaringClass0 = (Class) declaringClass;
|
||||
final Type superType = declaringClass0.getGenericSuperclass();
|
||||
if (superType instanceof ParameterizedType) {
|
||||
ParameterizedType superPT = (ParameterizedType) superType;
|
||||
Type[] atas = superPT.getActualTypeArguments();
|
||||
TypeVariable[] asts = declaringClass0.getSuperclass().getTypeParameters();
|
||||
if (atas.length == asts.length) {
|
||||
for (int i = 0; i < asts.length; i++) {
|
||||
if (asts[i] == type) return atas[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态创建类型为ParameterizedType或Class的Type
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user