Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

Kotlin Library Compatibility Issues and Proposed Fixes

Ouverte
#84 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
45/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
À l'abandon
Stack technique
java, kotlin, typescript
Domaine
tooling

Piste de recherche

Commencez dans DtsApi.java, au niveau de la logique de filtrage autour de la ligne 143, de la gestion des paramètres autour des lignes 962-969 et de replaceIgnoredNamespaces autour de la ligne 248. Reproduisez la génération avec MiSnap SDK v5.8.1 et inspectez les déclarations générées. C’est terminé lorsqu’il n’y a ni modules vides, ni noms de paramètres synthétiques invalides, ni génériques any invalides, et que les définitions se compilent correctement.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

I have been going through a library and was creating typings for it's various different .aar files. I noticed some issues that have already been highlighted here: https://github.com/NativeScript/android-dts-generator/issues/83 (@NathanWalker) and https://github.com/NativeScript/android-dts-generator/issues/75 (@farfromrefug).

Since I had a build issue with the generated typings I set about investigating the issues. I am proficient in TypeScript, however I'm no expert in terms of Kotlin which meant I could see what the issues were in the typing files, but wasn't sure how to solve them. Therefore, I investigated the issues via Claude Code and the solutions that were generated have solved my issues. The following description was also generated by Claude Code, I did so to make sure that everything that was found is listed accurately:

Summary

While generating TypeScript definitions for Kotlin-based Android libraries (specifically MiSnap SDK v5.8.1), three critical issues were discovered that prevent proper type generation. This document outlines each issue, provides examples, and proposes fixes.

Environment

  • DTS Generator Version: 4.0.0
  • Test Library: MiSnap SDK v5.8.1 (Kotlin-based Android library)
  • Kotlin Version: 1.8.20 (as seen in generated code)
  • Java Target: 17

Issue 1: Kotlin Serializer Classes Generate Invalid TypeScript

Problem

Kotlin's kotlinx.serialization compiler generates classes with double dollar signs ($$serializer) in their bytecode names. The DTS generator processes these, creating invalid TypeScript with empty module declarations.

Example from Bytecode
com/miteksystems/misnap/core/Barcode$$serializer.class
com/miteksystems/misnap/core/MiSnapSettings$$serializer.class
Generated TypeScript (Invalid)
export module  {  // ❌ Empty module name!
    export module Barcode {
        export class serializer extends kotlinx.serialization.internal.GeneratedSerializer<com.miteksystems.misnap.core.Barcode> {
            public static class: java.lang.Class<com.miteksystems.misnap.core.Barcode..serializer>;  // ❌ Double dots
            public static INSTANCE: com.miteksystems.misnap.core.Barcode..serializer;  // ❌ Double dots
        }
    }
}
Root Cause

In DtsApi.java line 541, the code replaces $ with .:

String[] currParts = currClass.getClassName().replace('$', '.').split("\\.");

For Barcode$$serializer:

  1. Replace $ → .: Barcode..serializer
  2. Split on .: ["Barcode", "", "serializer"]
  3. Empty string in array creates module { (invalid!)
Impact
  • 63 empty module declarations in test file
  • 126 invalid double-dot type references
  • TypeScript compilation fails
Proposed Fix

Add $$serializer to the filtered class list in DtsApi.java around line 143:

if (currentFileClassname.startsWith("java.util.function") ||
        currentFileClassname.startsWith("android.support.v4.media.routing.MediaRouterJellybeanMr1") ||
        currentFileClassname.startsWith("android.support.v4.media.routing.MediaRouterJellybeanMr2") ||
        currentFileClassname.contains(".debugger.") ||
        currentFileClassname.endsWith("package-info") ||
        currentFileClassname.endsWith("module-info") ||
        currentFileClassname.endsWith("Kt") ||
        currentFileClassname.contains("$$serializer")) {  // ← NEW LINE
    continue;
}
Why This Fix is Safe
  • $$serializer classes are Kotlin compiler internals for serialization
  • They're never directly used by application code
  • Filtering them is similar to filtering other compiler-generated classes (already done for Kt suffix)

Issue 2: Kotlin Synthetic Parameter Names Are Invalid TypeScript

Problem

Kotlin compiler generates synthetic setter methods with the parameter name <set-?> in the LocalVariableTable. The DTS generator reads this directly, creating invalid TypeScript identifiers.

Example from Bytecode (javap output)
public final void setInitialDelay(java.lang.Integer);
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0       6     0  this   Lcom/miteksystems/misnap/core/MiSnapSettings$Analysis;
        0       6     1  <set-?>  Ljava/lang/Integer;
Generated TypeScript (Invalid)
public setInitialDelay(<set-?>: java.lang.Integer): void;  // ❌ Invalid identifier
public setEnableAiBasedRts(<set-?>: java.lang.Boolean): void;  // ❌ Invalid identifier
public setMotionDetectorSensitivity(<set-?>: com.miteksystems.misnap.core.MiSnapSettings.Analysis.MotionDetectorSensitivity): void;  // ❌ Invalid identifier
Root Cause

In DtsApi.java lines 962-969, the code reads parameter names from bytecode but doesn't sanitize Kotlin synthetic names:

if (localVariable != null) {
    String name = localVariable.getName();
    // No sanitization for <set-?> or other synthetic names!
    if (reservedJsKeywords.contains(name)) {
        sb.append(name + "_");
    } else {
        sb.append(name);  // Writes <set-?> directly
    }
}
Impact
  • 68 occurrences in test file
  • All Kotlin property setter methods affected
  • TypeScript parser fails on angle bracket identifiers
Proposed Fix

Sanitize synthetic parameter names by deriving meaningful names from method names:

if (localVariable != null) {
    String name = localVariable.getName();

    // Sanitize Kotlin synthetic parameter names like <set-?>
    if (name.startsWith("<") && name.endsWith(">")) {
        // For setter methods, derive parameter name from method name
        String methodName = m.getName();
        if (methodName.startsWith("set") && methodName.length() > 3) {
            // setInitialDelay -> initialDelay
            name = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
        } else {
            // Fallback to "value" for other synthetic names
            name = "value";
        }
    }

    if (reservedJsKeywords.contains(name)) {
        System.out.println(String.format("Appending _ to reserved JS keyword %s", name));
        sb.append(name + "_");
    } else {
        sb.append(name);
    }
}
Result After Fix
public setInitialDelay(initialDelay: java.lang.Integer): void;  // ✅ Valid and semantic!
public setEnableAiBasedRts(enableAiBasedRts: java.lang.Boolean): void;  // ✅ Valid and semantic!
public setMotionDetectorSensitivity(motionDetectorSensitivity: com.miteksystems.misnap.core.MiSnapSettings.Analysis.MotionDetectorSensitivity): void;  // ✅ Valid and semantic!
Why This Fix is Safe
  • Only affects synthetic Kotlin parameter names (those with < and >)
  • Generates semantically meaningful names matching the property being set
  • Follows common naming conventions (same pattern as Kotlin itself uses in Kotlin files)

Issue 3: Kotlin Type Generics Create Invalid any<...> Syntax

Problem

Kotlin standard library types (kotlin.jvm.functions.*, kotlin.properties.*) are in the "ignored namespaces" list and get replaced with any. However, the regex replacement preserves generic type parameters, creating invalid TypeScript syntax (any is not a generic type).

Example from Bytecode
public final class FragmentViewBindingDelegate<T extends ViewBinding>
    implements kotlin.properties.ReadOnlyProperty<androidx.fragment.app.Fragment, T>
Generated TypeScript (Invalid)
export class FragmentViewBindingDelegate<T> extends any<androidx.fragment.app.Fragment,any> {  // ❌ any is not generic!
    public getViewBindingFactory(): any<globalAndroid.view.View,any>;  // ❌ Invalid syntax
    public constructor(fragment: androidx.fragment.app.Fragment, viewBindingFactory: any<any,any>);  // ❌ Invalid syntax
}
Root Cause

In DtsApi.java line 248, the regex pattern doesn't include commas and spaces in the character class for matching generic parameters:

String regexFormat = "(?<Replace>%s(?:(?:\\.[a-zA-Z\\d]*)|<[a-zA-Z\\d\\.<>]*>)*)(?<Suffix>[^a-zA-Z\\d]+)";
//                                                           ^^^^^^^^^^^^^^ Missing comma and space!

When the regex encounters kotlin.properties.ReadOnlyProperty<Fragment, T>:

  1. Matches up to: kotlin.properties.ReadOnlyProperty
  2. Encounters < which is [^a-zA-Z\d], so it becomes the Suffix
  3. Replacement: any< + remaining text
  4. Result: any<Fragment, T> (invalid!)
Impact
  • ~30 occurrences across various Kotlin function and property types
  • All Kotlin lambda and property delegate types affected
  • TypeScript compilation fails
Proposed Fix

Update the regex to include commas, spaces, and match end-of-string:

private String replaceIgnoredNamespaces(String content) {
    // Updated regex to properly capture generics with commas, spaces, and nested angle brackets
    // Also matches end of string or line as valid suffix
    String regexFormat = "(?<Replace>%s(?:(?:\\.[a-zA-Z\\d]*)|<[a-zA-Z\\d\\.<>, ]*>)*)(?<Suffix>[^a-zA-Z\\d]+|$)";
    //                                                                     ^^^^^ Added comma and space
    //                                                                                        ^^^ Added end-of-string

    for (String ignoredNamespace : this.getIgnoredNamespaces()) {
        String regexString = String.format(regexFormat, ignoredNamespace.replace(".", "\\."));
        content = content.replaceAll(regexString, "any$2");
        regexString = String.format(regexFormat, getGlobalAliasedClassName(ignoredNamespace).replace(".", "\\."));
        content = content.replaceAll(regexString, "any$2");
    }

    // replace "extends any" with "extends java.lang.Object"
    content = content.replace(" extends any ", String.format(" extends %s ", DtsApi.JavaLangObject));

    return content;
}
Result After Fix
export class FragmentViewBindingDelegate<T> extends java.lang.Object {  // ✅ Valid TypeScript!
    public getViewBindingFactory(): any;  // ✅ Valid TypeScript!
    public constructor(fragment: androidx.fragment.app.Fragment, viewBindingFactory: any);  // ✅ Valid TypeScript!
}
Why This Fix is Safe
  • Only affects types in the ignored namespaces list (already being replaced with any)
  • Properly strips all generic parameters when replacing, creating valid TypeScript
  • The regex already existed; this just makes it work correctly for types with commas in generics

Testing Results

Test Environment
  • Library: MiSnap SDK v5.8.1 (11 modules)
  • Project: NativeScript mobile app
  • TypeScript Version: As configured by NativeScript
Before Fixes
  • ❌ Empty module declarations: 63
  • ❌ Double-dot references: 126
  • ❌ Invalid <set-?> parameters: 68
  • ❌ Invalid any<...> syntax: ~30
  • ❌ Total TypeScript errors: 287+
After Fixes
  • ✅ Empty module declarations: 0
  • ✅ Double-dot references: 0
  • ✅ Invalid parameters: 0
  • ✅ Invalid any<...> syntax: 0
  • ✅ All type definitions compile successfully
  • ✅ NativeScript project runs without issues
Generated File Sizes (Example: misnap-core.d.ts)
  • Before: 3,789 lines with errors
  • After: 3,096 lines (693 lines of invalid code removed)
  • Reduction: 18.3% smaller, 100% valid

Compatibility

These fixes specifically target Kotlin-generated bytecode patterns that are:

  • Standard Kotlin compiler output (not library-specific)
  • Present in any modern Kotlin Android library
  • Not handled by the current generator logic

The fixes are backward compatible - they only affect Kotlin libraries and don't change behavior for Java-only libraries.


Proposed Changes Summary

File: dts-generator/src/main/java/com/telerik/dts/DtsApi.java

Change 1 (around line 143):

// Add to filtered classes list
currentFileClassname.contains("$$serializer")

Change 2 (lines 965-976, in getMethodParamSignature method):

// Sanitize Kotlin synthetic parameter names
if (name.startsWith("<") && name.endsWith(">")) {
    String methodName = m.getName();
    if (methodName.startsWith("set") && methodName.length() > 3) {
        name = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
    } else {
        name = "value";
    }
}

Change 3 (line 249, in replaceIgnoredNamespaces method):

// Update regex pattern
String regexFormat = "(?<Replace>%s(?:(?:\\.[a-zA-Z\\d]*)|<[a-zA-Z\\d\\.<>, ]*>)*)(?<Suffix>[^a-zA-Z\\d]+|$)";

References


Tested With:

  • MiSnap SDK v5.8.1 (Mitek Systems)
  • NativeScript 8.x
  • Multiple Kotlin-based AndroidX libraries

Let me know if I should commit the changes so that they can be tested :)

Langage dominant
Java
Étoiles
96
Forks
25
Métriques de merge des PR
Aucune PR mergée en 30 j

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de NativeScript/android-dts-generator

Toutes les issues de NativeScript/android-dts-generator

Issues similaires

Plus d'issues Java

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.