如何将请求参数赋值给方法参数---java的debug和release编译方式

原文地址

参考地址参考地址参考地址

Java编译成.class 有两种方式

使用javac,默认使用的release方式。

release模式下对于函数参数会改变

[java]  view plain  copy
 print ?
  1. public class Test{    
  2.     private static void sayHello(){    
  3.         System.out.println("Hello world");    
  4.     }    
  5.      
  6.     public static void main(String[] args){    
  7.         sayHello();    
  8.     }    
  9. }  
使用不同的编译方法编译类文件,可以发现,使用debug方法编译产生的Test.class(如下)和用release方法编译(如下)出来的参数名上有所区别。

debug方法:

[java]  view plain  copy
 print ?
  1. public class Test    
  2. {    
  3.   private static void sayHello()    
  4.   {    
  5.     System.out.println("Hello world");    
  6.   }    
  7.      
  8.   public static void main(String[] args) {    
  9.     sayHello();    
  10.   }    
  11. }  
release方法:
[java]  view plain  copy
 print ?
  1. public class Test    
  2. {    
  3.   private static void sayHello()    
  4.   {    
  5.     System.out.println("Hello world");    
  6.   }    
  7.      
  8.   public static void main(String[] paramArrayOfString) {    
  9.     sayHello();    
  10.   }    
  11. }  
这也可以 解释为什么在spring MVC 中controller的注解初始化参数建议指定名称:

[java]  view plain  copy
 print ?
  1. @RequestMapping(/test/{str})    
  2. public String test(@PathVariable String str){    
  3.      System.out.println(str);    
  4.      return null;    
  5. }  

项目部署如果使用的是release版本,这样str(参数中的str发生变化)而非RequestMapping中的{str}这样就对应不起来了。。。然而dubug模式下函数参数不会发生变化。。

---------------------------------------------------------------------------------------------------------------------------------------------


在springMVC有如下代码:

public Boolean employeeHasRole(Integer employeeId, Integer roleId) {
        //
    }
请求为XX/XXX.do?employeeId=1&roleId=1

在编写MVC框架时,想通过反射获取类方法的参数,也就是不通过注解,将http请求中的参数和方法中的参数进行映射。参考链接中有如下三种方法:

  1. compile with debug information(以debug模式编译)。
  2. The default implementation uses asm ClassReader to do so(asm字节码增强实现)。
  3. java8 method.getParameters()方法。

以下是方法2的具体实现,代码地址


package com.bwx.mvc.xmltools;

import com.bwx.test.controller.UserAction;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by bwx on 2017/9/6.
 */
public class MethodParamNamesScanner {

    /**
     * 获取方法参数名列表
     *
     * @param clazz
     * @param m
     * @return
     * @throws IOException
     */
    public static List<String> getMethodParamNames(Class<?> clazz, Method m) throws IOException {
        try (InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class")) {
            return getMethodParamNames(in,m);
        }

    }
    public static List<String> getMethodParamNames(InputStream in, Method m) throws IOException {
        try (InputStream ins=in) {
            return getParamNames(ins,
                    new EnclosingMetadata(m.getName(),Type.getMethodDescriptor(m), m.getParameterTypes().length));
        }

    }
    /**
     * 获取构造器参数名列表
     *
     * @param clazz
     * @param constructor
     * @return
     */
    public static List<String> getConstructorParamNames(Class<?> clazz, Constructor<?> constructor) {
        try (InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class")) {
            return getConstructorParamNames(in, constructor);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return new ArrayList<String>();
    }
    public static List<String> getConstructorParamNames(InputStream ins, Constructor<?> constructor) {
        try (InputStream in = ins) {
            return getParamNames(in, new EnclosingMetadata(constructor.getName(),Type.getConstructorDescriptor(constructor),
                    constructor.getParameterTypes().length));
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return new ArrayList<String>();
    }
    /**
     * 获取参数名列表辅助方法
     *
     * @param in
     * @param m
     * @return
     * @throws IOException
     */
    private static List<String> getParamNames(InputStream in, EnclosingMetadata m) throws IOException {
        ClassReader cr = new ClassReader(in);
        ClassNode cn = new ClassNode();
        cr.accept(cn, ClassReader.EXPAND_FRAMES);// 建议EXPAND_FRAMES
        // ASM树接口形式访问
        List<MethodNode> methods = cn.methods;
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < methods.size(); ++i) {
            List<LocalVariable> varNames = new ArrayList<LocalVariable>();
            MethodNode method = methods.get(i);
            // 验证方法签名
            if (method.desc.equals(m.desc)&&method.name.equals(m.name)) {
//              System.out.println("desc->"+method.desc+":"+m.desc);
                List<LocalVariableNode> local_variables = method.localVariables;
                for (int l = 0; l < local_variables.size(); l++) {
                    String varName = local_variables.get(l).name;
                    // index-记录了正确的方法本地变量索引。(方法本地变量顺序可能会被打乱。而index记录了原始的顺序)
                    int index = local_variables.get(l).index;
                    if (!"this".equals(varName)) // 非静态方法,第一个参数是this
                        varNames.add(new LocalVariable(index, varName));
                }
                LocalVariable[] tmpArr = varNames.toArray(new LocalVariable[varNames.size()]);
                // 根据index来重排序,以确保正确的顺序
                Arrays.sort(tmpArr);
                for (int j = 0; j < m.size; j++) {
                    list.add(tmpArr[j].name);
                }
                break;

            }

        }
        return list;
    }

    /**
     * 方法本地变量索引和参数名封装
     * @author xby Administrator
     */
    static class LocalVariable implements Comparable<LocalVariable> {
        public int index;
        public String name;

        public LocalVariable(int index, String name) {
            this.index = index;
            this.name = name;
        }

        public int compareTo(LocalVariable o) {
            return this.index - o.index;
        }
    }

    /**
     * 封装方法描述和参数个数
     *
     * @author xby Administrator
     */
    static class EnclosingMetadata {
        //method name
        public String name;
        // method description
        public String desc;
        // params size
        public int size;

        public EnclosingMetadata(String name,String desc, int size) {
            this.name=name;
            this.desc = desc;
            this.size = size;
        }
    }

    public static void main(String[] args) throws IOException {
        for (Method m : UserAction.class.getDeclaredMethods()) {
            List<String> list = getMethodParamNames(UserAction.class, m);
            System.out.println(m.getName() + ":");
            for (String str : list) {
                System.out.println(str);
            }
            System.out.println("------------------------");
        }
    }
}


其中asm maven依赖为

<dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-all</artifactId>
            <version>${asm.version}</version>
        </dependency>

其中 这篇代码,虽然在psvm中运行正常,但是将代码用到web项目(tomcat)中,会出现class not found,因为

ClassReader cr = new ClassReader(className);

调用了classloader,

public ClassReader(String var1) throws IOException {
    this(a(ClassLoader.getSystemResourceAsStream(var1.replace('.', '/') + ".class"), true));
}

该方法中少写了斜杠“/”,特此记录。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值