diff --git a/src/org/redkale/boot/NodeHttpServer.java b/src/org/redkale/boot/NodeHttpServer.java index fe326377d..1b982759e 100644 --- a/src/org/redkale/boot/NodeHttpServer.java +++ b/src/org/redkale/boot/NodeHttpServer.java @@ -9,6 +9,7 @@ import java.lang.reflect.*; import java.net.InetSocketAddress; import java.util.*; import java.util.logging.Level; +import java.util.regex.Pattern; import javax.annotation.Resource; import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.net.*; @@ -84,9 +85,9 @@ public final class NodeHttpServer extends NodeServer { }, WebSocketNode.class); } - protected void loadHttpServlet(final AnyValue conf, final ClassFilter filter) throws Exception { + protected void loadHttpServlet(final AnyValue servletsConf, final ClassFilter filter) throws Exception { final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - final String prefix = conf == null ? "" : conf.getValue("path", ""); + final String prefix = servletsConf == null ? "" : servletsConf.getValue("path", ""); final String threadName = "[" + Thread.currentThread().getName() + "] "; List> list = new ArrayList(filter.getFilterEntrys()); list.sort((FilterEntry o1, FilterEntry o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode @@ -136,6 +137,85 @@ public final class NodeHttpServer extends NodeServer { } } if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); + loadRestServlet(servletsConf); } + protected void loadRestServlet(final AnyValue servletsConf) throws Exception { + final String prefix = servletsConf == null ? "" : servletsConf.getValue("path", ""); + AnyValue restConf = serverConf == null ? null : serverConf.getAnyValue("rest"); + if (restConf == null) return; //不存在REST服务 + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + final String threadName = "[" + Thread.currentThread().getName() + "] "; + final List> ss = sb == null ? null : new ArrayList<>(); + + final Class superClass = (Class) Class.forName(restConf.getValue("servlet", DefaultRestServlet.class.getName())); + + final boolean autoload = restConf.getBoolValue("autoload", true); + final boolean mustsign = restConf.getBoolValue("mustsign", false); //是否只加载标记@RestService的Service类 + final Pattern[] includes = ClassFilter.toPattern(restConf.getValue("includes", "").split(";")); + final Pattern[] excludes = ClassFilter.toPattern(restConf.getValue("excludes", "").split(";")); + final Set hasServices = new HashSet<>(); + for (AnyValue item : restConf.getAnyValues("service")) { + hasServices.add(item.getValue("value", "")); + } + + super.interceptorServiceWrappers.forEach((wrapper) -> { + if (!wrapper.getName().isEmpty()) return; //只加载resourceName为空的service + final Class stype = wrapper.getType(); + if (mustsign && stype.getAnnotation(RestService.class) == null) return; + + final String stypename = stype.getName(); + if (stypename.startsWith("org.redkale.")) return; + if (!autoload && !hasServices.contains(stypename)) return; + if (excludes != null && !hasServices.contains(stypename)) { + for (Pattern reg : excludes) { + if (reg.matcher(stypename).matches()) return; + } + } + if (includes != null && !hasServices.contains(stypename)) { + boolean match = false; + for (Pattern reg : includes) { + if (reg.matcher(stypename).matches()) { + match = true; + break; + } + } + if (!match) return; + } + + RestHttpServlet servlet = RestServletBuilder.createRestServlet(superClass, wrapper.getName(), stype); + if (servlet == null) return; + try { + Field serviceField = servlet.getClass().getDeclaredField("_service"); + serviceField.setAccessible(true); + serviceField.set(servlet, wrapper.getService()); + } catch (Exception e) { + throw new RuntimeException(wrapper.getType() + " generate rest servlet error", e); + } + httpServer.addHttpServlet(servlet, prefix, (AnyValue) null); + if (ss != null) { + String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value(); + for (int i = 0; i < mappings.length; i++) { + mappings[i] = prefix + mappings[i]; + } + ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings)); + } + }); + //输出信息 + if (ss != null && sb != null) { + Collections.sort(ss, (AbstractMap.SimpleEntry o1, AbstractMap.SimpleEntry o2) -> o1.getKey().compareTo(o2.getKey())); + int max = 0; + for (AbstractMap.SimpleEntry as : ss) { + if (as.getKey().length() > max) max = as.getKey().length(); + } + for (AbstractMap.SimpleEntry as : ss) { + sb.append(threadName).append(" Loaded ").append(as.getKey()); + for (int i = 0; i < max - as.getKey().length(); i++) { + sb.append(' '); + } + sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); + } + } + if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); + } } diff --git a/src/org/redkale/net/http/BasedHttpServlet.java b/src/org/redkale/net/http/BasedHttpServlet.java index 43224229a..97d1baf33 100644 --- a/src/org/redkale/net/http/BasedHttpServlet.java +++ b/src/org/redkale/net/http/BasedHttpServlet.java @@ -16,6 +16,7 @@ import java.lang.reflect.Method; import java.nio.*; import java.util.*; import java.util.concurrent.*; +import java.util.logging.*; import jdk.internal.org.objectweb.asm.*; import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static jdk.internal.org.objectweb.asm.Opcodes.*; @@ -30,7 +31,11 @@ import org.redkale.service.RetResult; */ public abstract class BasedHttpServlet extends HttpServlet { - public static final int RET_METHOD_ERROR = 1800_0001; + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + public static final int RET_SERVER_ERROR = 1800_0001; + + public static final int RET_METHOD_ERROR = 1800_0002; /** * 配合 BasedHttpServlet 使用。 @@ -95,6 +100,18 @@ public abstract class BasedHttpServlet extends HttpServlet { private Map.Entry[] actions; + /** + * 异常输出 + * + * @param req HTTP请求对象 + * @param resp HTTP响应对象 + * @param exp 异常 + */ + protected void sendExceptionResult(HttpRequest req, HttpResponse resp, Throwable exp) { + logger.log(Level.SEVERE, "request = " + req, exp); + resp.finishJson(new RetResult(RET_SERVER_ERROR, "Server Error")); + } + public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException { return true; } diff --git a/src/org/redkale/net/http/DefaultRestServlet.java b/src/org/redkale/net/http/DefaultRestServlet.java new file mode 100644 index 000000000..09717da13 --- /dev/null +++ b/src/org/redkale/net/http/DefaultRestServlet.java @@ -0,0 +1,29 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.io.IOException; + +/** + * 默认Servlet, 没有配置RestHttpServlet实现类则使用该默认类 + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +public class DefaultRestServlet extends RestHttpServlet { + + @Override + protected Object currentUser(HttpRequest req) throws IOException { + return new Object(); + } + + @Override + public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException { + return true; + } + +} diff --git a/src/org/redkale/net/http/RestHttpServlet.java b/src/org/redkale/net/http/RestHttpServlet.java new file mode 100644 index 000000000..1c943439f --- /dev/null +++ b/src/org/redkale/net/http/RestHttpServlet.java @@ -0,0 +1,21 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.io.IOException; + +/** + * + * 详情见: http://redkale.org + * + * @author zhangjx + * @param + */ +public abstract class RestHttpServlet extends BasedHttpServlet { + + protected abstract T currentUser(HttpRequest req) throws IOException; + +} diff --git a/src/org/redkale/net/http/RestMapping.java b/src/org/redkale/net/http/RestMapping.java new file mode 100644 index 000000000..af41bd897 --- /dev/null +++ b/src/org/redkale/net/http/RestMapping.java @@ -0,0 +1,47 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * 只能依附在Service实现类的public方法上 + * value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService,的默认路径为/hello)。 + *

+ *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(RestMappings.class) +public @interface RestMapping { + + boolean ignore() default false; //是否屏蔽该方法的转换 + + /** + * 请求的方法名, 不能含特殊字符 + * 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前) + * + * @return name + */ + String name() default ""; + + boolean authignore() default true; //是否跳过鉴权,默认跳过 + + int actionid() default 0; //操作ID值,鉴权时用到, 对应@WebAction.actionid + + String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebAction.methods + + String contentType() default ""; //设置Response的ContentType 默认值为 text/plain; charset=utf-8 + + String jsvar() default ""; //以application/javascript输出对象是指明js的对象名,该值存在时则忽略contentType()的值 +} diff --git a/src/org/redkale/net/http/RestMappings.java b/src/org/redkale/net/http/RestMappings.java new file mode 100644 index 000000000..67ba7effe --- /dev/null +++ b/src/org/redkale/net/http/RestMappings.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * RestMapping 的多用类 + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface RestMappings { + + RestMapping[] value(); +} diff --git a/src/org/redkale/net/http/RestParam.java b/src/org/redkale/net/http/RestParam.java new file mode 100644 index 000000000..d4d63bc1b --- /dev/null +++ b/src/org/redkale/net/http/RestParam.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 只能依附在Service类的方法的参数上 + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RestParam { + + String value(); //参数名 + + /** + * 参数是否从header取, 默认使用 request.getJsonParameter, 设置为true则使用 request.getJsonHeader 取值 + * + * @return 是否从header取 + */ + boolean header() default false; +} diff --git a/src/org/redkale/net/http/RestService.java b/src/org/redkale/net/http/RestService.java new file mode 100644 index 000000000..92b502f16 --- /dev/null +++ b/src/org/redkale/net/http/RestService.java @@ -0,0 +1,34 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 只能依附在Service类上,value默认为Service的类名去掉Service字样的字符串小写 (如HelloService,的默认路径为 hello)。 + *

+ *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface RestService { + + boolean ignore() default false; //是否屏蔽该类的转换 + + String value() default ""; //模块名, 只能是模板名,不能含特殊字符 + + boolean repair() default true; //同@WebServlet的repair属性 + + int module() default 0; //模块ID值,鉴权时用到, 对应@WebServlet.ignore + +} diff --git a/src/org/redkale/net/http/RestServletBuilder.java b/src/org/redkale/net/http/RestServletBuilder.java new file mode 100644 index 000000000..6f88e9567 --- /dev/null +++ b/src/org/redkale/net/http/RestServletBuilder.java @@ -0,0 +1,690 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import jdk.internal.org.objectweb.asm.Type; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; +import org.redkale.source.Flipper; + +/** + * 以find开头的方法且参数只有一个且参数类型为primitive class或String,则RestParam值默认为# + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +public final class RestServletBuilder { + + private static final Set EXCLUDERMETHODS = new HashSet<>(); + + static { + for (Method m : Object.class.getMethods()) { + EXCLUDERMETHODS.add(m.getName()); + } + } + + private RestServletBuilder() { + } + + //待实现 + public static T createRestServlet(final Class baseServletClass, final String serviceName, final Class serviceType) { + if (baseServletClass == null || serviceType == null) return null; + if (!RestHttpServlet.class.isAssignableFrom(baseServletClass)) return null; + int mod = baseServletClass.getModifiers(); + if (!java.lang.reflect.Modifier.isPublic(mod)) return null; + if (java.lang.reflect.Modifier.isAbstract(mod)) return null; + final String supDynName = baseServletClass.getName().replace('.', '/'); + final String serviceDesc = Type.getDescriptor(serviceType); + final String webServletDesc = Type.getDescriptor(WebServlet.class); + final String httpRequestDesc = Type.getDescriptor(HttpRequest.class); + final String httpResponseDesc = Type.getDescriptor(HttpResponse.class); + final String authDesc = Type.getDescriptor(BasedHttpServlet.AuthIgnore.class); + final String actionDesc = Type.getDescriptor(BasedHttpServlet.WebAction.class); + final String serviceTypeString = serviceType.getName().replace('.', '/'); + final Class userType = getSuperUserType(baseServletClass); + + final RestService controller = serviceType.getAnnotation(RestService.class); + if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet + ClassLoader loader = Sncp.class.getClassLoader(); + String newDynName = serviceTypeString.substring(0, serviceTypeString.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet"; + if (!serviceName.isEmpty()) { + boolean normal = true; + for (char ch : serviceName.toCharArray()) {//含特殊字符的使用hash值 + if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false; + } + newDynName += "_" + (normal ? serviceName : Sncp.hash(serviceName)); + } + try { + return ((Class) Class.forName(newDynName.replace('/', '.'))).newInstance(); + } catch (Exception ex) { + } + Method currentUserMethod = null; + try { + currentUserMethod = baseServletClass.getDeclaredMethod("currentUser", HttpRequest.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + //------------------------------------------------------------------------------ + final String defmodulename = (controller != null && !controller.value().isEmpty()) ? controller.value() : serviceType.getSimpleName().replaceAll("Service.*$", ""); + for (char ch : defmodulename.toCharArray()) { + if (!((ch >= '0' && ch <= '9') || ch == '$' || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符 + throw new RuntimeException(serviceType.getName() + " has illeal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ $"); + } + } + + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + AsmMethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); + { //注入 @WebServlet 注解 + av0 = cw.visitAnnotation(webServletDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "/" + defmodulename.toLowerCase() + "/*"); + av1.visitEnd(); + } + av0.visit("moduleid", controller == null ? 0 : controller.module()); + av0.visit("repair", controller == null ? true : controller.repair()); + av0.visitEnd(); + } + + { //注入 @Resource private XXXService _service; + fv = cw.visitField(ACC_PRIVATE, "_service", serviceDesc, null, null); + av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true); + av0.visitEnd(); + fv.visitEnd(); + } + { //构造函数 + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + final List entrys = new ArrayList<>(); + for (final Method method : serviceType.getMethods()) { + Class[] extypes = method.getExceptionTypes(); + if (extypes.length > 1) continue; + if (extypes.length == 1 && extypes[0] != IOException.class) continue; + if (EXCLUDERMETHODS.contains(method.getName())) continue; + if ("init".equals(method.getName())) continue; + if ("destroy".equals(method.getName())) continue; + + RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class); + boolean ignore = false; + for (RestMapping mapping : mappings) { + if (mapping.ignore()) { + ignore = true; + break; + } + } + if (ignore) continue; + if (mappings.length == 0) { //没有Mapping,设置一个默认值 + MappingEntry entry = new MappingEntry(null, defmodulename, method); + if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat"); + entrys.add(entry); + } else { + for (RestMapping mapping : mappings) { + MappingEntry entry = new MappingEntry(mapping, defmodulename, method); + if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat"); + entrys.add(entry); + } + } + } + if (entrys.isEmpty()) return null; + + for (final MappingEntry entry : entrys) { + final Method method = entry.mappingMethod; + final Class returnType = method.getReturnType(); + final String methodDesc = Type.getMethodDescriptor(method); + final Parameter[] params = method.getParameters(); + + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, entry.name, "(" + httpRequestDesc + httpResponseDesc + ")V", null, new String[]{"java/io/IOException"})); + //mv.setDebug(true); + mv.debugLine(); + if (entry.authignore) { //设置 AuthIgnore + av0 = mv.visitAnnotation(authDesc, true); + av0.visitEnd(); + } + final int maxStack = 3 + params.length; + List varInsns = new ArrayList<>(); + int maxLocals = 3; + boolean hasVisitWebAction = false; + final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar; + int argIndex = 0; + for (final Parameter param : params) { + final Class ptype = param.getType(); + RestParam annpara = param.getAnnotation(RestParam.class); + String n = annpara == null || annpara.value().isEmpty() ? null : annpara.value(); + if (n == null) { + if (param.isNamePresent()) { + n = param.getName(); + } else { + n = (++argIndex > 1) ? ("bean" + argIndex) : "bean"; + } + } + if ((entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) { + if (ptype.isPrimitive() || ptype == String.class) n = "#"; + } + if (!hasVisitWebAction) { + hasVisitWebAction = true; + //设置 WebAction + av0 = mv.visitAnnotation(actionDesc, true); + av0.visit("url", "/" + defmodulename.toLowerCase() + "/" + entry.name + ("#".equals(n) ? "/" : "")); + av0.visit("actionid", entry.actionid); + + AnnotationVisitor av1 = av0.visitArray("methods"); + for (String m : entry.methods) { + av1.visit(null, m); + } + av1.visitEnd(); + + av0.visitEnd(); + } + final String pname = n; + final boolean hd = annpara == null ? false : annpara.header(); + + if ("#".equals(pname)) { //从request.getRequstURI 中去参数 + if (ptype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;)B", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;)S", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false); + mv.visitVarInsn(FSTORE, maxLocals); + varInsns.add(new int[]{FLOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;)J", false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[]{LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false); + mv.visitVarInsn(DSTORE, maxLocals); + varInsns.add(new int[]{DLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getRequstURILastPath", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + } else { + throw new RuntimeException(method + " only " + RestParam.class.getSimpleName() + "(#) to Type(primitive class or String)"); + } + } else if (ptype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getBooleanHeader" : "getBooleanParameter", "(Ljava/lang/String;Z)Z", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn("0"); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getHeader" : "getParameter", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;)B", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getShortHeader" : "getShortParameter", "(Ljava/lang/String;S)S", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn("0"); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getHeader" : "getParameter", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getIntHeader" : "getIntParameter", "(Ljava/lang/String;I)I", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[]{ILOAD, maxLocals}); + } else if (ptype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(FCONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getFloatHeader" : "getFloatParameter", "(Ljava/lang/String;F)F", false); + mv.visitVarInsn(FSTORE, maxLocals); + varInsns.add(new int[]{FLOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(LCONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getLongHeader" : "getLongParameter", "(Ljava/lang/String;J)J", false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[]{LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(DCONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getDoubleHeader" : "getDoubleParameter", "(Ljava/lang/String;D)D", false); + mv.visitVarInsn(DSTORE, maxLocals); + varInsns.add(new int[]{DLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn(""); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getHeader" : "getParameter", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } else if (ptype == Flipper.class) { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getFlipper", "()Lorg/redkale/source/Flipper;", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "findFlipper", "(Lorg/redkale/net/http/HttpRequest;)Lorg/redkale/source/Flipper;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } else if (ptype == userType) { //当前用户对象的类名 + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "currentUser", Type.getMethodDescriptor(currentUserMethod), false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); + mv.visitLdcInsn(pname); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", hd ? "getJsonHeader" : "getJsonParameter", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } + maxLocals++; + } // end params for each + + if (!hasVisitWebAction) { //当无参数时则没有设置过 WebAction + hasVisitWebAction = true; + //设置 WebAction + av0 = mv.visitAnnotation(actionDesc, true); + av0.visit("url", "/" + defmodulename.toLowerCase() + "/" + entry.name); + av0.visit("actionid", entry.actionid); + av0.visitEnd(); + } + + mv.visitVarInsn(ALOAD, 0); //调用this + mv.visitFieldInsn(GETFIELD, newDynName, "_service", serviceDesc); + for (int[] ins : varInsns) { + mv.visitVarInsn(ins[0], ins[1]); + } + mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeString, method.getName(), methodDesc, false); + if (returnType == void.class) { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + //mv.visitFieldInsn(GETSTATIC, "org/redkale/service/RetResult", "SUCCESS", "Lorg/redkale/service/RetResult;"); + mv.visitMethodInsn(INVOKESTATIC, "org/redkale/service/RetResult", "success", "()Lorg/redkale/service/RetResult;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJson", "(Lorg/redkale/service/RetResult;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendRetResult", "(Lorg/redkale/net/http/HttpResponse;Lorg/redkale/service/RetResult;)V", false); + mv.visitInsn(RETURN); + } else if (returnType == boolean.class) { + mv.visitVarInsn(ISTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == byte.class) { + mv.visitVarInsn(ISTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == short.class) { + mv.visitVarInsn(ISTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == char.class) { + mv.visitVarInsn(ISTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == int.class) { + mv.visitVarInsn(ISTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == float.class) { + mv.visitVarInsn(FSTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(FLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(FLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == long.class) { + mv.visitVarInsn(LSTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(LLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(LLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals += 2; + } else if (returnType == double.class) { + mv.visitVarInsn(DSTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(DLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(DLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals += 2; + } else if (returnType == String.class) { + mv.visitVarInsn(ASTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == File.class) { + mv.visitVarInsn(ASTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/io/File;)V", false); + } else { + throw new RuntimeException(method + " cannot set return Type (java.io.File) to jsvar"); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (RetResult.class.isAssignableFrom(returnType)) { + mv.visitVarInsn(ASTORE, maxLocals); + if (jsvar == null) { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJson", "(Lorg/redkale/service/RetResult;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendRetResult", "(Lorg/redkale/net/http/HttpResponse;Lorg/redkale/service/RetResult;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面 + mv.visitVarInsn(ASTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finish", "(Ljava/lang/String;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else { + mv.visitVarInsn(ASTORE, maxLocals); + if (jsvar == null) { + mv.visitVarInsn(ALOAD, 2); //response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJson", "(Ljava/lang/Object;)V", false); + } else { + //mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(jsvar); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpResponse", "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); + //mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "sendJsResult", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/String;Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } + mv.visitMaxs(maxStack, maxLocals); + + } // end for each + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + try { + return ((Class) newClazz).newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Class getSuperUserType(Class servletClass) { + java.lang.reflect.Type type = servletClass.getGenericSuperclass(); + if (type instanceof Class) return getSuperUserType((Class) type); + if (type instanceof java.lang.reflect.ParameterizedType) { + java.lang.reflect.ParameterizedType pt = (java.lang.reflect.ParameterizedType) type; + if (pt.getRawType() == RestHttpServlet.class) { + java.lang.reflect.Type usert = pt.getActualTypeArguments()[0]; + if (usert instanceof Class) return (Class) usert; + } + } + return null; + } + + private static class MappingEntry { + + private static final RestMapping DEFAULT__MAPPING; + + static { + try { + DEFAULT__MAPPING = MappingEntry.class.getDeclaredMethod("mapping").getAnnotation(RestMapping.class); + } catch (Exception e) { + throw new Error(e); + } + } + + public MappingEntry(RestMapping mapping, final String defmodulename, Method method) { + if (mapping == null) mapping = DEFAULT__MAPPING; + this.ignore = mapping.ignore(); + String n = mapping.name().toLowerCase(); + if (n.isEmpty()) n = method.getName().toLowerCase().replace(defmodulename.toLowerCase(), ""); + this.name = n; + this.mappingMethod = method; + this.methods = mapping.methods(); + this.authignore = mapping.authignore(); + this.actionid = mapping.actionid(); + this.contentType = mapping.contentType(); + this.jsvar = mapping.jsvar(); + } + + public final Method mappingMethod; + + public final boolean ignore; + + public final String name; + + public final String[] methods; + + public final boolean authignore; + + public final int actionid; + + public final String contentType; + + public final String jsvar; + + @RestMapping() + void mapping() { //用于获取Mapping 默认值 + } + + @Override + public int hashCode() { + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + return this.name.equals(((MappingEntry) obj).name); + } + + } +}