Skip to content

Commit 7000a54

Browse files
authored
Merge pull request #501 from NativeScript/pete/feature-implement-interfaces
Classes can implement multiple interfaces
2 parents dcb4b81 + 1be4f57 commit 7000a54

File tree

15 files changed

+999
-812
lines changed

15 files changed

+999
-812
lines changed

binding-generator/src/main/java/com/tns/bindings/Dump.java

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -199,34 +199,36 @@ public void generateProxy(ApplicationWriter aw, String proxyName, ClassDescripto
199199
String methodOverride = methodOverrides[i];
200200
methodOverridesSet.add(methodOverride);
201201
}
202-
generateProxy(aw, proxyName, classTo, methodOverridesSet);
203-
}
204202

205-
public void generateProxy(ApplicationWriter aw, ClassDescriptor classTo, String[] methodOverrides, int ignored)
206-
{
207-
HashSet<String> methodOverridesSet = new HashSet<String>();
203+
generateProxy(aw, proxyName, classTo, methodOverridesSet, null);
204+
}
205+
206+
public void generateProxy(ApplicationWriter aw, ClassDescriptor classTo, String[] methodOverrides, int ignored)
207+
{
208+
HashSet<String> methodOverridesSet = new HashSet<String>();
209+
208210
for (int i = 0; i < methodOverrides.length; i++)
209211
{
210212
String methodOverride = methodOverrides[i];
211213
methodOverridesSet.add(methodOverride);
212214
}
213-
generateProxy(aw, "0", classTo, methodOverridesSet);
215+
216+
generateProxy(aw, "0", classTo, methodOverridesSet, null);
214217
}
215218

216219
public void generateProxy(ApplicationWriter aw, String proxyName, ClassDescriptor classTo)
217220
{
218-
generateProxy(aw, proxyName, classTo, null);
221+
generateProxy(aw, proxyName, classTo, null, null);
219222
}
220223

221224
public void generateProxy(ApplicationWriter aw, ClassDescriptor classTo)
222225
{
223-
generateProxy(aw, "0", classTo, null);
224-
}
226+
generateProxy(aw, "0", classTo, null, null);
227+
}
225228

226-
public void generateProxy(ApplicationWriter aw, String proxyName, ClassDescriptor classTo, HashSet<String> methodOverrides)
229+
public void generateProxy(ApplicationWriter aw, String proxyName, ClassDescriptor classTo, HashSet<String> methodOverrides, HashSet<ClassDescriptor> implementedInterfaces)
227230
{
228231
String classSignature = getAsmDescriptor(classTo);
229-
//String methodSignature = org.objectweb.asm.Type.getMethodDescriptor(Object.class.getMethods()[0]);
230232

231233
String tnsClassSignature = LCOM_TNS +
232234
classSignature.substring(1, classSignature.length() - 1).replace("$", "_");
@@ -237,8 +239,8 @@ public void generateProxy(ApplicationWriter aw, String proxyName, ClassDescripto
237239

238240
tnsClassSignature += ";";
239241

240-
ClassVisitor cv = generateClass(aw, classTo, classSignature, tnsClassSignature);
241-
MethodDescriptor[] methods = getSupportedMethods(classTo, methodOverrides);
242+
ClassVisitor cv = generateClass(aw, classTo, classSignature, tnsClassSignature, implementedInterfaces);
243+
MethodDescriptor[] methods = getSupportedMethods(classTo, methodOverrides, implementedInterfaces);
242244

243245
methods = groupMethodsByNameAndSignature(methods);
244246

@@ -332,12 +334,17 @@ private void collectInterfaceMethods(ClassDescriptor clazz, HashSet<String> meth
332334
}
333335
}
334336

335-
private MethodDescriptor[] getSupportedMethods(ClassDescriptor clazz, HashSet<String> methodOverrides)
337+
private MethodDescriptor[] getSupportedMethods(ClassDescriptor clazz, HashSet<String> methodOverrides, HashSet<ClassDescriptor> interfacesToImplement)
336338
{
337339
ArrayList<MethodDescriptor> result = new ArrayList<MethodDescriptor>();
338340

339341
collectInterfaceMethods(clazz, methodOverrides, result);
340342

343+
for (ClassDescriptor iface : interfacesToImplement)
344+
{
345+
collectInterfaceMethods(iface, methodOverrides, result);
346+
}
347+
341348
if (!clazz.isInterface())
342349
{
343350
HashMap<String, MethodDescriptor> finalMethods = new HashMap<String, MethodDescriptor>();
@@ -601,13 +608,13 @@ private void generateHashCodeSuper(ClassVisitor cv)
601608

602609
private void generateMethod(ClassVisitor cv, ClassDescriptor classTo, MethodDescriptor method, int methodNumber, String classSignature, String tnsClassSignature, int fieldBit)
603610
{
604-
if (ProxyGenerator.IsLogEnabled) Log.d("Generator", "generatingMethod " + method.getName());
611+
if (ProxyGenerator.IsLogEnabled) {
612+
Log.d("Generator", "generatingMethod " + method.getName());
613+
}
605614

606615
//TODO: handle checked exceptions
607616
String methodDexSignature = getDexMethodDescriptor(method);
608617
String[] exceptions = new String[0];
609-
610-
611618
MethodVisitor mv;
612619
int methodModifiers = getDexModifiers(method);
613620

@@ -620,6 +627,7 @@ private void generateMethod(ClassVisitor cv, ClassDescriptor classTo, MethodDesc
620627
{
621628
generateInitializedBlock(mv, thisRegister, classSignature, tnsClassSignature);
622629
}
630+
623631
generateCallOverrideBlock(mv, method, thisRegister, classSignature, tnsClassSignature, methodDexSignature, fieldBit);
624632

625633
mv.visitEnd();
@@ -919,25 +927,39 @@ private void generateInitializedField(ClassVisitor cv)
919927

920928
static final String[] classImplentedInterfaces = new String[] { "Lcom/tns/NativeScriptHashCodeProvider;" };
921929
static final String[] interfaceImplementedInterfaces = new String[] { "Lcom/tns/NativeScriptHashCodeProvider;", "" };
922-
private ClassVisitor generateClass(ApplicationWriter aw, ClassDescriptor classTo, String classSignature, String tnsClassSignature)
930+
931+
private ClassVisitor generateClass(ApplicationWriter aw, ClassDescriptor classTo, String classSignature, String tnsClassSignature, HashSet<ClassDescriptor> implementedInterfaces)
923932
{
924933
ClassVisitor cv;
925934

926935
int classModifiers = getDexModifiers(classTo);
927-
String[] implentedInterfaces = classImplentedInterfaces;
936+
ArrayList<String> interfacesToImplement = new ArrayList(Arrays.asList(classImplentedInterfaces));
937+
928938
if (classTo.isInterface())
929939
{
930940
interfaceImplementedInterfaces[1] = classSignature; //new String[] { "Lcom/tns/NativeScriptHashCodeProvider;", classSignature };
931-
implentedInterfaces = interfaceImplementedInterfaces;
941+
for(String interfaceToImpl : interfaceImplementedInterfaces) {
942+
if(!interfacesToImplement.contains(interfaceToImpl)) {
943+
interfacesToImplement.add(interfaceToImpl);
944+
}
945+
}
946+
932947
classSignature = objectClass;
933948
}
934949
else
935950
{
936-
implentedInterfaces = classImplentedInterfaces;
951+
if(implementedInterfaces != null) {
952+
for(ClassDescriptor interfaceToImpl : implementedInterfaces) {
953+
interfacesToImplement.add(getAsmDescriptor(interfaceToImpl));
954+
}
955+
}
937956
}
938957

939-
cv = aw.visitClass(classModifiers, tnsClassSignature, null, classSignature, implentedInterfaces);
940-
cv.visit(0, classModifiers, tnsClassSignature, null, classSignature, implentedInterfaces);
958+
String[] interfacesToImplementArr = new String[interfacesToImplement.size()];
959+
interfacesToImplementArr = interfacesToImplement.toArray(interfacesToImplementArr);
960+
961+
cv = aw.visitClass(classModifiers, tnsClassSignature, null, classSignature, interfacesToImplementArr);
962+
cv.visit(0, classModifiers, tnsClassSignature, null, classSignature, interfacesToImplementArr);
941963
cv.visitSource(classTo.getName() + ".java", null);
942964
return cv;
943965
}

binding-generator/src/main/java/com/tns/bindings/ProxyGenerator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,16 @@ public String generateProxy(String proxyName, ClassDescriptor classToProxy, Stri
4444
methodOverridesSet.add(methodOverride);
4545
}
4646
}
47-
return generateProxy(proxyName, classToProxy, methodOverridesSet, isInterface);
47+
48+
return generateProxy(proxyName, classToProxy, methodOverridesSet, null, isInterface);
4849
}
4950

50-
public String generateProxy(String proxyName, ClassDescriptor classToProxy, HashSet<String> methodOverrides, boolean isInterface) throws IOException
51+
public String generateProxy(String proxyName, ClassDescriptor classToProxy, HashSet<String> methodOverrides, HashSet<ClassDescriptor> implementedInterfaces, boolean isInterface) throws IOException
5152
{
5253
ApplicationWriter aw = new ApplicationWriter();
5354
aw.visit();
5455

55-
dump.generateProxy(aw, proxyName, classToProxy, methodOverrides);
56+
dump.generateProxy(aw, proxyName, classToProxy, methodOverrides, implementedInterfaces);
5657

5758
aw.visitEnd();
5859
byte[] generatedBytes = aw.toByteArray();

build-artifacts/project-template-gradle/src/main/assets/internal/ts_helpers.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090

9191
__extends_ts(Child, Parent);
9292

93+
9394
if (Parent.extend) {
9495
Child.__isPrototypeImplementationObject = true;
9596
Child.__proto__ = Parent;
@@ -105,9 +106,19 @@
105106
return extended;
106107
};
107108
}
109+
110+
function Interfaces(interfacesArr) {
111+
return function (target) {
112+
if(interfacesArr instanceof Array) {
113+
// attach interfaces: [] to the object
114+
target.prototype.interfaces = interfacesArr;
115+
}
116+
}
117+
}
108118

109119
global.__native = __native;
110120
global.__extends = __extends;
111121
global.__decorate = __decorate;
112122
global.JavaProxy = JavaProxy;
123+
global.Interfaces = Interfaces;
113124
})()

runtime/src/main/java/com/tns/ClassResolver.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public ClassResolver(Runtime runtime)
1111
this.runtime = runtime;
1212
}
1313

14-
public Class<?> resolveClass(String fullClassName, DexFactory dexFactory, String[] methodOverrides, boolean isInterface) throws ClassNotFoundException, IOException
14+
public Class<?> resolveClass(String fullClassName, DexFactory dexFactory, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException
1515
{
1616
String cannonicalClassName = fullClassName.replace('/', '.');
1717
String name = null;
@@ -33,15 +33,16 @@ public Class<?> resolveClass(String fullClassName, DexFactory dexFactory, String
3333
if (name == null || name == "")
3434
{
3535
if(isInterface)
36-
{
36+
{
3737
name = "";
38-
} else
39-
{
38+
}
39+
else
40+
{
4041
name = "0";
4142
}
4243
}
4344

44-
clazz = dexFactory.resolveClass(name, className, methodOverrides, isInterface);
45+
clazz = dexFactory.resolveClass(name, className, methodOverrides, implementedInterfaces, isInterface);
4546
}
4647

4748
if (clazz == null)

runtime/src/main/java/com/tns/DexFactory.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.zip.ZipOutputStream;
1717

1818
import com.tns.bindings.ProxyGenerator;
19+
import com.tns.bindings.desc.ClassDescriptor;
1920
import com.tns.bindings.desc.reflection.ClassInfo;
2021

2122
import dalvik.system.DexClassLoader;
@@ -63,7 +64,7 @@ public DexFactory(Logger logger, ClassLoader classLoader, File dexBaseDir, Strin
6364
static long totalMultiDexTime = 0;
6465
static long totalLoadDexTime = 0;
6566

66-
public Class<?> resolveClass(String name, String className, String[] methodOverrides, boolean isInterface) throws ClassNotFoundException, IOException
67+
public Class<?> resolveClass(String name, String className, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException
6768
{
6869
String fullClassName = className.replace("$", "_");
6970

@@ -115,7 +116,7 @@ public Class<?> resolveClass(String name, String className, String[] methodOverr
115116
logger.write("generating proxy in place");
116117
}
117118

118-
dexFilePath = this.generateDex(name, classToProxy, methodOverrides, isInterface);
119+
dexFilePath = this.generateDex(name, classToProxy, methodOverrides, implementedInterfaces, isInterface);
119120
dexFile = new File(dexFilePath);
120121
long stopGenTime = System.nanoTime();
121122
totalGenTime += stopGenTime - startGenTime;
@@ -187,6 +188,7 @@ public Class<?> findClass(String className) throws ClassNotFoundException
187188
{
188189
return existingClass;
189190
}
191+
190192
return classLoader.loadClass(canonicalName);
191193
}
192194

@@ -250,25 +252,37 @@ private File getDexFile(String className) throws InvalidClassException
250252
{
251253
logger.write("Looking for proxy file: " + dexFilePath + " Result: NOT Found. Proxy Gen needed. ClassName: " + className);
252254
}
255+
253256
return null;
254257
}
255258

256-
private String generateDex(String proxyName, String className, String[] methodOverrides, boolean isInterface) throws ClassNotFoundException, IOException
259+
private String generateDex(String proxyName, String className, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException
257260
{
258261
Class<?> classToProxy = Class.forName(className);
259262

260263
HashSet<String> methodOverridesSet = null;
264+
HashSet<ClassDescriptor> implementedInterfacesSet = new HashSet<ClassDescriptor>();
265+
261266
if (methodOverrides != null)
262267
{
263268
methodOverridesSet = new HashSet<String>();
264269
for (int i = 0; i < methodOverrides.length; i++)
265270
{
266271
String methodOverride = methodOverrides[i];
272+
267273
methodOverridesSet.add(methodOverride);
268274
}
269275
}
270276

271-
return proxyGenerator.generateProxy(proxyName, new ClassInfo(classToProxy) , methodOverridesSet, isInterface);
277+
if (implementedInterfaces.length > 0) {
278+
for(int j = 0; j < implementedInterfaces.length; j++) {
279+
if(!implementedInterfaces[j].isEmpty()) {
280+
implementedInterfacesSet.add(new ClassInfo(Class.forName(implementedInterfaces[j])));
281+
}
282+
}
283+
}
284+
285+
return proxyGenerator.generateProxy(proxyName, new ClassInfo(classToProxy) , methodOverridesSet, implementedInterfacesSet, isInterface);
272286
}
273287

274288
private void updateDexThumbAndPurgeCache()

runtime/src/main/java/com/tns/Runtime.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,11 @@ public void run()
304304
return result;
305305
}
306306

307+
// TODO: Pete: new param - implementedInterfaces
307308
@RuntimeCallable
308-
private Class<?> resolveClass(String fullClassName, String[] methodOverrides, boolean isInterface) throws ClassNotFoundException, IOException
309+
private Class<?> resolveClass(String fullClassName, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException
309310
{
310-
Class<?> javaClass = classResolver.resolveClass(fullClassName, dexFactory, methodOverrides, isInterface);
311+
Class<?> javaClass = classResolver.resolveClass(fullClassName, dexFactory, methodOverrides, implementedInterfaces, isInterface);
311312

312313
return javaClass;
313314
}

0 commit comments

Comments
 (0)