如何全局搜索maven项目中引用jar包中的文件

在开发过程中,遇到过一件事,当时本地启动服务,页面调用远程接口的时候一直报找不到服务,但是又找不到哪里错误,这个时候发现启动过程中,打印了一段信息,觉得有可能是跟这边有关,这段信息是System.out直接打印出来的(代码不规范),找不到是哪个类跑出来的,是引用的jar包里面的,全局Crtl+shift+F也搜不到jar包里面的,一步步跟踪,代码太多,很难找到(虽然到最后跟这行信息没关系,问写源代码的同事说这段信息可以忽略,原因在于网络vpn的问题)。

这个时候就想到了一个问题,如何全局搜索maven项目中引用jar包中的文件。

解决这个问题

1、首先需要找到项目引用的所有jar包

2、对jar包进行反编译

3、内容搜索

最后解决过程如下:

1、找到项目工程引用的jar包

mvn dependency:copy-dependencies -DoutputDirectory=/Users/taoxuefeng/mvnlib

使用该命令可以将项目中引用的所有jar包拷贝到指定目录

2、反编译

反编译,idea自带反编译,jd-gui也支持,可惜那些都是页面化的,不能程序控制,这里使用的是crf反编译

3、内容搜索

这里就不多说了,很简单

代码如下:

1、pom

指定crf反编译依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>cfrtest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
            <distribution>repo</distribution>
        </license>
    </licenses>
    <dependencies>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.benf</groupId>
            <artifactId>cfr</artifactId>
            <version>0.151</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
    </dependencies>
</project>

2、反编译核心类

输入jar包文件夹地址,和反编译代码存放地址,会自动进行反编译

package com.taoge.cfrtest;

/**
 * Desc:
 *
 * @author taoxuefeng
 * @date 2021/9/24
 */

import org.benf.cfr.reader.api.CfrDriver;
import org.benf.cfr.reader.util.getopt.OptionsImpl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * @author hengyunabc 2018-11-16
 */
public class Decompiler {

    public static Long cfr(String source, String targetPath) throws IOException {
        Long start = System.currentTimeMillis();
        List<String> files = new ArrayList<>();
        File file = new File(source);
        if (file.isDirectory()) {
            File[] fileList = file.listFiles();
            for (File temp : fileList) {
                files.add(temp.getAbsolutePath());
            }
        } else {
            files.add(source);
        }
        // target dir
        HashMap<String, String> outputMap = new HashMap<>();
        outputMap.put("outputdir", targetPath);
        OptionsImpl options = new OptionsImpl(outputMap);
        CfrDriver cfrDriver = new CfrDriver.Builder().withBuiltOptions(options).build();
        cfrDriver.analyse(files);
        Long end = System.currentTimeMillis();
        return (end - start);
    }

}

2、搜索结果

搜索结果类,记录了文件名,绝对路径地址,开始结束时间,以及匹配到的文件行

package com.taoge.cfrtest;

import java.util.List;

/**
 * Desc:
 *
 * @author taoxuefeng
 * @date 2021/11/19
 */
public class SearchResult {

    private String fileName;

    private String absolutePath;

    private List<Integer> lineList;

    private Long startTime;

    private Long endTime;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getAbsolutePath() {
        return absolutePath;
    }

    public void setAbsolutePath(String absolutePath) {
        this.absolutePath = absolutePath;
    }

    public List<Integer> getLineList() {
        return lineList;
    }

    public void setLineList(List<Integer> lineList) {
        this.lineList = lineList;
    }

    public Long getStartTime() {
        return startTime;
    }

    public void setStartTime(Long startTime) {
        this.startTime = startTime;
    }

    public Long getEndTime() {
        return endTime;
    }

    public void setEndTime(Long endTime) {
        this.endTime = endTime;
    }
}

3、搜索

这个就不多说了,反编译后得到一堆文件,对里面的文件递归搜索,并生成搜索结果

package com.taoge.cfrtest;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Desc:
 *
 * @author taoxuefeng
 * @date 2021/11/18
 */
public class SearchFile {

    public static List<SearchResult> search(String targetPath, String searchContent) {
        List<SearchResult> searchResults = new ArrayList<>();
        File file = new File(targetPath);
        if (file.isDirectory()) {
            for (File childFile : file.listFiles()) {
                if (childFile.isFile()) {
                    SearchResult result = search(childFile, searchContent);
                    if (Objects.nonNull(result)) {
                        searchResults.add(result);
                    }
                } else {
                    searchResults.addAll(search(childFile.getAbsolutePath(), searchContent));
                }
            }
        } else {
            SearchResult result = search(file, searchContent);
            if (Objects.nonNull(result)) {
                searchResults.add(result);
            }
        }
        return searchResults;
    }

    private static SearchResult search(File file, String searchContent) {
        try {
            SearchResult searchResult = new SearchResult();
            searchResult.setAbsolutePath(file.getAbsolutePath());
            searchResult.setFileName(file.getName());
            searchResult.setStartTime(System.currentTimeMillis());
            List<String> contentLines = FileUtils.readLines(file, "utf-8");
            if (Objects.nonNull(contentLines)) {
                List<Integer> lineResultList = new ArrayList<>();
                for (int i = 0; i < contentLines.size(); i++) {
                    String line = contentLines.get(i);
                    if (Objects.nonNull(line) && line.contains(searchContent)) {
                        lineResultList.add(i + 1);
                    }
                }
                if (lineResultList.size() > 0) {
                    searchResult.setLineList(lineResultList);
                    searchResult.setEndTime(System.currentTimeMillis());
                    return searchResult;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

4、main方法

指定上面mvn生成的目录地址,输出反编译文件地址,以及搜索的内容

package com.taoge.cfrtest;

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

/**
 * Desc:
 *
 * @author taoxuefeng
 * @date 2021/11/19
 */
public class Main {

    private static final String sourceDir = "/Users/taoxuefeng/mvnlib";

    private static final String targetDir = "./cfr_output_jar";

    private static final String searchContent = "this.putQueryParameter";

    public static void main(String[] args) throws IOException {
        Long time = Decompiler.cfr(sourceDir, targetDir);
        System.out.println(String.format("反编译时间: %dms", time));
        Long startTime = System.currentTimeMillis();
        List<SearchResult> searchResults = SearchFile.search(targetDir, searchContent);
        Long endTime = System.currentTimeMillis();
        System.out.println(String.format("搜索时间: %dms", (endTime - startTime)));
        for (SearchResult searchResult : searchResults) {
            System.out.println("搜索结果--------------");
            System.out.println(searchResult.getAbsolutePath());
            System.out.println(searchResult.getFileName());
            System.out.println(searchResult.getLineList());
        }
    }
}

5、运行

results matching ""

    No results matching ""