讲师中心 微信公众号
AI工具推荐 视频效率加速

ASM 教程:在 Class 文件中使用 ASM 将参数注解映射到对应的方法参数

大墨吖_7319

大墨吖_7319

发布时间:2025-09-30 18:22:20

|

853人浏览过

|

来源于php中文网

原创

asm 教程:在 class 文件中使用 asm 将参数注解映射到对应的方法参数

摘要

在使用 ASM 处理 Class 文件时,将方法参数的注解映射到对应的参数并非总是直观的。由于 Class 文件中的参数索引与方法描述符中的参数位置可能不一致,尤其是在存在编译器生成的合成参数时,直接的索引对应关系可能失效。本教程将介绍一种基于 Java 反射实现思路的解决方案,该方案通过假设合成参数位于方法参数列表的前端,从而实现注解与参数的正确映射。本文将提供详细的代码示例,展示如何在 ASM 中实现这一映射逻辑,并讨论其局限性和适用场景。

正文

在处理 Java Class 文件时,一个常见的需求是读取方法的参数注解。然而,Java 虚拟机规范指出,parameter_annotations 表中的第 i 个条目不一定对应于方法描述符中的第 i 个参数描述符。这在存在合成参数(例如内部类的构造函数中的外部类实例)的情况下尤为常见。这意味着,在使用 ASM 的 MethodVisitor.visitParameterAnnotation 方法时,传入的参数索引可能与实际的参数位置不匹配。

那么,如何才能正确地将参数注解映射到对应的参数呢?

一种可行的解决方案是模仿 Java 反射框架的做法。Java 反射在处理参数注解时,会假设合成参数位于方法参数列表的前端。如果参数注解的数量与参数的数量不匹配,反射框架会尝试将注解向下移动,以适应合成参数的存在。

以下是一个使用 ASM 实现类似逻辑的示例:

Java Api Extractor
Java Api Extractor

从 Java 项目中提取 Controller 层接口定义为 JSON 数据。

下载
import org.objectweb.asm.*;

import java.io.IOException;
import java.util.List;

public class ReadParameters extends ClassVisitor {
    public static void main(String[] args) throws IOException {
        for(Class<?> cl: List.of(Example.class, Example.Inner.class)) {
            System.out.println(cl);
            new ClassReader(cl.getName())
                .accept(new ReadParameters(), ClassReader.SKIP_CODE);
            System.out.println();
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor,
                                     String signature, String[] exceptions) {
        System.out.println(" " + name);
        return new ParameterVisitor(name, descriptor);
    }

    static class ParameterVisitor extends MethodVisitor {
        final Type[] parameterTypes;
        int offset;

        ParameterVisitor(String name, String desc) {
            super(Opcodes.ASM9);
            parameterTypes = Type.getArgumentTypes(desc);
        }

        @Override
        public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
            offset = parameterTypes.length - parameterCount;
            for(int i = 0; i < offset; i++)
                System.out.printf(" %3d %-20s %s%n",
                    i, parameterTypes[i].getClassName(), "(synthetic)");
        }

        @Override
        public AnnotationVisitor visitParameterAnnotation(
                int parameter, String descriptor, boolean visible) {
            parameter += offset;
            System.out.printf(" %3d %-20s %s%n", parameter,
                parameterTypes[parameter].getClassName(),
                Type.getType(descriptor).getClassName());
            return null;
        }
    }

    protected ReadParameters() {
        super(Opcodes.ASM9);
    }
}

在这个示例中,ParameterVisitor 类负责处理方法参数的注解。visitAnnotableParameterCount 方法用于确定参数注解的数量,并计算出合成参数的偏移量 offset。在 visitParameterAnnotation 方法中,我们将传入的参数索引 parameter 加上 offset,从而得到实际的参数位置。

注意事项:

  • 这种方法依赖于合成参数位于参数列表前端的假设。虽然这在大多数情况下是成立的,但并非总是如此。例如,在某些编译器实现中,合成参数可能会被添加到参数列表的末尾。
  • Java 反射框架在处理局部类和匿名类的构造函数时,如果参数数量不匹配,会选择忽略该不匹配。这意味着,对于这些特殊情况,上述 ASM 实现可能无法正确地映射参数注解。
  • 对于普通方法,Java 反射框架在参数数量不匹配时会抛出异常。因此,在处理方法时,建议也采用类似的策略,以确保数据的完整性。

总结:

虽然将参数注解映射到对应的参数可能很复杂,但通过模仿 Java 反射框架的思路,我们可以实现一种相对可靠的解决方案。在实际应用中,需要根据具体的场景和需求,仔细考虑各种边界情况,并采取相应的处理策略。尤其需要注意合成参数的位置以及不同类型类的构造函数的特殊性。通过谨慎的设计和实现,我们可以确保在使用 ASM 处理 Class 文件时,能够正确地获取和使用参数注解信息。

热门AI工具

更多
VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

4336

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

306

2025.12.06

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

0

2026.11.03

Tailwind CSS 响应式布局怎么写
Tailwind CSS 响应式布局怎么写

Tailwind CSS 响应式布局通常从移动端样式写起,再用 sm、md、lg 等前缀调整不同屏幕宽度下的网格、间距和导航。本专题整理断点配置、Grid 与 Flex 自适应布局及常见溢出问题,帮助你逐步完成多设备适配。

0

2026.11.03

Tailwind CSS 常用类名怎么记
Tailwind CSS 常用类名怎么记

Tailwind CSS 类名很多,先按布局、间距、文字、颜色和状态分组记忆,再通过官方文档检索具体写法。本专题结合类名排序、动态拼接失效、自定义实用类等问题,帮助你建立常用类名的速查方法。

0

2026.11.03

码上飞入口地址合集
码上飞入口地址合集

本专题汇总了码上飞(CodeFlying)的官方入口地址合集,涵盖官网主站及网页版在线使用入口,支持注册登录后直接在线体验零代码AI应用生成。同时整理了APP端下载渠道与小程序入口,助你快速访问平台,通过自然语言描述需求即可生成应用、小程序或网站。

0

2026.11.03

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

20

2026.11.02

Uvicorn使用教程
Uvicorn使用教程

本专题汇总了Uvicorn使用教程与启动运行指南,涵盖其作为Python ASGI服务器的定位与特点,以及命令行启动(uvicorn main:app --reload)、参数配置(host/port/workers)、程序内嵌运行与Gunicorn结合部署等核心用法。同时整理了热重载调试、日志配置与生产环境部署优化等技巧,助你快速掌握Uvicorn的运行与配置。

20

2026.11.02

Uvicorn安装配置教程
Uvicorn安装配置教程

本专题汇总了Uvicorn的安装配置教程与部署指南,涵盖通过pip安装Uvicorn、启动FastAPI/Starlette应用、开发模式热重载(--reload)及多进程工作模式配置等核心操作。同时整理了结合Gunicorn的生产部署方案、HTTPS与反向代理配置及性能调优技巧,助你快速完成Uvicorn服务的安装与上线部署。

20

2026.11.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn