maven
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.24.0</version>
</dependency>
代码
package com.xx;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.Type;
import com.shocksoft.component.util.JacksonUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;
/**
* 接口-接口实现 合并
*/
public class ScanMain {
private static MethodDeclaration findMatchingMethod(ClassOrInterfaceDeclaration implementationClass, String methodName, List<Type> paramTypes) {
for (MethodDeclaration method : implementationClass.getMethods()) {
if (method.getNameAsString().equals(methodName) && haveSameParameters(method, paramTypes)) {
return method;
}
}
return null;
}
private static boolean haveSameParameters(MethodDeclaration method, List<Type> paramTypes) {
List<Type> methodParamTypes = method.getParameters().stream()
.map(Parameter::getType)
.collect(Collectors.toList());
return methodParamTypes.containsAll(paramTypes) && paramTypes.containsAll(methodParamTypes);
}
private static void dd(MData mData) throws Exception {
// 读取源代码文件
JavaParser javaParser = new JavaParser();
String api = mData.getApiFile();
String apiImpl = mData.getApiImplFile();
CompilationUnit apiUnit = javaParser.parse(new File(api)).getResult().get();
CompilationUnit apiImplUnit = javaParser.parse(new File(apiImpl)).getResult().get();
String apiClassName = mData.getApiClassName();
String apiImplClassName = mData.getApiImplClassName();
ClassOrInterfaceDeclaration apiClass = apiUnit.getInterfaceByName(apiClassName).orElse(null);
ClassOrInterfaceDeclaration apiImplClass = apiImplUnit.getClassByName(apiImplClassName).orElse(null);
assert apiClass != null;
assert apiImplClass != null;
StringBuilder src = new StringBuilder();
src.append(apiUnit.getPackageDeclaration().get()).append("\n");
Set<String> importPackage = new LinkedHashSet<>();
NodeList<ImportDeclaration> apiPack = apiUnit.getImports();
NodeList<ImportDeclaration> apiImplPack = apiImplUnit.getImports();
for (ImportDeclaration declaration : apiPack) {
importPackage.add(declaration.toString());
}
for (ImportDeclaration declaration : apiImplPack) {
importPackage.add(declaration.toString());
}
for (String s : importPackage) {
src.append(s.replace("\n", "")).append("\n");
}
Set<String> importAn = new LinkedHashSet<>();
NodeList<AnnotationExpr> apiAn = apiClass.getAnnotations();
for (AnnotationExpr annotation : apiAn) {
importAn.add(annotation.toString());
}
NodeList<AnnotationExpr> apiImplAn = apiImplClass.getAnnotations();
for (AnnotationExpr annotation : apiImplAn) {
importAn.add(annotation.toString());
}
for (String s : importAn) {
src.append(s).append("\n");
}
src.append("public class " + apiClassName + " {").append("\n");
List<FieldDeclaration> fields = apiImplClass.getFields();
for (FieldDeclaration field : fields) {
src.append(field.toString()).append("\n");
}
Map<String, String> methodImplementationMap = new LinkedHashMap<>();
List<MethodDeclaration> interfaceMethods = apiClass.getMethods();
for (MethodDeclaration interfaceMethod : interfaceMethods) {
String interfaceMethodName = interfaceMethod.getNameAsString();
List<Type> interfaceMethodParamTypes = interfaceMethod.getParameters().stream()
.map(Parameter::getType)
.collect(Collectors.toList());
MethodDeclaration implementedMethod = findMatchingMethod(apiImplClass, interfaceMethodName, interfaceMethodParamTypes);
if (implementedMethod != null) {
methodImplementationMap.put(interfaceMethod.toString(), implementedMethod.getBody().get().toString());
}
}
for (Map.Entry<String, String> entry : methodImplementationMap.entrySet()) {
src.append(entry.getKey().replace(";", "")).append("\n");
src.append(entry.getValue()).append("\n");
}
src.append("}");
// System.out.println(src);
FileUtil.writeUtf8String(src.toString(), api);
FileUtil.del(apiImpl);
}
@Data
public static class MData {
private String apiImplFile;
private String apiFile;
private String apiClassName;
private String apiImplClassName;
}
public static List<MData> scan() {
List<String> list = scanClassesWithAnnotation("com.xx", RestController.class);
List<MData> mm = new ArrayList<>();
for (String s : list) {
if (StrUtil.contains(s, "ApiImpl")) {
String impl = StrUtil.replace(s, "\\target\\classes", "\\src\\main\\java");
impl = StrUtil.replace(impl, ".class", ".java");
String api = StrUtil.replace(impl, "\\impl", "");
api = StrUtil.replace(api, "Impl", "");
if (new File(api).exists()) {
MData e = new MData();
e.setApiImplFile(impl);
e.setApiFile(api);
e.setApiClassName(FileUtil.getName(api).replace(".java", ""));
e.setApiImplClassName(FileUtil.getName(impl).replace(".java", ""));
mm.add(e);
} else {
System.out.println(api);
}
}
}
return mm;
}
public static void main(String[] args) throws Exception {
// dd();
List<MData> data = scan();
System.out.println("检测到需要优化的项目 " + data.size());
int i = 1;
for (MData mData : data) {
System.out.println("正在处理 " + i++);
dd(mData);
}
cleanEmptyDir();
System.out.println("ok");
}
public static List<String> scanClassesWithAnnotation(String packageName, Class<?> annotationClass) {
List<String> classes = new ArrayList<>();
String packagePath = packageName.replace('.', '/');
URL resource = Thread.currentThread().getContextClassLoader().getResource(packagePath);
if (resource != null) {
File directory = new File(resource.getFile());
if (directory.exists() && directory.isDirectory()) {
scanDirectory(directory, packageName, annotationClass, classes);
}
}
return classes;
}
private static void scanDirectory(File directory, String packageName, Class<?> annotationClass, List<String> classes) {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
String subPackageName = packageName + "." + file.getName();
scanDirectory(file, subPackageName, annotationClass, classes);
} else if (file.getName().endsWith(".class")) {
String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
try {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent((Class<? extends Annotation>) annotationClass)) {
classes.add(file.getAbsolutePath());
}
if (clazz.isAnnotationPresent(RestController.class)
&& !clazz.isAnnotationPresent(Tag.class)
) {
System.out.println(className);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
public static void cleanEmptyDir() {
// 替换为你想要清理的目录路径
File directory = new File("D:\\workspace\\xxx\\src\\main\\java\\com\\xx");
deleteEmptyDirectories(directory);
}
/**
* 删除所有空目录
*
* @param directory 要清理的目录
*/
public static void deleteEmptyDirectories(File directory) {
if (directory.exists() && directory.isDirectory()) {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteEmptyDirectories(file);
}
}
}
// 再次检查目录是否为空,如果是,则删除
if (directory.listFiles().length == 0) {
directory.delete();
System.out.println("Deleted empty directory: " + directory.getAbsolutePath());
}
}
}
}