Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue converting proxied v8 java array to java object #351

Closed
narsinallamilli opened this issue Jun 6, 2024 · 8 comments · Fixed by #352
Closed

issue converting proxied v8 java array to java object #351

narsinallamilli opened this issue Jun 6, 2024 · 8 comments · Fixed by #352
Assignees
Labels
enhancement New feature or request

Comments

@narsinallamilli
Copy link

narsinallamilli commented Jun 6, 2024

Proxied Java V8 object is manipulated in javascript to set array field but it doesn't set. However List works.

`
public class Apple {
private String[] appleColors;

public String[] getAppleColors() {
    return appleColors;
}

public void setAppleColors(String[] appleColors) {
    this.appleColors = appleColors;
}

}

//kotlin test
@test
fun testSamp() {
try {
val javetV8Engine = javetEngineV8Pool.getEngine()
val javetV8Runtime = javetV8Engine.v8Runtime
val javetBridgeConverter = JavetBridgeConverter()
javetBridgeConverter.config.setReflectionObjectFactory(JavetReflectionObjectFactory.instance);
javetV8Runtime.setConverter(javetBridgeConverter)
val apple = Apple()
javetV8Runtime.globalObject.set("apple", apple);
javetV8Runtime.getExecutor("""
apple.appleColors = ['a']
""".trimIndent()).executeVoid();
println(apple.appleColors)
javetV8Runtime.lowMemoryNotification()
} catch (javetException: JavetException) {
println(javetException)
}
}
Above test outputs
null
if the appleColors is changed to List<String> the output is
[a]
`

@caoccao
Copy link
Owner

caoccao commented Jun 7, 2024

This is the expected behavior: Native JS array is always converted to List<Object>.

@narsinallamilli
Copy link
Author

narsinallamilli commented Jun 7, 2024

@caoccao the object classes are of third party libs, so there is no way I can change from Array to List, isn't there any workaround?
Do you mean List is set to Object[] type?

@caoccao
Copy link
Owner

caoccao commented Jun 7, 2024

I think you may inject a JS function as follows.

  1. Write a Java method (e.g. list2Array) that converts List<Object> to Object[].
  2. Inject that Java method as a JS function list2Array.
  3. Call external.acceptObjectArray(list2Array(nativeJSArray)).

@caoccao
Copy link
Owner

caoccao commented Jun 7, 2024

That might be possible, and indirect. I'll investigate that later. Please stay in tune.

@narsinallamilli
Copy link
Author

Thank you, I guess this should be handled by JavetProxyPluginArray.

caoccao added a commit that referenced this issue Jun 7, 2024
@caoccao caoccao self-assigned this Jun 7, 2024
@caoccao caoccao added the enhancement New feature or request label Jun 7, 2024
@caoccao
Copy link
Owner

caoccao commented Jun 7, 2024

Please check commit 1 and commit 2 out. By calling Object.seal(), JS array will be converted to Object[] instead of List<Object>. It's disabled by default, but can be turned on. This feature will be included in the next release. Please let me know if you have any questions. By the way, thank you for the donation!

v8Runtime.getConverter().getConfig().setSealedEnabled(true);
assertArrayEquals(
        new Object[]{1, 2},
        v8Runtime.getExecutor("Object.seal([1,2])").executeObject());
assertArrayEquals(
        new Object[]{"a", "b"},
        v8Runtime.getExecutor("Object.seal(['a','b'])").executeObject());
assertArrayEquals(
        new Object[]{},
        v8Runtime.getExecutor("Object.seal([])").executeObject());

@caoccao caoccao linked a pull request Jun 9, 2024 that will close this issue
@narsinallamilli
Copy link
Author

narsinallamilli commented Jun 9, 2024

@caoccao

I tested out this feature, however I see the the java array field is not set.

public class Apple {
    private String[] appleColors;


    public String[] getAppleColors() {
        return appleColors;
    }

    public void setAppleColors(String[] appleColors) {
        this.appleColors = appleColors;
    }
}

@Test
    fun testSamp() = try {
        val javetV8Engine = javetEngineV8Pool.getEngine()
        val javetV8Runtime = javetV8Engine.v8Runtime
        val javetBridgeConverter = JavetBridgeConverter()
        javetBridgeConverter.config.setReflectionObjectFactory(JavetReflectionObjectFactory.instance);
        javetBridgeConverter.config.setSealedEnabled(true)
        javetV8Runtime.converter = javetBridgeConverter
        val apple = Apple()
        javetV8Runtime.globalObject.set("apple", apple);
        javetV8Runtime.getExecutor("""
            apple.appleColors = Object.seal(['narsi'])
        """.trimIndent()).executeVoid()
        println(apple.appleColors)
        javetV8Runtime.lowMemoryNotification()

    } catch (javetException: JavetException) {
        println(javetException)

    }

output is
null

However if I change appleColors type to Object[] its works.

@caoccao
Copy link
Owner

caoccao commented Jun 9, 2024

That is unfortunate. It's hard to cast Object[] to any other types of array, because:

  1. The converter doesn't know the target type.
  2. Even if the target type is known, the converter has to go over every element to validate the type. That's O(N) and impacts the performance considerably.

In this case, I suggest you implement your own proxy plugin. Please let me know if you have any questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants