- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在制作一个 Java 字节码编辑器,它将字节码转换为某种可由用户更改的中间代码,然后将该代码解析回字节码。目前,方法声明看起来很糟糕且难以阅读。但是,好吧,它确实有效。
method [public,static] testMethod (Ljava/lang/Object;)Ljava/lang/Object; throws [java/lang/Exception] <T:Ljava/lang/Object;>(TT;)TT;
如您所见,我从
获得了访问标志、方法名称、方法描述、泛型签名和异常org.objectweb.asm.ClassVisitor#visitMethod
是否有一种方便的方法使其看起来像原始源代码,然后从该漂亮的字符串中提取所有信息?上面的方法应该是这样的:
public static <T> T testMethod(T) throws Exception
谢谢!
最佳答案
如果您实现method
public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions)
您已经拥有了大部分所需的信息,您可以将这些信息组装成人类可读的声明。最大的障碍是签名,但幸运的是,ASM 库已经提供了有助于此目的的工具。
以下代码使用 SignatureReader
和 TraceSignatureVisitor
来格式化它们。不幸的是,它需要一些后处理,因为它没有分离类型参数和方法参数,并且省略了非泛型方法的 Object
返回类型。此外,仅当存在通用异常时,它才会生成异常列表,因此我们必须手动执行此操作。
static String decode(int access, String name, String desc,
String signature, String[] exceptions) {
if(signature == null) signature = desc;
StringBuilder sb = new StringBuilder();
appendModifiers(sb, access);
TraceSignatureVisitor v = new TraceSignatureVisitor(0);
new SignatureReader(signature).accept(v);
String declaration = v.getDeclaration(), rType = v.getReturnType();
if(declaration.charAt(0) == '<')
sb.append(declaration, 0, declaration.indexOf("(")).append(' ');
else if(rType.isEmpty() || rType.charAt(0) == '[')
sb.append("java.lang.Object");
sb.append(rType).append(' ').append(name)
.append(declaration, declaration.indexOf('('), declaration.length());
if((access & Opcodes.ACC_VARARGS) != 0 && declaration.endsWith("[])"))
sb.replace(sb.length() - 3, sb.length(), "...)");
String genericExceptions = v.getExceptions();
if(genericExceptions != null && !v.getDeclaration().isEmpty())
sb.append(" throws ").append(genericExceptions);
else if(exceptions != null && exceptions.length > 0) {
sb.append(" throws ");
int pos = sb.length();
for(String e:exceptions) sb.append(e).append(", ");
int e = sb.length() - 2;
sb.setLength(e);
for(; pos < e; pos++) if(sb.charAt(pos) == '/') sb.setCharAt(pos, '.');
}
return sb.toString();
}
private static void appendModifiers(StringBuilder buf, int access) {
for(int bit; access != 0; access -= bit) {
bit = access & -access;
buf.append(switch(bit) {
case Opcodes.ACC_PUBLIC -> "public ";
case Opcodes.ACC_PRIVATE -> "private ";
case Opcodes.ACC_PROTECTED -> "protected ";
case Opcodes.ACC_STATIC -> "static ";
case Opcodes.ACC_FINAL -> "final ";
case Opcodes.ACC_ABSTRACT -> "abstract ";
case Opcodes.ACC_NATIVE -> "native ";
case Opcodes.ACC_SYNCHRONIZED -> "synchronized ";
default -> "";
});
}
}
appendModifiers
方法已针对最近的 Java 版本进行了调整,对于旧版本,请查看 here
它还会手动解码修饰符,正如您在最后看到的那样,但这没什么大不了的。
如果你测试它:
String[] exceptions={"java/lang/Exception"};
System.out.println(decode(9, "testMethod",
"(Ljava/lang/Object;)Ljava/lang/Object;",
"<T:Ljava/lang/Object;>(TT;)TT;", exceptions));
它将打印:
public static <T> T testMethod(T) throws java.lang.Exception
<小时/>
当解析这样的声明时,它会变得更加复杂。由于您要实现一个编辑器而不是汇编器,因此您可能会考虑为不同功能提供不同的编辑器组件的替代方案,例如修饰符的复选框和组合框、名称的文本字段和参数类型的列表编辑器。
此时,我建议学习 Type
类(class)。它允许提取 parameter types和 return type从签名并应用更改后,您可以 recreate a signature .
同样,SignatureReader
和 SignatureWriter
可能有助于以结构化方式处理通用签名,而不是将它们转换为文本形式并重新解析该形式。
关于java - pretty-print Java 方法签名并解析回来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33025409/
我的问题:在没有多余括号的情况下漂亮地打印表达式的最干净的方法是什么? 我有以下 lambda 表达式的表示: Term ::= Fun(String x, Term t) | App(
我正在创建一些脚本和程序来使用获取提交信息 git log --pretty= -1 我想知道此命令的输出是否适合由程序(管道)解析或仅用于呈现给人类(瓷器)。例如,在某些项目中,我正在获取提交 S
当我构建应用程序时,我使用的是 adonis js 项目版本 5 和 Node js 版本 14 以及 docker 版本 20 一切正常但是当我创建 docker 图像并运行容器 docker 时我
使用 mongo v2.4.5 shell,db.col.find().pretty() 在 osx 控制台或 linux ubuntu 12.04 bash 上对我来说打印效果不佳。 使用和不使用
我想将一些printf/sprintf/fprintf语句重构为ostream/sstream/fstream 语句。有问题的代码漂亮地打印了一系列整数和 float ,使用空格填充和固定的小数点数。
我理解大多数具有动态 Web 内容的编程语言中 \t 和 \n 的概念。与大多数人一样,我使用它们的目的是转换所有花哨的 HTML,使其在查看源代码时可读且“漂亮”。目前,我正在制作一个使用 PHP
System.Type 类的名称属性在泛型类型的情况下返回一个奇怪的结果。有没有办法让类型名称的格式更接近我指定的方式?示例:typeof(List).OriginalName == "List" 最
我正在尝试在 Haskell 中漂亮地打印一棵二叉树,这样如果您将头向左转,它应该看起来像一棵树。树中的每一层都应比上一层缩进 2 个空格。 这是预期的输出: -- 18 --
如何在 gdb 中禁用特定的 pretty-print ? 例如,禁用 C++11 std::unique_ptr 打印机。 gdb 帮助或文档未提供真实世界或工作示例。 最佳答案 这对我有用: (g
编辑 我不只是问“缩进”每一行代码,还问“ pretty-print ”和/或更广泛的“缩进”定义,其中行将根据它们包含的内容进行分组/拆分。 这是一个函数(我编写它是为了解决欧拉问题,但这不是重点:
有没有办法像 SBCL 一样以清晰的方式打印评估嵌套语法引号的结果?这在编写宏时调试嵌套语法引号时非常有用。例如,在 Clojure 1.8 中, (let [x '(1 2)] ``(~~@x))
R有多个软件包,可帮助从统计模型输出中打印“漂亮”表(LaTeX/HTML/TEXT),并轻松比较替代模型规范的结果。 其中一些软件包是apsrtable,xtable,memisc,texreg,o
python Data Classes实例还包括一个字符串表示方法,但是当类具有多个字段和/或更长的字段值时,它的结果对于 pretty-print 目的来说并不足够。 基本上,我正在寻找一种方法来自
我需要进行这样的舍入并将其转换为字符: as.character(round(5.9999,2)) 我希望它成为6.00,但它只是给我6 无论如何,我可以让它显示6.00吗? 最佳答案 尝试以下任一方
当我对源使用各种选项进行缩进时,它会执行我想要的操作,但也会使* s在指针类型中的位置困惑: -int send_pkt(tpkt_t* pkt, void* opt_data); -void
我试过 pprint来自 pprint ,但它的输出只有一行,没有多行输出,也没有缩进。 最佳答案 我使用namedtuple的 _asdict 方法。 但是,它返回 OrderedDict其中ppr
我正在为 ocaml 寻找代码格式化程序或 pretty-print 。类似于 gofmt 的 go 编程语言。它最好保留注释。 我正在更正提交内容,并且某些代码的格式使其难以阅读。 最佳答案 如果你
假设我有一个如下定义的二叉树数据结构 type 'a tree = | Node of 'a tree * 'a * 'a tree | Nil 我有一个树的实例,如下所示: let
我正在使用 Pretty Dropdowns ( https://www.npmjs.com/package/pretty-dropdowns ) 作为我的下拉菜单,并且我有一个允许用户将行附加到表单
我正在使用 pretty-print Data.Text.Prettyprint.Doc 。现在我想以不同的方式设计我的输出,并认为语义注释的想法非常适合这里。考虑以下示例 {-# LANGUAGE
我是一名优秀的程序员,十分优秀!