注释处理工具

2023-10-26

文章目录


pom

<!-- swagger依赖 -->
<dependency>
	<groupId>com.spring4all</groupId>
	<artifactId>swagger-spring-boot-starter</artifactId>
	<version>1.8.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>28.0-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
	<groupId>commons-lang</groupId>
	<artifactId>commons-lang</artifactId>
	<version>2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.5</version>
</dependency>

CommnetUtil

package com.example.demo;

import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ClassUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * java 注释工具
 */
public class CommnetUtil {

    /**
     * 反射时默认的包
     */
    private static final String defaultPackage = "com.example.demo.";
    private static final String get_prefix = " get";
    private static final String get_field_name = "GET_FIELD_NAME";
    private static final String set_prefix = " set";
    private static final String set_field_name = "SET_FIELD_NAME";
    private static final String field = "FIELD";
    private static final String left_brackets = "(";

    private static final String get_template = "     /**\n" +
            "     * @return GET_FIELD_NAME\n" +
            "     */\n";
    private static final String set_template = "     /**\n" +
            "     * @param  FIELD SET_FIELD_NAME\n" +
            "     */\n";
    private static final String constructor_template = "     /**\n" +
            "     * 构造函数\n" +
            "     */\n";

    private static final List<String> annotationList = Collections.singletonList("@Override");

    /**
     * 处理 dto pojo vo 等类
     *
     */
    private static void buildDto(){
        String path = "";
        File file = new File("path");
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File item : files) {
                processSingleFile(item);
            }
            return;
        }
        processSingleFile(file);
    }

    /**
     * 处理单个类文件
     * @param file 类文件
     */
    private static void processSingleFile(File file) {
        try {
            Map<String, String> apiMap = buildApiMap(file);
            File tempFile = File.createTempFile("code_temp_" + file.getName(), ".txt");
            List<String> strings = FileUtils.readLines(file, "UTF-8");
            LinkedList<String> linkedList = new LinkedList<>();
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            long preOffset = 0;
            for (String string : strings) {
                randomAccessFile.readLine();
                long offset = randomAccessFile.getFilePointer();
                doList(linkedList, string + "\n");

                if (null == string || "".equals(string)) {
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (!(string.contains(left_brackets) && string.contains("public")) ) {
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (string.contains(set_prefix)) {
                    if (hadComment(linkedList)) {
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        continue;
                    }
                    String oriSetField = string.substring(string.indexOf(set_prefix) + set_prefix.length(), string.lastIndexOf(left_brackets));
                    String setField = oriSetField.toLowerCase();
                    System.out.println(setField);
                    boolean containsKey = apiMap.containsKey(setField);
                    if (!containsKey) {
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        continue;
                    }
                    String comment = set_template.replace(set_field_name, apiMap.get(setField)).replace(field,
                            oriSetField.substring(0, 1).toLowerCase() + oriSetField.substring(1));
                    RafUtil.append(tempFile, comment.getBytes(StandardCharsets.UTF_8));
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (string.contains(get_prefix)) {
                    if (hadComment(linkedList)) {
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        continue;
                    }
                    String getField = string.substring(string.indexOf(get_prefix) + get_prefix.length(), string.lastIndexOf(left_brackets)).toLowerCase();
                    boolean containsKey = apiMap.containsKey(getField);
                    if (!containsKey) {
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        continue;
                    }
                    String comment = get_template.replace(get_field_name, apiMap.get(getField));
                    RafUtil.append(tempFile, comment.getBytes(StandardCharsets.UTF_8));
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (string.contains(file.getName().replace(".java", ""))) {
                    if (hadComment(linkedList)) {
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        continue;
                    }

                    RafUtil.append(tempFile, constructor_template.getBytes(StandardCharsets.UTF_8));
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                }
            }
            FileUtils.copyFile(tempFile, file);
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 存当前读取行的前3行内容
     * @param list 存储容器
     * @param line 当前行
     */
    private static void doList(LinkedList<String> list, String line){
        list.add(line);
        int customSize = 3;
        int size = list.size();
        if (size >= customSize) {
            list.removeFirst();
        }
    }

    /**
     * 构造一个 [方法名(小写)->注释内容] 的map
     * @param file 操作的文件
     * @return map
     * @throws ClassNotFoundException ClassNotFoundException
     * @throws IOException IOException
     */
    private static Map<String,String> buildApiMap(File file) throws ClassNotFoundException, IOException {
        String name = file.getName();
        String className = name.substring(0, name.lastIndexOf("."));
        Map<String, String> apiMap = new HashMap<>();
        Class aClass = ClassUtils.getClass(defaultPackage + className);
        for (Field declaredField : aClass.getDeclaredFields()) {
            ApiModelProperty declaredAnnotation = declaredField.getDeclaredAnnotation(ApiModelProperty.class);
            if (declaredAnnotation != null) {
                apiMap.put(declaredField.getName().toLowerCase(), declaredAnnotation.value());
                continue;
            }
            ApiParam apiParam = declaredField.getDeclaredAnnotation(ApiParam.class);
            if (apiParam != null) {
                apiMap.put(declaredField.getName().toLowerCase(), apiParam.value());
            }
        }

        // 可能有些字段上没加 @ApiParam、@ApiModelProperty 等注解;就使用正则进行注释匹配,使用分组取出注释内容
        List<String> lines = FileUtils.readLines(file, "UTF-8");
        StringBuilder strBuilder = new StringBuilder();
        for (String line : lines) {
            strBuilder.append(line).append("\n");
        }
        String[] codeBlockArr = strBuilder.toString().split(";");
        // javadoc注释:(前导空格 /** 换行)(前导空格 * 空格一个 )(注释内容)(前导空格 * 任意字符)(前导空格 private 后空格 类型声明)(字段名)
        Pattern pattern = Pattern.compile("([\\s]*/[*]{2}\\n)([\\s]*[*][\\s])([\\w\u4e00-\u9fa5/+();()、,\\-: :]*)([\\s]*[*]{1}.*)([\\s]*private[\\s]*[\\w<>\\[\\]]*[\\s]*)([\\w\\d]*)");
        // 双斜线注释: (前导空格 // 后空格)(注释内容)(换行)(前导空格 * 任意字符)(前导空格 private 后空格 类型声明)(字段名)
        Pattern patternSlash = Pattern.compile("([\\s]*//[\\s]*)([\\w\u4e00-\u9fa5/+();()、,\\-: :]*)([\\n])([\\s]*private[\\s]*[\\w<>\\[\\]]*[\\s]*)([\\w\\d]*)");
        for (String aPrivate: codeBlockArr) {
            Matcher matcher = pattern.matcher(aPrivate);
            if (matcher.find()) {
                try {
                    String key = matcher.group(6);
                    String val = matcher.group(3);
                    if (!apiMap.containsKey(key.toLowerCase())) {
                        apiMap.put(key.toLowerCase(), val);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                continue;
            }
            Matcher matcherSlash = patternSlash.matcher(aPrivate);
            if (matcherSlash.find()) {
                try {
                    String key = matcherSlash.group(5);
                    String val = matcherSlash.group(2);
                    if (!apiMap.containsKey(key.toLowerCase())) {
                        apiMap.put(key.toLowerCase(), val);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                continue;
            }
        }
        return apiMap;
    }

    /**
     * 判断当前行的前几行有没有javadoc注释(有的话就不加注释了,防止重复)
     * @param linkedList 存放前几行的容器
     * @return 有-true; 没有-fals
     */
    private static boolean hadComment(LinkedList<String> linkedList) {
        StringBuilder strBuilder = new StringBuilder();
        for (String line : linkedList) {
            strBuilder.append(line);
        }
        String pre3Line = strBuilder.toString();
        Pattern pattern = Pattern.compile("([\\s]*[*]{1}\\.*)");
        return pattern.matcher(pre3Line).find();
    }

    /**
     * 去除层后缀获取文件名
     * @param file 文件
     * @return 截取后的文件名,没有匹配到后缀时,返回原文件名
     */
    private static String getName(File file){
        String mapper_suffix = "Mapper";
        String service_suffix = "Service";
        String serviceImpl_suffix = "ServiceImpl";
        String controller_suffix = "Controller";
        String fileName = file.getName();
        String name = fileName;
        if (fileName.contains(mapper_suffix)) {
            name = fileName.substring(0, fileName.lastIndexOf(mapper_suffix));
        } else if (fileName.contains(service_suffix)) {
            name = fileName.substring(0, fileName.lastIndexOf(service_suffix));
        } else if (fileName.contains(serviceImpl_suffix)) {
            name = fileName.substring(0, fileName.lastIndexOf(serviceImpl_suffix));
        } else if (fileName.contains(controller_suffix)) {
            name = fileName.substring(0, fileName.lastIndexOf(controller_suffix));
        } else {
            System.out.println("no_suffix: " + fileName);
        }
        return name;
    }

    /**
     * 构造一个[文件名,[方法名,方法整个注释内容]] 的map
     * @param file 要处理的当前文件
     * @param fileNameMap 结果map
     */
    private static void buildMethodMap(File file, HashMap<String, HashMap<String, String>> fileNameMap) {
        String name = getName(file);
        if (null == name) {
            return ;
        }
        HashMap<String, String> methodName_CommentMap = new HashMap<>();
        fileNameMap.put(name, methodName_CommentMap);
        try {
            List<String> lines = FileUtils.readLines(file, "UTF-8");
            StringBuilder strBuilder = new StringBuilder();
            for (String line : lines) {
                strBuilder.append(line).append("\n");
            }
            String[] codeBlockArr = strBuilder.toString().split(";");
            for (String codeBlock : codeBlockArr) {
                if (codeBlock.contains("{")) {
                    for (String lineBlock : codeBlock.split("\\{")) {
                        processCodeBlock(lineBlock, methodName_CommentMap);
                    }
                    continue;
                }
                processCodeBlock(codeBlock, methodName_CommentMap);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // tab 开头的 javadoc 注释
    static Pattern pattern_t = Pattern.compile("([\\t].*/[*]{2}.*\\n[\\s\\S]*[*]{1}[/]{1}\\n)([\\s]*[a-zA-Z<>\\[\\] ]*[\\s]{1,3})(\\b\\w*[(])");
    // 空格开头的 javadoc 注释
    static Pattern pattern3 = Pattern.compile("([\\s]{4}/[*]{2}.*\\n[\\s\\S]*[*]{1}[/]{1}\\n)([\\s]*[a-zA-Z<>\\[\\] ]*[\\s]{1,3})(\\b\\w*[(])");
    // 空格开头的 javadoc 注释;方法上方有注解
    static Pattern pattern4 = Pattern.compile("([\\s]{4}/[*]{2}.*\\n[\\s\\S]*[*]{1}[/]{1}\\n)([\\s]*[@].*\\n)([\\s]*[a-zA-Z<>\\[\\] ]*[\\s]{1,3})(\\b\\w*[(])");

    private static void processCodeBlock(String codeBlock, HashMap<String, String> methodName_CommentMap){
        Matcher matcher = pattern3.matcher(codeBlock);
        if (matcher.find()) {
            try {
                String key = matcher.group(3);
                String val = matcher.group(1);
                key = processKey(key);
                methodName_CommentMap.put(key.substring(0, key.indexOf("(")), val);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        Matcher matcher4 = pattern4.matcher(codeBlock);
        if (matcher4.find()) {
            try {
                String key = matcher4.group(4);
                String val = matcher4.group(1);
                key = processKey(key);
                methodName_CommentMap.put(key.substring(0, key.indexOf("(")), val);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        Matcher matcherT = pattern_t.matcher(codeBlock);
        if (matcherT.find()) {
            try {
                String key = matcherT.group(3);
                String val = matcherT.group(1);
                key = processKey(key);
                methodName_CommentMap.put(key.substring(0, key.indexOf("(")), val);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 去除key前面的多余内容
     * @param key 要处理的key
     * @return key
     */
    private static String processKey(String key) {
        if (key == null) {
            return null;
        }
        String trim = key.trim();
        return trim.substring(key.indexOf(" ") + 1);
    }

    private static void syncCommnet() {
        String src = "";
        String dest = "";
        File file = new File(src);
        File fileDest = new File(dest);
        if (!file.exists() || !fileDest.exists()) {
            return;
        }
        HashMap<String, HashMap<String, String>> fileNameMap = new HashMap<>();
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File item : files) {
                if (item.isDirectory()) {
                    System.out.println(item.getName() + ": is_dir");
                    continue;
                }
                buildMethodMap(item, fileNameMap);
            }
        } else {
            buildMethodMap(file, fileNameMap);
        }
        // src dir ok
        //
        boolean directory = fileDest.isDirectory();
        if (directory) {
            File[] files = fileDest.listFiles();
            for (File item : files) {
                syncFile(item, fileNameMap.get(getName(item)));
                System.out.println(item.getName() + "==>> OK");
            }
        } else {
            syncFile(fileDest, fileNameMap.get(getName(fileDest)));
        }
    }

    private static void syncFile(File file, Map<String, String> methodNameMap) {
        if (methodNameMap == null) {
            return;
        }
        try {
            File tempFile = File.createTempFile("code_temp_" + file.getName(), ".txt");
            List<String> strings = FileUtils.readLines(file, "UTF-8");
            LinkedList<String> linkedList = new LinkedList<>();
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            long preOffset = 0;
            String preLine = null;
            for (String string : strings) {
                randomAccessFile.readLine();
                long offset = randomAccessFile.getFilePointer();
                doList(linkedList, string + "\n");

                if (null == string || "".equals(string)) {
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (annotationList.contains(string.trim())) {
                    preLine = string + "\n";
                    preOffset = offset;
                    continue;
                }
                if (!(string.contains(left_brackets))) {
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                if (hadComment(linkedList)) {
                    RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                    preOffset = offset;
                    continue;
                }
                String[] blockArr = string.split(" ");
                for (String block : blockArr) {
                    if (block == null) {
                        continue;
                    }
                    if (methodNameMap.containsKey(block.trim())) {
                        RafUtil.append(tempFile, (methodNameMap.get(block.trim())).getBytes(StandardCharsets.UTF_8));
                        if (preLine != null) {
                            RafUtil.append(tempFile, preLine.getBytes(StandardCharsets.UTF_8));
                            preLine = null;
                        }
                        RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                        preOffset = offset;
                        break;
                    }
                    // 括号和方法名在一起的情况
                    if (block.contains("(")) {
                        String methodName = block.substring(0, block.indexOf("("));
                        if (methodNameMap.containsKey(methodName.trim())) {
                            RafUtil.append(tempFile, (methodNameMap.get(methodName.trim())).getBytes(StandardCharsets.UTF_8));
                            if (preLine != null) {
                                RafUtil.append(tempFile, preLine.getBytes(StandardCharsets.UTF_8));
                                preLine = null;
                            }
                            RafUtil.append(tempFile, RafUtil.getBytes(file, preOffset, offset));
                            preOffset = offset;
                            break;
                        }
                    }
                }
            }
            FileUtils.copyFile(tempFile, file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

注释处理工具 的相关文章

  • 数据库设计规范(详细)

    数据规范化设计 一 数据规范化 仅有好的RDBMS并不足以避免数据冗余 必须在数据库的设计中创建好的表结构 Dr E F codd 最初定义了规范化的三个级别 范式是具有最小冗余的表结构 这些范式是 1 第一范式 1st NF First

随机推荐

  • linux配置浮动IP

    在高可用集群环境中 一般都需要使用浮动IP来实现web高可用 High Availability 浮动IP的概念以及为什么需要浮动IP请参考 浮动IP FLOAT IP 本篇文章主要讲实际操作步骤 可以是双机 也可以是多机 主服务器为172
  • VLOOKUP函数匹配结果不正确?错误结果是怎么得出来的?[已解决]

    匹配结果不正确主要是以下2个方面入手 是否是精确匹配 range lookup 参数为 FALSE或0 检查所有的数据是否带空格等 官方帮助文档 Microsoft Excel 中 VLOOKUP 函数的语法和用法 语法 VLOOKUP l
  • [yotroy.cool]WSL安装CUDA独显 PyTorch 深度学习环境配置,测速为什么要用WSL?

    个人博客https www yotroy cool 欢迎关注我哦 前言 为了预习大三课程 想提前学习下PyTorch 于是我遇到了神仙学习教程 动手学深度学习 同时以此为参考完成了环境配置 感谢大佬们无私奉献Thanks 本教程展示了独显w
  • 等精度测频的原理和基于FPGA的实现

    我们通过FPGA测量信号频率 一般来说有两种方案 传统测频法和等精度测频法 方案一 传统测频是在一段闸门时间内直接对输入信号的周期进行计数 也被叫做直接测频法 设闸门信号为gate 检测待测信号上升沿 然后判断gate是否为高电平 若为高电
  • 转置矩阵,逆矩阵和倒转置矩阵

    单位矩阵 转置矩阵 transpose matrix 在线性代数中 矩阵A的转置是另一个矩阵AT 也写做Atr tA或A 由下列等价动作建立 把A的横行写为AT的纵列 把A的纵列写为AT的横行 形式上说 m n矩阵A的转置是n m矩阵 fo
  • 【ctfshow】PHP特性2

    目录 web100 web101 web102 web103 web104 web105 web106 web107 web108 web109 web110 web100 include ctfshow php flag in class
  • ascii码图片

    铁臂阿童木 be be Nc R o uQ bo Jod e dd e d
  • lora模块学习一

    LoRa TM 调制解调器采用扩频调制和前向纠错技术 与传统的FSK或OOK调制技术相比 这种技术不仅扩大了无线通讯链路的覆盖范围 而且还提高了链路的鲁棒性 在设计中 可以通过调整扩频因子 SF 调制带宽 BW 和编码率 CR 三个关键设计
  • cuda-gdb 调试方法:cuda gdb中的可调参数

    cuda gdb 中存在一些可调的参数 可以通过 set cuda lt tunable name gt
  • php实现ETH原生签名交易sendRowTransaction

    文章目录 1 安装GMP 之前需要先安装m4 不然会出错 2 然后ubuntu安装gmp 3 然后安装PHP gmp扩展 4 安装scrypt 扩展 4 撤销sudoers文件写权限 命令 参考文章链接 1 安装GMP 之前需要先安装m4
  • window.location.href跳转带有token的新链接时显示空白页

    问题 从A平台跳到B平台并自动登录B平台 后端生成包含token的完整链接传给前端 前端window location href打开时页面显示空白页 手动刷新才会跳到新链接 原因 用window location href跳转新链接可能会带
  • JIO学习(一)输入流综述

    一 字节输入流 java io InputStream java lang Object java io InputStream 所有已实现的接口 Closeable 直接已知子类 AudioInputStream ByteArrayInp
  • Pinia从入门到精通

    一 为什么使用 Pinia Pinia 是 Vue 的专属状态管理库 它允许你跨组件或页面共享状态 如果你熟悉组合式 API 的话 你可能会认为可以通过一行简单的 export const state reactive 来共享一个全局状态
  • /dev/null 1 & 2的用法

    应用背景 devnull 1 2的介绍 把错误输出和标准输出都导入日志testlog里 屏蔽标准输出和错误输出信息 tee命令如何把标准输出和错误输出都导入testlog里 应用背景 如下例所示 aa是不识别的命令 在执行 test sh时
  • 模拟退火法、遗传算法求解多皇后问题

    一 问题背景 多皇后问题是一个经典的问题 在一个 N x N 的棋盘上放置 N 个皇后 使其不能互相攻击 每行 每列 每一斜线上分别只能放置一个皇后 求解 N 皇后问题的复杂度随 N 呈指数级增加 传统的求解方法采用基于回溯算法的策略 当
  • 最简单的8421码计算方法

    很简单 0 9 就是按照二进制来的 0 0000 1 0001 9 1001 超出9以后把10进制情况下的数按照个十百千万的位数拆开 并把每一位按照8421转换后合起来 10 10000 11 10001 19 11001 20 10000
  • 多元线性回归分析spss结果解读_Spss的线性回归做法及结果解读

    上一节我们讲过了eviews做多元回归 但是很多同学做问卷之类的都需要用到spss 所以这节我教一下大家如何用spss做多元回归 并对结果进行解读 再对大家所疑惑的显著水平做一些白话的解释 一 线性回归的操作 将因变量和自变量移入对应的框中
  • C++ primer 之定义行为像指针的类

    提前声明 这是一篇水博 1 使用智能指针实现 include
  • markdown常用语法

    排版常用功能 在我们排版时 使用得最多的无非就是以下几种效果 标题 加粗 斜体 删除线 无序列表 有序列表 引用 代码块 分割线 标题 标题分为六个级别 几个 就是几级标题 需要注意的是 和标题之间要有空格 加粗 这是粗体效果 也就是在文字
  • 注释处理工具

    文章目录 pom CommnetUtil RafUtil https blog csdn net wwq921220 article details 119515809 pom