SNCP、REST支持部分含泛型继承的类
This commit is contained in:
@@ -79,7 +79,7 @@ public final class Rest {
|
|||||||
private Rest() {
|
private Rest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MethodParamClassVisitor extends ClassVisitor {
|
static class MethodParamClassVisitor extends ClassVisitor {
|
||||||
|
|
||||||
private final Map<String, List<String>> fieldmap;
|
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) {
|
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||||
if (java.lang.reflect.Modifier.isStatic(access)) return null;
|
if (java.lang.reflect.Modifier.isStatic(access)) return null;
|
||||||
List<String> fieldnames = new ArrayList<>();
|
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) {
|
return new MethodVisitor(Opcodes.ASM5) {
|
||||||
@Override
|
@Override
|
||||||
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
|
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的元素集合比方法的参数多
|
//返回的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();
|
String n = clazz.getName();
|
||||||
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
|
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
|
||||||
Map<String, List<String>> map = new HashMap<>();
|
|
||||||
if (in == null) return map;
|
if (in == null) return map;
|
||||||
try {
|
try {
|
||||||
new ClassReader(Utility.readBytesThenClose(in)).accept(new MethodParamClassVisitor(Opcodes.ASM5, map), 0);
|
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 (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.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");
|
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 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 Set<String> messageNames = new HashSet<>();
|
||||||
final List<Method> messageMethods = new ArrayList<>();
|
final List<Method> messageMethods = new ArrayList<>();
|
||||||
for (Method method : webSocketType.getMethods()) {
|
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 (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");
|
if (!HttpServlet.class.isAssignableFrom(baseServletType)) throw new RuntimeException(baseServletType + " is not HttpServlet Class on createRestServlet");
|
||||||
int mod = baseServletType.getModifiers();
|
int mod = baseServletType.getModifiers();
|
||||||
@@ -782,7 +785,7 @@ public final class Rest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ignore) continue;
|
if (ignore) continue;
|
||||||
paramtypes.add(method.getGenericParameterTypes());
|
paramtypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType));
|
||||||
if (mappings.length == 0) { //没有Mapping,设置一个默认值
|
if (mappings.length == 0) { //没有Mapping,设置一个默认值
|
||||||
MappingEntry entry = new MappingEntry(methodidex, null, bigmodulename, method);
|
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");
|
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的方法
|
if (entrys.isEmpty()) return null; //没有可HttpMapping的方法
|
||||||
//将每个Service可转换的方法生成HttpServlet对应的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 Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>();
|
||||||
|
|
||||||
final List<RestConvert[]> restConverts = new ArrayList<>();
|
final List<RestConvert[]> restConverts = new ArrayList<>();
|
||||||
@@ -986,7 +989,7 @@ public final class Rest {
|
|||||||
}
|
}
|
||||||
av1.visitEnd();
|
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.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
|
||||||
|
|
||||||
av0.visitEnd();
|
av0.visitEnd();
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
for (Method method : this.getClass().getDeclaredMethods()) {
|
for (Method method : this.getClass().getDeclaredMethods()) {
|
||||||
if (!method.getName().equals("createWebSocket")) continue;
|
if (!method.getName().equals("createWebSocket")) continue;
|
||||||
if (method.getParameterCount() > 0) continue;
|
if (method.getParameterCount() > 0) continue;
|
||||||
Type rt = method.getGenericReturnType();
|
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), this.getClass());
|
||||||
if (rt instanceof ParameterizedType) {
|
if (rt instanceof ParameterizedType) {
|
||||||
msgtype = ((ParameterizedType) rt).getActualTypeArguments()[1];
|
msgtype = ((ParameterizedType) rt).getActualTypeArguments()[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ public final class SncpClient {
|
|||||||
|
|
||||||
public SncpAction(final Class clazz, Method method, DLong actionid) {
|
public SncpAction(final Class clazz, Method method, DLong actionid) {
|
||||||
this.actionid = actionid == null ? Sncp.hash(method) : actionid;
|
this.actionid = actionid == null ? Sncp.hash(method) : actionid;
|
||||||
Type rt = method.getGenericReturnType();
|
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), clazz);
|
||||||
if (rt instanceof TypeVariable) {
|
if (rt instanceof TypeVariable) {
|
||||||
TypeVariable tv = (TypeVariable) rt;
|
TypeVariable tv = (TypeVariable) rt;
|
||||||
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
|
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.resultTypes = rt == void.class ? null : rt;
|
||||||
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||||
this.futureCreator = boolReturnTypeFuture ? Creator.create((Class<? extends CompletableFuture>) method.getReturnType()) : null;
|
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.paramClass = method.getParameterTypes();
|
||||||
this.method = method;
|
this.method = method;
|
||||||
Annotation[][] anns = method.getParameterAnnotations();
|
Annotation[][] anns = method.getParameterAnnotations();
|
||||||
|
|||||||
@@ -588,9 +588,9 @@ public final class SncpDynServlet extends SncpServlet {
|
|||||||
try {
|
try {
|
||||||
SncpServletAction instance = (SncpServletAction) newClazz.newInstance();
|
SncpServletAction instance = (SncpServletAction) newClazz.newInstance();
|
||||||
instance.method = method;
|
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[] 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) {
|
if (rt instanceof TypeVariable) {
|
||||||
TypeVariable tv = (TypeVariable) rt;
|
TypeVariable tv = (TypeVariable) rt;
|
||||||
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
|
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
|
||||||
|
|||||||
@@ -56,6 +56,35 @@ public abstract class TypeToken<T> {
|
|||||||
return true;
|
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
|
* 动态创建类型为ParameterizedType或Class的Type
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user