文档章节

字节码故事——“Can I obtain parameter name from Bytecode”

舍瓦温
 舍瓦温
发布于 2015/06/04 21:08
字数 659
阅读 33
收藏 0

需求就是这样丰富多彩,保不齐哪天,你需要从通过读取字节码中了解一个类。这看起来没什么,ASM来搞定。一切都那么顺利,直到你需要获取类中方法的参数名……

我就是这样,今天需要为一些已经打成 jar 的类提供在线的远程方法调用,也就是要读取字节码,找出所有的方法,包括这些方法的返回值、参数名称和类型。首先想到的是翻出 ASM ,用 visitMethod。

public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    if((Opcodes.ACC_PUBLIC & access)>0) {
      System.err.println("method name: " + name);
      System.err.println("return type: " + Type.getReturnType(desc));
      System.err.println("argument types: " + Arrays.toString(Type.getArgumentTypes(desc)));
    }
    return super.visitMethod(access, name, desc, signature, exceptions);
  }

然后你发现,方法名、返回值、参数类型都是有的,但是参数名称真没有, ** 因为在 bytecode 里,参数名已经消失了**!

好吧,我严谨一点说:

在JDK 8 之前,Bytecode 里真的没有方法的参数名

那 JDK 8 里就有了? 是的,但你需要在 compile 的时候加个参数

javac -parameters

添加这个参数之后,Bytecode里相当于被插入这么一行

private static final String __PARANAMER_DATA = "v1.0 \n"
      + "<init> com.example.PeopleService peopleService \n"
      + "setName java.lang.String,java.lang.String givenName,familyName \n";
      + "setDateOfBirth int,int,int day,month,year \n";

对,就是这么一个格式化的字符串,将方法的类型和名称单独赋值给了 __PARANAMER_DATA

现在你就能找到梦寐以求的方法参数名了。

如果 JDK 8 之前版本编译的 class 怎么办?其实 -parameters 这种方案来自于 paranamer。从 JDK 5.0 开始,paranamer 就可以通过在编译结果里添加 __PARANAMER_DATA 这样一个常量来达到让字节码读取者获得方法参数名的目的了。只是到 JDK 8,这个方案被“收编”了,成了 buildin 了。

所以在 JDK 8 之前版本中,如果 class 编译是可控的话,可以在 class 编译的过程使用 paranamer-generator.jar 的 API 来实现 -parameters 的效果。大概是这样

ParanamerGenerator generator = new QdoxParanamerGenerator();
generator.processSourcePath(path + "/src/test", path + "/target/test-classes/");

paranamer 也提供了 ANT、MAVEN(利用插件) 的构建支持。

一个paranamer的贡献者提供了 JavadocParanamer,可以通过读取 javadoc 来获得方法参数名。

总的来说,获取方法参数名这么件小事,却是刚需,paranamer 提供了一整套的方案来实现。

© 著作权归作者所有

共有 人打赏支持
舍瓦温
粉丝 6
博文 14
码字总数 8280
作品 0
呼和浩特
程序员
深入字节码 -- 玩转 ASM-Bytecode

本文是《深入字节码 -- 使用 ASM 实现 AOP》的后续博文。在上一篇文章中介绍了如何使用 ASM 动态安插代码到类中,从而简单实现 Aop。文章得到了广大朋友好评,我也希望可以不负众望继续写出可...

哈库纳
2013/09/23
0
0
Jvm与字节码——类的方法区模型

从一个类开始 我们从一个简单类开始说起: 这是一段平凡得不能再平凡的Java代码,稍微有点编程语言入门知识的人都能理解它表达的意思: 创建一个名为SimpleClass的类; 定义一个入口main方法...

溜达向日葵
08/31
0
0
震惊,西方的程序员跑得居然这么快

昨天刚刚发表了一篇文章(ProGuard又搞了个大新闻),主要吐槽的是项目里面使用ProGuard工具导致的一个诡异的坑。其中根本的原因就是,ProGuard混淆Java注解类的时候,把两个方法混淆成同样的...

Kaede
2017/03/21
0
0
[Python源码学习]之bytecode

Python 代码首先被编译成 bytecode,然后才被解释器进行执行。 bytecode 可被缓存动.pyc或.pyo文件内。 bytecode 对应源码中的 PyCodeObject 结构体对象 生成 .pyc 文件 代码中通过import使用...

晨曦之光
2012/05/08
670
0
JIT 即时编译的运作原理

JIT just-in-time,被翻译为即时编译,要理解即时编译我觉得和普通的编译(C,C++等静态语言)相对比便可理解,普通编译可以说是 all before runtime,在你运行程序前你需要提前把程序完全编...

big_cat
2015/12/03
113
0

没有更多内容

加载失败,请刷新页面

加载更多

你为什么在Redis里读到了本应过期的数据

一个事故的故事 晚上睡的正香突然被电话吵醒,对面是开发焦急的声音:我们的程序在访问redis的时候读到了本应过期的key导致整个业务逻辑出了问题,需要马上解决。 看到这里你可能会想:这是不...

IT--小哥
今天
2
0
祝大家节日快乐,阖家幸福! centos GnuTLS 漏洞

yum update -y gnutls 修复了GnuTLS 漏洞。更新到最新 gnutls.x86_64 0:2.12.23-22.el6 版本

yizhichao
昨天
5
0
Scrapy 1.5.0之选择器

构造选择器 Scrapy选择器是通过文本(Text)或 TextResponse 对象构造的 Selector 类的实例。 它根据输入类型自动选择最佳的解析规则(XML vs HTML): >>> from scrapy.selector import Sele...

Eappo_Geng
昨天
4
0
Windows下Git多账号配置,同一电脑多个ssh-key的管理

Windows下Git多账号配置,同一电脑多个ssh-key的管理   这一篇文章是对上一篇文章《Git-TortoiseGit完整配置流程》的拓展,所以需要对上一篇文章有所了解,当然直接往下看也可以,其中也有...

morpheusWB
昨天
5
0
中秋快乐!!!

HiBlock
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部