Closed McMurat closed 10 months ago
Can you provide the code that reproduces the issue?
public interface JsTool extends JSObject { }
public class JsToolImpl implements JsTool { }
Then in some class with an exported getTools() method:
public JsTool[] getTools() {
JsTool[] t = new JsTool[1];
t[0] = new JsToolImpl();
return t;
}
Calling this in JS will return [ undefined ].
@McMurat I wrote following test:
@Test
public void createArrayAndReturnToJS() {
assertEquals("23,42", concatFoo(() -> new J[] {
() -> 23,
() -> 42
}));
}
@JSBody(params = "supplier", script = "let array = supplier.get(); "
+ "return array[0].foo() + ',' + array[1].foo();")
private static native String concatFoo(JArraySupplier supplier);
interface JArraySupplier extends JSObject {
J[] get();
}
interface J extends JSObject {
int foo();
}
and it passes. What am I doing wrong?
@konsoletyper Thank you very much for your feedback.
Okay, that's interesting that it works when using the JSBody annotation here. I created a minimal example project to reproduce the issue for you:
package org.example;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
public class Main {
@JSBody(params = {"provider"}, script = "initializeContent(provider);")
static native void initializeContent(JsProvider provider);
public static void main(String[] args) {
initializeContent(new JsProviderImpl());
}
}
class JsProviderImpl implements JsProvider {
@Override
public JsTool[] getTools() {
return new JsTool[] { new JsToolImpl() };
}
}
interface JsProvider extends JSObject {
JsTool[] getTools();
}
interface JsTool extends JSObject {}
class JsToolImpl implements JsTool {}
and here is the HTML/JS:
<html>
<head>
<title></title>
<script src="build/generated/teavm/js/TestTeaVM.js"></script>
<script>
window.initializeContent = (provider) => {
const tools = provider.getTools();
console.log(tools);
};
main();
</script>
</head>
<body></body>
</html>
and the gradle build.gradle (groovy):
plugins {
id 'java'
id "war"
id "org.teavm" version "0.9.0"
}
group = 'org.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
teavm.js {
addedToWebApp = false
obfuscated = true
mainClass = "org.example.Main"
entryPointName = "main"
outOfProcess = true
}
dependencies {
implementation teavm.libs.jso
}
When running this example in the browser, you will get [undefined]
in the console. Using the developer tools will also confirm that this is indeed the value undefined and not just a string "undefined". This issue ís already present in 0.9.0, so i am stuck with 0.8.1 at the moment.
The difference between your test and mine was in using lambdas. This should not be the case, but somewhere after 0.9.0 I broken mechanism that processes invokedynamics before running JSO transformations. With classes instead of lambdas I can reproduce this issue in my tests.
Your commit "JS: fix unwrapping JS objects implemented in Java" fixed the issue for me. But i noticed that the compiled js file size in obfuscated mode is nearly 2x larger than the one which TeaVM 0.8.1 (or 0.9.0 ) was generating. Are there any recent changes which could cause this?
But i noticed that the compiled js file size in obfuscated mode is nearly 2x larger than the one which TeaVM 0.8.1 (or 0.9.0 ) was generating
I don't know. If there was any way for me to reproduce it, I could try to find the reason.
@McMurat I'm closing this issue, since I fixed it. If you have a separate issue with code size, you can create a new issue. There never was intention to make generated code bigger. Even more: according to my tests, TeaVM from master produces smaller obfuscated code compared to 0.9.0. It can be anything, without any details about your project I can't tell what's wrong. You can try to build without obfuscation and see what's the difference.
@konsoletyper thank you very much for your help! I will look into it and open a new issue as soon as I have enough evidence to describe what's going on.
There is a regression in 10.0.0-SNAPSHOT: There is an issue when an JSObject type array is returned in a JSO interface called from JavaScript. TeaVM calls otji_JS_wrap on such arrays before returning, which will otji_JSWrapper_unwrap each element, but as the $js field is not present for JSObject types, the return value is an array of many undefined values: [undefined, undefined, ...]
This happened to me after upgrading from version 8.1.0.