From aa4207031121e25aabc5d32bb44392e068f9d77e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 27 Sep 2015 18:12:52 +0300 Subject: [PATCH] Add javadocs --- .../src/main/java/org/teavm/jso/JSBody.java | 96 ++++++++++++++++++- .../main/java/org/teavm/jso/JSIndexer.java | 12 +-- .../src/main/java/org/teavm/jso/JSMethod.java | 9 +- .../src/main/java/org/teavm/jso/JSObject.java | 39 ++++++++ .../main/java/org/teavm/jso/JSProperty.java | 12 +-- .../java/org/teavm/jso/browser/Screen.java | 4 + .../java/org/teavm/jso/browser/Storage.java | 8 ++ .../org/teavm/jso/dom/html/HTMLDocument.java | 5 + .../main/java/org/teavm/jso/package-info.java | 62 ++++++++++++ 9 files changed, 230 insertions(+), 17 deletions(-) create mode 100644 teavm-jso/src/main/java/org/teavm/jso/package-info.java diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSBody.java b/teavm-jso/src/main/java/org/teavm/jso/JSBody.java index 3a893979d..fae89add3 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JSBody.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JSBody.java @@ -23,10 +23,102 @@ import java.lang.annotation.Target; /** *

Indicates that method is to have native JavaScript implementation. * Method only can take and return primitive values and {@link JSObject}s. - * JSBody script can't call Java methods, but you can pass callbacks wrapped into {@link JSFunctor}. * Note that unless method is static, it must belong to class that implements {@link JSObject}. * If applied to non-native method, original Java body will be overwritten by JavaScript.

* + *

Example:

+ * + *
+ *    {@literal @}JSBody(params = { "message" }, script = "window.alert(message);")
+ *    public static native void alert(String message);
+ * 
+ * + *

The motivation for params field is the following: Java can avoid inclusion of parameter names + * into bytecode (for example, you can compile with no debug information). In order the JSO implementation + * with no access to original source code could work properly, JSO forces developer to specify parameter + * names explicitly.

+ * + * + *

Type conversion

+ * + *

A method marked with JSBody annotation is restricted to take parameters of allowed types. + * A type is allowed if it is either:

+ * + * + * + *

Java primitives are converted to corresponding JavaScript primitives, except for char, + * which does not have corresponding JavaScript representation. JSO implementation converts Java chars to JavaScript + * numbers, and expects a JavaScript number when converting to a Java character.

+ * + *

Java arrays are converted to JavaScript arrays and vice versa. Arrays are passed by copy.

+ * + *

java.lang.String objects are converted to JavaScript string.

+ * + *

Overlay types are passed as is.

+ * + * + *

Passing functions

+ * + *

Sometimes JavaScript functions expect you to pass a function as a parameter value. JSO allows you to + * pass special form of overlay objects as functions. These overlay objects must be interfaces with exactly one + * parameter and marked with {@link JSFunctor} annotation. Example:

+ * + *
+ *    {@literal @}JSFunctor
+ *    interface TimerHandler extends JSObject {
+ *        void onTimer();
+ *    }
+ *
+ *    {@literal @}JSBody(params = { "handler", "delay" }, script = "return window.setTimeout(handler, delay);")
+ *    public static native int setTimeout(TimerHandler handler, int delay);
+ * 
+ * + * + *

Calling Java methods from JSBody

+ * + *

You can call Java methods from JSBody script. You should use the following notation: + * + *

javaMethods.get('method reference').invoke([instance, ] param1 [, param2 ...]);
+ * + *

The method reference has the following format:

+ * + *
+ * (PackageName .)* ClassName . MethodName MethodDescriptor
+ * 
+ * + *

where

+ * + *
+ * PackageName = Identifier
+ * ClassName = Identifier
+ * MethodName = Identifier
+ * MethodDescriptor = ( TypeDescriptor ) V)
+ *                         | ( TypeDescriptor ) TypeDescriptor
+ * TypeDescriptor = Z | B | C | S | I | J | F | D
+ *                | L QualifiedClassName ; | [ TypeDescriptor.
+ * 
+ * + *

that is similar to method + * descriptors augmented with class and method names.

+ * + *

For example,

+ * + *
+ *    {@literal @}JSBody(params = { "message" }, script = "javaMethods.get('org.teavm.jso.browser.Window"
+ *            + ".alert(Ljava/lang/String;)V').invoke(message);")
+ *    public static native void alertCaller(String message);
+ * 
+ * + *

Note that get method must take string constant. Dynamic resolution of Java methods may + * not work on some platforms.

+ * + * @see JSObject * @author Alexey Andreev */ @Retention(RetentionPolicy.RUNTIME) @@ -38,7 +130,7 @@ public @interface JSBody { String[] params(); /** - *

JavaScript implementation.

+ *

JavaScript code.

*/ String script(); } diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSIndexer.java b/teavm-jso/src/main/java/org/teavm/jso/JSIndexer.java index 7f07f22ec..fd94230b7 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JSIndexer.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JSIndexer.java @@ -26,16 +26,16 @@ import java.lang.annotation.Target; *

Getter indexer is a method that returns value and takes exactly one parameter. In * this case annotation is equivalent to this:

* - *
{@code
- * @JSBody(params = "index", script = "return this[index];")
- * }
+ *
+ * {@literal @}JSBody(params = "index", script = "return this[index];")
+ * 
* *

Setter indexer is a method that takes two parameter and does not return any value. * Ins this case annotation is equivalent to the following:

* - *
{@code
- * @JSBody(params = { "index", "value" }, script = "this[index] = value;")
- * }
+ *
+ * {@literal @}JSBody(params = { "index", "value" }, script = "this[index] = value;")
+ * 
* * @author Alexey Andreev */ diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSMethod.java b/teavm-jso/src/main/java/org/teavm/jso/JSMethod.java index 9029492ec..de2abc5af 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JSMethod.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JSMethod.java @@ -23,13 +23,16 @@ import java.lang.annotation.Target; /** *

Marks abstract member method as a JavaScript method. This is equivalent to the following:

* - *
{@code
- * @JSBody(params = ..., script = "return new this.methodName(...);")
- * }
+ *
+ * {@literal @}JSBody(params = ..., script = "return new this.methodName(...);")
+ * 
* *

where methodName is method's name by default or a name, directly specified by * this annotation.

* + *

JSMethod can be avoided. This means that if you define abstract method on overlay class or interface, + * and don't specify any annotations, this method is treated as marked by JSMethod.

+ * * @author Alexey Andreev */ @Retention(RetentionPolicy.RUNTIME) diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSObject.java b/teavm-jso/src/main/java/org/teavm/jso/JSObject.java index 66d0841f4..a3f5d74b6 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JSObject.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JSObject.java @@ -16,7 +16,46 @@ package org.teavm.jso; /** + *

The base type for all overlay types. Overlay types are Java types that represent JavaScript object, + * and therefore can be passed to and from JavaScript code.

* + *

An overlay type is an abstract class or an interface that extends/implements JSObject. An overlay type + * has following restrictions:

+ * + * + * + *

To simplify creation of overlay objects, you can use shortcut annotations instead of {@link JSBody}: + * {@link JSMethod}, {@link JSProperty} and {@link JSIndexer}.

+ * + *

Example:

+ * + *
+ * public abstract class Int32Array implements JSObject {
+ *     {@literal @}JSBody(params = {}, script = "return this.length;")
+ *     public native int getLength();
+ *
+ *     {@literal @}JSIndexer
+ *     public abstract int get(int index);
+ *
+ *     {@literal @}JSIndexer
+ *     public abstract void set(int index, int value);
+ *
+ *     {@literal @}JSBody(params = "length", script = "return new Int32Array(length);")
+ *     public static native ArrayBuffer create(int length);
+ *
+ *     {@literal @}JSBody(params = "buffer", script = "return new Int32Array(buffer);")
+ *     public static native ArrayBuffer create(ArrayBuffer buffer);
+ *
+ *     {@literal @}JSBody(params = { "buffer", "offset", "length" },
+ *             script = "return new Int32Array(buffer, offset, length);")
+ *     public static native ArrayBuffer create(ArrayBuffer buffer, int offset, int length);
+ * }
+ * 
+ * + * @see JSBody * @author Alexey Andreev */ public interface JSObject { diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSProperty.java b/teavm-jso/src/main/java/org/teavm/jso/JSProperty.java index 7cdfc6b24..90a4d74d3 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JSProperty.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JSProperty.java @@ -27,17 +27,17 @@ import java.lang.annotation.Target; * (or is in case of boolean getter). It must not take any parameters and must return a value. * For getter annotation is equivalent to the following:

* - *
{@code
- * @JSBody(params = {}, script = "return this.propertyName;")
- * }
+ *
+ * {@literal @}JSBody(params = {}, script = "return this.propertyName;")
+ * 
* *

Setter's name must conform the Java Beans specification, i.e. start with set prefix * It must take exactly one parameter and must not return a value. * For setter annotation is equivalent to the following:

* - *
{@code
- * @JSBody(params = "value", script = "this.propertyName = value;")
- * }
+ *
+ * {@literal @}JSBody(params = "value", script = "this.propertyName = value;")
+ * 
* *

By default propertyName is calculated from method's name according to Java Beans specification, * otherwise the name specified by annotation is taken.

diff --git a/teavm-jso/src/main/java/org/teavm/jso/browser/Screen.java b/teavm-jso/src/main/java/org/teavm/jso/browser/Screen.java index 904fe80b1..e0e60cd5a 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/browser/Screen.java +++ b/teavm-jso/src/main/java/org/teavm/jso/browser/Screen.java @@ -37,4 +37,8 @@ public interface Screen extends JSObject { @JSProperty int getColorDepth(); + + static Screen current() { + return Window.current().getScreen(); + } } diff --git a/teavm-jso/src/main/java/org/teavm/jso/browser/Storage.java b/teavm-jso/src/main/java/org/teavm/jso/browser/Storage.java index 2c66f1abe..5bb2d7518 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/browser/Storage.java +++ b/teavm-jso/src/main/java/org/teavm/jso/browser/Storage.java @@ -35,4 +35,12 @@ public abstract class Storage implements JSObject { public abstract void removeItem(String key); public abstract void clear(); + + public static Storage getSessionStorage() { + return Window.current().getSessionStorage(); + } + + public static Storage getLocalStorage() { + return Window.current().getLocalStorage(); + } } diff --git a/teavm-jso/src/main/java/org/teavm/jso/dom/html/HTMLDocument.java b/teavm-jso/src/main/java/org/teavm/jso/dom/html/HTMLDocument.java index 24b6e0e12..b14474148 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/dom/html/HTMLDocument.java +++ b/teavm-jso/src/main/java/org/teavm/jso/dom/html/HTMLDocument.java @@ -16,6 +16,7 @@ package org.teavm.jso.dom.html; import org.teavm.jso.JSProperty; +import org.teavm.jso.browser.Window; import org.teavm.jso.dom.events.EventTarget; import org.teavm.jso.dom.xml.Document; @@ -45,4 +46,8 @@ public interface HTMLDocument extends Document, EventTarget { @JSProperty int getScrollTop(); + + static HTMLDocument current() { + return Window.current().getDocument(); + } } diff --git a/teavm-jso/src/main/java/org/teavm/jso/package-info.java b/teavm-jso/src/main/java/org/teavm/jso/package-info.java new file mode 100644 index 000000000..c51b633a0 --- /dev/null +++ b/teavm-jso/src/main/java/org/teavm/jso/package-info.java @@ -0,0 +1,62 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

JSO is a specification that describes how Java platform can interact with JavaScript code. + * There are two parts of this specification: JSO core, that defines mapping between Java and JavaScript + * objects and JSO APIs, that define Java wrappers around various JavaScript and HTML5 APIs. + * The latter part is simply application of the former one. JSO implementor must implement only the first part, + * and it may ignore the second part, since it should work properly this way. However, it may implement + * some of the APIs itself in some cases, for example to improve performance.

+ * + *

The first part of JSO is directly in this package. All subpackages declare the second part of JSO.

+ * + *

JSO does not do anything itself. It is only a set of interfaces that define interaction. + * To use JSO in your application, you should include one of its implementations, that may exist for + * different platforms, such as JVM, RoboVM, Android, TeaVM or bck2brwsr.

+ * + * + *

JSBody annotation

+ * + *

The easiest way to invoke JavaScript code from Java is to define native method marked with the + * {@link org.teavm.jso.JSBody} annotation that contains the JavaScript code.

+ * + *

Example:

+ * + *
+ *    {@literal @}JSBody(params = { "message" }, script = "window.alert(message);")
+ *    public static native void alert(String message);
+ * 
+ * + * + *

Overlay types

+ * + *

Often you need to pass complex values between Java and JavaScript. Primitives are usually insufficient for + * this purposed. JSO comes with concept of overlay types, that are usable from both Java and JavaScript. + * For detailed description, see {@link org.teavm.jso.JSObject} interface.

+ * + *

When wrapping JavaScript APIs in Java classes, you usually write boilerplate {@link org.teavm.jso.JSBody} like + * this:

+ * + *
+ * {@literal @}JSBody(params = "newChild", script = "return this.appendChild(newChild);")
+ * Node appendChild(Node newChild);
+ * 
+ * + *

JSO offers shortcut annotations that help to avoid such boilerplate. They are: {@link org.teavm.jso.JSMethod}, + * {@link org.teavm.jso.JSProperty}, {@link org.teavm.jso.JSIndexer}. + * + */ +package org.teavm.jso;