如果解决了你的问题 记得点赞收藏哦!!!
Snoar 扫描 重复率高 怎么解决
前言
最近公司一些项目 需要被Sonar扫描 bug率为0 代码重复必须降到0.5!!!
我是感觉很鸡肋啊~
bug修改 安全问题修改修改还可以理解 代码重复率是干嘛?论文查重?
当然最好的办法 是封装 但是写代码的人一批一批 很难统一啊
–
一、针对老代码sonar扫描需要改重复率的问题
看着重复率百分之66.66% 一脸懵
百度了很久 也没有一个快速解决的办法
最后改着改着 发现了一些蒙蔽手段吧~
二、相对快速的解决办法
方法一:
在每一行后面都加上一句无关紧要的log
这样可以解决部分的重复率问题~ 但是也和sonar的扫描规则有关系~ 不一定好用
这种重复性的工作我做成了一个 java方法 自动加
代码如下(示例):
package com.lfm.fileschange.controller;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 引入在每一个java类中 加上@Slf4j 在java文件中 加入 每一行加入log去解决
*
* @creator 刘芳明
* @createTime 2024/7/8 11:25
*
* @modifier
* @modifyTime
* @modifyRemark
*/
public class JavaFileModifier {
private static final String INFO_DECLARATION = "private static final String INFO = \"ABC\";";
private static final List<String> EXEMPT_KEYWORDS = Arrays.asList("continue", "return", "break", "throw");
public static void main(String[] args) {
String inputFolderPath = "E:\\workspace\\static-desensitization\\src\\main\\java\\com\\ghca\\masking"; // Replace with your input folder path
String outputFolderPath = "D:\\output"; // Replace with your desired output folder path
File inputFolder = new File(inputFolderPath);
File outputFolder = new File(outputFolderPath);
if (!outputFolder.exists()) {
outputFolder.mkdirs();
}
try {
Files.walk(Paths.get(inputFolderPath))
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".java"))
.forEach(path -> {
try {
List<String> lines = readLinesFromFile(path.toString());
boolean hasEnumDefinition = containsEnumDefinition(lines);
List<String> modifiedLines = hasEnumDefinition ? lines : modifyLines(lines);
String outputFilePath = outputFolderPath + File.separator + inputFolder.toPath().relativize(path).toString();
File outputFile = new File(outputFilePath);
outputFile.getParentFile().mkdirs(); // Create parent directories if they don't exist
writeLinesToFile(modifiedLines, outputFilePath);
System.out.println("File modified successfully: " + path);
} catch (IOException e) {
System.err.println("Error processing file: " + path + " - " + e.getMessage());
}
});
} catch (IOException e) {
System.err.println("Error walking through files: " + e.getMessage());
}
}
private static List<String> readLinesFromFile(String filePath) throws IOException {
List<String> lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
private static boolean containsEnumDefinition(List<String> lines) {
for (String line : lines) {
if (line.trim().startsWith("enum ")) {
return true;
}
}
return false;
}
private static List<String> modifyLines(List<String> lines) {
List<String> modifiedLines = new ArrayList<>();
boolean classFound = false;
boolean infoAdded = false;
boolean inCatchBlock = false;
boolean inEnumBlock = false;
for (String line : lines) {
// Check if the line contains a class declaration
if (!classFound && line.trim().matches(".*\\bclass\\b.*")) {
classFound = true;
modifiedLines.add(line);
modifiedLines.add(INFO_DECLARATION);
infoAdded = true;
continue;
}
// Check if the line starts an enum block
if (line.trim().startsWith("enum ")) {
inEnumBlock = true;
}
// Check if the line ends an enum block
if (inEnumBlock && line.trim().endsWith("};")) {
inEnumBlock = false;
}
// Check if the line starts a catch block
if (line.trim().startsWith("catch (")) {
inCatchBlock = true;
}
// Check if the line ends a catch block
if (inCatchBlock && line.trim().endsWith("}")) {
inCatchBlock = false;
}
// Skip modifications inside enum block
if (inEnumBlock) {
modifiedLines.add(line);
continue;
}
// Modify method statements
if (infoAdded && line.trim().endsWith(";") && !inCatchBlock) {
if (shouldModifyLine(line) && !isExemptLine(line)) {
modifiedLines.add(line + " log.info(INFO);");
} else {
modifiedLines.add(line);
}
} else {
modifiedLines.add(line);
}
}
return modifiedLines;
}
private static boolean shouldModifyLine(String line) {
String trimmedLine = line.trim();
// Check if the line contains exempt keywords
for (String keyword : EXEMPT_KEYWORDS) {
if (trimmedLine.startsWith(keyword) || trimmedLine.equals(keyword + ";")) {
return false;
}
}
// Check for other conditions where modification should not be done
if (trimmedLine.startsWith("public") || trimmedLine.startsWith("private")
|| trimmedLine.startsWith("protected") || trimmedLine.startsWith("class ")
|| trimmedLine.startsWith("interface ") || trimmedLine.startsWith("enum ")
|| trimmedLine.contains("try") || trimmedLine.contains("catch")) {
return false;
}
return true;
}
private static boolean isExemptLine(String line) {
String trimmedLine = line.trim();
// Check if the line is an exempt line
for (String keyword : EXEMPT_KEYWORDS) {
if (trimmedLine.equals(keyword + ";")) {
return true;
}
}
return false;
}
private static void writeLinesToFile(List<String> lines, String filePath) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
for (String line : lines) {
writer.write(line);
writer.newLine();
}
}
}
}
没有做太多的优化 反正比手加快一点吧~
方法二
只能说是去修改一些 变量的值
比如说这种 定义了 一个变量 在其他方法里面也叫这个名字 就会重复
只能修改 让类里面尽量有不重复的变量名去降低
直接用快捷键 shift+f6 还是太慢
于是我又双叒叕写了一个 自动实现这个玩意 直接上代码吧
代码中方法变量的替换
引入
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.24.0</version>
</dependency>
代码如下(示例):
package com.lfm.fileschange.controller;
import com.github.javaparser.*;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
/**
* 修改变量随机名字解决
*
* @creator 刘芳明
* @createTime 2024/7/8 11:26
*
* @modifier
* @modifyTime
* @modifyRemark
*/
public class JavaVariableRenamer {
public static void main(String[] args) throws IOException {
String sourceFolder = "E:\\workspace\\static-desensitization\\src\\main\\java\\com\\ghca\\masking";
String outputFolder = "D:\\output";
List<File> javaFiles = listJavaFiles(sourceFolder);
for (File javaFile : javaFiles) {
String modifiedCode = modifyVariableNames(javaFile);
Path outputPath = Paths.get(outputFolder, getRelativePath(javaFile, sourceFolder));
try {
Files.createDirectories(outputPath.getParent()); // Ensure the parent directories exist
} catch (IOException e) {
throw new RuntimeException(e);
}
try (BufferedWriter writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)) {
writer.write(modifiedCode);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
System.out.println("All Java files processed and saved to output folder.");
}
private static List<File> listJavaFiles(String sourceFolder) {
List<File> javaFiles = new ArrayList<>();
File directory = new File(sourceFolder);
// 使用递归方式来查找所有的 Java 文件
findJavaFiles(directory, javaFiles);
return javaFiles;
}
private static void findJavaFiles(File directory, List<File> javaFiles) {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
// 如果是文件夹,则递归调用 findJavaFiles
findJavaFiles(file, javaFiles);
} else if (file.isFile() && file.getName().endsWith(".java")) {
// 如果是以 .java 结尾的文件,则加入到 javaFiles 列表中
javaFiles.add(file);
}
}
}
}
private static String modifyVariableNames(File javaFile) throws IOException {
// Read Java file content
String code = new String(Files.readAllBytes(javaFile.toPath()), StandardCharsets.UTF_8);
// Create JavaParser instance
JavaParser javaParser = new JavaParser();
try {
// Parse the code using JavaParser
ParseResult<CompilationUnit> parse = javaParser.parse(code);
if (parse.isSuccessful()) {
CompilationUnit cu = parse.getResult().get(); // Get the CompilationUnit object
// Map to store original-to-new variable names
Map<String, String> variableMap = new HashMap<>();
Random random = new Random();
// Visit each method in the CompilationUnit
cu.findAll(MethodDeclaration.class).forEach(method -> {
// Collect variable names within each method
method.findAll(VariableDeclarator.class).forEach(variable -> {
String originalName = variable.getNameAsString();
if (!variableMap.containsKey(originalName)) {
String randomName = generateRandomName(random);
variableMap.put(originalName, randomName);
}
});
// Modify variable names within method bodies
method.accept(new VoidVisitorAdapter<Void>() {
@Override
public void visit(VariableDeclarator n, Void arg) {
String originalName = n.getNameAsString();
if (variableMap.containsKey(originalName)) {
n.setName(variableMap.get(originalName));
}
}
@Override
public void visit(NameExpr n, Void arg) {
String originalName = n.getNameAsString();
if (variableMap.containsKey(originalName)) {
n.setName(variableMap.get(originalName));
}
}
}, null);
});
// Convert modified CompilationUnit back to code string
return cu.toString();
} else {
// Handle parsing errors or warnings
System.err.println("Parsing failed: " + parse.getProblems());
return ""; // or handle as appropriate
}
} catch (ParseProblemException e) {
// Handle parsing exceptions
e.printStackTrace();
return ""; // or handle as appropriate
}
}
private static String generateRandomName(Random random) {
StringBuilder sb = new StringBuilder();
int length = random.nextInt(5) + 3; // Random length between 3 and 7 for variable names
for (int i = 0; i < length; i++) {
char ch = (char) ('a' + random.nextInt(26));
sb.append(ch);
}
return sb.toString();
}
private static String getRelativePath(File file, String sourceFolder) {
String filePath = file.getAbsolutePath();
if (filePath.startsWith(sourceFolder)) {
return filePath.substring(sourceFolder.length() + 1);
}
return file.getName(); // fallback to file name if unable to determine relative path
}
}
实体类的批量替换
引入
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.24.0</version>
</dependency>
package com.lfm.fileschange.controller;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class JavaFileProcessor {
private static final Random RANDOM = new Random();
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
// 生成随机字符串的方法
private static String generateRandomString(int length) {
StringBuilder randomString = new StringBuilder();
for (int i = 0; i < length; i++) {
randomString.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length())));
}
return randomString.toString();
}
// 递归处理文件夹中的Java文件
private static void processFiles(File folder, String outputFolderPath) {
File outputFolder = new File(outputFolderPath);
if (!outputFolder.exists() && !outputFolder.mkdirs()) {
System.out.println("Failed to create output folder: " + outputFolderPath);
return;
}
if (folder == null || !folder.isDirectory()) {
System.out.println("Invalid directory: " + folder);
return;
}
File[] files = folder.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
processFiles(file, outputFolderPath + File.separator + file.getName());
} else if (file.isFile() && file.getName().endsWith(".java")) {
processJavaFile(file, outputFolderPath);
}
}
}
// 处理单个Java文件
private static void processJavaFile(File file, String outputFolderPath) {
try (FileInputStream in = new FileInputStream(file)) {
JavaParser parser = new JavaParser();
ParseResult<CompilationUnit> result = parser.parse(in);
if (result.getResult().isPresent()) {
CompilationUnit cu = result.getResult().get();
Map<String, String> varMap = new HashMap<>();
// 首先访问所有字段并生成新的变量名
new FieldVisitor().visit(cu, varMap);
// 然后替换变量名
new VariableRenamer(varMap).visit(cu, null);
// 写入新文件
try (FileWriter writer = new FileWriter(getNewFileName(file, outputFolderPath))) {
writer.write(cu.toString());
}
} else {
System.err.println("Parsing failed for file: " + file.getAbsolutePath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 访问字段并生成新变量名
private static class FieldVisitor extends VoidVisitorAdapter<Map<String, String>> {
@Override
public void visit(FieldDeclaration fd, Map<String, String> varMap) {
for (VariableDeclarator var : fd.getVariables()) {
String oldVarName = var.getNameAsString();
String newVarName = generateRandomString(8);
varMap.put(oldVarName, newVarName);
}
super.visit(fd, varMap);
}
}
// 替换变量名,跳过注解中的变量和注解属性值
private static class VariableRenamer extends ModifierVisitor<Void> {
private final Map<String, String> varMap;
public VariableRenamer(Map<String, String> varMap) {
this.varMap = varMap;
}
@Override
public Visitable visit(NameExpr n, Void arg) {
if (isInAnnotation(n)) {
return n; // 跳过注解中的变量
}
if (varMap.containsKey(n.getNameAsString())) {
return new NameExpr(varMap.get(n.getNameAsString()));
}
return super.visit(n, arg);
}
@Override
public Visitable visit(SimpleName n, Void arg) {
if (isInAnnotation(n)) {
return n; // 跳过注解中的变量
}
if (varMap.containsKey(n.getIdentifier())) {
n.setIdentifier(varMap.get(n.getIdentifier()));
}
return super.visit(n, arg);
}
@Override
public Visitable visit(MemberValuePair mvp, Void arg) {
if (mvp.getValue() instanceof StringLiteralExpr) {
StringLiteralExpr value = (StringLiteralExpr) mvp.getValue();
if (varMap.containsKey(value.getValue())) {
value.setString(varMap.get(value.getValue()));
}
}
return super.visit(mvp, arg);
}
private boolean isInAnnotation(SimpleName n) {
return n.findAncestor(AnnotationExpr.class).isPresent();
}
private boolean isInAnnotation(NameExpr n) {
return n.findAncestor(AnnotationExpr.class).isPresent();
}
}
// 生成新文件名,并确保输出文件夹存在
private static String getNewFileName(File file, String outputFolderPath) {
File outputFolder = new File(outputFolderPath);
if (!outputFolder.exists()) {
outputFolder.mkdirs();
}
String originalName = file.getName();
String newName = originalName.substring(0, originalName.lastIndexOf('.')) + ".java";
return outputFolderPath + File.separator + newName;
}
// 主方法,用于测试
public static void main(String[] args) {
String folderPath = "E:\\workspace\\static-desensitization\\src\\main\\java\\com\\ghca\\masking\\engine\\infa\\basic\\xmlbean";
String outputFolderPath = "D:\\output1";
File folder = new File(folderPath);
processFiles(folder, outputFolderPath);
}
}
总结
费了九牛二虎的力气 去解决重复率 就很无语。。。。。。
这两段代码 就贡献出来吧!具体调优什么的 自行改改啵~
有一天你也遇到这样的问题 如果可以用 就不用加班了~