Skip to content

Commit bf8feeb

Browse files
committed
添加定制化的ClassWriter
1 parent 3dc7f60 commit bf8feeb

File tree

5 files changed

+199
-2
lines changed

5 files changed

+199
-2
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.github.luiox.morpher.asm.writer;
2+
3+
import com.github.luiox.morpher.jar.JarReader;
4+
import org.objectweb.asm.ClassReader;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import java.io.IOException;
9+
import java.nio.file.FileVisitResult;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.SimpleFileVisitor;
13+
import java.nio.file.attribute.BasicFileAttributes;
14+
import java.util.*;
15+
16+
public class CommonSuperClassProvider implements ICommonSuperClassProvider {
17+
private static final Logger logger = LoggerFactory.getLogger(CommonSuperClassProvider.class);
18+
19+
Map<String, String> superClassNameMap = new HashMap<>();
20+
21+
public Map<String, String> getSuperClassNameMap() {
22+
return superClassNameMap;
23+
}
24+
25+
public void scan(String folderPath) {
26+
List<Path> zips = new ArrayList<>();
27+
try {
28+
Files.walkFileTree(Path.of(folderPath), new SimpleFileVisitor<>() {
29+
@Override
30+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
31+
if (!Files.isDirectory(file)) {
32+
String fileName = file.toString().toLowerCase();
33+
if (fileName.endsWith(".zip") || fileName.endsWith(".jar") || fileName.endsWith(".jmod")) {
34+
zips.add(file);
35+
}
36+
}
37+
return FileVisitResult.CONTINUE;
38+
}
39+
});
40+
} catch (IOException e) {
41+
System.err.println("Error walking file tree: " + e.getMessage());
42+
return;
43+
}
44+
for (var zip : zips) {
45+
// 读取每个jar
46+
// 读取每个class
47+
try {
48+
JarReader jarReader = new JarReader(zip.toString());
49+
jarReader.read((filePath, is) -> {
50+
try {
51+
if (filePath.contains("module-info.class")) {
52+
return;
53+
}
54+
if (!filePath.endsWith(".class")) {
55+
return;
56+
}
57+
byte[] data = is.readAllBytes();
58+
ClassReader reader = new ClassReader(data);
59+
var className = reader.getClassName();
60+
var superName = reader.getSuperName();
61+
superClassNameMap.put(className, superName);
62+
} catch (Exception e) {
63+
logger.error("Error reading class file: {}", filePath, e);
64+
}
65+
});
66+
} catch (Exception e) {
67+
logger.error("Error reading jar file: {}", zip, e);
68+
}
69+
}
70+
}
71+
72+
public List<String> getSuperClasses(String type) {
73+
List<String> superClasses = new ArrayList<>();
74+
Set<String> visited = new HashSet<>();
75+
76+
// 初始检查
77+
if (!superClassNameMap.containsKey(type)) {
78+
// 如果不包含,那么输出信息到串口
79+
logger.error("type not found: {}", type);
80+
return List.of("java/lang/Object");
81+
}
82+
83+
String currentType = type;
84+
while (true) {
85+
// 检查是否已经访问过,避免循环
86+
if (visited.contains(currentType)) {
87+
logger.error("circular dependency found: {}", currentType);
88+
break;
89+
}
90+
visited.add(currentType);
91+
92+
// 先检查是否包含
93+
if (!superClassNameMap.containsKey(currentType)) {
94+
// 不包含就得先输出
95+
logger.error("type not found: {}", currentType);
96+
break;
97+
}
98+
99+
// 添加当前的类到列表
100+
superClasses.add(currentType);
101+
102+
// 获取当前类型的直接父类
103+
String superClass = superClassNameMap.get(currentType);
104+
105+
// 如果superClass为null,那就是java/lang/Object
106+
// 如果当前是java/lang/Object了,那么应该结束了
107+
if (superClass == null) {
108+
superClass = "java/lang/Object";
109+
break;
110+
}
111+
112+
// 更新当前类型为父类,继续循环
113+
currentType = superClass;
114+
}
115+
116+
return superClasses.reversed();
117+
}
118+
119+
@Override
120+
public String getCommonSuperClasses(String type1, String type2) {
121+
// 获取type1的父类列表
122+
List<String> superClasses1 = getSuperClasses(type1);
123+
// 获取type2的父类列表
124+
List<String> superClasses2 = getSuperClasses(type2);
125+
// 获取两个父类列表的长度
126+
int size = Math.min(superClasses1.size(), superClasses2.size());
127+
// 初始化索引
128+
int i = 0;
129+
// 遍历两个父类列表,找到第一个不相等的父类
130+
while (i < size && superClasses1.get(i).equals(superClasses2.get(i))) {
131+
i++;
132+
}
133+
// 如果没有找到不相等的父类,返回Object
134+
if (i == 0) {
135+
return "java/lang/Object";
136+
} else {
137+
// 返回第一个不相等的父类
138+
return superClasses1.get(i - 1);
139+
}
140+
}
141+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.github.luiox.morpher.asm.writer;
2+
3+
import org.objectweb.asm.ClassReader;
4+
import org.objectweb.asm.ClassWriter;
5+
6+
/**
7+
* 定制化分析公共父类的ClassWriter
8+
*/
9+
public class DelegatingSuperClassWriter extends ClassWriter {
10+
11+
ICommonSuperClassProvider provider;
12+
13+
public DelegatingSuperClassWriter(ICommonSuperClassProvider provider, int flags) {
14+
super(flags);
15+
this.provider = provider;
16+
}
17+
18+
public DelegatingSuperClassWriter(ICommonSuperClassProvider provider, ClassReader classReader, int flags) {
19+
super(classReader, flags);
20+
this.provider = provider;
21+
}
22+
23+
@Override
24+
protected String getCommonSuperClass(String type1, String type2) {
25+
return provider.getCommonSuperClasses(type1, type2);
26+
}
27+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.github.luiox.morpher.asm.writer;
2+
3+
public interface ICommonSuperClassProvider {
4+
/**
5+
* 获取两个类的公共父类
6+
* @param type1 类1的InternalName,例如geny/Generator$Action
7+
* @param type2 类2的InternalName,例如geny/Generator$Action
8+
* @return 返回一个字符串,表示两个类的公共父类
9+
*/
10+
String getCommonSuperClasses(String type1, String type2);
11+
}

morpher-api/src/main/java/com/github/luiox/morpher/transformer/PassHelper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ void iterateClassNodeWithInfo(@NotNull IPassContext context,
1515
int rflag,
1616
int wflag,
1717
@NotNull Consumer<ClassNode> consumer);
18+
19+
void addLibPath(@NotNull String path);
1820
}

morpher-api/src/main/java/com/github/luiox/morpher/transformer/PassHelperImpl.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.luiox.morpher.transformer;
22

3+
import com.github.luiox.morpher.asm.writer.CommonSuperClassProvider;
4+
import com.github.luiox.morpher.asm.writer.DelegatingSuperClassWriter;
35
import com.github.luiox.morpher.info.ClassInfo;
46
import com.github.luiox.morpher.model.ClassResource;
57
import com.github.luiox.morpher.model.ResourceContainer;
@@ -33,6 +35,17 @@ public static PassHelperImpl getInstance() {
3335
return Instance;
3436
}
3537

38+
private CommonSuperClassProvider superClassProvider;
39+
40+
@Override
41+
public void addLibPath(@NotNull String path) {
42+
if (superClassProvider == null) {
43+
superClassProvider = new CommonSuperClassProvider();
44+
}
45+
superClassProvider.scan(path);
46+
}
47+
48+
3649
/**
3750
* 遍历所有ClassNode并执行指定操作。
3851
*
@@ -86,8 +99,11 @@ public void iterateClassNodeWithInfo(@NotNull IPassContext ctx,
8699
consumer.accept(classNode);
87100
// 根据参数写回去
88101
ClassWriter classWriter;
89-
90-
classWriter = new ClassWriter(wflag);
102+
if (superClassProvider == null) {
103+
classWriter = new ClassWriter(wflag);
104+
} else {
105+
classWriter = new DelegatingSuperClassWriter(superClassProvider, rflag);
106+
}
91107

92108
try {
93109
classNode.accept(classWriter);

0 commit comments

Comments
 (0)