Skip to content

Commit 9cd0c73

Browse files
committed
Add static and default interface methods support
1 parent 37c6ae6 commit 9cd0c73

19 files changed

Lines changed: 998 additions & 583 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ bin/
1919
.settings
2020

2121
.classpath
22+
android-runtime.iml

test-app/build-tools/android-metadata-generator/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ compileJava {
3636
compileJava.outputs.dir("$rootDir/dist/classes")
3737

3838
dependencies {
39-
compile 'org.apache.bcel:bcel:6.0'
39+
compile 'org.apache.bcel:bcel:6.2'
4040
compile files("./src/libs/dx.jar")
4141
}
4242

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Builder.java

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package com.telerik.metadata;
22

33
import java.io.File;
4+
import java.lang.reflect.Array;
5+
import java.lang.reflect.Method;
6+
import java.net.URL;
7+
import java.net.URLClassLoader;
48
import java.util.ArrayList;
59
import java.util.Arrays;
610
import java.util.Comparator;
711
import java.util.HashMap;
12+
import java.util.HashSet;
813
import java.util.List;
914
import java.util.Map;
1015

@@ -124,7 +129,9 @@ private static void setNodeMembers(ClassDescriptor clazz, TreeNode node, TreeNod
124129
}
125130

126131
MethodDescriptor[] allMethods = ClassUtil.getAllMethods(clazz);
127-
MethodDescriptor[] methods = clazz.getMethods();
132+
MethodDescriptor[] classImplementedMethods = clazz.getMethods();
133+
MethodDescriptor[] interfaceImplementedMethods = getDefaultMethodsFromImplementedInterfaces(clazz, classImplementedMethods);
134+
MethodDescriptor[] methods = concatenate(classImplementedMethods, interfaceImplementedMethods);
128135

129136
Arrays.sort(methods, methodNameComparator);
130137

@@ -151,8 +158,8 @@ private static void setNodeMembers(ClassDescriptor clazz, TreeNode node, TreeNod
151158
&& (m1.isPublic() || m1.isProtected())
152159
&& (isStatic == m1IsStatic)
153160
&& (m1.getName().equals(mi.name) && (m1
154-
.getArgumentTypes().length == m
155-
.getArgumentTypes().length))) {
161+
.getArgumentTypes().length == m
162+
.getArgumentTypes().length))) {
156163
if (++countUnique > 1) {
157164
break;
158165
}
@@ -162,7 +169,7 @@ private static void setNodeMembers(ClassDescriptor clazz, TreeNode node, TreeNod
162169

163170
TypeDescriptor[] params = m.getArgumentTypes();
164171
mi.signature = getMethodSignature(root, m.getReturnType(),
165-
params);
172+
params);
166173

167174
if (mi.signature != null) {
168175
if (isStatic) {
@@ -195,7 +202,7 @@ private static void setFieldInfo(ClassDescriptor clazz, TreeNode node, TreeNode
195202
TypeDescriptor t = f.getType();
196203
boolean isPrimitive = ClassUtil.isPrimitive(t);
197204

198-
fi.valueType = isPrimitive ? TreeNode.getPrimitive(t): getOrCreateNode(root, t);
205+
fi.valueType = isPrimitive ? TreeNode.getPrimitive(t) : getOrCreateNode(root, t);
199206
fi.isFinalType = f.isFinal();
200207

201208
if (f.isStatic()) {
@@ -242,8 +249,38 @@ private static void getFieldsFromImplementedInterfaces(ClassDescriptor clazz, Tr
242249
}
243250
}
244251

252+
private static MethodDescriptor[] getDefaultMethodsFromImplementedInterfaces(ClassDescriptor clazz, MethodDescriptor[] originalClassMethodDescriptors) {
253+
HashSet<MethodDescriptor> defaultMethods = getAllDefaultMethodsFromImplementedInterfaces(clazz);
254+
HashSet<MethodDescriptor> classMethods = new HashSet<MethodDescriptor>(Arrays.asList(originalClassMethodDescriptors));
255+
defaultMethods.removeAll(classMethods);
256+
257+
return defaultMethods.toArray(new MethodDescriptor[0]);
258+
}
259+
260+
private static HashSet<MethodDescriptor> getAllDefaultMethodsFromImplementedInterfaces(ClassDescriptor clazz) {
261+
return getAllDefaultMethodsFromImplementedInterfacesRecursively(clazz, new HashSet<MethodDescriptor>());
262+
}
263+
264+
private static HashSet<MethodDescriptor> getAllDefaultMethodsFromImplementedInterfacesRecursively(ClassDescriptor clazz, HashSet<MethodDescriptor> collectedDefaultMethods) {
265+
String[] implementedInterfacesNames = clazz.getInterfaceNames();
266+
267+
for (String implementedInterfaceName : implementedInterfacesNames) {
268+
ClassDescriptor interfaceClass = ClassRepo.findClass(implementedInterfaceName);
269+
270+
for (MethodDescriptor md : interfaceClass.getMethods()) {
271+
if (!md.isStatic() && !md.isAbstract()) {
272+
collectedDefaultMethods.add(md);
273+
}
274+
}
275+
276+
collectedDefaultMethods.addAll(getAllDefaultMethodsFromImplementedInterfacesRecursively(interfaceClass, new HashSet<MethodDescriptor>()));
277+
}
278+
279+
return collectedDefaultMethods;
280+
}
281+
245282
private static TreeNode getOrCreateNode(TreeNode root, TypeDescriptor type)
246-
throws Exception {
283+
throws Exception {
247284
TreeNode node;
248285

249286
String typeName = type.getSignature();
@@ -272,7 +309,7 @@ private static TreeNode getOrCreateNode(TreeNode root, ClassDescriptor clazz, St
272309

273310
if (ClassUtil.isArray(clazz)) {
274311
throw new UnsupportedOperationException("unexpected class="
275-
+ clazz.getClassName());
312+
+ clazz.getClassName());
276313
}
277314

278315
TreeNode node = root;
@@ -307,7 +344,7 @@ private static TreeNode getOrCreateNode(TreeNode root, ClassDescriptor clazz, St
307344
if (child == null) {
308345
child = node.createChild(outerClassname);
309346
child.nodeType = outer.isInterface() ? TreeNode.Interface
310-
: TreeNode.Class;
347+
: TreeNode.Class;
311348
if (outer.isStatic()) {
312349
child.nodeType |= TreeNode.Static;
313350
}
@@ -324,7 +361,7 @@ private static TreeNode getOrCreateNode(TreeNode root, ClassDescriptor clazz, St
324361
child.nodeType = tmp.nodeType;
325362
} else {
326363
child.nodeType = clazz.isInterface() ? TreeNode.Interface
327-
: TreeNode.Class;
364+
: TreeNode.Class;
328365
if (clazz.isStatic()) {
329366
child.nodeType |= TreeNode.Static;
330367
}
@@ -337,8 +374,8 @@ private static TreeNode getOrCreateNode(TreeNode root, ClassDescriptor clazz, St
337374
baseClass = ClassUtil.getClassByName(predefinedSuperClassname);
338375
} else {
339376
baseClass = clazz.isInterface()
340-
? ClassUtil.getClassByName("java.lang.Object")
341-
: ClassUtil.getSuperclass(clazz);
377+
? ClassUtil.getClassByName("java.lang.Object")
378+
: ClassUtil.getSuperclass(clazz);
342379
}
343380
if (baseClass != null) {
344381
node.baseClassNode = getOrCreateNode(root, baseClass, null);
@@ -358,7 +395,7 @@ private static void copyBasePublicApi(ClassDescriptor baseClass, TreeNode node,
358395
}
359396

360397
private static TreeNode createArrayNode(TreeNode root, String className)
361-
throws Exception {
398+
throws Exception {
362399
TreeNode currentNode = root;
363400
String currentClassname = className;
364401

@@ -385,7 +422,7 @@ private static TreeNode createArrayNode(TreeNode root, String className)
385422
} else {
386423
ClassDescriptor clazz = ClassRepo.findClass(name);
387424
child.nodeType = clazz.isInterface() ? TreeNode.Interface
388-
: TreeNode.Class;
425+
: TreeNode.Class;
389426
if (clazz.isStatic()) {
390427
child.nodeType |= TreeNode.Static;
391428
}
@@ -397,22 +434,22 @@ private static TreeNode createArrayNode(TreeNode root, String className)
397434
}
398435

399436
private static ArrayList<TreeNode> getMethodSignature(TreeNode root,
400-
TypeDescriptor retType, TypeDescriptor[] params) throws Exception {
437+
TypeDescriptor retType, TypeDescriptor[] params) throws Exception {
401438
ArrayList<TreeNode> sig = new ArrayList<TreeNode>();
402439
boolean isVoid = retType.equals(TypeDescriptor.VOID);
403440

404441
TreeNode node = null;
405442
if (!isVoid) {
406443
boolean isPrimitive = ClassUtil.isPrimitive(retType);
407444
node = isPrimitive ? TreeNode.getPrimitive(retType)
408-
: getOrCreateNode(root, retType);
445+
: getOrCreateNode(root, retType);
409446
}
410447
sig.add(node);
411448

412449
for (TypeDescriptor param : params) {
413450
boolean isPrimitive = ClassUtil.isPrimitive(param);
414451
node = isPrimitive ? TreeNode.getPrimitive(param)
415-
: getOrCreateNode(root, param);
452+
: getOrCreateNode(root, param);
416453
if (node == null) {
417454
return null;
418455
}
@@ -421,4 +458,16 @@ private static ArrayList<TreeNode> getMethodSignature(TreeNode root,
421458

422459
return sig;
423460
}
461+
462+
private static <T> T[] concatenate(T[] a, T[] b) {
463+
int aLen = a.length;
464+
int bLen = b.length;
465+
466+
@SuppressWarnings("unchecked")
467+
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
468+
System.arraycopy(a, 0, c, 0, aLen);
469+
System.arraycopy(b, 0, c, aLen, bLen);
470+
471+
return c;
472+
}
424473
}

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/ClassDirectory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ private static void readDirectory(ClassDirectory dir, String path)
4040
throws IOException {
4141
List<File> subDirs = new ArrayList<File>();
4242
File currentDir = new File(path);
43-
for (File file : currentDir.listFiles()) {
43+
File[] files = currentDir.listFiles();
44+
for (File file : files) {
4445
if (file.isFile()) {
4546
String name = file.getName();
4647
if (name.endsWith(CLASS_EXT)) {

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/bcl/MethodInfo.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import org.apache.bcel.classfile.Method;
77
import org.apache.bcel.generic.Type;
88

9+
import java.lang.reflect.Modifier;
10+
911
public class MethodInfo implements MethodDescriptor {
1012
private final Method m;
1113

@@ -33,6 +35,11 @@ public boolean isStatic() {
3335
return m.isStatic();
3436
}
3537

38+
@Override
39+
public boolean isAbstract() {
40+
return m.isAbstract();
41+
}
42+
3643
@Override
3744
public String getName() {
3845
return m.getName();
@@ -62,4 +69,19 @@ public TypeDescriptor getReturnType() {
6269
public MetadataInfoAnnotationDescriptor getMetadataInfoAnnotation() {
6370
return null;
6471
}
72+
73+
@Override
74+
public boolean equals(Object o) {
75+
if (this == o) return true;
76+
if (o == null || getClass() != o.getClass()) return false;
77+
78+
MethodInfo that = (MethodInfo) o;
79+
80+
return m.equals(that.m);
81+
}
82+
83+
@Override
84+
public int hashCode() {
85+
return m.hashCode();
86+
}
6587
}

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/desc/MethodDescriptor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public interface MethodDescriptor {
55
boolean isProtected();
66
boolean isSynthetic();
77
boolean isStatic();
8+
boolean isAbstract();
89

910
String getName();
1011
String getSignature();

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/dx/MethodInfo.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public boolean isStatic() {
4343
return AccessFlags.isStatic(method.getAccessFlags());
4444
}
4545

46+
@Override
47+
public boolean isAbstract() {
48+
return AccessFlags.isAbstract(method.getAccessFlags());
49+
}
50+
4651
@Override
4752
public String getName() {
4853
Dex dex = dexFile.getDex();
@@ -59,12 +64,12 @@ public String getSignature() {
5964
MethodId methodId = dex.methodIds().get(method.getMethodIndex());
6065
ProtoId methodProtoId = dex.protoIds().get(methodId.getProtoIndex());
6166
short[] parameterTypes = dex.readTypeList(methodProtoId.getParametersOffset()).getTypes();
62-
String signature = "(";
67+
StringBuilder signature = new StringBuilder("(");
6368
for (short paramId: parameterTypes) {
64-
signature += typeNames.get(paramId);
69+
signature.append(typeNames.get(paramId));
6570
}
66-
signature += ")" + getReturnType().getSignature();
67-
return signature;
71+
signature.append(")").append(getReturnType().getSignature());
72+
return signature.toString();
6873
}
6974

7075
@Override
@@ -156,4 +161,19 @@ public MetadataInfoAnnotationDescriptor getMetadataInfoAnnotation() {
156161

157162
return null;
158163
}
164+
165+
@Override
166+
public boolean equals(Object o) {
167+
if (this == o) return true;
168+
if (o == null || getClass() != o.getClass()) return false;
169+
170+
MethodInfo that = (MethodInfo) o;
171+
172+
return getSignature().equals(that.getSignature());
173+
}
174+
175+
@Override
176+
public int hashCode() {
177+
return getSignature().hashCode();
178+
}
159179
}

0 commit comments

Comments
 (0)