Skip to content

Conversation

@LazyImmortal
Copy link

@LazyImmortal LazyImmortal commented Nov 25, 2025

优化 JSMethod注解使用

  1. 添加JSMethod混淆规则,确保方法不被移除
  2. 添加JSMethod注解值,确保同名方法和混淆方法能被正常注册
  3. 优化QuickJSObject.setProperty(String, Class),确保类没有无参构造方法时,静态方法仍能被正常注册

消除 QuickJSObject警告

  1. 抑制QuickJSObject.convertToMap的类型转换警告
  2. 使用clazz.getConstructor().newInstance()替代废弃的clazz.newInstance()

Summary by Sourcery

优化基于 JSMethod 的 Java-to-JS 方法绑定,并清理 QuickJSObject 的警告。

新功能:

  • 允许 JSMethod 通过可选的注解值显式指定 JavaScript 方法名。

缺陷修复:

  • 确保对外暴露为 JS 的方法在目标类缺少无参构造函数或方法被混淆时,仍能被正确注册。

改进:

  • 更新 QuickJSObject,使用现代的反射实例化 API,并在无法创建实例时跳过非静态方法。
  • 在 QuickJSObject.convertToMap 中抑制并收紧类型转换,以消除不安全转换的警告。
  • 统一测试中的 JSMethod 使用方式,以覆盖带注解方法名映射行为。

构建:

  • 添加 ProGuard/R8 规则,以在允许方法被混淆的同时保留带有 JSMethod 注解的方法。
Original summary in English

Summary by Sourcery

Optimize JSMethod-based Java-to-JS method binding and clean up QuickJSObject warnings.

New Features:

  • Allow JSMethod to specify an explicit JavaScript method name via an optional annotation value.

Bug Fixes:

  • Ensure JS-exposed methods are correctly registered even when target classes lack a no-arg constructor or methods are obfuscated.

Enhancements:

  • Update QuickJSObject to use the modern reflective instantiation API and skip non-static methods when no instance can be created.
  • Suppress and tighten type casting in QuickJSObject.convertToMap to remove unsafe cast warnings.
  • Align JSMethod usage in tests to cover annotated method name mapping behavior.

Build:

  • Add ProGuard/R8 rules to retain methods annotated with JSMethod while allowing their obfuscation.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 25, 2025

Reviewer's Guide

通过以下方式优化带有 JSMethod 注解的 Java 方法在 QuickJS 中的暴露方式:为 JSMethod 注解新增可命名的 value 值;更新方法注册逻辑以尊重该名称并处理没有无参构造函数的类;为带有 JSMethod 的方法添加 ProGuard/R8 keep 规则;现代化基于反射的实例化方式;以及清理 QuickJSObject 中 Map 转换逻辑及相关测试中的类型安全警告。

QuickJSObject.setProperty 中更新后的 JSMethod 注册时序图

sequenceDiagram
    participant Caller
    participant QuickJSObject
    participant JavaClass
    participant JSObject

    Caller->>QuickJSObject: setProperty(name, clazz)
    activate QuickJSObject
    QuickJSObject->>JavaClass: clazz.getConstructor().newInstance()
    alt constructor exists and is accessible
        JavaClass-->>QuickJSObject: javaObj instance
    else constructor missing or not accessible
        JavaClass-->>QuickJSObject: throws exception
        QuickJSObject-->>QuickJSObject: javaObj remains null
    end

    QuickJSObject->>QuickJSObject: methods = clazz.getMethods()
    QuickJSObject->>JSObject: createNewJSObject()
    JSObject-->>QuickJSObject: jsObj

    loop for each method in methods
        QuickJSObject->>QuickJSObject: check if javaObj is null and method is non static
        alt javaObj is null and method is non static
            QuickJSObject-->>QuickJSObject: skip method
        else
            QuickJSObject->>QuickJSObject: jsMethod = method.getAnnotation(JSMethod)
            alt jsMethod is null
                QuickJSObject-->>QuickJSObject: skip method
            else
                QuickJSObject->>QuickJSObject: jsMethodName = jsMethod.value()
                alt jsMethodName is blank
                    QuickJSObject-->>QuickJSObject: jsMethodName = method.getName()
                end
                QuickJSObject->>JSObject: jsObj.setProperty(jsMethodName, lambda)
            end
        end
    end

    QuickJSObject->>QuickJSObject: setProperty(name, jsObj)
    QuickJSObject-->>Caller: return
    deactivate QuickJSObject
Loading

JSMethod 注解和 QuickJSObject 方法暴露的更新后类图

classDiagram
    class JSMethod {
        <<annotation>>
        +String value()
    }

    class QuickJSObject {
        -QuickJSContext context
        +void setProperty(String name, Class clazz)
        +void convertToMap(Object target, Object map, HashMap circulars, MapFilter filter, Object extra, MapCreator mapCreator)
    }

    class JSObject {
        +long getPointer()
        +void setProperty(String name, Object function)
    }

    class TestJava {
        +boolean test(String message)
        +boolean test(String message, int age)
        +boolean test(JSArray array)
        +boolean test(JSObject object)
        +boolean test(JSObject object, JSArray message, int age, String name)
    }

    JSMethod <|.. TestJava : annotates
    QuickJSObject --> JSObject : creates_and_populates
    QuickJSObject ..> JSMethod : reads_annotation
    QuickJSObject ..> TestJava : reflects_on_methods
    QuickJSObject ..> MapFilter : uses
    QuickJSObject ..> MapCreator : uses

    class MapFilter {
    }

    class MapCreator {
    }
Loading

File-Level Changes

Change Details Files
Update QuickJSObject.setProperty(String, Class<?>) to support JSMethod names, handle classes without no-arg constructors, and use modern reflection APIs.
  • 将已弃用的 clazz.newInstance() 替换为 clazz.getConstructor().newInstance(),并扩展异常处理范围以涵盖反射构造失败的情况。
  • 在实例化失败时允许 javaObj 保持为 null,并在没有实例时只跳过非静态方法,从而即使类没有无参构造函数也能注册静态的 JS 暴露方法。
  • 在遍历每个方法时读取其上的 JSMethod 注解,从 value 中推导对 JS 可见的方法名(当 value 为空时退回到 Java 方法名),并使用该名称将方法注册到 JSObject 上。
  • 重构方法注册逻辑以使用捕获的 finalJavaObj 引用,并将 method.invoke 的异常处理整合到单一的 catch 代码块中。
wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java
Suppress and tidy up generics-related warnings and formatting in QuickJSObject.convertToMap.
  • 在 convertToMap 上添加 @SuppressWarnings("unchecked"),以屏蔽 Map 和 ArrayList 操作中预期的未检查转换警告。
  • 规范 instanceof ArrayList 分支中的空格和缩进,以提升可读性而不改变行为。
wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java
Extend JSMethod annotation to carry an explicit JS method name.
  • 在 JSMethod 中新增一个默认值为空字符串的 value() 元素,使调用方可以为带注解的方法显式指定其向 JS 暴露的名称,同时在未提供该值时保持向后兼容。
wrapper-java/src/main/java/com/whl/quickjs/wrapper/JSMethod.java
Adjust Android tests to validate JSMethod name-based registration rather than relying on Java method names.
  • 将 TestJava 中的方法统一为相同的 Java 方法名 test,同时使用不同的 JSMethod("...") 值来显式定义它们向 JS 暴露时的名称。
  • 保持方法体不变,以确保在新的命名方案下仍然验证现有行为。
wrapper-android/src/androidTest/java/com/whl/quickjs/wrapper/QuickJSTest.java
Add ProGuard/R8 keep rules to preserve JSMethod-annotated methods during obfuscation while still allowing renaming.
  • 为所有标注了 @com.whl.quickjs.wrapper.JSMethod 的方法添加 -keepclassmembers,allowobfuscation 规则,使这些方法在混淆过程中被保留,但仍可根据需要重命名。
wrapper-android/consumer-rules.pro

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Original review guide in English

Reviewer's Guide

Optimizes how JSMethod-annotated Java methods are exposed to QuickJS by introducing a named JSMethod annotation value, updating method registration to respect that name and handle classes without no-arg constructors, adding ProGuard/R8 keep rules for JSMethod methods, modernizing reflection-based instantiation, and cleaning up type-safety warnings in QuickJSObject map conversion logic and related tests.

Sequence diagram for updated JSMethod registration in QuickJSObject.setProperty

sequenceDiagram
    participant Caller
    participant QuickJSObject
    participant JavaClass
    participant JSObject

    Caller->>QuickJSObject: setProperty(name, clazz)
    activate QuickJSObject
    QuickJSObject->>JavaClass: clazz.getConstructor().newInstance()
    alt constructor exists and is accessible
        JavaClass-->>QuickJSObject: javaObj instance
    else constructor missing or not accessible
        JavaClass-->>QuickJSObject: throws exception
        QuickJSObject-->>QuickJSObject: javaObj remains null
    end

    QuickJSObject->>QuickJSObject: methods = clazz.getMethods()
    QuickJSObject->>JSObject: createNewJSObject()
    JSObject-->>QuickJSObject: jsObj

    loop for each method in methods
        QuickJSObject->>QuickJSObject: check if javaObj is null and method is non static
        alt javaObj is null and method is non static
            QuickJSObject-->>QuickJSObject: skip method
        else
            QuickJSObject->>QuickJSObject: jsMethod = method.getAnnotation(JSMethod)
            alt jsMethod is null
                QuickJSObject-->>QuickJSObject: skip method
            else
                QuickJSObject->>QuickJSObject: jsMethodName = jsMethod.value()
                alt jsMethodName is blank
                    QuickJSObject-->>QuickJSObject: jsMethodName = method.getName()
                end
                QuickJSObject->>JSObject: jsObj.setProperty(jsMethodName, lambda)
            end
        end
    end

    QuickJSObject->>QuickJSObject: setProperty(name, jsObj)
    QuickJSObject-->>Caller: return
    deactivate QuickJSObject
Loading

Updated class diagram for JSMethod annotation and QuickJSObject method exposure

classDiagram
    class JSMethod {
        <<annotation>>
        +String value()
    }

    class QuickJSObject {
        -QuickJSContext context
        +void setProperty(String name, Class clazz)
        +void convertToMap(Object target, Object map, HashMap circulars, MapFilter filter, Object extra, MapCreator mapCreator)
    }

    class JSObject {
        +long getPointer()
        +void setProperty(String name, Object function)
    }

    class TestJava {
        +boolean test(String message)
        +boolean test(String message, int age)
        +boolean test(JSArray array)
        +boolean test(JSObject object)
        +boolean test(JSObject object, JSArray message, int age, String name)
    }

    JSMethod <|.. TestJava : annotates
    QuickJSObject --> JSObject : creates_and_populates
    QuickJSObject ..> JSMethod : reads_annotation
    QuickJSObject ..> TestJava : reflects_on_methods
    QuickJSObject ..> MapFilter : uses
    QuickJSObject ..> MapCreator : uses

    class MapFilter {
    }

    class MapCreator {
    }
Loading

File-Level Changes

Change Details Files
Update QuickJSObject.setProperty(String, Class<?>) to support JSMethod names, handle classes without no-arg constructors, and use modern reflection APIs.
  • Replace deprecated clazz.newInstance() with clazz.getConstructor().newInstance() and broaden exception handling to include reflective construction failures.
  • Allow javaObj to remain null when instantiation fails and skip only non-static methods when there is no instance, enabling registration of static JS-exposed methods even without a no-arg constructor.
  • Read the JSMethod annotation on each method, derive the JS-visible method name from its value (falling back to the Java method name when blank), and register it under that name on the JSObject.
  • Refactor method registration to use a captured finalJavaObj reference and consolidate exception handling for method.invoke into a single catch block.
wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java
Suppress and tidy up generics-related warnings and formatting in QuickJSObject.convertToMap.
  • Add @SuppressWarnings("unchecked") to convertToMap to silence expected unchecked cast warnings for Map and ArrayList operations.
  • Normalize spacing in instanceof ArrayList branches to improve readability without changing behavior.
wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java
Extend JSMethod annotation to carry an explicit JS method name.
  • Add a value() element with a default empty string to JSMethod so callers can specify the JS-exposed name for annotated methods while preserving backward compatibility when no value is provided.
wrapper-java/src/main/java/com/whl/quickjs/wrapper/JSMethod.java
Adjust Android tests to validate JSMethod name-based registration rather than relying on Java method names.
  • Change TestJava methods to share the same Java method name test while using different JSMethod("...") values to explicitly define their JS-exposed names.
  • Keep the method bodies the same to ensure existing behavior is still validated under the new naming scheme.
wrapper-android/src/androidTest/java/com/whl/quickjs/wrapper/QuickJSTest.java
Add ProGuard/R8 keep rules to preserve JSMethod-annotated methods during obfuscation while still allowing renaming.
  • Add a -keepclassmembers,allowobfuscation rule for any methods annotated with @com.whl.quickjs.wrapper.JSMethod so they are retained but may be obfuscated as needed.
wrapper-android/consumer-rules.pro

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - 我已经审核了你的改动,发现有一些需要处理的问题。

  • 在 QuickJSObject.setProperty(String, Class<?> ) 中,对 jsMethod.value() 使用 String.isBlank() 可能会在较老的 Java/Android 目标上引发兼容性问题;建议改成使用兼容性更好的检查方式,例如 value == null || value.trim().isEmpty()。
  • 新增的 consumer-rules.pro 中的 ProGuard 规则(-keepclassmembers,allowobfuscation class * { @com.whl.quickjs.wrapper.JSMethod ;)似乎缺少成员块的右大括号和分号;请再次核对并修正语法,以确保 keep 规则能够真正生效。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In QuickJSObject.setProperty(String, Class<?>), using String.isBlank() on jsMethod.value() may cause compatibility issues on older Java/Android targets; consider replacing it with a more broadly supported check like value == null || value.trim().isEmpty().
- The new ProGuard rule in consumer-rules.pro (-keepclassmembers,allowobfuscation class * { @com.whl.quickjs.wrapper.JSMethod <methods>;) appears to be missing a closing brace and semicolon for the members block; please double-check and correct the syntax so the keep rule is actually applied.

## Individual Comments

### Comment 1
<location> `wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java:106-115` </location>
<code_context>
     public void setProperty(String name, Class<?> clazz) {
         Object javaObj = null;
         try {
-            javaObj = clazz.newInstance();
-        } catch (IllegalAccessException e) {
+            javaObj = clazz.getConstructor().newInstance();
+        } catch (IllegalAccessException
+                 | InstantiationException
+                 | InvocationTargetException
+                 | NoSuchMethodException e) {
             e.printStackTrace();
-        } catch (InstantiationException e) {
-            e.printStackTrace();
-        }
-
-        if (javaObj == null) {
-            throw new NullPointerException("The JavaObj cannot be null. An error occurred in newInstance!");
         }

         JSObject jsObj = context.createNewJSObject();
         Method[] methods = clazz.getMethods();
+        Object finalJavaObj = javaObj;
</code_context>

<issue_to_address>
**issue (bug_risk):** Constructor failure leads to silent dropping of instance methods with only a stack trace as signal.

With the new use of `clazz.getConstructor().newInstance()`, a missing/inaccessible no-arg constructor (or a constructor that throws) leaves `javaObj` as `null`. The loop then only exposes static methods, and the failure is effectively hidden behind `e.printStackTrace()`. This makes misconfigurations (e.g., adding only a required-args constructor) hard to detect and can silently break JS bindings. Please surface this failure more explicitly: e.g., throw a clear runtime exception, log via your standard logger and fail fast, or support a caller-provided factory when direct instantiation isn’t possible.
</issue_to_address>

### Comment 2
<location> `wrapper-android/consumer-rules.pro:5-6` </location>
<code_context>
--keep class com.whl.quickjs.**{*;}
\ No newline at end of file
+-keep class com.whl.quickjs.**{*;}
+-keepclassmembers,allowobfuscation class * {
+    @com.whl.quickjs.wrapper.JSMethod <methods>;
+}
\ No newline at end of file
</code_context>

<issue_to_address>
**issue (bug_risk):** Allowing obfuscation of @JSMethod methods can break JS APIs that rely on default method names.

Because the binding uses the annotation value or falls back to method.getName() when the value is blank, obfuscating these methods means any JS API that relies on the default (blank) annotation will now be exposed under an obfuscated name in release builds. This is only safe if all JS-exposed methods use an explicit @JSMethod("...") value. If that isn’t guaranteed, consider removing allowobfuscation for these methods or splitting the rule so that only methods with blank annotation values remain unobfuscated.
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的 Review 有帮助,欢迎分享 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English

Hey there - I've reviewed your changes and found some issues that need to be addressed.

  • In QuickJSObject.setProperty(String, Class<?>), using String.isBlank() on jsMethod.value() may cause compatibility issues on older Java/Android targets; consider replacing it with a more broadly supported check like value == null || value.trim().isEmpty().
  • The new ProGuard rule in consumer-rules.pro (-keepclassmembers,allowobfuscation class * { @com.whl.quickjs.wrapper.JSMethod ;) appears to be missing a closing brace and semicolon for the members block; please double-check and correct the syntax so the keep rule is actually applied.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In QuickJSObject.setProperty(String, Class<?>), using String.isBlank() on jsMethod.value() may cause compatibility issues on older Java/Android targets; consider replacing it with a more broadly supported check like value == null || value.trim().isEmpty().
- The new ProGuard rule in consumer-rules.pro (-keepclassmembers,allowobfuscation class * { @com.whl.quickjs.wrapper.JSMethod <methods>;) appears to be missing a closing brace and semicolon for the members block; please double-check and correct the syntax so the keep rule is actually applied.

## Individual Comments

### Comment 1
<location> `wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java:106-115` </location>
<code_context>
     public void setProperty(String name, Class<?> clazz) {
         Object javaObj = null;
         try {
-            javaObj = clazz.newInstance();
-        } catch (IllegalAccessException e) {
+            javaObj = clazz.getConstructor().newInstance();
+        } catch (IllegalAccessException
+                 | InstantiationException
+                 | InvocationTargetException
+                 | NoSuchMethodException e) {
             e.printStackTrace();
-        } catch (InstantiationException e) {
-            e.printStackTrace();
-        }
-
-        if (javaObj == null) {
-            throw new NullPointerException("The JavaObj cannot be null. An error occurred in newInstance!");
         }

         JSObject jsObj = context.createNewJSObject();
         Method[] methods = clazz.getMethods();
+        Object finalJavaObj = javaObj;
</code_context>

<issue_to_address>
**issue (bug_risk):** Constructor failure leads to silent dropping of instance methods with only a stack trace as signal.

With the new use of `clazz.getConstructor().newInstance()`, a missing/inaccessible no-arg constructor (or a constructor that throws) leaves `javaObj` as `null`. The loop then only exposes static methods, and the failure is effectively hidden behind `e.printStackTrace()`. This makes misconfigurations (e.g., adding only a required-args constructor) hard to detect and can silently break JS bindings. Please surface this failure more explicitly: e.g., throw a clear runtime exception, log via your standard logger and fail fast, or support a caller-provided factory when direct instantiation isn’t possible.
</issue_to_address>

### Comment 2
<location> `wrapper-android/consumer-rules.pro:5-6` </location>
<code_context>
--keep class com.whl.quickjs.**{*;}
\ No newline at end of file
+-keep class com.whl.quickjs.**{*;}
+-keepclassmembers,allowobfuscation class * {
+    @com.whl.quickjs.wrapper.JSMethod <methods>;
+}
\ No newline at end of file
</code_context>

<issue_to_address>
**issue (bug_risk):** Allowing obfuscation of @JSMethod methods can break JS APIs that rely on default method names.

Because the binding uses the annotation value or falls back to method.getName() when the value is blank, obfuscating these methods means any JS API that relies on the default (blank) annotation will now be exposed under an obfuscated name in release builds. This is only safe if all JS-exposed methods use an explicit @JSMethod("...") value. If that isn’t guaranteed, consider removing allowobfuscation for these methods or splitting the rule so that only methods with blank annotation values remain unobfuscated.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 106 to 115
try {
javaObj = clazz.newInstance();
} catch (IllegalAccessException e) {
javaObj = clazz.getConstructor().newInstance();
} catch (IllegalAccessException
| InstantiationException
| InvocationTargetException
| NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}

if (javaObj == null) {
throw new NullPointerException("The JavaObj cannot be null. An error occurred in newInstance!");
}

JSObject jsObj = context.createNewJSObject();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 构造函数失败时,只打印堆栈而没有进一步处理,会导致实例方法被静默忽略。

在改为使用 clazz.getConstructor().newInstance() 之后,如果没有无参构造函数、无参构造不可访问,或者构造函数本身抛异常,javaObj 就会保持为 null。后续循环只会暴露静态方法,这个失败则被隐藏在 e.printStackTrace() 中。这样会让配置错误(例如只添加了带必填参数的构造函数)很难被发现,并且会在不明显的情况下破坏 JS 绑定。请更明确地暴露这类失败:例如抛出清晰的运行时异常、通过你们的标准日志组件记录并尽早失败,或者在无法直接实例化时支持调用方提供工厂方法。

Original comment in English

issue (bug_risk): Constructor failure leads to silent dropping of instance methods with only a stack trace as signal.

With the new use of clazz.getConstructor().newInstance(), a missing/inaccessible no-arg constructor (or a constructor that throws) leaves javaObj as null. The loop then only exposes static methods, and the failure is effectively hidden behind e.printStackTrace(). This makes misconfigurations (e.g., adding only a required-args constructor) hard to detect and can silently break JS bindings. Please surface this failure more explicitly: e.g., throw a clear runtime exception, log via your standard logger and fail fast, or support a caller-provided factory when direct instantiation isn’t possible.

Comment on lines +5 to +6
-keepclassmembers,allowobfuscation class * {
@com.whl.quickjs.wrapper.JSMethod <methods>;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 允许对带有 @JSmethod 的方法进行混淆,可能会破坏依赖默认方法名的 JS API。

当前绑定逻辑会使用注解中的 value,如果 value 为空则回退到 method.getName()。如果这些方法被混淆,那么任何依赖默认(空)注解值的 JS API 在发布构建中就会暴露为混淆后的方法名。仅当所有暴露给 JS 的方法都显式指定了 @JSmethod("...") 的值时,这才是安全的。如果无法保证这一点,建议对这些方法去掉 allowobfuscation,或者拆分规则,只对注解值为空的 @JSmethod 方法保持不混淆。

Original comment in English

issue (bug_risk): Allowing obfuscation of @JSmethod methods can break JS APIs that rely on default method names.

Because the binding uses the annotation value or falls back to method.getName() when the value is blank, obfuscating these methods means any JS API that relies on the default (blank) annotation will now be exposed under an obfuscated name in release builds. This is only safe if all JS-exposed methods use an explicit @JSmethod("...") value. If that isn’t guaranteed, consider removing allowobfuscation for these methods or splitting the rule so that only methods with blank annotation values remain unobfuscated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant