I'm implementing this and it works well but the prototype attribute is serving a very similar purpose to name and namespace attribute. The attribute is simple there because we cannot differentiate if the type represents a type that is already available in native code or if the type is introduced by java.
Similarly, we hit such ambiguity for interfaces. If you have a JsType interface, it is not clear that if such type is introduced by the app or if it is just a stub for existing type that is already available natively. These affects several stuff like how instanceof works (which is quite problematic) or if we should generate any code for the interface or not (which is more problematic in j2cl).
So the solution we came up with is to remove the prototype attribute and instead introduce isNative attribute. When the attribute is set to true, it basically tells the compiler to assume that the type already exists in native code (similar to the native keyword available for methods).
The prototype will be equivalent to the fully qualified javascript name (which is calculated based on JsType name/namespace, JsPackage etc). So above code becomes:
@JsType(namepace=GLOBAL, name="Object", isNative=true)
public class JsObject {
public static native String[] keys(JsObject obj);
public native boolean hasOwnProperty(String prop);
}
or if the package-info.java already has @JsPackage(name=GLOBAL), it could be re-written as
@JsType(isNative=true)
public class Object {
public static native String[] keys(Object obj);
public native boolean hasOwnProperty(String prop);
}
Based on this change, we also redefining how the instanceof works for native JsTypes.
If the native type is concrete, the instanceof will be generated in JavaScript as
obj instanceof <fully_qualified_js_name>
If the native type is an interface, the instanceof operation will always return true as it simply represents a loose javascript contract. [2]
For all non-native JsTypes, regular java instanceof semantic will apply. That means, for example, if you do (jso instanceof SomeJsTypeInterface), it will return false (earlier it would have returned true).
That's all for now. As always, feel free to send any comments and let me know what you think.
Cheers,
Goktug.
PS: Note that due this change, when the new annotations introduced, you will need to add isNative=true for all interfaces that is abstracting some javascript API. If you were using it for just generating unobfuscated names for java APIs then you can keep it as it is.
[2] We may later provide a way for developers to customize this behavior, like providing their own method to be called for instanceof.