Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions test-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
* -PandroidXMaterial=[androidx_material_version]
*/


import groovy.io.FileType
import groovy.json.JsonSlurper

import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import groovy.io.FileType
import java.security.MessageDigest
import javax.inject.Inject

apply plugin: "com.android.application"

def onlyX86 = project.hasProperty("onlyX86")
Expand Down Expand Up @@ -545,7 +548,7 @@ afterEvaluate { project ->
// if there's a project dependency search for its result jar file in the build/intermediates/runtime_library_classes folder
// this is the output folder in gradle 5.1.1, but it can be changed in the future versions of gradle
def jarDir = new File("${it.getBuildDir()}/intermediates/runtime_library_classes/${buildType.toLowerCase()}")
if(jarDir.exists()) {
if (jarDir.exists()) {
jarDir.eachFileRecurse(FileType.FILES) { file ->
if (file.path.endsWith(".jar")) {
processJar(file, jars)
Expand Down Expand Up @@ -574,7 +577,7 @@ def processJar(File jar, jars) {
// directory is a randomly generated string)
cleanupAllJars.inputs.files jar

task "${taskName}" (type: WorkerTask) {
task "${taskName}"(type: WorkerTask) {
dependsOn cleanupAllJars
extractAllJars.dependsOn it

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,20 @@ describe("Tests for runtime binding generator", function () {
expect(isInstanceOf).toEqual(true);
});

it("When_implementing_interface_and_its_implemented_interfaces", function() {
var impl = new com.tns.tests.MyDerivedPublicInterface({
methodOfMyDerivedPublicInterface: function(input) {
return "Le java " + input;
},
methodOfMyPublicInterface: function(input) {
return "Le java " + input;
}
});

try {
var C = java.lang.Class.forName("com.tns.gen.com.tns.tests.MyDerivedPublicInterface");
expect(C).not.toBe(null);

var expected = "Le java test derived method";
var actual = impl.methodOfMyPublicInterface("test derived method");
expect(actual).toBe(expected);
} catch (e) {
//fail("class was not found");
expect(true).toBe(false);
}
});
it("When_implementing_interface_and_its_implemented_interfaces", function() {
var impl = new com.tns.tests.MyDerivedPublicInterface({
methodOfMyDerivedPublicInterface: function(input) {
return "Le java " + input;
},
methodOfMyPublicInterface: function(input) {
return "Le java " + input;
}
});

var expected = "Le java test derived method";
var actual = impl.methodOfMyPublicInterface("test derived method");
expect(actual).toBe(expected);
});

it("When_generating_a_class_that_implements_interfaces_javascript", function() {

Expand Down
12 changes: 7 additions & 5 deletions test-app/runtime/src/main/java/com/tns/ClassResolver.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.tns;

import com.tns.system.classes.loading.ClassStorageService;

import java.io.IOException;

class ClassResolver {
private final Runtime runtime;
private final ClassStorageService classStorageService;

public ClassResolver(Runtime runtime) {
this.runtime = runtime;
ClassResolver(ClassStorageService classStorageService) {
this.classStorageService = classStorageService;
}

public Class<?> resolveClass(String baseClassName, String fullClassName, DexFactory dexFactory, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException {
Class<?> resolveClass(String baseClassName, String fullClassName, DexFactory dexFactory, String[] methodOverrides, String[] implementedInterfaces, boolean isInterface) throws ClassNotFoundException, IOException {
String canonicalClassName = fullClassName.replace('/', '.');
String canonicalBaseClassName = baseClassName.replace('/', '.');
String name = "";
Expand All @@ -24,7 +26,7 @@ public Class<?> resolveClass(String baseClassName, String fullClassName, DexFact
}

if (clazz == null) {
clazz = Runtime.getClassForName(className);
clazz = classStorageService.retrieveClass(className);
}

return clazz;
Expand Down
48 changes: 15 additions & 33 deletions test-app/runtime/src/main/java/com/tns/DexFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

import android.util.Log;

import com.tns.bindings.AnnotationDescriptor;
import com.tns.bindings.ProxyGenerator;
import com.tns.bindings.desc.ClassDescriptor;
import com.tns.bindings.desc.reflection.ClassInfo;
import com.tns.system.classes.loading.ClassStorageService;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
Expand All @@ -12,18 +18,11 @@
import java.io.InputStreamReader;
import java.io.InvalidClassException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.tns.bindings.AnnotationDescriptor;
import com.tns.bindings.ProxyGenerator;
import com.tns.bindings.desc.ClassDescriptor;
import com.tns.bindings.desc.reflection.ClassInfo;

import dalvik.system.DexClassLoader;

public class DexFactory {
Expand All @@ -34,11 +33,12 @@ public class DexFactory {
private final File odexDir;
private final String dexThumb;
private final ClassLoader classLoader;
private final ClassStorageService classStorageService;

private ProxyGenerator proxyGenerator;
private HashMap<String, Class<?>> injectedDexClasses = new HashMap<String, Class<?>>();

public DexFactory(Logger logger, ClassLoader classLoader, File dexBaseDir, String dexThumb) {
DexFactory(Logger logger, ClassLoader classLoader, File dexBaseDir, String dexThumb, ClassStorageService classStorageService) {
this.logger = logger;
this.classLoader = classLoader;
this.dexDir = dexBaseDir;
Expand All @@ -58,6 +58,7 @@ public DexFactory(Logger logger, ClassLoader classLoader, File dexBaseDir, Strin

this.updateDexThumbAndPurgeCache();
this.proxyGenerator.setProxyThumb(this.dexThumb);
this.classStorageService = classStorageService;
}

static long totalGenTime = 0;
Expand Down Expand Up @@ -154,36 +155,17 @@ public Class<?> resolveClass(String baseClassName, String name, String className
out.closeEntry();
out.close();
}
//

Class<?> result = null;
try {
// use DexFile instead of DexClassLoader to allow class loading
// within the default class loader
// Note: According to the official documentation, DexFile should not
// be directly used.
// However, this is the only viable way to get our dynamic classes
// loaded within the system class loader
Class<?> result;
DexClassLoader dexClassLoader = new DexClassLoader(jarFilePath, this.odexDir.getAbsolutePath(), null, classLoader);

if (isInterface) {
@SuppressWarnings("deprecation")
dalvik.system.DexFile df = dalvik.system.DexFile.loadDex(jarFilePath, new File(this.odexDir, fullClassName).getAbsolutePath(), 0);
result = df.loadClass(fullClassName, classLoader);
} else {
@SuppressWarnings("deprecation")
dalvik.system.DexFile df = dalvik.system.DexFile.loadDex(jarFilePath, new File(this.odexDir, desiredDexClassName).getAbsolutePath(), 0);
result = df.loadClass(desiredDexClassName, classLoader);
}
} catch (IOException e) {
Log.w("JS", String.format("Error resolving class %s: %s. Fall back to DexClassLoader."));
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
// fall back to DexClassLoader
DexClassLoader dexClassLoader = new DexClassLoader(jarFilePath, this.odexDir.getAbsolutePath(), null, classLoader);
if (isInterface) {
result = dexClassLoader.loadClass(fullClassName);
} else {
result = dexClassLoader.loadClass(desiredDexClassName);
}

classStorageService.storeClass(result.getName(), result);
this.injectedDexClasses.put(originalFullClassName, result);

return result;
Expand Down
Loading