Visitar URL original
feat: support native ES classes with lazy registration by NathanWalker · Pull Request #1983 · NativeScript/android · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
ci: unit test fixes
  • Loading branch information
NathanWalker committed Aug 15, 2026
commit a85598ae2ffb5cecfd3ff6ff60a708967f37ed8e
28 changes: 17 additions & 11 deletions test-app/runtime/src/main/cpp/MetadataNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,7 @@ MetadataNode::TypeMetadata* MetadataNode::EnsureExtendedESClass(Isolate* isolate

// Compute the proxy class name
string fullClassName;
string generatedCandidate;
if (!nativeClassName.empty() && nativeClassName.find('.') != string::npos) {
fullClassName = nativeClassName;
} else if (isInterface) {
Expand All @@ -1463,21 +1464,26 @@ MetadataNode::TypeMetadata* MetadataNode::EnsureExtendedESClass(Isolate* isolate
}

string extendNameAndLocation = "es" + HashESClassId(BuildESClassProxyIdentity(scriptName, baseClassName, className, methodOverrides, implementedInterfaces)) + "_" + className;
string candidate = TNS_PREFIX + CreateFullClassName(baseClassName, extendNameAndLocation);
generatedCandidate = TNS_PREFIX + CreateFullClassName(baseClassName, extendNameAndLocation);
fullClassName = generatedCandidate;
}

// collision handling for distinct classes that produce the same deterministic name
// (e.g. a class factory evaluated multiple times in the same script)
fullClassName = candidate;
int suffix = 2;
while (GetCachedExtendedClassData(isolate, fullClassName).extendedCtorFunction != nullptr) {
fullClassName = candidate + "_" + std::to_string(suffix++);
// Resolve through DexFactory, then key collision checks on the name it
// actually produced. Class.getName() drops the com.tns.gen/ request prefix,
// so looking up ExtendedCtorFuncCache with the request name never hit.
jclass clazz = nullptr;
string fullExtendedName;
int suffix = 2;
while (true) {
clazz = CallbackHandlers::ResolveClass(isolate, baseClassName, fullClassName, methodOverrides, implementedInterfaces, isInterface);
fullExtendedName = CallbackHandlers::ResolveClassName(isolate, clazz);
if (generatedCandidate.empty()
|| GetCachedExtendedClassData(isolate, fullExtendedName).extendedCtorFunction == nullptr) {
break;
}
fullClassName = generatedCandidate + "_" + std::to_string(suffix++);
}

// Resolve (generate or load) the Java proxy class through the regular DexFactory pipeline
auto clazz = CallbackHandlers::ResolveClass(isolate, baseClassName, fullClassName, methodOverrides, implementedInterfaces, isInterface);
auto fullExtendedName = CallbackHandlers::ResolveClassName(isolate, clazz);

// Tag the ES ctor the same way ExtendMethodCallback tags `.extend()`-created functions, so
// the rest of the runtime (construction, Java-initiated instantiation, `.class`, marshalling)
// treats it like any other extended class ctor
Expand Down
8 changes: 8 additions & 0 deletions test-app/runtime/src/main/java/com/tns/DexFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ public Class<?> resolveClass(String baseClassName, String name, String className

// strip the `com.tns.gen` off the base extended class name
String desiredDexClassName = this.getClassToProxyName(fullClassName);
// An explicit name like com.tns.gen.ESEagerNamedObject strips to a
// single identifier. ProxyGenerator then treats that as a suffix and
// emits java.lang.Object_ESEagerNamedObject while we try to load
// ESEagerNamedObject. Keep the qualified name so generation and load
// use the same class identity.
if (!desiredDexClassName.contains(".")) {
desiredDexClassName = fullClassName;
}

// when interfaces are extended as classes, we still want to preserve
// just the interface name without the extra file, line, column information
Expand Down