Search in sources :

Example 1 with MethodDebugVisitor

use of org.redkale.asm.MethodDebugVisitor in project redkale by redkale.

the class Rest method createRestWebSocketServlet.

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");
    final RestWebSocket rws = webSocketType.getAnnotation(RestWebSocket.class);
    if (rws == null || rws.ignore())
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") have not @RestWebSocket or @RestWebSocket.ignore=true on createRestWebSocketServlet");
    boolean valid = false;
    for (Constructor c : webSocketType.getDeclaredConstructors()) {
        if (c.getParameterCount() == 0 && (Modifier.isPublic(c.getModifiers()) || Modifier.isProtected(c.getModifiers()))) {
            valid = true;
            break;
        }
    }
    if (!valid)
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") must have public or protected Constructor on createRestWebSocketServlet");
    final String rwsname = ResourceFactory.formatResourceName(rws.name());
    if (!checkName(rws.catalog()))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9");
    if (!checkName(rwsname))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".name, only 0-9 a-z A-Z _ cannot begin 0-9");
    // ----------------------------------------------------------------------------------------
    final Set<Field> resourcesFieldSet = new LinkedHashSet<>();
    final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    final Set<String> resourcesFieldNameSet = new HashSet<>();
    Class clzz = webSocketType;
    do {
        for (Field field : clzz.getDeclaredFields()) {
            if (field.getAnnotation(Resource.class) == null)
                continue;
            if (resourcesFieldNameSet.contains(field.getName()))
                continue;
            if (Modifier.isStatic(field.getModifiers()))
                throw new RuntimeException(field + " cannot static on createRestWebSocketServlet");
            if (Modifier.isFinal(field.getModifiers()))
                throw new RuntimeException(field + " cannot final on createRestWebSocketServlet");
            if (!Modifier.isPublic(field.getModifiers()) && !Modifier.isProtected(field.getModifiers())) {
                throw new RuntimeException(field + " must be public or protected on createRestWebSocketServlet");
            }
            resourcesFieldNameSet.add(field.getName());
            resourcesFieldSet.add(field);
        }
    } while ((clzz = clzz.getSuperclass()) != Object.class);
    final List<Field> resourcesFields = new ArrayList<>(resourcesFieldSet);
    StringBuilder sb1 = new StringBuilder();
    StringBuilder sb2 = new StringBuilder();
    for (int i = 0; i < resourcesFields.size(); i++) {
        Field field = resourcesFields.get(i);
        sb1.append(Type.getDescriptor(field.getType()));
        sb2.append(Utility.getTypeDescriptor(field.getGenericType()));
    }
    final String resourceDescriptor = sb1.toString();
    final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString();
    // ----------------------------------------------------------------------------------------
    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()) {
        RestOnMessage rom = method.getAnnotation(RestOnMessage.class);
        if (rom == null)
            continue;
        String name = rom.name();
        if (Modifier.isFinal(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not final but (" + method + ")");
        if (Modifier.isStatic(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not static but (" + method + ")");
        if (method.getReturnType() != void.class)
            throw new RuntimeException("@RestOnMessage method must return void but (" + method + ")");
        if (method.getExceptionTypes().length > 0)
            throw new RuntimeException("@RestOnMessage method can not throw exception but (" + method + ")");
        if (name.isEmpty())
            throw new RuntimeException(method + " RestOnMessage.name is empty createRestWebSocketServlet");
        if (messageNames.contains(name))
            throw new RuntimeException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet");
        messageNames.add(name);
        messageMethods.add(method);
    }
    // ----------------------------------------------------------------------------------------
    final String resDesc = Type.getDescriptor(Resource.class);
    final String wsDesc = Type.getDescriptor(WebSocket.class);
    final String wsParamDesc = Type.getDescriptor(WebSocketParam.class);
    final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
    final String convertDisabledDesc = Type.getDescriptor(ConvertDisabled.class);
    final String webSocketParamName = Type.getInternalName(WebSocketParam.class);
    final String supDynName = WebSocketServlet.class.getName().replace('.', '/');
    final String webServletDesc = Type.getDescriptor(WebServlet.class);
    final String webSocketInternalName = Type.getInternalName(webSocketType);
    final String newDynName = webSocketInternalName.substring(0, webSocketInternalName.lastIndexOf('/') + 1) + "_Dyn" + webSocketType.getSimpleName() + "Servlet";
    final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName();
    final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName;
    final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message";
    final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName;
    final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer";
    final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName;
    // ----------------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        // RestDynSourceType
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true);
        av0.visit("value", Type.getType(Type.getDescriptor(webSocketType)));
        av0.visitEnd();
    }
    {
        // 注入 @WebServlet 注解
        String urlpath = (rws.catalog().isEmpty() ? "/" : ("/" + rws.catalog() + "/")) + rwsname;
        av0 = cw.visitAnnotation(webServletDesc, true);
        {
            AnnotationVisitor av1 = av0.visitArray("value");
            av1.visit(null, urlpath);
            av1.visitEnd();
        }
        av0.visit("moduleid", 0);
        av0.visit("repair", rws.repair());
        av0.visit("comment", rws.comment());
        av0.visitEnd();
    }
    {
        // 内部类
        cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
    }
    {
        // @Resource
        for (int i = 0; i < resourcesFields.size(); i++) {
            Field field = resourcesFields.get(i);
            Resource res = field.getAnnotation(Resource.class);
            java.lang.reflect.Type fieldType = field.getGenericType();
            fv = cw.visitField(ACC_PRIVATE, "_redkale_resource_" + i, Type.getDescriptor(field.getType()), fieldType == field.getType() ? null : Utility.getTypeDescriptor(fieldType), null);
            {
                av0 = fv.visitAnnotation(resDesc, true);
                av0.visit("name", res.name());
                av0.visitEnd();
            }
            fv.visitEnd();
        }
    }
    {
        // _DynWebSocketServlet构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message"));
        mv.visitFieldInsn(PUTFIELD, newDynName, "messageTextType", "Ljava/lang/reflect/Type;");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.liveinterval());
        mv.visitFieldInsn(PUTFIELD, newDynName, "liveinterval", "I");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.wsmaxconns());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxconns", "I");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.wsmaxbody());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.anyuser() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "anyuser", "Z");
        mv.visitInsn(RETURN);
        mv.visitMaxs(3, 1);
        mv.visitEnd();
    }
    {
        // createWebSocket 方法
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createWebSocket", "()" + wsDesc, "<G::Ljava/io/Serializable;T:Ljava/lang/Object;>()L" + WebSocket.class.getName().replace('.', '/') + "<TG;TT;>;", null));
        mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName);
        mv.visitInsn(DUP);
        for (int i = 0; i < resourcesFields.size(); i++) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_resource_" + i, Type.getDescriptor(resourcesFields.get(i).getType()));
        }
        mv.visitMethodInsn(INVOKESPECIAL, newDynWebSokcetFullName, "<init>", "(" + resourceDescriptor + ")V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2 + resourcesFields.size(), 1);
        mv.visitEnd();
    }
    {
        // createRestOnMessageConsumer
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createRestOnMessageConsumer", "()Ljava/util/function/BiConsumer;", "()Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", null));
        mv.visitTypeInsn(NEW, newDynConsumerFullName);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, newDynConsumerFullName, "<init>", "()V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
    }
    {
        // resourceName
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "resourceName", "()Ljava/lang/String;", null, null));
        mv.visitLdcInsn(rwsname);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    RestClassLoader newLoader = new RestClassLoader(loader);
    for (int i = 0; i < messageMethods.size(); i++) {
        // _DyncXXXWebSocketMessage 子消息List
        Method method = messageMethods.get(i);
        String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName + endfix, null, "java/lang/Object", new String[] { webSocketParamName, "java/lang/Runnable" });
        cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        Set<String> paramnames = new HashSet<>();
        String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method);
        List<String> names = asmParamMap.get(methodesc);
        Parameter[] params = method.getParameters();
        // 必须使用LinkedHashMap确保顺序
        final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap();
        for (int j = 0; j < params.length; j++) {
            // 字段列表
            Parameter param = params[j];
            String paramname = param.getName();
            RestParam rp = param.getAnnotation(RestParam.class);
            if (rp != null && !rp.name().isEmpty()) {
                paramname = rp.name();
            } else if (names != null && names.size() > j) {
                paramname = names.get(j);
            }
            if (paramnames.contains(paramname))
                throw new RuntimeException(method + " has same @RestParam.name");
            paramnames.add(paramname);
            paramap.put(paramname, param);
            fv = cw2.visitField(ACC_PUBLIC, paramname, Type.getDescriptor(param.getType()), param.getType() == param.getParameterizedType() ? null : Utility.getTypeDescriptor(param.getParameterizedType()), null);
            fv.visitEnd();
        }
        {
            // _redkale_websocket
            fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null);
            av0 = fv.visitAnnotation(convertDisabledDesc, true);
            av0.visitEnd();
            fv.visitEnd();
        }
        {
            // 空构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // getNames
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getNames", "()[Ljava/lang/String;", null, null));
            pushInt(mv, paramap.size());
            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
            int index = -1;
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitInsn(DUP);
                pushInt(mv, ++index);
                mv.visitLdcInsn(en.getKey());
                mv.visitInsn(AASTORE);
            }
            mv.visitInsn(ARETURN);
            mv.visitMaxs(paramap.size() + 2, 1);
            mv.visitEnd();
        }
        {
            // getValue
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getValue", "(Ljava/lang/String;)Ljava/lang/Object;", "<T:Ljava/lang/Object;>(Ljava/lang/String;)TT;", null));
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                Class paramType = en.getValue().getType();
                mv.visitLdcInsn(en.getKey());
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
                Label l1 = new Label();
                mv.visitJumpInsn(IFEQ, l1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, en.getKey(), Type.getDescriptor(paramType));
                if (paramType.isPrimitive()) {
                    Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(paramType, 1), 0).getClass();
                    mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), false);
                }
                mv.visitInsn(ARETURN);
                mv.visitLabel(l1);
            }
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        {
            // execute
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            mv.visitVarInsn(ALOAD, 1);
            mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name());
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, "preOnMessage", "(Ljava/lang/String;" + wsParamDesc + "Ljava/lang/Runnable;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 2);
            mv.visitEnd();
        }
        {
            // run
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, (newDynMessageFullName + endfix), en.getKey(), Type.getDescriptor(en.getValue().getType()));
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, method.getName(), Type.getMethodDescriptor(method), false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass((newDynMessageFullName + endfix).replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynXXXWebSocketMessage class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
            fv = cw2.visitField(ACC_PUBLIC, method.getAnnotation(RestOnMessage.class).name(), "L" + newDynMessageFullName + endfix + ";", null, null);
            fv.visitEnd();
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynMessageFullName.replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynXXXWebSocket class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynWebSokcetFullName, null, webSocketInternalName, null);
        cw2.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        {
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "<init>", "()V", false);
            for (int i = 0; i < resourcesFields.size(); i++) {
                Field field = resourcesFields.get(i);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, i + 1);
                mv.visitFieldInsn(PUTFIELD, newDynWebSokcetFullName, field.getName(), Type.getDescriptor(field.getType()));
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(2, 1 + resourcesFields.size());
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynRestOnMessageConsumer class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynConsumerFullName, "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", "java/lang/Object", new String[] { "java/util/function/BiConsumer" });
        cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName);
            mv.visitVarInsn(ASTORE, 3);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, newDynMessageFullName);
            mv.visitVarInsn(ASTORE, 4);
            for (int i = 0; i < messageMethods.size(); i++) {
                final Method method = messageMethods.get(i);
                String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
                final String messagename = method.getAnnotation(RestOnMessage.class).name();
                mv.visitVarInsn(ALOAD, 4);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";");
                Label ifLabel = new Label();
                mv.visitJumpInsn(IFNULL, ifLabel);
                mv.visitVarInsn(ALOAD, 4);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";");
                mv.visitVarInsn(ALOAD, 3);
                mv.visitMethodInsn(INVOKEVIRTUAL, (newDynMessageFullName + endfix), "execute", "(L" + newDynWebSokcetFullName + ";)V", false);
                mv.visitInsn(RETURN);
                mv.visitLabel(ifLabel);
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3 + messageMethods.size());
            mv.visitEnd();
        }
        {
            // 虚拟accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, WebSocket.class.getName().replace('.', '/'));
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynConsumerFullName.replace('/', '.'), cw2.toByteArray());
    }
    cw.visitEnd();
    Class<?> newClazz = newLoader.loadClass(newDynName.replace('/', '.'), cw.toByteArray());
    try {
        return (T) newClazz.getDeclaredConstructor().newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) Resource(javax.annotation.Resource) Type(org.redkale.asm.Type) ElementType(java.lang.annotation.ElementType)

Example 2 with MethodDebugVisitor

use of org.redkale.asm.MethodDebugVisitor in project redkale by redkale.

the class Sncp method createRemoteService.

/**
 * <blockquote><pre>
 * &#64;Resource(name = "")
 * &#64;SncpDyn(remote = true)
 * &#64;ResourceType(TestService.class)
 * public final class _DynRemoteTestService extends TestService{
 *
 *      private AnyValue _redkale_conf;
 *
 *      private SncpClient _redkale_client;
 *
 *      &#64;SncpDyn(remote = false, index = 0)
 *      public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
 *          _redkale_client.remote(0, selfrunnable, samerunnable, diffrunnable, bean);
 *      }
 *
 *      &#64;SncpDyn(remote = false, index = 1)
 *      public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
 *          return _redkale_client.remote(1, selfrunnable, samerunnable, diffrunnable, id);
 *      }
 *
 *      &#64;Override
 *      public void createSomeThing(TestBean bean){
 *          _redkale_client.remote(2, bean);
 *      }
 *
 *      &#64;Override
 *      public String findSomeThing(){
 *          return _redkale_client.remote(3);
 *      }
 *
 *      &#64;Override
 *      public String updateSomeThing(String id){
 *          return  _redkale_client.remote(4, id);
 *      }
 * }
 * </pre></blockquote>
 *
 * 创建远程模式的Service实例
 *
 * @param <T>                    Service泛型
 * @param classLoader            ClassLoader
 * @param name                   资源名
 * @param serviceTypeOrImplClass Service类
 * @param transportFactory       TransportFactory
 * @param clientAddress          本地IP地址
 * @param groups0                 所有的组节点,包含自身
 * @param conf                   启动配置项
 *
 * @return Service的远程模式实例
 */
@SuppressWarnings("unchecked")
public static <T extends Service> T createRemoteService(final ClassLoader classLoader, final String name, final Class<T> serviceTypeOrImplClass, final TransportFactory transportFactory, final InetSocketAddress clientAddress, final Set<String> groups0, final AnyValue conf) {
    if (serviceTypeOrImplClass == null)
        return null;
    if (!Service.class.isAssignableFrom(serviceTypeOrImplClass))
        return null;
    Set<String> groups = groups0 == null ? new HashSet<>() : groups0;
    ResourceFactory.checkResourceName(name);
    int mod = serviceTypeOrImplClass.getModifiers();
    boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface());
    if (!java.lang.reflect.Modifier.isPublic(mod))
        return null;
    final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
    final String clientName = SncpClient.class.getName().replace('.', '/');
    final String resDesc = Type.getDescriptor(Resource.class);
    final String clientDesc = Type.getDescriptor(SncpClient.class);
    final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
    final String anyValueDesc = Type.getDescriptor(AnyValue.class);
    ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceTypeOrImplClass.getSimpleName();
    try {
        Class newClazz = loader.loadClass(newDynName.replace('/', '.'));
        T rs = (T) newClazz.getDeclaredConstructor().newInstance();
        SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
        client.setRemoteGroups(groups);
        client.setRemoteGroupTransport(transportFactory.loadRemoteTransport(clientAddress, groups));
        Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
        c.setAccessible(true);
        c.set(rs, client);
        transportFactory.addSncpService(rs);
        return rs;
    } catch (Throwable ex) {
    }
    // ------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, serviceTypeOrImplClass.isInterface() ? new String[] { supDynName } : null);
    {
        av0 = cw.visitAnnotation(resDesc, true);
        av0.visit("name", name);
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
        ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class);
        av0.visit("value", Type.getType(Type.getDescriptor(rty == null ? serviceTypeOrImplClass : rty.value())));
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(sncpDynDesc, true);
        av0.visit("remote", Boolean.TRUE);
        av0.visitEnd();
    }
    {
        // 给新类加上 原有的Annotation
        for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
            if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType)
                continue;
            visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
        }
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
        fv.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null);
        fv.visitEnd();
    }
    {
        // 构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        // init
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "init", "(" + anyValueDesc + ")V", null, null));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 2);
        mv.visitEnd();
    }
    {
        // destroy
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "destroy", "(" + anyValueDesc + ")V", null, null));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 2);
        mv.visitEnd();
    }
    {
        // toString()
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNONNULL, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
        Label l2 = new Label();
        mv.visitJumpInsn(GOTO, l2);
        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "toSimpleString", "()Ljava/lang/String;", false);
        mv.visitLabel(l2);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    int i = -1;
    for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass)) {
        final int index = ++i;
        final java.lang.reflect.Method method = entry.method;
        {
            mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
            // mv.setDebug(true);
            {
                // 给参数加上 Annotation
                final Annotation[][] anns = method.getParameterAnnotations();
                for (int k = 0; k < anns.length; k++) {
                    for (Annotation ann : anns[k]) {
                        visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
                    }
                }
            }
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
            pushInt(mv, index);
            {
                // 传参数
                int paramlen = entry.paramTypes.length;
                pushInt(mv, paramlen);
                mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                java.lang.reflect.Type[] paramtypes = entry.paramTypes;
                int insn = 0;
                for (int j = 0; j < paramtypes.length; j++) {
                    final java.lang.reflect.Type pt = paramtypes[j];
                    mv.visitInsn(DUP);
                    insn++;
                    pushInt(mv, j);
                    if (pt instanceof Class && ((Class) pt).isPrimitive()) {
                        if (pt == long.class) {
                            mv.visitVarInsn(LLOAD, insn++);
                        } else if (pt == float.class) {
                            mv.visitVarInsn(FLOAD, insn++);
                        } else if (pt == double.class) {
                            mv.visitVarInsn(DLOAD, insn++);
                        } else {
                            mv.visitVarInsn(ILOAD, insn);
                        }
                        Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance((Class) pt, 1), 0).getClass();
                        mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), false);
                    } else {
                        mv.visitVarInsn(ALOAD, insn);
                    }
                    mv.visitInsn(AASTORE);
                }
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "remote", "(I[Ljava/lang/Object;)Ljava/lang/Object;", false);
            // mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
            if (method.getGenericReturnType() == void.class) {
                mv.visitInsn(POP);
                mv.visitInsn(RETURN);
            } else {
                Class returnclz = method.getReturnType();
                Class bigPrimitiveClass = returnclz.isPrimitive() ? java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(returnclz, 1), 0).getClass() : returnclz;
                mv.visitTypeInsn(CHECKCAST, (returnclz.isPrimitive() ? bigPrimitiveClass : returnclz).getName().replace('.', '/'));
                if (returnclz.isPrimitive()) {
                    String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/');
                    try {
                        java.lang.reflect.Method pm = bigPrimitiveClass.getMethod(returnclz.getSimpleName() + "Value");
                        mv.visitMethodInsn(INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false);
                    } catch (Exception ex) {
                        // 不可能会发生
                        throw new RuntimeException(ex);
                    }
                    if (returnclz == long.class) {
                        mv.visitInsn(LRETURN);
                    } else if (returnclz == float.class) {
                        mv.visitInsn(FRETURN);
                    } else if (returnclz == double.class) {
                        mv.visitInsn(DRETURN);
                    } else {
                        mv.visitInsn(IRETURN);
                    }
                } else {
                    mv.visitInsn(ARETURN);
                }
            }
            mv.visitMaxs(20, 20);
            mv.visitEnd();
        }
    }
    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 {
        T rs = (T) newClazz.getDeclaredConstructor().newInstance();
        SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
        client.setRemoteGroups(groups);
        client.setRemoteGroupTransport(transportFactory.loadRemoteTransport(clientAddress, groups));
        {
            Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
            c.setAccessible(true);
            c.set(rs, client);
        }
        {
            Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
            c.setAccessible(true);
            c.set(rs, conf);
        }
        transportFactory.addSncpService(rs);
        return rs;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) java.lang.reflect(java.lang.reflect) SncpAction(org.redkale.net.sncp.SncpClient.SncpAction) Resource(javax.annotation.Resource) Annotation(java.lang.annotation.Annotation) Type(org.redkale.asm.Type)

Example 3 with MethodDebugVisitor

use of org.redkale.asm.MethodDebugVisitor in project redkale by redkale.

the class Rest method createRestWebSocketServlet.

public static <T extends WebSocketServlet> T createRestWebSocketServlet(final ClassLoader classLoader, final Class<? extends WebSocket> webSocketType, MessageAgent messageAgent) {
    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");
    final RestWebSocket rws = webSocketType.getAnnotation(RestWebSocket.class);
    if (rws == null || rws.ignore())
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") have not @RestWebSocket or @RestWebSocket.ignore=true on createRestWebSocketServlet");
    boolean valid = false;
    for (Constructor c : webSocketType.getDeclaredConstructors()) {
        if (c.getParameterCount() == 0 && (Modifier.isPublic(c.getModifiers()) || Modifier.isProtected(c.getModifiers()))) {
            valid = true;
            break;
        }
    }
    if (!valid)
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") must have public or protected Constructor on createRestWebSocketServlet");
    final String rwsname = ResourceFactory.formatResourceName(rws.name());
    if (!checkName(rws.catalog()))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9");
    if (!checkName(rwsname))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".name, only 0-9 a-z A-Z _ cannot begin 0-9");
    // ----------------------------------------------------------------------------------------
    final Set<Field> resourcesFieldSet = new LinkedHashSet<>();
    final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    final Set<String> resourcesFieldNameSet = new HashSet<>();
    Class clzz = webSocketType;
    do {
        for (Field field : clzz.getDeclaredFields()) {
            if (field.getAnnotation(Resource.class) == null)
                continue;
            if (resourcesFieldNameSet.contains(field.getName()))
                continue;
            if (Modifier.isStatic(field.getModifiers()))
                throw new RuntimeException(field + " cannot static on createRestWebSocketServlet");
            if (Modifier.isFinal(field.getModifiers()))
                throw new RuntimeException(field + " cannot final on createRestWebSocketServlet");
            if (!Modifier.isPublic(field.getModifiers()) && !Modifier.isProtected(field.getModifiers())) {
                throw new RuntimeException(field + " must be public or protected on createRestWebSocketServlet");
            }
            resourcesFieldNameSet.add(field.getName());
            resourcesFieldSet.add(field);
        }
    } while ((clzz = clzz.getSuperclass()) != Object.class);
    // ----------------------------------------------------------------------------------------
    boolean namePresent = false;
    try {
        Method m0 = null;
        for (Method method : webSocketType.getMethods()) {
            if (method.getParameterCount() > 0) {
                m0 = method;
                break;
            }
        }
        namePresent = m0 == null ? true : m0.getParameters()[0].isNamePresent();
    } catch (Exception e) {
    }
    final Map<String, List<String>> asmParamMap = namePresent ? null : MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), webSocketType);
    final Set<String> messageNames = new HashSet<>();
    Method wildcardMethod = null;
    List<Method> mmethods = new ArrayList<>();
    for (Method method : webSocketType.getMethods()) {
        RestOnMessage rom = method.getAnnotation(RestOnMessage.class);
        if (rom == null)
            continue;
        String name = rom.name();
        if (!"*".equals(name) && !checkName(name))
            throw new RuntimeException("@RestOnMessage.name contains illegal characters on (" + method + ")");
        if (Modifier.isFinal(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not final but (" + method + ")");
        if (Modifier.isStatic(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not static but (" + method + ")");
        if (method.getReturnType() != void.class)
            throw new RuntimeException("@RestOnMessage method must return void but (" + method + ")");
        if (method.getExceptionTypes().length > 0)
            throw new RuntimeException("@RestOnMessage method can not throw exception but (" + method + ")");
        if (name.isEmpty())
            throw new RuntimeException(method + " RestOnMessage.name is empty createRestWebSocketServlet");
        if (messageNames.contains(name))
            throw new RuntimeException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet");
        messageNames.add(name);
        if ("*".equals(name)) {
            wildcardMethod = method;
        } else {
            mmethods.add(method);
        }
    }
    final List<Method> messageMethods = new ArrayList<>();
    messageMethods.addAll(mmethods);
    // wildcardMethod 必须放最后, _DynRestOnMessageConsumer 是按messageMethods顺序来判断的
    if (wildcardMethod != null)
        messageMethods.add(wildcardMethod);
    // ----------------------------------------------------------------------------------------
    final String resDesc = Type.getDescriptor(Resource.class);
    final String wsDesc = Type.getDescriptor(WebSocket.class);
    final String wsParamDesc = Type.getDescriptor(WebSocketParam.class);
    final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
    final String convertDisabledDesc = Type.getDescriptor(ConvertDisabled.class);
    final String webSocketParamName = Type.getInternalName(WebSocketParam.class);
    final String supDynName = WebSocketServlet.class.getName().replace('.', '/');
    final String webServletDesc = Type.getDescriptor(WebServlet.class);
    final String webSocketInternalName = Type.getInternalName(webSocketType);
    final String newDynName = "org/redkaledyn/http/restws/" + "_DynWebScoketServlet__" + webSocketType.getName().replace('.', '_').replace('$', '_');
    final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName();
    final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName;
    final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message";
    final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName;
    final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer";
    final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName;
    try {
        Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
        if (clz == null)
            clz = loader.loadClass(newDynName.replace('/', '.'));
        T servlet = (T) clz.getDeclaredConstructor().newInstance();
        Map<String, Annotation[]> msgclassToAnnotations = new HashMap<>();
        for (int i = 0; i < messageMethods.size(); i++) {
            // _DyncXXXWebSocketMessage 子消息List
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
            msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations());
        }
        clz.getField("_redkale_annotations").set(null, msgclassToAnnotations);
        if (rws.cryptor() != Cryptor.class) {
            Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance();
            // WebSocketServlet
            Field cryptorField = clz.getSuperclass().getDeclaredField("cryptor");
            cryptorField.setAccessible(true);
            cryptorField.set(servlet, cryptor);
        }
        if (messageAgent != null)
            ((WebSocketServlet) servlet).messageAgent = messageAgent;
        return servlet;
    } catch (Throwable e) {
    }
    final List<Field> resourcesFields = new ArrayList<>(resourcesFieldSet);
    StringBuilder sb1 = new StringBuilder();
    StringBuilder sb2 = new StringBuilder();
    for (int i = 0; i < resourcesFields.size(); i++) {
        Field field = resourcesFields.get(i);
        sb1.append(Type.getDescriptor(field.getType()));
        sb2.append(Utility.getTypeDescriptor(field.getGenericType()));
    }
    final String resourceDescriptor = sb1.toString();
    final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString();
    // ----------------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        // RestDyn
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true);
        av0.visit("simple", false);
        {
            AnnotationVisitor av1 = av0.visitArray("types");
            av1.visit(null, Type.getType("L" + newDynConsumerFullName.replace('.', '/') + ";"));
            av1.visit(null, Type.getType("L" + newDynWebSokcetFullName.replace('.', '/') + ";"));
            // 位置固定第三个,下面用Message类进行loadDecoder会用到
            av1.visit(null, Type.getType("L" + newDynMessageFullName.replace('.', '/') + ";"));
            av1.visitEnd();
        }
        av0.visitEnd();
    }
    {
        // RestDynSourceType
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true);
        av0.visit("value", Type.getType(Type.getDescriptor(webSocketType)));
        av0.visitEnd();
    }
    {
        // 注入 @WebServlet 注解
        String urlpath = (rws.catalog().isEmpty() ? "/" : ("/" + rws.catalog() + "/")) + rwsname;
        av0 = cw.visitAnnotation(webServletDesc, true);
        {
            AnnotationVisitor av1 = av0.visitArray("value");
            av1.visit(null, urlpath);
            av1.visitEnd();
        }
        av0.visit("name", rwsname);
        av0.visit("moduleid", 0);
        av0.visit("repair", rws.repair());
        av0.visit("comment", rws.comment());
        av0.visitEnd();
    }
    {
        // 内部类
        cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
            cw.visitInnerClass(newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
    }
    {
        // @Resource
        for (int i = 0; i < resourcesFields.size(); i++) {
            Field field = resourcesFields.get(i);
            Resource res = field.getAnnotation(Resource.class);
            java.lang.reflect.Type fieldType = field.getGenericType();
            fv = cw.visitField(ACC_PRIVATE, "_redkale_resource_" + i, Type.getDescriptor(field.getType()), fieldType == field.getType() ? null : Utility.getTypeDescriptor(fieldType), null);
            {
                av0 = fv.visitAnnotation(resDesc, true);
                av0.visit("name", res.name());
                av0.visitEnd();
            }
            fv.visitEnd();
        }
    }
    {
        // _redkale_annotations
        fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, "_redkale_annotations", "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;[Ljava/lang/annotation/Annotation;>;", null);
        fv.visitEnd();
    }
    {
        // _DynWebSocketServlet构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message"));
        mv.visitFieldInsn(PUTFIELD, newDynName, "messageRestType", "Ljava/lang/reflect/Type;");
        mv.visitVarInsn(ALOAD, 0);
        MethodDebugVisitor.pushInt(mv, rws.liveinterval());
        mv.visitFieldInsn(PUTFIELD, newDynName, "liveinterval", "I");
        mv.visitVarInsn(ALOAD, 0);
        MethodDebugVisitor.pushInt(mv, rws.wsmaxconns());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxconns", "I");
        mv.visitVarInsn(ALOAD, 0);
        MethodDebugVisitor.pushInt(mv, rws.wsmaxbody());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.mergemsg() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "mergemsg", "Z");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.anyuser() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "anyuser", "Z");
        mv.visitInsn(RETURN);
        mv.visitMaxs(3, 1);
        mv.visitEnd();
    }
    {
        // createWebSocket 方法
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createWebSocket", "()" + wsDesc, "<G::Ljava/io/Serializable;T:Ljava/lang/Object;>()L" + WebSocket.class.getName().replace('.', '/') + "<TG;TT;>;", null));
        mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName);
        mv.visitInsn(DUP);
        for (int i = 0; i < resourcesFields.size(); i++) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_resource_" + i, Type.getDescriptor(resourcesFields.get(i).getType()));
        }
        mv.visitMethodInsn(INVOKESPECIAL, newDynWebSokcetFullName, "<init>", "(" + resourceDescriptor + ")V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2 + resourcesFields.size(), 1);
        mv.visitEnd();
    }
    {
        // createRestOnMessageConsumer
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createRestOnMessageConsumer", "()Ljava/util/function/BiConsumer;", "()Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", null));
        mv.visitTypeInsn(NEW, newDynConsumerFullName);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, newDynConsumerFullName, "<init>", "()V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
    }
    {
        // resourceName
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "resourceName", "()Ljava/lang/String;", null, null));
        mv.visitLdcInsn(rwsname);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    RestClassLoader newLoader = new RestClassLoader(loader);
    Map<String, Annotation[]> msgclassToAnnotations = new HashMap<>();
    for (int i = 0; i < messageMethods.size(); i++) {
        // _DyncXXXWebSocketMessage 子消息List
        final Method method = messageMethods.get(i);
        String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
        String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
        msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations());
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynSuperMessageFullName, null, "java/lang/Object", new String[] { webSocketParamName, "java/lang/Runnable" });
        cw2.visitInnerClass(newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        Set<String> paramnames = new HashSet<>();
        String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method);
        List<String> names = asmParamMap == null ? null : asmParamMap.get(methodesc);
        // 删掉空元素
        if (names != null)
            while (names.remove(" ")) ;
        Parameter[] params = method.getParameters();
        // 必须使用LinkedHashMap确保顺序
        final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap();
        for (int j = 0; j < params.length; j++) {
            // 字段列表
            Parameter param = params[j];
            String paramname = param.getName();
            RestParam rp = param.getAnnotation(RestParam.class);
            if (rp != null && !rp.name().isEmpty()) {
                paramname = rp.name();
            } else if (names != null && names.size() > j) {
                paramname = names.get(j);
            }
            if (paramnames.contains(paramname))
                throw new RuntimeException(method + " has same @RestParam.name");
            paramnames.add(paramname);
            paramap.put(paramname, param);
            fv = cw2.visitField(ACC_PUBLIC, paramname, Type.getDescriptor(param.getType()), param.getType() == param.getParameterizedType() ? null : Utility.getTypeDescriptor(param.getParameterizedType()), null);
            fv.visitEnd();
        }
        if (method == wildcardMethod) {
            for (int j = 0; j < messageMethods.size(); j++) {
                Method method2 = messageMethods.get(j);
                if (method2 == wildcardMethod)
                    continue;
                String endfix2 = "_" + method2.getName() + "_" + (j > 9 ? j : ("0" + j));
                String newDynSuperMessageFullName2 = newDynMessageFullName + (method2 == wildcardMethod ? "" : endfix2);
                cw2.visitInnerClass(newDynSuperMessageFullName2, newDynName, newDynMessageSimpleName + endfix2, ACC_PUBLIC + ACC_STATIC);
                fv = cw2.visitField(ACC_PUBLIC, method2.getAnnotation(RestOnMessage.class).name(), "L" + newDynSuperMessageFullName2 + ";", null, null);
                fv.visitEnd();
            }
        }
        {
            // _redkale_websocket
            fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null);
            av0 = fv.visitAnnotation(convertDisabledDesc, true);
            av0.visitEnd();
            fv.visitEnd();
        }
        {
            // 空构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // getNames
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getNames", "()[Ljava/lang/String;", null, null));
            av0 = mv.visitAnnotation(convertDisabledDesc, true);
            av0.visitEnd();
            MethodDebugVisitor.pushInt(mv, paramap.size());
            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
            int index = -1;
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitInsn(DUP);
                MethodDebugVisitor.pushInt(mv, ++index);
                mv.visitLdcInsn(en.getKey());
                mv.visitInsn(AASTORE);
            }
            mv.visitInsn(ARETURN);
            mv.visitMaxs(paramap.size() + 2, 1);
            mv.visitEnd();
        }
        {
            // getValue
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getValue", "(Ljava/lang/String;)Ljava/lang/Object;", "<T:Ljava/lang/Object;>(Ljava/lang/String;)TT;", null));
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                Class paramType = en.getValue().getType();
                mv.visitLdcInsn(en.getKey());
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
                Label l1 = new Label();
                mv.visitJumpInsn(IFEQ, l1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynSuperMessageFullName, en.getKey(), Type.getDescriptor(paramType));
                if (paramType.isPrimitive()) {
                    Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(paramType, 1), 0).getClass();
                    mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), false);
                }
                mv.visitInsn(ARETURN);
                mv.visitLabel(l1);
            }
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        {
            // getAnnotations
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getAnnotations", "()[Ljava/lang/annotation/Annotation;", null, null));
            av0 = mv.visitAnnotation(convertDisabledDesc, true);
            av0.visitEnd();
            mv.visitFieldInsn(GETSTATIC, newDynName, "_redkale_annotations", "Ljava/util/Map;");
            mv.visitLdcInsn(newDynSuperMessageFullName);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
            mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;");
            mv.visitVarInsn(ASTORE, 1);
            mv.visitVarInsn(ALOAD, 1);
            Label l2 = new Label();
            mv.visitJumpInsn(IFNONNULL, l2);
            mv.visitInsn(ICONST_0);
            mv.visitTypeInsn(ANEWARRAY, "java/lang/annotation/Annotation");
            mv.visitInsn(ARETURN);
            mv.visitLabel(l2);
            mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] { "[Ljava/lang/annotation/Annotation;" }, 0, null);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitInsn(ARRAYLENGTH);
            mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "copyOf", "([Ljava/lang/Object;I)[Ljava/lang/Object;", false);
            mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;");
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        {
            // execute
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, newDynSuperMessageFullName, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            mv.visitVarInsn(ALOAD, 1);
            mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name());
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, "preOnMessage", "(Ljava/lang/String;" + wsParamDesc + "Ljava/lang/Runnable;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 2);
            mv.visitEnd();
        }
        {
            // run
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynSuperMessageFullName, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, (newDynSuperMessageFullName), en.getKey(), Type.getDescriptor(en.getValue().getType()));
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, method.getName(), Type.getMethodDescriptor(method), false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        byte[] bytes = cw2.toByteArray();
        Class cz = newLoader.loadClass((newDynSuperMessageFullName).replace('/', '.'), bytes);
        RedkaleClassLoader.putDynClass((newDynSuperMessageFullName).replace('/', '.'), bytes, cz);
    }
    if (wildcardMethod == null) {
        // _DynXXXWebSocketMessage class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
            cw2.visitInnerClass(newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
            fv = cw2.visitField(ACC_PUBLIC, method.getAnnotation(RestOnMessage.class).name(), "L" + newDynSuperMessageFullName + ";", null, null);
            fv.visitEnd();
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        byte[] bytes = cw2.toByteArray();
        Class cz = newLoader.loadClass(newDynMessageFullName.replace('/', '.'), bytes);
        RedkaleClassLoader.putDynClass(newDynMessageFullName.replace('/', '.'), bytes, cz);
    }
    {
        // _DynXXXWebSocket class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynWebSokcetFullName, null, webSocketInternalName, null);
        cw2.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        {
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "<init>", "()V", false);
            for (int i = 0; i < resourcesFields.size(); i++) {
                Field field = resourcesFields.get(i);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, i + 1);
                mv.visitFieldInsn(PUTFIELD, newDynWebSokcetFullName, field.getName(), Type.getDescriptor(field.getType()));
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(2, 1 + resourcesFields.size());
            mv.visitEnd();
        }
        {
            // RestDyn
            av0 = cw2.visitAnnotation(Type.getDescriptor(RestDyn.class), true);
            av0.visit("simple", false);
            av0.visitEnd();
        }
        cw2.visitEnd();
        byte[] bytes = cw2.toByteArray();
        Class cz = newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), bytes);
        RedkaleClassLoader.putDynClass(newDynWebSokcetFullName.replace('/', '.'), bytes, cz);
    }
    {
        // _DynRestOnMessageConsumer class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynConsumerFullName, "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", "java/lang/Object", new String[] { "java/util/function/BiConsumer" });
        cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
            cw2.visitInnerClass(newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName);
            mv.visitVarInsn(ASTORE, 3);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, newDynMessageFullName);
            mv.visitVarInsn(ASTORE, 4);
            for (int i = 0; i < messageMethods.size(); i++) {
                final Method method = messageMethods.get(i);
                String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
                String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix);
                final String messagename = method.getAnnotation(RestOnMessage.class).name();
                if (method == wildcardMethod) {
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitVarInsn(ALOAD, 3);
                    mv.visitMethodInsn(INVOKEVIRTUAL, newDynSuperMessageFullName, "execute", "(L" + newDynWebSokcetFullName + ";)V", false);
                } else {
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";");
                    Label ifLabel = new Label();
                    mv.visitJumpInsn(IFNULL, ifLabel);
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";");
                    mv.visitVarInsn(ALOAD, 3);
                    mv.visitMethodInsn(INVOKEVIRTUAL, newDynSuperMessageFullName, "execute", "(L" + newDynWebSokcetFullName + ";)V", false);
                    mv.visitInsn(RETURN);
                    mv.visitLabel(ifLabel);
                }
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3 + messageMethods.size());
            mv.visitEnd();
        }
        {
            // 虚拟accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, WebSocket.class.getName().replace('.', '/'));
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3);
            mv.visitEnd();
        }
        cw2.visitEnd();
        byte[] bytes = cw2.toByteArray();
        Class cz = newLoader.loadClass(newDynConsumerFullName.replace('/', '.'), bytes);
        RedkaleClassLoader.putDynClass(newDynConsumerFullName.replace('/', '.'), bytes, cz);
    }
    cw.visitEnd();
    byte[] bytes = cw.toByteArray();
    Class<?> newClazz = newLoader.loadClass(newDynName.replace('/', '.'), bytes);
    RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
    RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
    // 固定Message类
    JsonFactory.root().loadDecoder(newClazz.getAnnotation(RestDyn.class).types()[2]);
    RedkaleClassLoader.putReflectionPublicMethods(webSocketType.getName());
    Class cwt = webSocketType;
    do {
        RedkaleClassLoader.putReflectionDeclaredFields(cwt.getName());
    } while ((cwt = cwt.getSuperclass()) != Object.class);
    RedkaleClassLoader.putReflectionDeclaredConstructors(webSocketType, webSocketType.getName());
    try {
        T servlet = (T) newClazz.getDeclaredConstructor().newInstance();
        Field field = newClazz.getField("_redkale_annotations");
        field.set(null, msgclassToAnnotations);
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), field);
        if (rws.cryptor() != Cryptor.class) {
            RedkaleClassLoader.putReflectionDeclaredConstructors(rws.cryptor(), rws.cryptor().getName());
            Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance();
            // WebSocketServlet
            Field cryptorField = newClazz.getSuperclass().getDeclaredField("cryptor");
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), cryptorField);
            cryptorField.setAccessible(true);
            cryptorField.set(servlet, cryptor);
        }
        if (messageAgent != null)
            ((WebSocketServlet) servlet).messageAgent = messageAgent;
        return servlet;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : Resource(javax.annotation.Resource) MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) Type(org.redkale.asm.Type) ElementType(java.lang.annotation.ElementType)

Example 4 with MethodDebugVisitor

use of org.redkale.asm.MethodDebugVisitor in project redkale by redkale.

the class Sncp method createLocalServiceClass.

/**
 * <blockquote><pre>
 * public class TestService implements Service{
 *
 *      public String findSomeThing(){
 *          return "hello";
 *      }
 *
 *      &#64;RpcMultiRun(selfrun = false)
 *      public void createSomeThing(TestBean bean){
 *          //do something
 *      }
 *
 *      &#64;RpcMultiRun
 *      public String updateSomeThing(String id){
 *          return "hello" + id;
 *      }
 * }
 * </pre></blockquote>
 *
 * <blockquote><pre>
 * &#64;Resource(name = "")
 * &#64;SncpDyn(remote = false)
 * &#64;ResourceType(TestService.class)
 * public final class _DynLocalTestService extends TestService{
 *
 *      private AnyValue _redkale_conf;
 *
 *      private SncpClient _redkale_client;
 *
 *      &#64;Override
 *      public String toString() {
 *          return _redkale_selfstring == null ? super.toString() : _redkale_selfstring;
 *      }
 * }
 * </pre></blockquote>
 *
 * 创建Service的本地模式Class
 *
 * @param <T>              Service子类
 * @param classLoader      ClassLoader
 * @param name             资源名
 * @param serviceImplClass Service类
 *
 * @return Service实例
 */
@SuppressWarnings("unchecked")
protected static <T extends Service> Class<? extends T> createLocalServiceClass(ClassLoader classLoader, final String name, final Class<T> serviceImplClass) {
    if (serviceImplClass == null)
        return null;
    if (!Service.class.isAssignableFrom(serviceImplClass))
        return serviceImplClass;
    ResourceFactory.checkResourceName(name);
    int mod = serviceImplClass.getModifiers();
    if (!java.lang.reflect.Modifier.isPublic(mod))
        return serviceImplClass;
    if (java.lang.reflect.Modifier.isAbstract(mod))
        return serviceImplClass;
    final String supDynName = serviceImplClass.getName().replace('.', '/');
    final String clientName = SncpClient.class.getName().replace('.', '/');
    final String resDesc = Type.getDescriptor(Resource.class);
    final String clientDesc = Type.getDescriptor(SncpClient.class);
    final String anyValueDesc = Type.getDescriptor(AnyValue.class);
    final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
    ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    // String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceImplClass.getSimpleName();
    String newDynName = "org/redkaledyn/service/local/_DynLocalService__" + serviceImplClass.getName().replace('.', '_').replace('$', '_');
    if (!name.isEmpty()) {
        boolean normal = true;
        for (char ch : name.toCharArray()) {
            if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
                normal = false;
        }
        if (!normal)
            throw new RuntimeException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z");
        newDynName += "_" + (normal ? name : hash(name));
    }
    try {
        Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
        return (Class<T>) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz);
    } catch (ClassNotFoundException e) {
    } catch (Throwable t) {
        t.printStackTrace();
    }
    // ------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        av0 = cw.visitAnnotation(resDesc, true);
        av0.visit("name", name);
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(sncpDynDesc, true);
        av0.visit("remote", Boolean.FALSE);
        av0.visitEnd();
    }
    {
        // 给新类加上 原有的Annotation
        for (Annotation ann : serviceImplClass.getAnnotations()) {
            if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType)
                continue;
            MethodDebugVisitor.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
        }
    }
    {
        av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
        ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class);
        av0.visit("value", Type.getType(Type.getDescriptor(rty == null ? serviceImplClass : rty.value())));
        av0.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
        fv.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null);
        fv.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_messageagent", Type.getDescriptor(MessageAgent.class), null, null);
        fv.visitEnd();
    }
    {
        // 构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        // toString()
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNONNULL, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
        Label l2 = new Label();
        mv.visitJumpInsn(GOTO, l2);
        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "toSimpleString", "()Ljava/lang/String;", false);
        mv.visitLabel(l2);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    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);
    RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
    RedkaleClassLoader.putReflectionPublicClasses(newDynName.replace('/', '.'));
    RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
    try {
        Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c);
        c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c);
        c = newClazz.getDeclaredField(FIELDPREFIX + "_messageagent");
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c);
    } catch (Exception e) {
    }
    return (Class<T>) newClazz;
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) Resource(javax.annotation.Resource) MessageAgent(org.redkale.mq.MessageAgent) Annotation(java.lang.annotation.Annotation)

Example 5 with MethodDebugVisitor

use of org.redkale.asm.MethodDebugVisitor in project redkale by redkale.

the class Rest method createRestServlet.

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();
    if (!java.lang.reflect.Modifier.isPublic(mod))
        throw new RuntimeException(baseServletType + " is not Public Class on createRestServlet");
    if (java.lang.reflect.Modifier.isAbstract(mod)) {
        for (Method m : baseServletType.getDeclaredMethods()) {
            if (java.lang.reflect.Modifier.isAbstract(m.getModifiers())) {
                // @since 2.4.0
                throw new RuntimeException(baseServletType + " cannot contains a abstract Method on " + baseServletType);
            }
        }
    }
    final String restInternalName = Type.getInternalName(Rest.class);
    final String serviceDesc = Type.getDescriptor(serviceType);
    final String webServletDesc = Type.getDescriptor(WebServlet.class);
    final String resDesc = Type.getDescriptor(Resource.class);
    final String reqDesc = Type.getDescriptor(HttpRequest.class);
    final String respDesc = Type.getDescriptor(HttpResponse.class);
    final String convertDesc = Type.getDescriptor(Convert.class);
    final String typeDesc = Type.getDescriptor(java.lang.reflect.Type.class);
    final String retDesc = Type.getDescriptor(RetResult.class);
    final String httpResultDesc = Type.getDescriptor(HttpResult.class);
    final String httpScopeDesc = Type.getDescriptor(HttpScope.class);
    final String stageDesc = Type.getDescriptor(CompletionStage.class);
    final String flipperDesc = Type.getDescriptor(Flipper.class);
    final String channelDesc = Type.getDescriptor(ChannelContext.class);
    final String httpServletName = HttpServlet.class.getName().replace('.', '/');
    final String actionEntryName = HttpServlet.ActionEntry.class.getName().replace('.', '/');
    final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
    final String multiContextDesc = Type.getDescriptor(MultiContext.class);
    final String multiContextName = MultiContext.class.getName().replace('.', '/');
    final String mappingDesc = Type.getDescriptor(HttpMapping.class);
    final String httpParamDesc = Type.getDescriptor(HttpParam.class);
    final String httpParamsDesc = Type.getDescriptor(HttpParam.HttpParams.class);
    final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParameterStyle.class);
    final String reqInternalName = Type.getInternalName(HttpRequest.class);
    final String respInternalName = Type.getInternalName(HttpResponse.class);
    final String attrInternalName = Type.getInternalName(org.redkale.util.Attribute.class);
    final String retInternalName = Type.getInternalName(RetResult.class);
    final String serviceTypeInternalName = Type.getInternalName(serviceType);
    HttpUserType hut = baseServletType.getAnnotation(HttpUserType.class);
    final Class userType = (userType0 == null || userType0 == Object.class) ? (hut == null ? null : hut.value()) : userType0;
    if (userType != null && (userType.isPrimitive() || userType.getName().startsWith("java.") || userType.getName().startsWith("javax."))) {
        throw new RuntimeException(HttpUserType.class.getSimpleName() + " must be a JavaBean but found " + userType);
    }
    final String supDynName = baseServletType.getName().replace('.', '/');
    final RestService controller = serviceType.getAnnotation(RestService.class);
    // 标记为ignore=true不创建Servlet
    if (controller != null && controller.ignore())
        throw new RuntimeException(serviceType + " is ignore Rest Service Class");
    final boolean serrpconly = controller != null && controller.rpconly();
    ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    String stname = serviceType.getSimpleName();
    if (stname.startsWith("Service")) {
        // 类似ServiceWatchService这样的类保留第一个Service字样
        stname = "Service" + stname.substring("Service".length()).replaceAll("Service.*$", "");
    } else {
        stname = stname.replaceAll("Service.*$", "");
    }
    // String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + stname + "RestServlet";
    final String newDynName = "org/redkaledyn/http/rest/" + "_Dyn" + stname + "RestServlet__" + serviceType.getName().replace('.', '_').replace('$', '_') + "DynServlet";
    try {
        Class newClazz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
        if (newClazz == null)
            newClazz = loader.loadClass(newDynName.replace('/', '.'));
        T obj = (T) newClazz.getDeclaredConstructor().newInstance();
        final String defmodulename = getWebModuleNameLowerCase(serviceType);
        final String bigmodulename = getWebModuleName(serviceType);
        final Map<String, Object> classMap = new LinkedHashMap<>();
        final List<MappingEntry> entrys = new ArrayList<>();
        final List<java.lang.reflect.Type[]> paramTypes = new ArrayList<>();
        final List<java.lang.reflect.Type> retvalTypes = new ArrayList<>();
        final List<Object[]> restConverts = new ArrayList<>();
        final Map<java.lang.reflect.Type, String> typeRefs = new LinkedHashMap<>();
        final Map<String, Method> mappingurlToMethod = new HashMap<>();
        final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
        final Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>();
        {
            // entrys、paramTypes赋值
            final Method[] allMethods = serviceType.getMethods();
            Arrays.sort(allMethods, (m1, m2) -> {
                // 必须排序,否则paramTypes顺序容易乱
                int s = m1.getName().compareTo(m2.getName());
                if (s != 0)
                    return s;
                s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes()));
                return s;
            });
            int methodidex = 0;
            for (final Method method : allMethods) {
                if (Modifier.isStatic(method.getModifiers()))
                    continue;
                if (method.isSynthetic())
                    continue;
                if (EXCLUDERMETHODS.contains(method.getName()))
                    continue;
                if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) {
                    if ("init".equals(method.getName()))
                        continue;
                    if ("stop".equals(method.getName()))
                        continue;
                    if ("destroy".equals(method.getName()))
                        continue;
                }
                if (controller == null)
                    continue;
                RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class);
                if (!controller.automapping() && mappings.length < 1)
                    continue;
                boolean ignore = false;
                for (RestMapping mapping : mappings) {
                    if (mapping.ignore()) {
                        ignore = true;
                        break;
                    }
                }
                if (ignore)
                    continue;
                paramTypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType));
                retvalTypes.add(formatRestReturnType(method, serviceType));
                if (mappings.length == 0) {
                    // 没有Mapping,设置一个默认值
                    MappingEntry entry = new MappingEntry(serrpconly, methodidex, null, bigmodulename, method);
                    entrys.add(entry);
                } else {
                    for (RestMapping mapping : mappings) {
                        MappingEntry entry = new MappingEntry(serrpconly, methodidex, mapping, defmodulename, method);
                        entrys.add(entry);
                    }
                }
                methodidex++;
            }
            Collections.sort(entrys);
        }
        {
            // restConverts、typeRefs、mappingurlToMethod、restAttributes、bodyTypes赋值
            for (final MappingEntry entry : entrys) {
                mappingurlToMethod.put(entry.mappingurl, entry.mappingMethod);
                final Method method = entry.mappingMethod;
                final Class returnType = method.getReturnType();
                final Parameter[] params = method.getParameters();
                final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class);
                final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class);
                if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) {
                    restConverts.add(new Object[] { rcs, rcc });
                }
                // 解析方法中的每个参数
                List<Object[]> paramlist = new ArrayList<>();
                for (int i = 0; i < params.length; i++) {
                    final Parameter param = params[i];
                    final Class ptype = param.getType();
                    String n = null;
                    String comment = "";
                    boolean required = true;
                    int radix = 10;
                    RestHeader annhead = param.getAnnotation(RestHeader.class);
                    if (annhead != null) {
                        n = annhead.name();
                        radix = annhead.radix();
                        comment = annhead.comment();
                        required = annhead.required();
                    }
                    RestCookie anncookie = param.getAnnotation(RestCookie.class);
                    if (anncookie != null) {
                        n = anncookie.name();
                        radix = anncookie.radix();
                        comment = anncookie.comment();
                    }
                    RestSessionid annsid = param.getAnnotation(RestSessionid.class);
                    RestAddress annaddr = param.getAnnotation(RestAddress.class);
                    if (annaddr != null) {
                        comment = annaddr.comment();
                    }
                    RestBody annbody = param.getAnnotation(RestBody.class);
                    if (annbody != null) {
                        comment = annbody.comment();
                    }
                    RestUploadFile annfile = param.getAnnotation(RestUploadFile.class);
                    if (annfile != null) {
                        comment = annfile.comment();
                    }
                    RestURI annuri = param.getAnnotation(RestURI.class);
                    if (annuri != null) {
                        comment = annuri.comment();
                    }
                    RestUserid userid = param.getAnnotation(RestUserid.class);
                    if (userid != null) {
                        comment = "";
                    }
                    RestHeaders annheaders = param.getAnnotation(RestHeaders.class);
                    if (annheaders != null) {
                        comment = "";
                    }
                    RestParams annparams = param.getAnnotation(RestParams.class);
                    if (annparams != null) {
                        comment = "";
                    }
                    RestParam annpara = param.getAnnotation(RestParam.class);
                    if (annpara != null)
                        radix = annpara.radix();
                    if (annpara != null)
                        comment = annpara.comment();
                    if (annpara != null)
                        required = annpara.required();
                    if (n == null)
                        n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
                    // 用户类型特殊处理
                    if (n == null && ptype == userType)
                        n = "&";
                    if (n == null) {
                        if (param.isNamePresent()) {
                            n = param.getName();
                        } else if (ptype == Flipper.class) {
                            n = "flipper";
                        }
                    }
                    // n maybe is null
                    java.lang.reflect.Type paramtype = TypeToken.getGenericType(param.getParameterizedType(), serviceType);
                    paramlist.add(new Object[] { param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie, annbody, annfile, annuri, userid, annheaders, annparams, paramtype });
                }
                for (Object[] ps : paramlist) {
                    // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie, annbody, annfile, annuri, annuserid, annheaders, annparams, paramtype}
                    // 是否取userid
                    final boolean isuserid = ((RestUserid) ps[14]) != null;
                    // @RestUserid 不需要生成 @HttpParam
                    if ((ps[1] != null && ps[1].toString().indexOf('&') >= 0) || isuserid)
                        continue;
                    // @RestAddress 不需要生成 @HttpParam
                    if (((RestAddress) ps[8]) != null)
                        continue;
                    java.lang.reflect.Type pgtype = TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType);
                    if (pgtype != (Class) ps[2]) {
                        String refid = typeRefs.get(pgtype);
                        if (refid == null) {
                            refid = "_typeref_" + typeRefs.size();
                            typeRefs.put(pgtype, refid);
                        }
                    }
                    // 参数类型
                    final Parameter param = (Parameter) ps[0];
                    // 参数名
                    String pname = (String) ps[1];
                    // 参数类型
                    Class ptype = (Class) ps[2];
                    int radix = (Integer) ps[3];
                    String comment = (String) ps[4];
                    boolean required = (Boolean) ps[5];
                    RestParam annpara = (RestParam) ps[6];
                    RestSessionid annsid = (RestSessionid) ps[7];
                    RestAddress annaddr = (RestAddress) ps[8];
                    RestHeader annhead = (RestHeader) ps[9];
                    RestCookie anncookie = (RestCookie) ps[10];
                    RestBody annbody = (RestBody) ps[11];
                    RestUploadFile annfile = (RestUploadFile) ps[12];
                    RestURI annuri = (RestURI) ps[13];
                    RestUserid annuserid = (RestUserid) ps[14];
                    RestHeaders annheaders = (RestHeaders) ps[15];
                    RestParams annparams = (RestParams) ps[16];
                    if (CompletionHandler.class.isAssignableFrom(ptype)) {
                    // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class)
                    } else if (annsid != null) {
                    // HttpRequest.getSessionid(true|false)
                    } else if (annaddr != null) {
                    // HttpRequest.getRemoteAddr
                    } else if (annheaders != null) {
                    // HttpRequest.getHeaders
                    } else if (annparams != null) {
                    // HttpRequest.getParameters
                    } else if (annbody != null) {
                    // HttpRequest.getBodyUTF8 / HttpRequest.getBody
                    } else if (annfile != null) {
                    // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / HttpRequest.partsFiles
                    } else if (annuri != null) {
                    // HttpRequest.getRequestURI
                    } else if (annuserid != null) {
                    // HttpRequest.currentUserid
                    } else if ("#".equals(pname)) {
                    // 从request.getRequstURI 中取参数
                    } else if (pname != null && pname.charAt(0) == '#') {
                    // 从request.getRequstURIPath 中去参数
                    } else if ("&".equals(pname) && ptype == userType) {
                    // 当前用户对象的类名
                    } else if (ptype.isPrimitive()) {
                    } else if (ptype == String.class) {
                    } else if (ptype == ChannelContext.class) {
                    } else if (ptype == Flipper.class) {
                    } else {
                        // 其他Json对象
                        // 构建 RestHeader、RestCookie、RestAddress 等赋值操作
                        Class loop = ptype;
                        Set<String> fields = new HashSet<>();
                        Map<String, Object[]> attrParaNames = new LinkedHashMap<>();
                        do {
                            // 接口时getSuperclass可能会得到null
                            if (loop == null || loop.isInterface())
                                break;
                            for (Field field : loop.getDeclaredFields()) {
                                if (Modifier.isStatic(field.getModifiers()))
                                    continue;
                                if (Modifier.isFinal(field.getModifiers()))
                                    continue;
                                if (fields.contains(field.getName()))
                                    continue;
                                RestHeader rh = field.getAnnotation(RestHeader.class);
                                RestCookie rc = field.getAnnotation(RestCookie.class);
                                RestSessionid rs = field.getAnnotation(RestSessionid.class);
                                RestAddress ra = field.getAnnotation(RestAddress.class);
                                RestBody rb = field.getAnnotation(RestBody.class);
                                RestUploadFile ru = field.getAnnotation(RestUploadFile.class);
                                RestURI ri = field.getAnnotation(RestURI.class);
                                if (rh == null && rc == null && ra == null && rb == null && rs == null && ru == null && ri == null)
                                    continue;
                                org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field);
                                String attrFieldName;
                                String restname = "";
                                if (rh != null) {
                                    attrFieldName = "_redkale_attr_header_" + (field.getType() != String.class ? "json_" : "") + restAttributes.size();
                                    restname = rh.name();
                                } else if (rc != null) {
                                    attrFieldName = "_redkale_attr_cookie_" + restAttributes.size();
                                    restname = rc.name();
                                } else if (rs != null) {
                                    attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size();
                                    // 用于下面区分create值
                                    restname = rs.create() ? "1" : "";
                                } else if (ra != null) {
                                    attrFieldName = "_redkale_attr_address_" + restAttributes.size();
                                // restname = "";
                                } else if (rb != null && field.getType() == String.class) {
                                    attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size();
                                // restname = "";
                                } else if (rb != null && field.getType() == byte[].class) {
                                    attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size();
                                // restname = "";
                                } else if (rb != null && field.getType() != String.class && field.getType() != byte[].class) {
                                    attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size();
                                // restname = "";
                                } else if (ru != null && field.getType() == byte[].class) {
                                    attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size();
                                // restname = "";
                                } else if (ru != null && field.getType() == File.class) {
                                    attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size();
                                // restname = "";
                                } else if (ru != null && field.getType() == File[].class) {
                                    attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size();
                                // restname = "";
                                } else if (ri != null && field.getType() == String.class) {
                                    attrFieldName = "_redkale_attr_uri_" + restAttributes.size();
                                // restname = "";
                                } else {
                                    continue;
                                }
                                restAttributes.put(attrFieldName, attr);
                                attrParaNames.put(attrFieldName, new Object[] { restname, field.getType(), field.getGenericType(), ru });
                                fields.add(field.getName());
                            }
                        } while ((loop = loop.getSuperclass()) != Object.class);
                        if (!attrParaNames.isEmpty()) {
                            // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestBody字段
                            for (Map.Entry<String, Object[]> en : attrParaNames.entrySet()) {
                                if (en.getKey().contains("_header_")) {
                                    String headerkey = en.getValue()[0].toString();
                                    if ("Host".equalsIgnoreCase(headerkey)) {
                                    } else if ("Content-Type".equalsIgnoreCase(headerkey)) {
                                    } else if ("Connection".equalsIgnoreCase(headerkey)) {
                                    } else if ("Method".equalsIgnoreCase(headerkey)) {
                                    } else if (en.getKey().contains("_header_json_")) {
                                        String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size();
                                        bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]);
                                    }
                                } else if (en.getKey().contains("_cookie_")) {
                                } else if (en.getKey().contains("_sessionid_")) {
                                } else if (en.getKey().contains("_address_")) {
                                } else if (en.getKey().contains("_uri_")) {
                                } else if (en.getKey().contains("_bodystring_")) {
                                } else if (en.getKey().contains("_bodybytes_")) {
                                } else if (en.getKey().contains("_bodyjson_")) {
                                    // JavaBean 转 Json
                                    String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size();
                                    bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]);
                                } else if (en.getKey().contains("_uploadbytes_")) {
                                // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                                } else if (en.getKey().contains("_uploadfile_")) {
                                // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                                } else if (en.getKey().contains("_uploadfiles_")) {
                                // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                                }
                            }
                        }
                    }
                }
                java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType);
                Class rtc = returnType;
                if (rtc == void.class) {
                    rtc = RetResult.class;
                    grt = TYPE_RETRESULT_STRING;
                } else if (CompletionStage.class.isAssignableFrom(returnType)) {
                    ParameterizedType ptgrt = (ParameterizedType) grt;
                    grt = ptgrt.getActualTypeArguments()[0];
                    rtc = TypeToken.typeToClass(grt);
                    // 应该不会发生吧?
                    if (rtc == null)
                        rtc = Object.class;
                } else if (Flows.maybePublisherClass(returnType)) {
                    java.lang.reflect.Type grt0 = Flows.maybePublisherSubType(grt);
                    if (grt0 != null)
                        grt = grt0;
                }
                if (grt != rtc) {
                    String refid = typeRefs.get(grt);
                    if (refid == null) {
                        refid = "_typeref_" + typeRefs.size();
                        typeRefs.put(grt, refid);
                    }
                }
            }
        }
        for (Map.Entry<java.lang.reflect.Type, String> en : typeRefs.entrySet()) {
            Field refField = newClazz.getDeclaredField(en.getValue());
            refField.setAccessible(true);
            refField.set(obj, en.getKey());
        }
        for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) {
            Field attrField = newClazz.getDeclaredField(en.getKey());
            attrField.setAccessible(true);
            attrField.set(obj, en.getValue());
        }
        for (Map.Entry<String, java.lang.reflect.Type> en : bodyTypes.entrySet()) {
            Field genField = newClazz.getDeclaredField(en.getKey());
            genField.setAccessible(true);
            genField.set(obj, en.getValue());
        }
        for (int i = 0; i < restConverts.size(); i++) {
            Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1));
            genField.setAccessible(true);
            Object[] rc = restConverts.get(i);
            genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]));
        }
        Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME);
        typesfield.setAccessible(true);
        java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][];
        paramtypeArray = paramTypes.toArray(paramtypeArray);
        typesfield.set(obj, paramtypeArray);
        Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME);
        retfield.setAccessible(true);
        java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()];
        rettypeArray = retvalTypes.toArray(rettypeArray);
        retfield.set(obj, rettypeArray);
        Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME);
        tostringfield.setAccessible(true);
        java.util.function.Supplier<String> sSupplier = () -> JsonConvert.root().convertTo(classMap);
        tostringfield.set(obj, sSupplier);
        Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry");
        restactMethod.setAccessible(true);
        Field tmpentrysfield = HttpServlet.class.getDeclaredField("_actionmap");
        tmpentrysfield.setAccessible(true);
        HashMap<String, HttpServlet.ActionEntry> innerEntryMap = (HashMap) restactMethod.invoke(obj);
        for (Map.Entry<String, HttpServlet.ActionEntry> en : innerEntryMap.entrySet()) {
            Method m = mappingurlToMethod.get(en.getKey());
            if (m != null)
                en.getValue().annotations = HttpServlet.ActionEntry.annotations(m);
        }
        tmpentrysfield.set(obj, innerEntryMap);
        return obj;
    } catch (ClassNotFoundException e) {
    } catch (Throwable e) {
        e.printStackTrace();
    }
    // ------------------------------------------------------------------------------
    final String defmodulename = getWebModuleNameLowerCase(serviceType);
    final String bigmodulename = getWebModuleName(serviceType);
    final String catalog = controller == null ? "" : controller.catalog();
    if (!checkName(catalog))
        throw new RuntimeException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9");
    if (!checkName(defmodulename))
        throw new RuntimeException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ cannot begin 0-9");
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    final List<MappingEntry> entrys = new ArrayList<>();
    final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
    final Map<String, Object> classMap = new LinkedHashMap<>();
    final Map<java.lang.reflect.Type, String> typeRefs = new LinkedHashMap<>();
    final List<java.lang.reflect.Type[]> paramTypes = new ArrayList<>();
    final List<java.lang.reflect.Type> retvalTypes = new ArrayList<>();
    final Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>();
    final List<Object[]> restConverts = new ArrayList<>();
    final Map<String, Method> mappingurlToMethod = new HashMap<>();
    cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        // RestDynSourceType
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true);
        av0.visit("value", Type.getType(Type.getDescriptor(serviceType)));
        av0.visitEnd();
    }
    boolean dynsimple = true;
    // 获取所有可以转换成HttpMapping的方法
    int methodidex = 0;
    final MessageMultiConsumer mmc = serviceType.getAnnotation(MessageMultiConsumer.class);
    if (mmc != null && (mmc.module() == null || mmc.module().isEmpty())) {
        throw new RuntimeException("@" + MessageMultiConsumer.class.getSimpleName() + ".module can not empty in " + serviceType.getName());
    }
    if (mmc != null && !checkName2(mmc.module())) {
        throw new RuntimeException(serviceType.getName() + " have illegal " + MessageMultiConsumer.class.getSimpleName() + ".module, only 0-9 a-z A-Z _ - . cannot begin 0-9");
    }
    if (mmc != null) {
        MethodDebugVisitor.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(mmc.annotationType()), true), mmc);
    }
    final Method[] allMethods = serviceType.getMethods();
    Arrays.sort(allMethods, (m1, m2) -> {
        // 必须排序,否则paramTypes顺序容易乱
        int s = m1.getName().compareTo(m2.getName());
        if (s != 0)
            return s;
        s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes()));
        return s;
    });
    for (final Method method : allMethods) {
        if (Modifier.isStatic(method.getModifiers()))
            continue;
        if (method.isSynthetic())
            continue;
        if (EXCLUDERMETHODS.contains(method.getName()))
            continue;
        if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) {
            if ("init".equals(method.getName()))
                continue;
            if ("stop".equals(method.getName()))
                continue;
            if ("destroy".equals(method.getName()))
                continue;
        }
        if (controller == null)
            continue;
        RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class);
        if (!controller.automapping() && mappings.length < 1)
            continue;
        boolean ignore = false;
        for (RestMapping mapping : mappings) {
            if (mapping.ignore()) {
                ignore = true;
                break;
            }
        }
        if (ignore)
            continue;
        Class[] extypes = method.getExceptionTypes();
        if (extypes.length > 0) {
            for (Class exp : extypes) {
                if (!RuntimeException.class.isAssignableFrom(exp) && !IOException.class.isAssignableFrom(exp)) {
                    throw new RuntimeException("@" + RestMapping.class.getSimpleName() + " only for method(" + method + ") with throws IOException");
                }
            }
        }
        if (mmc != null && method.getReturnType() != void.class) {
            throw new RuntimeException("@" + RestMapping.class.getSimpleName() + " only for method(" + method + ") with return void by @" + MessageMultiConsumer.class.getSimpleName() + " Service");
        }
        paramTypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType));
        retvalTypes.add(formatRestReturnType(method, serviceType));
        if (mappings.length == 0) {
            // 没有Mapping,设置一个默认值
            MappingEntry entry = new MappingEntry(serrpconly, methodidex, null, bigmodulename, 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(serrpconly, methodidex, mapping, defmodulename, method);
                if (entrys.contains(entry))
                    throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
                entrys.add(entry);
            }
        }
        methodidex++;
    }
    // 没有可HttpMapping的方法
    if (entrys.isEmpty())
        return null;
    Collections.sort(entrys);
    RestClassLoader newLoader = new RestClassLoader(loader);
    final int moduleid = controller == null ? 0 : controller.moduleid();
    {
        // 注入 @WebServlet 注解
        String urlpath = "";
        boolean repair = controller == null ? true : controller.repair();
        String comment = controller == null ? "" : controller.comment();
        av0 = cw.visitAnnotation(webServletDesc, true);
        {
            AnnotationVisitor av1 = av0.visitArray("value");
            boolean pound = false;
            for (MappingEntry entry : entrys) {
                if (entry.existsPound) {
                    pound = true;
                    break;
                }
            }
            if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) {
                for (MappingEntry entry : entrys) {
                    String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name;
                    if ("//".equals(suburl)) {
                        suburl = "/";
                    } else if (suburl.length() > 2 && suburl.endsWith("/")) {
                        suburl += "*";
                    }
                    urlpath += "," + suburl;
                    av1.visit(null, suburl);
                }
                if (urlpath.length() > 0)
                    urlpath = urlpath.substring(1);
            } else {
                urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + defmodulename + "/*";
                av1.visit(null, urlpath);
            }
            av1.visitEnd();
        }
        av0.visit("name", defmodulename);
        av0.visit("moduleid", moduleid);
        av0.visit("repair", repair);
        av0.visit("comment", comment);
        av0.visitEnd();
        classMap.put("type", serviceType.getName());
        classMap.put("url", urlpath);
        classMap.put("moduleid", moduleid);
        classMap.put("repair", repair);
    // classMap.put("comment", comment); //不显示太多信息
    }
    {
        // 内部类
        cw.visitInnerClass(actionEntryName, httpServletName, HttpServlet.ActionEntry.class.getSimpleName(), ACC_PROTECTED + ACC_FINAL + ACC_STATIC);
        for (final MappingEntry entry : entrys) {
            cw.visitInnerClass(newDynName + "$" + entry.newActionClassName, newDynName, entry.newActionClassName, ACC_PRIVATE + ACC_STATIC);
        }
    }
    {
        // 注入 @Resource  private XXXService _service;
        fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null);
        av0 = fv.visitAnnotation(resDesc, true);
        av0.visit("name", "");
        av0.visitEnd();
        fv.visitEnd();
    }
    {
        // 注入 @Resource(name = "APP_HOME")  private File _redkale_home;
        fv = cw.visitField(ACC_PRIVATE, "_redkale_home", Type.getDescriptor(File.class), null, null);
        av0 = fv.visitAnnotation(resDesc, true);
        av0.visit("name", "APP_HOME");
        av0.visitEnd();
        fv.visitEnd();
    }
    {
        // _servicemap字段 Map<String, XXXService>
        fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null);
        fv.visitEnd();
    }
    {
        // _redkale_tostringsupplier字段 Supplier<String>
        fv = cw.visitField(ACC_PRIVATE, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;", "Ljava/util/function/Supplier<Ljava/lang/String;>;", null);
        fv.visitEnd();
    }
    {
        // 构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    // 将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法
    boolean namePresent = false;
    try {
        Method m0 = null;
        for (final MappingEntry entry : entrys) {
            if (entry.mappingMethod.getParameterCount() > 0) {
                m0 = entry.mappingMethod;
                break;
            }
        }
        namePresent = m0 == null ? true : m0.getParameters()[0].isNamePresent();
    } catch (Exception e) {
    }
    final Map<String, List<String>> asmParamMap = namePresent ? null : MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), serviceType);
    Map<String, byte[]> innerClassBytesMap = new LinkedHashMap<>();
    for (final MappingEntry entry : entrys) {
        RestUploadFile mupload = null;
        Class muploadType = null;
        final Method method = entry.mappingMethod;
        final Class returnType = method.getReturnType();
        final java.lang.reflect.Type retvalType = formatRestReturnType(method, serviceType);
        final String methodDesc = Type.getMethodDescriptor(method);
        final Parameter[] params = method.getParameters();
        final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class);
        final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class);
        if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) {
            restConverts.add(new Object[] { rcs, rcc });
        }
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.newMethodName, "(" + reqDesc + respDesc + ")V", null, new String[] { "java/io/IOException" }));
        // mv.setDebug(true);
        mv.debugLine();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
        Label lmapif = new Label();
        mv.visitJumpInsn(IFNONNULL, lmapif);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
        Label lserif = new Label();
        mv.visitJumpInsn(GOTO, lserif);
        mv.visitLabel(lmapif);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitLdcInsn(REST_HEADER_RESOURCE_NAME);
        mv.visitLdcInsn("");
        mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHeader", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
        mv.visitTypeInsn(CHECKCAST, serviceTypeInternalName);
        mv.visitLabel(lserif);
        mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { serviceTypeInternalName });
        mv.visitVarInsn(ASTORE, 3);
        final int maxStack = 3 + params.length;
        List<int[]> varInsns = new ArrayList<>();
        int maxLocals = 4;
        List<String> asmParamNames = asmParamMap == null ? null : asmParamMap.get(method.getName() + ":" + Type.getMethodDescriptor(method));
        // 删掉空元素
        if (asmParamNames != null)
            while (asmParamNames.remove(" ")) ;
        List<Object[]> paramlist = new ArrayList<>();
        // 解析方法中的每个参数
        for (int i = 0; i < params.length; i++) {
            final Parameter param = params[i];
            final Class ptype = param.getType();
            String n = null;
            String comment = "";
            boolean required = true;
            int radix = 10;
            RestHeader annhead = param.getAnnotation(RestHeader.class);
            if (annhead != null) {
                if (ptype != String.class && ptype != InetSocketAddress.class)
                    throw new RuntimeException("@RestHeader must on String or InetSocketAddress Parameter in " + method);
                n = annhead.name();
                radix = annhead.radix();
                comment = annhead.comment();
                if (n.isEmpty())
                    throw new RuntimeException("@RestHeader.value is illegal in " + method);
            }
            RestCookie anncookie = param.getAnnotation(RestCookie.class);
            if (anncookie != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestCookie and @RestHeader cannot on the same Parameter in " + method);
                if (ptype != String.class)
                    throw new RuntimeException("@RestCookie must on String Parameter in " + method);
                n = anncookie.name();
                radix = anncookie.radix();
                comment = anncookie.comment();
                if (n.isEmpty())
                    throw new RuntimeException("@RestCookie.value is illegal in " + method);
            }
            RestSessionid annsid = param.getAnnotation(RestSessionid.class);
            if (annsid != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestSessionid and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestSessionid and @RestCookie cannot on the same Parameter in " + method);
                if (ptype != String.class)
                    throw new RuntimeException("@RestSessionid must on String Parameter in " + method);
            }
            RestAddress annaddr = param.getAnnotation(RestAddress.class);
            if (annaddr != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestAddress and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestAddress and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestAddress and @RestSessionid cannot on the same Parameter in " + method);
                if (ptype != String.class)
                    throw new RuntimeException("@RestAddress must on String Parameter in " + method);
                comment = annaddr.comment();
            }
            RestBody annbody = param.getAnnotation(RestBody.class);
            if (annbody != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestBody and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestBody and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestBody and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestBody and @RestAddress cannot on the same Parameter in " + method);
                if (ptype.isPrimitive())
                    throw new RuntimeException("@RestBody cannot on primitive type Parameter in " + method);
                comment = annbody.comment();
            }
            RestUploadFile annfile = param.getAnnotation(RestUploadFile.class);
            if (annfile != null) {
                if (mupload != null)
                    throw new RuntimeException("@RestUploadFile repeat in " + method);
                mupload = annfile;
                muploadType = ptype;
                if (annhead != null)
                    throw new RuntimeException("@RestUploadFile and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestUploadFile and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestUploadFile and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestUploadFile and @RestAddress cannot on the same Parameter in " + method);
                if (annbody != null)
                    throw new RuntimeException("@RestUploadFile and @RestBody cannot on the same Parameter in " + method);
                if (ptype != byte[].class && ptype != File.class && ptype != File[].class)
                    throw new RuntimeException("@RestUploadFile must on byte[] or File or File[] Parameter in " + method);
                comment = annfile.comment();
            }
            RestURI annuri = param.getAnnotation(RestURI.class);
            if (annuri != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestURI and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestURI and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestURI and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestURI and @RestAddress cannot on the same Parameter in " + method);
                if (annbody != null)
                    throw new RuntimeException("@RestURI and @RestBody cannot on the same Parameter in " + method);
                if (annfile != null)
                    throw new RuntimeException("@RestURI and @RestUploadFile cannot on the same Parameter in " + method);
                if (ptype != String.class)
                    throw new RuntimeException("@RestURI must on String Parameter in " + method);
                comment = annuri.comment();
            }
            RestUserid userid = param.getAnnotation(RestUserid.class);
            if (userid != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestUserid and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestUserid and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestUserid and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestUserid and @RestAddress cannot on the same Parameter in " + method);
                if (annbody != null)
                    throw new RuntimeException("@RestUserid and @RestBody cannot on the same Parameter in " + method);
                if (annfile != null)
                    throw new RuntimeException("@RestUserid and @RestUploadFile cannot on the same Parameter in " + method);
                if (!ptype.isPrimitive() && !java.io.Serializable.class.isAssignableFrom(ptype))
                    throw new RuntimeException("@RestUserid must on java.io.Serializable Parameter in " + method);
                comment = "";
            }
            RestHeaders annheaders = param.getAnnotation(RestHeaders.class);
            if (annheaders != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestHeaders and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestHeaders and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestHeaders and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestHeaders and @RestAddress cannot on the same Parameter in " + method);
                if (annbody != null)
                    throw new RuntimeException("@RestHeaders and @RestBody cannot on the same Parameter in " + method);
                if (annfile != null)
                    throw new RuntimeException("@RestHeaders and @RestUploadFile cannot on the same Parameter in " + method);
                if (userid != null)
                    throw new RuntimeException("@RestHeaders and @RestUserid cannot on the same Parameter in " + method);
                if (!TYPE_MAP_STRING_STRING.equals(param.getParameterizedType()))
                    throw new RuntimeException("@RestHeaders must on Map<String, String> Parameter in " + method);
                comment = "";
            }
            RestParams annparams = param.getAnnotation(RestParams.class);
            if (annparams != null) {
                if (annhead != null)
                    throw new RuntimeException("@RestParams and @RestHeader cannot on the same Parameter in " + method);
                if (anncookie != null)
                    throw new RuntimeException("@RestParams and @RestCookie cannot on the same Parameter in " + method);
                if (annsid != null)
                    throw new RuntimeException("@RestParams and @RestSessionid cannot on the same Parameter in " + method);
                if (annaddr != null)
                    throw new RuntimeException("@RestParams and @RestAddress cannot on the same Parameter in " + method);
                if (annbody != null)
                    throw new RuntimeException("@RestParams and @RestBody cannot on the same Parameter in " + method);
                if (annfile != null)
                    throw new RuntimeException("@RestParams and @RestUploadFile cannot on the same Parameter in " + method);
                if (userid != null)
                    throw new RuntimeException("@RestParams and @RestUserid cannot on the same Parameter in " + method);
                if (annheaders != null)
                    throw new RuntimeException("@RestParams and @RestHeaders cannot on the same Parameter in " + method);
                if (!TYPE_MAP_STRING_STRING.equals(param.getParameterizedType()))
                    throw new RuntimeException("@RestParams must on Map<String, String> Parameter in " + method);
                comment = "";
            }
            RestParam annpara = param.getAnnotation(RestParam.class);
            if (annpara != null)
                radix = annpara.radix();
            if (annpara != null)
                comment = annpara.comment();
            if (annpara != null)
                required = annpara.required();
            if (n == null)
                n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
            // 用户类型特殊处理
            if (n == null && ptype == userType)
                n = "&";
            if (n == null && asmParamNames != null && asmParamNames.size() > i)
                n = asmParamNames.get(i);
            if (n == null) {
                if (param.isNamePresent()) {
                    n = param.getName();
                } else if (ptype == Flipper.class) {
                    n = "flipper";
                } else {
                    throw new RuntimeException("Parameter " + param.getName() + " not found name by @RestParam  in " + method);
                }
            }
            if (annhead == null && anncookie == null && annsid == null && annaddr == null && annbody == null && annfile == null && !ptype.isPrimitive() && ptype != String.class && ptype != Flipper.class && !CompletionHandler.class.isAssignableFrom(ptype) && !ptype.getName().startsWith("java") && n.charAt(0) != '#' && !"&".equals(n)) {
                // 判断Json对象是否包含@RestUploadFile
                Class loop = ptype;
                do {
                    // 接口时getSuperclass可能会得到null
                    if (loop == null || loop.isInterface())
                        break;
                    for (Field field : loop.getDeclaredFields()) {
                        if (Modifier.isStatic(field.getModifiers()))
                            continue;
                        if (Modifier.isFinal(field.getModifiers()))
                            continue;
                        RestUploadFile ruf = field.getAnnotation(RestUploadFile.class);
                        if (ruf == null)
                            continue;
                        if (mupload != null)
                            throw new RuntimeException("@RestUploadFile repeat in " + method + " or field " + field);
                        mupload = ruf;
                        muploadType = field.getType();
                    }
                } while ((loop = loop.getSuperclass()) != Object.class);
            }
            java.lang.reflect.Type paramtype = TypeToken.getGenericType(param.getParameterizedType(), serviceType);
            paramlist.add(new Object[] { param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie, annbody, annfile, annuri, userid, annheaders, annparams, paramtype });
        }
        Map<String, Object> mappingMap = new LinkedHashMap<>();
        {
            // 设置 Annotation
            // 设置 HttpMapping
            boolean reqpath = false;
            for (Object[] ps : paramlist) {
                if ("#".equals((String) ps[1])) {
                    reqpath = true;
                    break;
                }
            }
            if (method.getAnnotation(Deprecated.class) != null) {
                av0 = mv.visitAnnotation(Type.getDescriptor(Deprecated.class), true);
                av0.visitEnd();
            }
            av0 = mv.visitAnnotation(mappingDesc, true);
            String url = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name + (reqpath ? "/" : "");
            if ("//".equals(url))
                url = "/";
            av0.visit("url", url);
            av0.visit("name", (defmodulename.isEmpty() ? "" : (defmodulename + "_")) + entry.name);
            av0.visit("example", entry.example);
            av0.visit("rpconly", entry.rpconly);
            av0.visit("auth", entry.auth);
            av0.visit("cacheseconds", entry.cacheseconds);
            av0.visit("actionid", entry.actionid);
            av0.visit("comment", entry.comment);
            AnnotationVisitor av1 = av0.visitArray("methods");
            for (String m : entry.methods) {
                av1.visit(null, m);
            }
            av1.visitEnd();
            java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType);
            Class rtc = returnType;
            if (rtc == void.class) {
                rtc = RetResult.class;
                grt = TYPE_RETRESULT_STRING;
            } else if (CompletionStage.class.isAssignableFrom(returnType)) {
                ParameterizedType ptgrt = (ParameterizedType) grt;
                grt = ptgrt.getActualTypeArguments()[0];
                rtc = TypeToken.typeToClass(grt);
                // 应该不会发生吧?
                if (rtc == null)
                    rtc = Object.class;
            }
            av0.visit("result", Type.getType(Type.getDescriptor(rtc)));
            if (grt != rtc) {
                String refid = typeRefs.get(grt);
                if (refid == null) {
                    refid = "_typeref_" + typeRefs.size();
                    typeRefs.put(grt, refid);
                }
                av0.visit("resultref", refid);
            }
            av0.visitEnd();
            mappingMap.put("url", url);
            mappingMap.put("rpconly", entry.rpconly);
            mappingMap.put("auth", entry.auth);
            mappingMap.put("cacheseconds", entry.cacheseconds);
            mappingMap.put("actionid", entry.actionid);
            mappingMap.put("comment", entry.comment);
            mappingMap.put("methods", entry.methods);
            mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
            entry.mappingurl = url;
        }
        {
            // 设置 Annotation
            av0 = mv.visitAnnotation(httpParamsDesc, true);
            AnnotationVisitor av1 = av0.visitArray("value");
            // 设置 HttpParam
            for (Object[] ps : paramlist) {
                // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie, annbody, annfile, annuri, annuserid, annheaders, annparams, paramtype}
                String n = ps[1].toString();
                // 是否取userid
                final boolean isuserid = ((RestUserid) ps[14]) != null;
                // @RestUserid 不需要生成 @HttpParam
                if (n.indexOf('&') >= 0 || isuserid)
                    continue;
                // @RestAddress 不需要生成 @HttpParam
                if (((RestAddress) ps[8]) != null)
                    continue;
                // 是否取getHeader 而不是 getParameter
                final boolean ishead = ((RestHeader) ps[9]) != null;
                // 是否取getCookie
                final boolean iscookie = ((RestCookie) ps[10]) != null;
                // 是否取getBody
                final boolean isbody = ((RestBody) ps[11]) != null;
                AnnotationVisitor av2 = av1.visitAnnotation(null, httpParamDesc);
                av2.visit("name", (String) ps[1]);
                if (((Parameter) ps[0]).getAnnotation(Deprecated.class) != null) {
                    av2.visit("deprecated", true);
                }
                av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2])));
                java.lang.reflect.Type pgtype = TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType);
                if (pgtype != (Class) ps[2]) {
                    String refid = typeRefs.get(pgtype);
                    if (refid == null) {
                        refid = "_typeref_" + typeRefs.size();
                        typeRefs.put(pgtype, refid);
                    }
                    av2.visit("typeref", refid);
                }
                av2.visit("radix", (Integer) ps[3]);
                if (ishead) {
                    av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.HEADER.name());
                    av2.visit("example", ((RestHeader) ps[9]).example());
                } else if (iscookie) {
                    av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.COOKIE.name());
                    av2.visit("example", ((RestCookie) ps[10]).example());
                } else if (isbody) {
                    av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.BODY.name());
                    av2.visit("example", ((RestBody) ps[11]).example());
                } else if (ps[6] != null) {
                    av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.QUERY.name());
                    av2.visit("example", ((RestParam) ps[6]).example());
                }
                av2.visit("comment", (String) ps[4]);
                av2.visit("required", (Boolean) ps[5]);
                av2.visitEnd();
            }
            av1.visitEnd();
            av0.visitEnd();
        }
        int uploadLocal = 0;
        if (mupload != null) {
            // 存在文件上传
            if (muploadType == byte[].class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false);
                mv.visitLdcInsn(mupload.maxLength());
                mv.visitLdcInsn(mupload.fileNameReg());
                mv.visitLdcInsn(mupload.contentTypeReg());
                mv.visitMethodInsn(INVOKEVIRTUAL, multiContextName, "partsFirstBytes", "(JLjava/lang/String;Ljava/lang/String;)[B", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                uploadLocal = maxLocals;
            } else if (muploadType == File.class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;");
                mv.visitLdcInsn(mupload.maxLength());
                mv.visitLdcInsn(mupload.fileNameReg());
                mv.visitLdcInsn(mupload.contentTypeReg());
                mv.visitMethodInsn(INVOKEVIRTUAL, multiContextName, "partsFirstFile", "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)Ljava/io/File;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                uploadLocal = maxLocals;
            } else if (muploadType == File[].class) {
                // File[]
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;");
                mv.visitLdcInsn(mupload.maxLength());
                mv.visitLdcInsn(mupload.fileNameReg());
                mv.visitLdcInsn(mupload.contentTypeReg());
                mv.visitMethodInsn(INVOKEVIRTUAL, multiContextName, "partsFiles", "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)[Ljava/io/File;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                uploadLocal = maxLocals;
            }
            maxLocals++;
        }
        List<Map<String, Object>> paramMaps = new ArrayList<>();
        // 获取每个参数的值
        boolean hasAsyncHandler = false;
        for (Object[] ps : paramlist) {
            Map<String, Object> paramMap = new LinkedHashMap<>();
            // 参数类型
            final Parameter param = (Parameter) ps[0];
            // 参数名
            String pname = (String) ps[1];
            // 参数类型
            Class ptype = (Class) ps[2];
            int radix = (Integer) ps[3];
            String comment = (String) ps[4];
            boolean required = (Boolean) ps[5];
            RestParam annpara = (RestParam) ps[6];
            RestSessionid annsid = (RestSessionid) ps[7];
            RestAddress annaddr = (RestAddress) ps[8];
            RestHeader annhead = (RestHeader) ps[9];
            RestCookie anncookie = (RestCookie) ps[10];
            RestBody annbody = (RestBody) ps[11];
            RestUploadFile annfile = (RestUploadFile) ps[12];
            RestURI annuri = (RestURI) ps[13];
            RestUserid userid = (RestUserid) ps[14];
            RestHeaders annheaders = (RestHeaders) ps[15];
            RestParams annparams = (RestParams) ps[16];
            java.lang.reflect.Type pgentype = (java.lang.reflect.Type) ps[17];
            if (dynsimple && (annsid != null || annaddr != null || annhead != null || anncookie != null || annfile != null || annheaders != null))
                dynsimple = false;
            // 是否取getHeader 而不是 getParameter
            final boolean ishead = annhead != null;
            // 是否取getCookie
            final boolean iscookie = anncookie != null;
            paramMap.put("name", pname);
            paramMap.put("type", ptype.getName());
            if (CompletionHandler.class.isAssignableFrom(ptype)) {
                // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class)
                if (ptype == CompletionHandler.class) {
                    mv.visitVarInsn(ALOAD, 2);
                    mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Ljava/nio/channels/CompletionHandler;", false);
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                } else {
                    mv.visitVarInsn(ALOAD, 3);
                    mv.visitVarInsn(ALOAD, 2);
                    mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
                    mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "(Ljava/lang/Class;)Ljava/nio/channels/CompletionHandler;", false);
                    mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                }
                hasAsyncHandler = true;
            } else if (annsid != null) {
                // HttpRequest.getSessionid(true|false)
                mv.visitVarInsn(ALOAD, 1);
                mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (annaddr != null) {
                // HttpRequest.getRemoteAddr
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (annheaders != null) {
                // HttpRequest.getHeaders
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHeaders", "()Ljava/util/Map;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (annparams != null) {
                // HttpRequest.getParameters
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getParameters", "()Ljava/util/Map;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (annbody != null) {
                // HttpRequest.getBodyUTF8 / HttpRequest.getBody
                if (ptype == String.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false);
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                } else if (ptype == byte[].class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false);
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                } else {
                    // JavaBean 转 Json
                    String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size();
                    bodyTypes.put(typefieldname, pgentype);
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitVarInsn(ALOAD, 0);
                    mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBodyJson", "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", false);
                    mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype));
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                }
            } else if (annfile != null) {
                // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / HttpRequest.partsFiles
                mv.visitVarInsn(ALOAD, 4);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (annuri != null) {
                // HttpRequest.getRequestURI
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequestURI", "()Ljava/lang/String;", false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (userid != null) {
                // HttpRequest.currentUserid
                mv.visitVarInsn(ALOAD, 1);
                if (ptype == int.class) {
                    mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
                } else if (ptype == long.class) {
                    mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
                } else {
                    mv.visitLdcInsn(Type.getType(Type.getInternalName(ptype)));
                }
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentUserid", "(Ljava/lang/Class;)Ljava/io/Serializable;", false);
                if (ptype == int.class) {
                    mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
                    mv.visitInsn(ICONST_0);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
                    mv.visitMethodInsn(INVOKESTATIC, restInternalName, "orElse", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false);
                    mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
                    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
                    mv.visitVarInsn(ISTORE, maxLocals);
                    varInsns.add(new int[] { ILOAD, maxLocals });
                } else if (ptype == long.class) {
                    mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
                    mv.visitInsn(LCONST_0);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
                    mv.visitMethodInsn(INVOKESTATIC, restInternalName, "orElse", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false);
                    mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
                    mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
                    mv.visitVarInsn(LSTORE, maxLocals);
                    varInsns.add(new int[] { LLOAD, maxLocals });
                    maxLocals++;
                } else {
                    mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype));
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                }
            } else if ("#".equals(pname)) {
                // 从request.getRequstURI 中取参数
                if (ptype == boolean.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "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, reqInternalName, "getRequstURILastPath", "()Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false);
                    mv.visitVarInsn(ISTORE, maxLocals);
                    varInsns.add(new int[] { ILOAD, maxLocals });
                } else if (ptype == short.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURILastPath", "()Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false);
                    mv.visitVarInsn(ISTORE, maxLocals);
                    varInsns.add(new int[] { ILOAD, maxLocals });
                } else if (ptype == char.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "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, reqInternalName, "getRequstURILastPath", "()Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(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.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "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, reqInternalName, "getRequstURILastPath", "()Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)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, reqInternalName, "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, reqInternalName, "getRequstURILastPath", "()Ljava/lang/String;", false);
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                } else {
                    throw new RuntimeException(method + " only " + RestParam.class.getSimpleName() + "(#) to Type(primitive class or String)");
                }
            } else if (pname.charAt(0) == '#') {
                // 从request.getRequstURIPath 中去参数
                if (ptype == boolean.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("false");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)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.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false);
                    mv.visitVarInsn(ISTORE, maxLocals);
                    varInsns.add(new int[] { ILOAD, maxLocals });
                } else if (ptype == short.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false);
                    mv.visitVarInsn(ISTORE, maxLocals);
                    varInsns.add(new int[] { ILOAD, maxLocals });
                } else if (ptype == char.class) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(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.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(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.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)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.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                    mv.visitIntInsn(BIPUSH, radix);
                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)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.substring(1));
                    mv.visitLdcInsn("0");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)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.visitLdcInsn(pname.substring(1));
                    mv.visitLdcInsn("");
                    mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequstURIPath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                    mv.visitVarInsn(ASTORE, maxLocals);
                    varInsns.add(new int[] { ALOAD, maxLocals });
                } else {
                    throw new RuntimeException(method + " only " + RestParam.class.getSimpleName() + "(#) to Type(primitive class or String)");
                }
            } else if ("&".equals(pname) && ptype == userType) {
                // 当前用户对象的类名
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentUser", "()Ljava/lang/Object;", false);
                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype));
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (ptype == boolean.class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitLdcInsn(pname);
                mv.visitInsn(ICONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "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, reqInternalName, ishead ? "getHeader" : "getParameter", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                mv.visitIntInsn(BIPUSH, radix);
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false);
                mv.visitVarInsn(ISTORE, maxLocals);
                varInsns.add(new int[] { ILOAD, maxLocals });
            } else if (ptype == short.class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitIntInsn(BIPUSH, radix);
                mv.visitLdcInsn(pname);
                mv.visitInsn(ICONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getShortHeader" : "getShortParameter", "(ILjava/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, reqInternalName, ishead ? "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.visitIntInsn(BIPUSH, radix);
                mv.visitLdcInsn(pname);
                mv.visitInsn(ICONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getIntHeader" : "getIntParameter", "(ILjava/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, reqInternalName, ishead ? "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.visitIntInsn(BIPUSH, radix);
                mv.visitLdcInsn(pname);
                mv.visitInsn(LCONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getLongHeader" : "getLongParameter", "(ILjava/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, reqInternalName, ishead ? "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, reqInternalName, iscookie ? "getCookie" : (ishead ? "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 == ChannelContext.class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getChannelContext", "()" + channelDesc, false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else if (ptype == Flipper.class) {
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getFlipper", "()" + flipperDesc, false);
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
            } else {
                // 其他Json对象
                mv.visitVarInsn(ALOAD, 1);
                if (param.getType() == param.getParameterizedType()) {
                    mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
                } else {
                    mv.visitVarInsn(ALOAD, 0);
                    mv.visitFieldInsn(GETFIELD, newDynName, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;");
                    // 方法下标
                    MethodDebugVisitor.pushInt(mv, entry.methodidx);
                    mv.visitInsn(AALOAD);
                    int paramidx = -1;
                    for (int i = 0; i < params.length; i++) {
                        if (params[i] == param) {
                            paramidx = i;
                            break;
                        }
                    }
                    // 参数下标
                    MethodDebugVisitor.pushInt(mv, paramidx);
                    mv.visitInsn(AALOAD);
                }
                mv.visitLdcInsn(pname);
                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getJsonHeader" : "getJsonParameter", "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", false);
                mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
                mv.visitVarInsn(ASTORE, maxLocals);
                varInsns.add(new int[] { ALOAD, maxLocals });
                JsonFactory.root().loadDecoder(param.getParameterizedType());
                // 构建 RestHeader、RestCookie、RestAddress 等赋值操作
                Class loop = ptype;
                Set<String> fields = new HashSet<>();
                Map<String, Object[]> attrParaNames = new LinkedHashMap<>();
                do {
                    // 接口时getSuperclass可能会得到null
                    if (loop == null || loop.isInterface())
                        break;
                    for (Field field : loop.getDeclaredFields()) {
                        if (Modifier.isStatic(field.getModifiers()))
                            continue;
                        if (Modifier.isFinal(field.getModifiers()))
                            continue;
                        if (fields.contains(field.getName()))
                            continue;
                        RestHeader rh = field.getAnnotation(RestHeader.class);
                        RestCookie rc = field.getAnnotation(RestCookie.class);
                        RestSessionid rs = field.getAnnotation(RestSessionid.class);
                        RestAddress ra = field.getAnnotation(RestAddress.class);
                        RestBody rb = field.getAnnotation(RestBody.class);
                        RestUploadFile ru = field.getAnnotation(RestUploadFile.class);
                        RestURI ri = field.getAnnotation(RestURI.class);
                        if (rh == null && rc == null && ra == null && rb == null && rs == null && ru == null && ri == null)
                            continue;
                        if (rh != null && field.getType() != String.class && field.getType() != InetSocketAddress.class)
                            throw new RuntimeException("@RestHeader must on String Field in " + field);
                        if (rc != null && field.getType() != String.class)
                            throw new RuntimeException("@RestCookie must on String Field in " + field);
                        if (rs != null && field.getType() != String.class)
                            throw new RuntimeException("@RestSessionid must on String Field in " + field);
                        if (ra != null && field.getType() != String.class)
                            throw new RuntimeException("@RestAddress must on String Field in " + field);
                        if (rb != null && field.getType().isPrimitive())
                            throw new RuntimeException("@RestBody must on cannot on primitive type Field in " + field);
                        if (ru != null && field.getType() != byte[].class && field.getType() != File.class && field.getType() != File[].class) {
                            throw new RuntimeException("@RestUploadFile must on byte[] or File or File[] Field in " + field);
                        }
                        if (ri != null && field.getType() != String.class)
                            throw new RuntimeException("@RestURI must on String Field in " + field);
                        org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field);
                        String attrFieldName;
                        String restname = "";
                        if (rh != null) {
                            attrFieldName = "_redkale_attr_header_" + (field.getType() != String.class ? "json_" : "") + restAttributes.size();
                            restname = rh.name();
                        } else if (rc != null) {
                            attrFieldName = "_redkale_attr_cookie_" + restAttributes.size();
                            restname = rc.name();
                        } else if (rs != null) {
                            attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size();
                            // 用于下面区分create值
                            restname = rs.create() ? "1" : "";
                        } else if (ra != null) {
                            attrFieldName = "_redkale_attr_address_" + restAttributes.size();
                        // restname = "";
                        } else if (rb != null && field.getType() == String.class) {
                            attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size();
                        // restname = "";
                        } else if (rb != null && field.getType() == byte[].class) {
                            attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size();
                        // restname = "";
                        } else if (rb != null && field.getType() != String.class && field.getType() != byte[].class) {
                            attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size();
                        // restname = "";
                        } else if (ru != null && field.getType() == byte[].class) {
                            attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size();
                        // restname = "";
                        } else if (ru != null && field.getType() == File.class) {
                            attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size();
                        // restname = "";
                        } else if (ru != null && field.getType() == File[].class) {
                            attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size();
                        // restname = "";
                        } else if (ri != null && field.getType() == String.class) {
                            attrFieldName = "_redkale_attr_uri_" + restAttributes.size();
                        // restname = "";
                        } else {
                            continue;
                        }
                        restAttributes.put(attrFieldName, attr);
                        attrParaNames.put(attrFieldName, new Object[] { restname, field.getType(), field.getGenericType(), ru });
                        fields.add(field.getName());
                    }
                } while ((loop = loop.getSuperclass()) != Object.class);
                if (!attrParaNames.isEmpty()) {
                    // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestBody字段
                    // 加载JsonBean
                    mv.visitVarInsn(ALOAD, maxLocals);
                    Label lif = new Label();
                    // if(bean != null) {
                    mv.visitJumpInsn(IFNULL, lif);
                    for (Map.Entry<String, Object[]> en : attrParaNames.entrySet()) {
                        RestUploadFile ru = (RestUploadFile) en.getValue()[3];
                        mv.visitVarInsn(ALOAD, 0);
                        mv.visitFieldInsn(GETFIELD, newDynName, en.getKey(), attrDesc);
                        mv.visitVarInsn(ALOAD, maxLocals);
                        mv.visitVarInsn(ALOAD, en.getKey().contains("_upload") ? uploadLocal : 1);
                        if (en.getKey().contains("_header_")) {
                            String headerkey = en.getValue()[0].toString();
                            if ("Host".equalsIgnoreCase(headerkey)) {
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHost", "()Ljava/lang/String;", false);
                            } else if ("Content-Type".equalsIgnoreCase(headerkey)) {
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getContentType", "()Ljava/lang/String;", false);
                            } else if ("Connection".equalsIgnoreCase(headerkey)) {
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getConnection", "()Ljava/lang/String;", false);
                            } else if ("Method".equalsIgnoreCase(headerkey)) {
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getMethod", "()Ljava/lang/String;", false);
                            } else if (en.getKey().contains("_header_json_")) {
                                String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size();
                                bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]);
                                mv.visitVarInsn(ALOAD, 0);
                                mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;");
                                mv.visitLdcInsn(headerkey);
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getJsonHeader", "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", false);
                                mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1]));
                                JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]);
                            } else {
                                mv.visitLdcInsn(headerkey);
                                mv.visitLdcInsn("");
                                mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHeader", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                            }
                        } else if (en.getKey().contains("_cookie_")) {
                            mv.visitLdcInsn(en.getValue()[0].toString());
                            mv.visitLdcInsn("");
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getCookie", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
                        } else if (en.getKey().contains("_sessionid_")) {
                            mv.visitInsn(en.getValue()[0].toString().isEmpty() ? ICONST_0 : ICONST_1);
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false);
                        } else if (en.getKey().contains("_address_")) {
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false);
                        } else if (en.getKey().contains("_uri_")) {
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequestURI", "()Ljava/lang/String;", false);
                        } else if (en.getKey().contains("_bodystring_")) {
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false);
                        } else if (en.getKey().contains("_bodybytes_")) {
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false);
                        } else if (en.getKey().contains("_bodyjson_")) {
                            // JavaBean 转 Json
                            String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size();
                            bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]);
                            mv.visitVarInsn(ALOAD, 0);
                            mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;");
                            mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBodyJson", "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", false);
                            mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1]));
                            JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]);
                        } else if (en.getKey().contains("_uploadbytes_")) {
                        // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                        } else if (en.getKey().contains("_uploadfile_")) {
                        // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                        } else if (en.getKey().contains("_uploadfiles_")) {
                        // 只需mv.visitVarInsn(ALOAD, 4), 无需处理
                        }
                        mv.visitMethodInsn(INVOKEINTERFACE, attrInternalName, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
                    }
                    // end if }
                    mv.visitLabel(lif);
                    mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] { ptype.getName().replace('.', '/') }, 0, null);
                }
            }
            maxLocals++;
            paramMaps.add(paramMap);
        }
        // end params for each
        // mv.visitVarInsn(ALOAD, 0); //调用this
        // mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
        mv.visitVarInsn(ALOAD, 3);
        for (int[] ins : varInsns) {
            mv.visitVarInsn(ins[0], ins[1]);
        }
        mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false);
        if (hasAsyncHandler) {
            mv.visitInsn(RETURN);
        } else if (returnType == void.class) {
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
            // 方法下标
            MethodDebugVisitor.pushInt(mv, entry.methodidx);
            mv.visitInsn(AALOAD);
            mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + typeDesc + "Ljava/lang/Object;)V", false);
            mv.visitInsn(RETURN);
        } else if (returnType == boolean.class) {
            mv.visitVarInsn(ISTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ILOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == byte.class) {
            mv.visitVarInsn(ISTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ILOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == short.class) {
            mv.visitVarInsn(ISTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ILOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == char.class) {
            mv.visitVarInsn(ISTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ILOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == int.class) {
            mv.visitVarInsn(ISTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ILOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == float.class) {
            mv.visitVarInsn(FSTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(FLOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == long.class) {
            mv.visitVarInsn(LSTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(LLOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals += 2;
        } else if (returnType == double.class) {
            mv.visitVarInsn(DSTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(DLOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals += 2;
        } else if (returnType == byte[].class) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, maxLocals);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "([B)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == String.class) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, maxLocals);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == File.class) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, maxLocals);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) {
            // returnType == String.class 必须放在前面
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, maxLocals);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (RetResult.class.isAssignableFrom(returnType)) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + retDesc + ")V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + retDesc + ")V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (HttpResult.class.isAssignableFrom(returnType)) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + httpResultDesc + ")V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + httpResultDesc + ")V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (HttpScope.class.isAssignableFrom(returnType)) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + httpScopeDesc + ")V", false);
            } else {
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + httpScopeDesc + ")V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (CompletionStage.class.isAssignableFrom(returnType)) {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + stageDesc + ")V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + stageDesc + ")V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (Flows.maybePublisherClass(returnType)) {
            // Flow.Publisher
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishPublisher", "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishPublisher", "(" + typeDesc + "Ljava/lang/Object;)V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else if (returnType == retvalType) {
            // 普通JavaBean或JavaBean[]
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + Type.getDescriptor(JsonConvert.class) + typeDesc + "Ljava/lang/Object;)V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + typeDesc + "Ljava/lang/Object;)V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        } else {
            mv.visitVarInsn(ASTORE, maxLocals);
            // response
            mv.visitVarInsn(ALOAD, 2);
            if (rcs != null && rcs.length > 0) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", false);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;");
                // 方法下标
                MethodDebugVisitor.pushInt(mv, entry.methodidx);
                mv.visitInsn(AALOAD);
                mv.visitVarInsn(ALOAD, maxLocals);
                mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + "Ljava/lang/Object;)V", false);
            }
            mv.visitInsn(RETURN);
            maxLocals++;
        }
        mv.visitMaxs(maxStack, maxLocals);
        mappingMap.put("params", paramMaps);
        {
            // _Dync_XXX__HttpServlet.class
            ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
            cw2.visit(V11, ACC_SUPER, newDynName + "$" + entry.newActionClassName, null, httpServletName, null);
            cw2.visitInnerClass(newDynName + "$" + entry.newActionClassName, newDynName, entry.newActionClassName, ACC_PRIVATE + ACC_STATIC);
            {
                fv = cw2.visitField(0, "servlet", "L" + newDynName + ";", null, null);
                fv.visitEnd();
            }
            {
                mv = new MethodDebugVisitor(cw2.visitMethod(0, "<init>", "(L" + newDynName + ";)V", null, null));
                mv.visitVarInsn(ALOAD, 0);
                mv.visitMethodInsn(INVOKESPECIAL, httpServletName, "<init>", "()V", false);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitFieldInsn(PUTFIELD, newDynName + "$" + entry.newActionClassName, "servlet", "L" + newDynName + ";");
                mv.visitInsn(RETURN);
                mv.visitMaxs(2, 2);
                mv.visitEnd();
            }
            // if (false) {
            // mv = new MethodDebugVisitor(cw2.visitMethod(ACC_SYNTHETIC, "<init>", "(L" + newDynName + ";L" + newDynName + "$" + entry.newActionClassName + ";)V", null, null));
            // mv.visitVarInsn(ALOAD, 0);
            // mv.visitVarInsn(ALOAD, 1);
            // mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, "<init>", "L" + newDynName + ";", false);
            // mv.visitInsn(RETURN);
            // mv.visitMaxs(2, 3);
            // mv.visitEnd();
            // }
            {
                mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(" + reqDesc + respDesc + ")V", null, new String[] { "java/io/IOException" }));
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynName + "$" + entry.newActionClassName, "servlet", "L" + newDynName + ";");
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, entry.newMethodName, "(" + reqDesc + respDesc + ")V", false);
                mv.visitInsn(RETURN);
                mv.visitMaxs(3, 3);
                mv.visitEnd();
            }
            cw2.visitEnd();
            byte[] bytes = cw2.toByteArray();
            newLoader.addClass((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes);
            innerClassBytesMap.put((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes);
        }
    }
    // end  for each
    // HashMap<String, ActionEntry> _createRestActionEntry() {
    // HashMap<String, ActionEntry> map = new HashMap<>();
    // map.put("asyncfind3", new ActionEntry(100000,200000,"asyncfind3", new String[]{},null,false,false,0, new _Dync_asyncfind3_HttpServlet()));
    // map.put("asyncfind2", new ActionEntry(1,2,"asyncfind2", new String[]{"GET", "POST"},null,false,true,0, new _Dync_asyncfind2_HttpServlet()));
    // return map;
    // }
    {
        // _createRestActionEntry 方法
        mv = new MethodDebugVisitor(cw.visitMethod(0, "_createRestActionEntry", "()Ljava/util/HashMap;", "()Ljava/util/HashMap<Ljava/lang/String;L" + actionEntryName + ";>;", null));
        // mv.setDebug(true);
        mv.visitTypeInsn(NEW, "java/util/HashMap");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false);
        mv.visitVarInsn(ASTORE, 1);
        for (final MappingEntry entry : entrys) {
            mappingurlToMethod.put(entry.mappingurl, entry.mappingMethod);
            mv.visitVarInsn(ALOAD, 1);
            // name
            mv.visitLdcInsn(entry.mappingurl);
            // new ActionEntry
            mv.visitTypeInsn(NEW, actionEntryName);
            mv.visitInsn(DUP);
            // moduleid
            MethodDebugVisitor.pushInt(mv, moduleid);
            // actionid
            MethodDebugVisitor.pushInt(mv, entry.actionid);
            // name
            mv.visitLdcInsn(entry.mappingurl);
            // methods
            MethodDebugVisitor.pushInt(mv, entry.methods.length);
            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
            for (int i = 0; i < entry.methods.length; i++) {
                mv.visitInsn(DUP);
                MethodDebugVisitor.pushInt(mv, i);
                mv.visitLdcInsn(entry.methods[i]);
                mv.visitInsn(AASTORE);
            }
            // method
            mv.visitInsn(ACONST_NULL);
            // rpconly
            mv.visitInsn(entry.rpconly ? ICONST_1 : ICONST_0);
            // auth
            mv.visitInsn(entry.auth ? ICONST_1 : ICONST_0);
            // cacheseconds
            MethodDebugVisitor.pushInt(mv, entry.cacheseconds);
            mv.visitTypeInsn(NEW, newDynName + "$" + entry.newActionClassName);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, "<init>", "(L" + newDynName + ";)V", false);
            mv.visitMethodInsn(INVOKESPECIAL, actionEntryName, "<init>", "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZZILorg/redkale/net/http/HttpServlet;)V", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false);
            mv.visitInsn(POP);
        }
        mv.visitVarInsn(ALOAD, 1);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();
    }
    for (Map.Entry<String, java.lang.reflect.Type> en : bodyTypes.entrySet()) {
        fv = cw.visitField(ACC_PRIVATE, en.getKey(), "Ljava/lang/reflect/Type;", null, null);
        av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true);
        av0.visit("value", en.getValue().toString());
        av0.visitEnd();
        fv.visitEnd();
    }
    for (Map.Entry<java.lang.reflect.Type, String> en : typeRefs.entrySet()) {
        fv = cw.visitField(ACC_PRIVATE, en.getValue(), "Ljava/lang/reflect/Type;", null, null);
        av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true);
        av0.visit("value", en.getKey().toString());
        av0.visitEnd();
        fv.visitEnd();
    }
    for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) {
        fv = cw.visitField(ACC_PRIVATE, en.getKey(), attrDesc, null, null);
        av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true);
        av0.visit("value", en.getValue().toString());
        av0.visitEnd();
        fv.visitEnd();
    }
    for (int i = 1; i <= restConverts.size(); i++) {
        fv = cw.visitField(ACC_PRIVATE, REST_CONVERT_FIELD_PREFIX + i, convertDesc, null, null);
        fv.visitEnd();
    }
    {
        // _paramtypes字段 java.lang.reflect.Type[][]
        fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null);
        av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true);
        StringBuilder sb = new StringBuilder().append('[');
        for (java.lang.reflect.Type[] rs : paramTypes) {
            sb.append(Arrays.toString(rs)).append(',');
        }
        av0.visit("value", sb.append(']').toString());
        av0.visitEnd();
        fv.visitEnd();
    }
    {
        // _returntypes字段 java.lang.reflect.Type[]
        fv = cw.visitField(ACC_PRIVATE, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;", null, null);
        av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true);
        av0.visit("value", retvalTypes.toString());
        av0.visitEnd();
        fv.visitEnd();
    }
    // classMap.put("mappings", mappingMaps); //不显示太多信息
    {
        // toString函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/function/Supplier", "get", "()Ljava/lang/Object;", true);
        mv.visitTypeInsn(CHECKCAST, "java/lang/String");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        // RestDyn
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true);
        av0.visit("simple", (Boolean) dynsimple);
        av0.visitEnd();
    }
    cw.visitEnd();
    byte[] bytes = cw.toByteArray();
    newLoader.addClass(newDynName.replace('/', '.'), bytes);
    try {
        Class<?> newClazz = newLoader.findClass(newDynName.replace('/', '.'));
        innerClassBytesMap.forEach((n, bs) -> {
            try {
                RedkaleClassLoader.putDynClass(n, bs, newLoader.findClass(n));
                RedkaleClassLoader.putReflectionClass(n);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        });
        RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
        RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
        for (java.lang.reflect.Type t : retvalTypes) {
            JsonFactory.root().loadEncoder(t);
        }
        T obj = ((Class<T>) newClazz).getDeclaredConstructor().newInstance();
        {
            Field serviceField = newClazz.getDeclaredField(REST_SERVICE_FIELD_NAME);
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), serviceField);
            Field servicemapField = newClazz.getDeclaredField(REST_SERVICEMAP_FIELD_NAME);
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), servicemapField);
        }
        for (Map.Entry<java.lang.reflect.Type, String> en : typeRefs.entrySet()) {
            Field refField = newClazz.getDeclaredField(en.getValue());
            refField.setAccessible(true);
            refField.set(obj, en.getKey());
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), refField);
        }
        for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) {
            Field attrField = newClazz.getDeclaredField(en.getKey());
            attrField.setAccessible(true);
            attrField.set(obj, en.getValue());
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), attrField);
        }
        for (Map.Entry<String, java.lang.reflect.Type> en : bodyTypes.entrySet()) {
            Field genField = newClazz.getDeclaredField(en.getKey());
            genField.setAccessible(true);
            genField.set(obj, en.getValue());
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField);
        }
        for (int i = 0; i < restConverts.size(); i++) {
            Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1));
            genField.setAccessible(true);
            Object[] rc = restConverts.get(i);
            genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]));
            RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField);
        }
        Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME);
        typesfield.setAccessible(true);
        java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][];
        paramtypeArray = paramTypes.toArray(paramtypeArray);
        typesfield.set(obj, paramtypeArray);
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), typesfield);
        Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME);
        retfield.setAccessible(true);
        java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()];
        rettypeArray = retvalTypes.toArray(rettypeArray);
        retfield.set(obj, rettypeArray);
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), retfield);
        Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME);
        tostringfield.setAccessible(true);
        java.util.function.Supplier<String> sSupplier = () -> JsonConvert.root().convertTo(classMap);
        tostringfield.set(obj, sSupplier);
        RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), tostringfield);
        Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry");
        restactMethod.setAccessible(true);
        RedkaleClassLoader.putReflectionMethod(newDynName.replace('/', '.'), restactMethod);
        Field tmpentrysfield = HttpServlet.class.getDeclaredField("_actionmap");
        tmpentrysfield.setAccessible(true);
        HashMap<String, HttpServlet.ActionEntry> innerEntryMap = (HashMap) restactMethod.invoke(obj);
        for (Map.Entry<String, HttpServlet.ActionEntry> en : innerEntryMap.entrySet()) {
            Method m = mappingurlToMethod.get(en.getKey());
            if (m != null)
                en.getValue().annotations = HttpServlet.ActionEntry.annotations(m);
        }
        tmpentrysfield.set(obj, innerEntryMap);
        RedkaleClassLoader.putReflectionField(HttpServlet.class.getName(), tmpentrysfield);
        return obj;
    } catch (Throwable e) {
        throw new RuntimeException(e);
    }
}
Also used : java.lang.reflect(java.lang.reflect) org.redkale.convert(org.redkale.convert) org.redkale.asm(org.redkale.asm) java.util(java.util) Flipper(org.redkale.source.Flipper) java.util.concurrent(java.util.concurrent) org.redkale.net(org.redkale.net) java.lang.annotation(java.lang.annotation) CompletionHandler(java.nio.channels.CompletionHandler) Resource(javax.annotation.Resource) COMPUTE_FRAMES(org.redkale.asm.ClassWriter.COMPUTE_FRAMES) Opcodes(org.redkale.asm.Opcodes) Type(org.redkale.asm.Type) ElementType(java.lang.annotation.ElementType) RUNTIME(java.lang.annotation.RetentionPolicy.RUNTIME) InetSocketAddress(java.net.InetSocketAddress) org.redkale.convert.json(org.redkale.convert.json) org.redkale.util(org.redkale.util) java.io(java.io) Sncp(org.redkale.net.sncp.Sncp) MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) org.redkale.service(org.redkale.service) org.redkale.mq(org.redkale.mq) InetSocketAddress(java.net.InetSocketAddress) java.lang.reflect(java.lang.reflect) java.io(java.io) java.util(java.util) org.redkale.util(org.redkale.util) Flipper(org.redkale.source.Flipper) Type(org.redkale.asm.Type) ElementType(java.lang.annotation.ElementType) CompletionHandler(java.nio.channels.CompletionHandler) MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor)

Aggregations

MethodDebugVisitor (org.redkale.asm.MethodDebugVisitor)7 Resource (javax.annotation.Resource)6 Type (org.redkale.asm.Type)5 Annotation (java.lang.annotation.Annotation)3 ElementType (java.lang.annotation.ElementType)3 java.lang.reflect (java.lang.reflect)3 CompletionHandler (java.nio.channels.CompletionHandler)2 MessageAgent (org.redkale.mq.MessageAgent)2 SncpAction (org.redkale.net.sncp.SncpClient.SncpAction)2 java.io (java.io)1 java.lang.annotation (java.lang.annotation)1 RUNTIME (java.lang.annotation.RetentionPolicy.RUNTIME)1 InetSocketAddress (java.net.InetSocketAddress)1 java.util (java.util)1 java.util.concurrent (java.util.concurrent)1 org.redkale.asm (org.redkale.asm)1 COMPUTE_FRAMES (org.redkale.asm.ClassWriter.COMPUTE_FRAMES)1 Opcodes (org.redkale.asm.Opcodes)1 org.redkale.convert (org.redkale.convert)1 org.redkale.convert.json (org.redkale.convert.json)1