Skip to content

Commit f95ab85

Browse files
author
Mihail Slavchev
authored
Merge pull request #603 from NativeScript/slavchev/metadata-from-dex
extract common facade for BCL and DX implementations
2 parents 5374ad9 + 81a0603 commit f95ab85

18 files changed

Lines changed: 502 additions & 179 deletions

android-metadata-generator/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ sourceSets {
3232
}
3333

3434
dependencies {
35-
compile files("./src/libs/bcel-5.2.jar")
35+
compile files("./src/libs/bcel-5.2.jar")
36+
compile files("./src/libs/dx.jar")
3637
}
3738

3839
task makeDistDir {
948 KB
Binary file not shown.

android-metadata-generator/src/src/com/telerik/metadata/Builder.java

Lines changed: 38 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,15 @@
1010

1111
import com.telerik.metadata.TreeNode.FieldInfo;
1212
import com.telerik.metadata.TreeNode.MethodInfo;
13-
14-
import org.apache.bcel.classfile.Attribute;
15-
import org.apache.bcel.classfile.ConstantUtf8;
16-
import org.apache.bcel.classfile.InnerClass;
17-
import org.apache.bcel.classfile.InnerClasses;
18-
import org.apache.bcel.classfile.JavaClass;
19-
import org.apache.bcel.classfile.Method;
20-
import org.apache.bcel.classfile.Field;
21-
import org.apache.bcel.generic.Type;
13+
import com.telerik.metadata.desc.ClassDescriptor;
14+
import com.telerik.metadata.desc.FieldDescriptor;
15+
import com.telerik.metadata.desc.MethodDescriptor;
16+
import com.telerik.metadata.desc.TypeDescriptor;
2217

2318
public class Builder {
24-
private static class MethodNameComparator implements Comparator<Method> {
19+
private static class MethodNameComparator implements Comparator<MethodDescriptor> {
2520
@Override
26-
public int compare(Method o1, Method o2) {
21+
public int compare(MethodDescriptor o1, MethodDescriptor o2) {
2722
return o1.getName().compareTo(o2.getName());
2823
}
2924
}
@@ -38,7 +33,7 @@ public static TreeNode build(String[] paths) throws Exception {
3833
JarFile jar = JarFile.readJar(path);
3934
ClassRepo.cacheJarFile(jar);
4035
} else if (file.isDirectory()) {
41-
ClassDirectrory dir = ClassDirectrory.readDirectory(path);
36+
ClassDirectory dir = ClassDirectory.readDirectory(path);
4237
ClassRepo.cacheJarFile(dir);
4338
}
4439
}
@@ -56,7 +51,7 @@ public static TreeNode build(String[] paths) throws Exception {
5651
// e.g. we are processing jars with API 21 while we have in
5752
// our class path API 17
5853
// Class<?> clazz = Class.forName(className, false, loader);
59-
JavaClass clazz = ClassRepo.findClass(className);
54+
ClassDescriptor clazz = ClassRepo.findClass(className);
6055
generate(clazz, root);
6156
} catch (Throwable e) {
6257
System.out.println("Skip " + className);
@@ -67,11 +62,11 @@ public static TreeNode build(String[] paths) throws Exception {
6762
return root;
6863
}
6964

70-
private static Boolean isClassPublic(JavaClass clazz) {
65+
private static Boolean isClassPublic(ClassDescriptor clazz) {
7166
Boolean isPublic = true;
7267

7368
try {
74-
JavaClass currClass = clazz;
69+
ClassDescriptor currClass = clazz;
7570
while (currClass != null) {
7671
if (!currClass.isPublic() && !currClass.isProtected()) {
7772
isPublic = false;
@@ -87,7 +82,7 @@ private static Boolean isClassPublic(JavaClass clazz) {
8782
return isPublic;
8883
}
8984

90-
private static void generate(JavaClass clazz, TreeNode root) throws Exception {
85+
private static void generate(ClassDescriptor clazz, TreeNode root) throws Exception {
9186
if (!isClassPublic(clazz)) {
9287
return;
9388
}
@@ -96,18 +91,18 @@ private static void generate(JavaClass clazz, TreeNode root) throws Exception {
9691
setNodeMembers(clazz, node, root);
9792
}
9893

99-
private static void setNodeMembers(JavaClass clazz, TreeNode node, TreeNode root) throws Exception {
94+
private static void setNodeMembers(ClassDescriptor clazz, TreeNode node, TreeNode root) throws Exception {
10095
Map<String, MethodInfo> existingMethods = new HashMap<String, MethodInfo>();
10196
for (MethodInfo mi : node.instanceMethods) {
10297
existingMethods.put(mi.name + mi.sig, mi);
10398
}
10499

105-
Method[] allMethods = ClassUtil.getAllMethods(clazz);
106-
Method[] methods = clazz.getMethods();
100+
MethodDescriptor[] allMethods = ClassUtil.getAllMethods(clazz);
101+
MethodDescriptor[] methods = clazz.getMethods();
107102

108103
Arrays.sort(methods, methodNameComparator);
109104

110-
for (Method m : methods) {
105+
for (MethodDescriptor m : methods) {
111106
if (m.isSynthetic())
112107
continue;
113108

@@ -116,7 +111,7 @@ private static void setNodeMembers(JavaClass clazz, TreeNode node, TreeNode root
116111

117112
MethodInfo mi = new MethodInfo(m);
118113
int countUnique = 0;
119-
for (Method m1 : allMethods) {
114+
for (MethodDescriptor m1 : allMethods) {
120115
boolean m1IsStatic = m1.isStatic();
121116
if (!m1.isSynthetic()
122117
&& (m1.isPublic() || m1.isProtected())
@@ -130,7 +125,7 @@ private static void setNodeMembers(JavaClass clazz, TreeNode node, TreeNode root
130125
}
131126
mi.isResolved = countUnique == 1;
132127

133-
Type[] params = m.getArgumentTypes();
128+
TypeDescriptor[] params = m.getArgumentTypes();
134129
mi.signature = getMethodSignature(root, m.getReturnType(),
135130
params);
136131

@@ -149,20 +144,20 @@ private static void setNodeMembers(JavaClass clazz, TreeNode node, TreeNode root
149144
}
150145
}
151146

152-
Field[] fields = clazz.getFields();
147+
FieldDescriptor[] fields = clazz.getFields();
153148

154149
setFieldInfo(clazz, node, root, fields, null);
155150

156151
// adds static fields from interface to implementing class because java can call them from implementing class... no problem.
157152
getFieldsFromImplementedInterfaces(clazz, node, root, fields);
158153
}
159154

160-
private static void setFieldInfo(JavaClass clazz, TreeNode node, TreeNode root, Field[] fields, JavaClass interfaceClass) throws Exception {
161-
for (Field f : fields) {
155+
private static void setFieldInfo(ClassDescriptor clazz, TreeNode node, TreeNode root, FieldDescriptor[] fields, ClassDescriptor interfaceClass) throws Exception {
156+
for (FieldDescriptor f : fields) {
162157
if (f.isPublic() || f.isProtected()) {
163158
FieldInfo fi = new FieldInfo(f.getName());
164159

165-
Type t = f.getType();
160+
TypeDescriptor t = f.getType();
166161
boolean isPrimitive = ClassUtil.isPrimitive(t);
167162

168163
fi.valueType = isPrimitive ? TreeNode.getPrimitive(t): getOrCreateNode(root, t);
@@ -184,11 +179,11 @@ private static void setFieldInfo(JavaClass clazz, TreeNode node, TreeNode root,
184179
}
185180
}
186181

187-
private static void getFieldsFromImplementedInterfaces(JavaClass clazz, TreeNode node, TreeNode root, Field[] classFields) throws Exception {
188-
Field[] fields = null;
189-
List<Field> originalClassFields = Arrays.asList(classFields);
190-
191-
JavaClass interfaceClass = null;
182+
private static void getFieldsFromImplementedInterfaces(ClassDescriptor clazz, TreeNode node, TreeNode root, FieldDescriptor[] classFields) throws Exception {
183+
FieldDescriptor[] fields = null;
184+
List<FieldDescriptor> originalClassFields = Arrays.asList(classFields);
185+
186+
ClassDescriptor interfaceClass = null;
192187
String[] implementedInterfacesNames = clazz.getInterfaceNames();
193188
if(implementedInterfacesNames.length > 0) {
194189
for(String currInterface : implementedInterfacesNames) {
@@ -198,7 +193,7 @@ private static void getFieldsFromImplementedInterfaces(JavaClass clazz, TreeNode
198193

199194
//if interface and implementing class declare the same static field name the class take precedence
200195
if(originalClassFields.size() > 0) {
201-
for(Field f : fields) {
196+
for(FieldDescriptor f : fields) {
202197
if(originalClassFields.contains(f)) {
203198
return;
204199
}
@@ -210,7 +205,7 @@ private static void getFieldsFromImplementedInterfaces(JavaClass clazz, TreeNode
210205
}
211206
}
212207

213-
private static TreeNode getOrCreateNode(TreeNode root, Type type)
208+
private static TreeNode getOrCreateNode(TreeNode root, TypeDescriptor type)
214209
throws Exception {
215210
TreeNode node;
216211

@@ -220,14 +215,14 @@ private static TreeNode getOrCreateNode(TreeNode root, Type type)
220215
node = createArrayNode(root, typeName);
221216
} else {
222217
String name = ClassUtil.getCanonicalName(type.getSignature());
223-
JavaClass clazz = ClassRepo.findClass(name);
218+
ClassDescriptor clazz = ClassRepo.findClass(name);
224219
node = getOrCreateNode(root, clazz);
225220
}
226221

227222
return node;
228223
}
229224

230-
private static TreeNode getOrCreateNode(TreeNode root, JavaClass clazz) throws Exception {
225+
private static TreeNode getOrCreateNode(TreeNode root, ClassDescriptor clazz) throws Exception {
231226
if (ClassUtil.isPrimitive(clazz)) {
232227
return TreeNode.getPrimitive(clazz);
233228
}
@@ -240,30 +235,6 @@ private static TreeNode getOrCreateNode(TreeNode root, JavaClass clazz) throws E
240235
TreeNode node = root;
241236
String name = ClassUtil.getSimpleName(clazz);
242237

243-
if (clazz.getClassName().contains("$")) {
244-
boolean found = false;
245-
for (Attribute a : clazz.getAttributes()) {
246-
if (a instanceof InnerClasses) {
247-
InnerClass[] i = ((InnerClasses) a).getInnerClasses();
248-
for (InnerClass ic : i) {
249-
250-
ConstantUtf8 cname = (ConstantUtf8) clazz
251-
.getConstantPool().getConstant(ic.getInnerNameIndex());
252-
String innerClassname = cname.getBytes();
253-
254-
if (name.equals(innerClassname)) {
255-
int flags = ic.getInnerAccessFlags();
256-
clazz.setAccessFlags(flags);
257-
found = true;
258-
break;
259-
}
260-
}
261-
}
262-
if (found)
263-
break;
264-
}
265-
}
266-
267238
String[] packages = clazz.getPackageName().split("\\.");
268239

269240
for (String p : packages) {
@@ -275,8 +246,8 @@ private static TreeNode getOrCreateNode(TreeNode root, JavaClass clazz) throws E
275246
node = child;
276247
}
277248

278-
JavaClass outer = ClassUtil.getEnclosingClass(clazz);
279-
ArrayList<JavaClass> outerClasses = new ArrayList<JavaClass>();
249+
ClassDescriptor outer = ClassUtil.getEnclosingClass(clazz);
250+
ArrayList<ClassDescriptor> outerClasses = new ArrayList<ClassDescriptor>();
280251
while (outer != null) {
281252
if (!outer.isPublic()) {
282253
return null;
@@ -318,7 +289,7 @@ private static TreeNode getOrCreateNode(TreeNode root, JavaClass clazz) throws E
318289
}
319290
node = child;
320291
if (node.baseClassNode == null) {
321-
JavaClass baseClass = clazz.isInterface() ? ClassUtil
292+
ClassDescriptor baseClass = clazz.isInterface() ? ClassUtil
322293
.getClassByName("java.lang.Object") : ClassUtil
323294
.getSuperclass(clazz);
324295
if (baseClass != null) {
@@ -330,7 +301,7 @@ private static TreeNode getOrCreateNode(TreeNode root, JavaClass clazz) throws E
330301
return node;
331302
}
332303

333-
private static void copyBasePublicApi(JavaClass baseClass, TreeNode node,
304+
private static void copyBasePublicApi(ClassDescriptor baseClass, TreeNode node,
334305
TreeNode root) throws Exception {
335306
while ((baseClass != null) && !baseClass.isPublic()) {
336307
setNodeMembers(baseClass, node, root);
@@ -364,7 +335,7 @@ private static TreeNode createArrayNode(TreeNode root, String className)
364335
child.nodeType = node.nodeType;
365336
child.arrayElement = node;
366337
} else {
367-
JavaClass clazz = ClassRepo.findClass(name);
338+
ClassDescriptor clazz = ClassRepo.findClass(name);
368339
child.nodeType = clazz.isInterface() ? TreeNode.Interface
369340
: TreeNode.Class;
370341
if (clazz.isStatic()) {
@@ -378,9 +349,9 @@ private static TreeNode createArrayNode(TreeNode root, String className)
378349
}
379350

380351
private static ArrayList<TreeNode> getMethodSignature(TreeNode root,
381-
Type retType, Type[] params) throws Exception {
352+
TypeDescriptor retType, TypeDescriptor[] params) throws Exception {
382353
ArrayList<TreeNode> sig = new ArrayList<TreeNode>();
383-
boolean isVoid = retType.equals(Type.VOID);
354+
boolean isVoid = retType.equals(TypeDescriptor.VOID);
384355

385356
TreeNode node = null;
386357
if (!isVoid) {
@@ -390,7 +361,7 @@ private static ArrayList<TreeNode> getMethodSignature(TreeNode root,
390361
}
391362
sig.add(node);
392363

393-
for (Type param : params) {
364+
for (TypeDescriptor param : params) {
394365
boolean isPrimitive = ClassUtil.isPrimitive(param);
395366
node = isPrimitive ? TreeNode.getPrimitive(param)
396367
: getOrCreateNode(root, param);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.telerik.metadata;
2+
3+
import com.telerik.metadata.desc.ClassDescriptor;
4+
5+
import java.io.File;
6+
import java.io.IOException;
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
import org.apache.bcel.classfile.ClassParser;
13+
14+
public class ClassDirectory implements ClassMapProvider {
15+
private final String path;
16+
private final Map<String, ClassDescriptor> classMap;
17+
private static final String CLASS_EXT = ".class";
18+
private static final String DEX_EXT = ".dex";
19+
20+
private ClassDirectory(String path) {
21+
this.path = path;
22+
this.classMap = new HashMap<String, ClassDescriptor>();
23+
}
24+
25+
public Map<String, ClassDescriptor> getClassMap() {
26+
return classMap;
27+
}
28+
29+
public String getPath() {
30+
return path;
31+
}
32+
33+
public static ClassDirectory readDirectory(String path) throws IOException {
34+
ClassDirectory dir = new ClassDirectory(path);
35+
readDirectory(dir, path);
36+
return dir;
37+
}
38+
39+
private static void readDirectory(ClassDirectory dir, String path)
40+
throws IOException {
41+
List<File> subDirs = new ArrayList<File>();
42+
File currentDir = new File(path);
43+
for (File file : currentDir.listFiles()) {
44+
if (file.isFile()) {
45+
String name = file.getName();
46+
if (name.endsWith(CLASS_EXT)) {
47+
ClassDescriptor clazz = getClassDescriptor(name, file);
48+
dir.classMap.put(clazz.getClassName(), clazz);
49+
}
50+
} else if (file.isDirectory()) {
51+
subDirs.add(file);
52+
}
53+
}
54+
for (File sd: subDirs) {
55+
readDirectory(dir, sd.getAbsolutePath());
56+
}
57+
}
58+
59+
private static ClassDescriptor getClassDescriptor(String name, File file) throws IOException {
60+
ClassDescriptor clazz = null;
61+
if (name.endsWith(CLASS_EXT)) {
62+
ClassParser cp = new ClassParser(file.getAbsolutePath());
63+
clazz = new com.telerik.metadata.bcl.ClassInfo(cp.parse());
64+
} else if (name.endsWith(DEX_EXT)) {
65+
// TODO:
66+
}
67+
68+
return clazz;
69+
}
70+
}

0 commit comments

Comments
 (0)