代码扫描接口调用关系

<dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>3.2.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-collections4</artifactId>
      <version>4.4</version>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10.1</version>
    </dependency>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>19.0</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.11.0</version>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>
    <dependency>
      <groupId>com.github.javaparser</groupId>
      <artifactId>javaparser-core</artifactId>
      <version>3.25.9</version>

    </dependency>
    <dependency>
      <groupId>fr.inria.gforge.spoon</groupId>
      <artifactId>spoon-core</artifactId>
      <version> 7.5.0</version>
    </dependency>

将项目统一放在一个目录下,进行关联扫描

public class CodeAnalyzer {

    static Map<String, List<String>> interfacesDubboMap = new HashMap<>();
    static String searchFolder = "E:\\workspace4"; // 替换为你的搜索路径


    public static void main(String[] args) throws Exception {
        List<String> interfaces = FileUtils.readLines(new File("E:\\workspace4\\interface.txt"), "UTF-8");
        
        for (String dubbo : interfaces) {
            dubbo = dubbo.trim();
            interfacesDubboMap.put(dubbo, Lists.newArrayList());

            String searchText = dubbo; // 替换为你要搜索的具体文本

            int indexOf = searchText.lastIndexOf(".");
            String interfaceName = searchText.substring(0, indexOf);
            String interfaceClassName = searchText.substring(indexOf + 1, searchText.length());
            String methodName = interfaceClassName;


            extracted(searchText, searchFolder, Lists.newArrayList(methodName), interfaceName, interfaceClassName);
        }

     
        String jsonString = new Gson().toJson(interfacesDubboMap);
        System.out.println(jsonString);


    }

    /**
     * 同package 的 方法调用
     * @param absolutePath
     * @param methodNames
     * @param interfaceClassName
     * @return
     * @throws IOException
     */
    private static List<String> findSamePackageClassPath(String absolutePath, List<String> methodNames, String interfaceClassName) throws IOException {
        String samePackagePath = Paths.get(absolutePath).getParent().toString();
        Set<String> path1s = Sets.newHashSet();
        Set<String> duplicates = Sets.newHashSet();
        for (String methodName : methodNames) {
            List<String> pathsForClassName =  findFileBySearchText(samePackagePath, interfaceClassName);
            List<String> pathsForMethodName =  findFileBySearchText(samePackagePath, methodName);

            // pathsForClassName pathsForMethodName 找出同样的数据
            path1s.addAll(pathsForClassName);
            duplicates.addAll(pathsForMethodName);


        }
        duplicates.retainAll(path1s);

        return Lists.newArrayList(duplicates);
    }

    private static void extracted(String searchText, String absolutePath, List<String> methodNames, String interfaceName, String interfaceClassName) throws Exception {
        if (CollectionUtils.isEmpty(methodNames)) {
            return;
        }

        List<String> allPath = Lists.newArrayList();
        List<String> samePackageClassPaths = Lists.newArrayList();
        // 同包下的路径下的文件,同包下的 不会import , 按方法名 查找调用, 首次循环不执行
        if (!StringUtils.equals(absolutePath, searchFolder)) {
            samePackageClassPaths = findSamePackageClassPath(absolutePath, methodNames, interfaceClassName);
            allPath.addAll(samePackageClassPaths);
        }

        // 调用远程方法 所在的类
        List<String> paths = findFileBySearchText(searchFolder, interfaceName + "." + interfaceClassName);
        allPath.addAll(paths);

        System.out.println("searchText :   " + interfaceName + "." + interfaceClassName + " " + methodNames +" \n samePackageClassPaths:" + samePackageClassPaths
        + "\n paths: " + paths);

        for (String path : allPath) {
            // 读取Java源文件内容
            String sourceCode = new String(Files.readAllBytes(Paths.get(path)));

            // 创建JavaParser实例并解析源代码
            CompilationUnit cu = StaticJavaParser.parse(sourceCode);

            if (!cu.getPackageDeclaration().isPresent()) {
                System.out.println("=====" + cu.toString());
                continue;
            }

            Context context = new Context();
            context.setInterfacePackageName(interfaceName);
            context.setInterfaceClassName(interfaceClassName);
            // 所在包名
            String packageName = cu.getPackageDeclaration().get().getName().toString();
            context.setPackageName(packageName);


            //是否注入了 对应的service
            boolean variableName = findVariableName(cu, context);
            if (!variableName) {
                continue;
            }


            // 变量所在方法名
            Set<MethodDeclaration> methodSet = Sets.newHashSet();
            List<MethodDeclaration> methodDeclarations = analyzeMethodCode(cu, methodNames, methodSet);
            if (CollectionUtils.isEmpty(methodDeclarations)) {
                continue;
            }

            methodDeclarations = methodDeclarations.stream().filter(m -> methodIsPublic(m)).collect(Collectors.toList());

            List<String> methods = methodDeclarations.stream()
                    .map(method -> method.getNameAsString())
                    .collect(Collectors.toList());


            if (path.toLowerCase().endsWith("controller.java")) {
                getControllerInterfaceUrl(searchText, path, methodDeclarations);
                continue;
            }

            context.setMethodName(methods);

            extracted(searchText, path, context.getMethodName(), context.getPackageName(), context.getClassName());
        }
    }

    private static void getControllerInterfaceUrl(String searchText, String path, List<MethodDeclaration> methodDeclarations) {
        for (MethodDeclaration methodDeclaration : methodDeclarations) {
            if (!isControllerMethod(methodDeclaration)) {
                continue;
            }
            List<StringLiteralExpr> list = methodDeclaration.findAll(StringLiteralExpr.class);
            if (CollectionUtils.isNotEmpty(list)) {
                StringLiteralExpr interfaceUrl =
                        list.stream()
                        		// 此处修改判断为controll提供的接口
                                .filter(e -> e.getValue().endsWith(".htm"))
                                .findFirst().get();
                String interfaceHtmlName = interfaceUrl.getValue();
                System.out.println("find controller:" + path + "  interface: " + interfaceHtmlName);

                List<String> htmls = interfacesDubboMap.getOrDefault(searchText, Lists.newArrayList());
                htmls.add(interfaceHtmlName);
            }
        }
    }


    private static boolean methodIsPublic(MethodDeclaration methodDeclaration) {
        return methodDeclaration.getModifiers().stream().anyMatch(x -> x.getKeyword().equals(Modifier.Keyword.PUBLIC));
    }

    private static List<String> findFileBySearchText(String searchFolder, String searchText) {
        List<String> findPath = Lists.newArrayList();

        try (Stream<Path> paths = Files.walk(Paths.get(searchFolder))) {
            // 过滤掉隐藏文件
            paths.filter(Files::isRegularFile)
            		// 排除测试类
                    .filter(x -> x.toString().endsWith(".java") && !x.toString().endsWith("TestM.java"))
                    .forEach(filePath -> {

                        try (BufferedReader reader = Files.newBufferedReader(filePath)) {
                            String line;
                            while ((line = reader.readLine()) != null) {
                                if (line.contains(searchText)) {
                                    System.out.println("searchFile:" + searchText + "   Found match in file: " + filePath.toAbsolutePath());
                                    findPath.add(filePath.toAbsolutePath().toString());
                                    break; // 如果只需要找到第一处匹配就可退出,则使用break;否则注释掉此行以查找所有匹配行
                                }
                            }
                        } catch (IOException e) {
                            System.err.format("Encountered an error reading file %s%n", filePath);
                            e.printStackTrace();
                        }
                    });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return findPath;
    }

    private static List<MethodDeclaration> analyzeMethodCode(CompilationUnit cu, List<String> methodNames, Set<MethodDeclaration> methodSet) throws Exception {
        // 遍历并打印出所有的方法声明
        int size = methodSet.size();
        for (String methodName : methodNames) {
            StringInMethodVisitor visitor = new StringInMethodVisitor(methodName);
            visitor.visit(cu, null);
            // 输出包含目标字符串的方法名及其所在位置
            List<MethodDeclaration> matchingMethods = visitor.getMatchingMethods();

            for (MethodDeclaration method : matchingMethods) {
                methodSet.add(method);
            }
        }
        // 存在表示是 controller中对外的方法,一般不回在controller内重复调用同一个RequestMapping方法
        List<MethodDeclaration> declarationList = methodSet.stream().filter(x -> !isControllerMethod(x)).collect(Collectors.toList());

        int size2 = declarationList.size();
		if (size != size2) {
            List<String> methods = declarationList.stream().map(x -> x.getNameAsString()).collect(Collectors.toList());

            List<MethodDeclaration> newSet = analyzeMethodCode(cu, methods, Sets.newHashSet(declarationList));

            methodSet.addAll(newSet);  
        }
 		 
 	    return Lists.newArrayList(methodSet);

    }

    private static boolean isControllerMethod(MethodDeclaration methodDeclaration) {
        NodeList<AnnotationExpr> annotations = methodDeclaration.getAnnotations();

        Optional<AnnotationExpr> requestMapping = annotations.stream().filter(x -> x.getNameAsString().contains("RequestMapping")).findAny();

        return requestMapping.isPresent();
    }


    public static boolean findVariableName(CompilationUnit cu, Context context) {
        boolean findQuoteVariable = false;
        for (TypeDeclaration type : cu.getTypes()) {
            if (type instanceof ClassOrInterfaceDeclaration) {
                ClassOrInterfaceDeclaration decl = (ClassOrInterfaceDeclaration) type;
                context.setClassName(decl.getNameAsString());
                ((ClassOrInterfaceDeclaration) type).getImplementedTypes().forEach(item -> {
                    if (item.getNameAsString().toLowerCase().contains("service")) {
                        System.out.println("Found ClassOrInterfaceDeclaration : " + type.getNameAsString());
                        context.setClassName(item.getNameAsString());
                    }
                });
            }

            for (Object field : type.getFields()) {
                if (!(field instanceof FieldDeclaration)) {
                    continue;
                }

                FieldDeclaration fieldDecl = ((FieldDeclaration) field);

                List<VariableDeclarator> variables = fieldDecl.getVariables();

                Optional<VariableDeclarator> declaratorOptional = variables.stream()
                        .filter(var -> var.getTypeAsString().equals(context.getInterfaceClassName()))
                        .findFirst();
                if (declaratorOptional.isPresent()) {
                    context.setDeclarationName(declaratorOptional.get().getName().toString());
                    findQuoteVariable = true;
                }
            }
        }

        return findQuoteVariable;
    }


    // 创建一个自定义访问者来查找包含目标字符串的方法
    static class StringInMethodVisitor extends VoidVisitorAdapter<Void> {
        private List<MethodDeclaration> matchingMethods = new ArrayList<>();
        private String targetString;

        public StringInMethodVisitor(String targetString) {
            this.targetString = targetString;
        }

        @Override
        public void visit(MethodDeclaration md, Void arg) {
            if (md.toString().toLowerCase().contains(targetString.toLowerCase())) {
                matchingMethods.add(md);
            }
            super.visit(md, arg);
        }

        public List<MethodDeclaration> getMatchingMethods() {
            return matchingMethods;
        }
    }


}

@Data
public class Context {
    String interfaceClassName;
    String interfacePackageName;

    String packageName;

    String className;

    List<String> methodName;

    String declarationName;

}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例代码,可以在uni-app中调用PDA扫描功能: 1. 首先,需要创建一个原生插件。在项目目录下创建一个名为 "com.example.pda" 的文件夹,创建一个名为 "PdaPlugin.java" 的文件,代码如下: ```java package com.example.pda; import android.content.Intent; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Log; import com.dtr.zbar.build.ZBarDecoder; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import io.dcloud.feature.uniapp.annotation.UniPlugin; @UniPlugin(name = "PdaPlugin") public class PdaPlugin { private static final String TAG = "PdaPlugin"; // 扫描结果回调函数 private static OnScanResultListener sListener; // 开始扫描 public void startScan(final JSONObject options, final OnScanResultListener listener) { // 保存回调函数 sListener = listener; // 打开扫描界面 Intent intent = new Intent("com.example.pda.SCAN"); intent.putExtra("SCAN_MODE", "QR_CODE_MODE"); intent.setPackage("com.example.pda"); UniApplication.getContext().startActivity(intent); } // 扫描结果回调函数 public static void onScanResult(String result) { if (sListener != null) { sListener.onScanResult(result); } } // 扫描结果回调接口 public interface OnScanResultListener { void onScanResult(String result); } } ``` 2. 在 "AndroidManifest.xml" 文件中添加以下代码: ```xml <activity android:name=".ScanActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> ``` 3. 创建一个名为 "ScanActivity.java" 的文件,代码如下: ```java package com.example.pda; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import com.dtr.zbar.build.ZBarDecoder; public class ScanActivity extends Activity { private static final String TAG = "ScanActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 扫描结果返回 if (getIntent().getAction().equals("com.example.pda.SCAN")) { Intent intent = new Intent("com.example.pda.SCAN_RESULT"); intent.putExtra("SCAN_RESULT", ZBarDecoder.scanImage(this)); setResult(RESULT_OK, intent); finish(); } } } ``` 4. 在 uni-app 中调用插件,代码如下: ```javascript import { PdaPlugin } from '@uni-app-plus/pda-plugin'; // 开始扫描 PdaPlugin.startScan({}, { onScanResult(result) { console.log('扫描结果:', result); } }); ``` 以上代码仅作为参考,具体实现可能会因为PDA型号、系统版本等因素而有所不同,需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值