当前位置: 首页 > news >正文

技术小谈|反射和类加载的一个简单应用

        

        小明是一个刚入职不久的初级开发,虽然他掌握了很多Java的基础知识,但工作中一直没有机会用上,时常感到有些迷茫。某天,领导突然安排他编写一个系统的数据字典,由于项目代码风格良好,实体类中的字段都有中文名称,并且使用注解注释上了。面对这个任务,小明觉得如果手动维护太麻烦了,既费时间,又废精力,但他突然想起学习时提到的反射机制以及类加载,似乎可以用来动态获取类的信息。于是他深入研究,成功利用反射自动生成数据字典。

        好了,刚刚那个是需求背景,接下来我们简单聊一下这个小功能,说实话这个事情谁都可以做,无非就是做的快慢的事情,这里想用这个无非就是想说平常我们有些东西用起来代码写确实会时间更长一些,但是现在有了AI,我们有这个想法后在让AI来帮我们做这个事情确实会很容易。

        当然这里 作者只是抛砖引玉,这个东西实际上确实有这么个活,然后我把想法告诉了chatgpt,让他按照我说的写出了这段代码,加上调试,以及运行一共也就不到一个小时就搞定了,最后输出成了一个txt的文档,然后转换一下 直接复制到了excel,确实比纯手工维护方便很多,当然肯定会有其他问题,只不过在我这边跑通了而已,这个其实像网上的逆向原理也是差不多的。话不多说上代码:

package com.demo;// todo  这个包这里的注解是作者公司封装的
import com.demo.Comment;import javax.persistence.Column;
import javax.persistence.Table;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;public class AnnotationProcessor {public static void main(String[] args) {// todo 只需要在这里定义路径即可,避免重复硬编码String basePackagePath = "/Users/xx/job/com/demo/xxx/data/dao";String entityPath = basePackagePath + "/target/classes/com/demo/xxx/data/dao/entity"; // 只需调整这里路径,其他地方动态引用   注意 这里读取的是编译后的文件File dir = new File(entityPath);List<String> result = new ArrayList<>();// 检查目录是否存在且为有效目录if (dir.exists() && dir.isDirectory()) {File[] files = dir.listFiles((file) -> file.getName().endsWith(".class"));if (files != null) {URL[] urls;try {// 将目录路径转换为URL,用于类加载器urls = new URL[]{dir.toURI().toURL()};} catch (MalformedURLException e) {throw new RuntimeException("URL转换失败: " + dir.getAbsolutePath(), e);}// 使用自定义类加载器加载类文件try (URLClassLoader classLoader = new URLClassLoader(urls)) {for (File file : files) {// 根据文件路径获取类名String className = getClassNameFromFile(file, entityPath, basePackagePath);try {// 处理类中的注解processClassAnnotations(className, classLoader, result);} catch (NoClassDefFoundError e) {System.err.println("加载类时出现NoClassDefFoundError: " + className);e.printStackTrace();} catch (Exception e) {System.err.println("处理类时出错: " + className);e.printStackTrace();}}} catch (Exception e) {System.err.println("类加载时出错: " + e.getMessage());e.printStackTrace();}}} else {System.err.println("目录 " + entityPath + " 不存在或不是有效目录。");}// 写入结果到文件writeToFile(result);}// 从文件名获取类的全限定名,避免硬编码package,动态构建类路径private static String getClassNameFromFile(File file, String basePath, String basePackagePath) {String absolutePath = file.getAbsolutePath();String classPath = absolutePath.replace(basePath + "/", "").replace("/", ".").replace(".class", "");return basePackagePath.replace("/", ".") + "." + classPath;   // 根据基础包路径动态拼接类名}// 处理类中的注解,提取表名、列名及注释信息private static void processClassAnnotations(String className, ClassLoader classLoader, List<String> result) {try {// 使用类加载器加载指定的类Class<?> clazz = Class.forName(className, true, classLoader);Table tableAnnotation = clazz.getAnnotation(Table.class);if (tableAnnotation != null) {String tableName = tableAnnotation.name();for (Field field : clazz.getDeclaredFields()) {Column columnAnnotation = field.getAnnotation(Column.class);if (columnAnnotation != null) {String columnName = columnAnnotation.name();Comment commentAnnotation = field.getAnnotation(Comment.class);String comment = commentAnnotation != null ? commentAnnotation.value() : "";// 构建结果行,格式:表名 | 列名 | 注释String line = tableName + " | " + columnName + " | " + comment;result.add(line);}}}} catch (NoClassDefFoundError e) {System.err.println("加载类时出现NoClassDefFoundError: " + className);e.printStackTrace();} catch (Exception e) {System.err.println("处理类时出错: " + className);e.printStackTrace();}}// 将结果写入到txt文件中private static void writeToFile(List<String> result) {System.out.println("开始写入文件……");System.out.println("当前工作目录: " + System.getProperty("user.dir"));try (FileWriter writer = new FileWriter("output.txt")) {for (String line : result) {writer.write(line + System.lineSeparator());}} catch (IOException e) {System.err.println("写入文件时出错: " + e.getMessage());e.printStackTrace();}}
}

        


http://www.mrgr.cn/news/34586.html

相关文章:

  • 解密.baxia勒索病毒:.baxia勒索病毒的攻击手法及防护建议
  • Avatarify——实时面部替换工具,允许用户通过网络摄像头将自己的表情映射到虚拟人物或名人头像上
  • webservice cxf框架 jaxrs jaxws spring整合 接口测试方法 wsdl报文详解 springboot整合 拦截器 复杂参数类型
  • 苍穹外卖学习笔记(十)
  • 什么是反射,反射用途,spring哪些地方用到了反射,我们项目中哪些地方用到了反射
  • Mysql进阶
  • 一篇关于网络的文章
  • 研一奖学金计划2024/9/23有感
  • BEV学习--Nuscenes数据集解读
  • 用Flowise+OneAPI+Ollama做一个在线翻译工作流
  • 如何登录通义灵码,快速开启AI编码之旅?
  • 基于单片机巡迹避障智能小车系统
  • 设计模式相关知识
  • SpringBoot+Aop+注解方式 实现多数据源动态切换
  • vcruntime140_1.dll无法继续执行代码的6种解决方法
  • Undet for sketchup 2023.3注册机 支持草图大师sketchup2021-2022-2023
  • 数据结构之图的遍历
  • MySQL | 使用 HAVING 子句进行高级数据筛选
  • 数据链路层协议 —— 以太网协议
  • 如何快速免费搭建自己的Docker私有镜像源来解决Docker无法拉取镜像的问题(搭建私有镜像源解决群晖Docker获取注册表失败的问题)