Skip to content

Commit

Permalink
Cleanup/update javadoc for jsinterop annotations.
Browse files Browse the repository at this point in the history
Change-Id: I3f64fab263d42705838a557021d5bd67755be7db
Review-Link: https://gwt-review.googlesource.com/#/c/17124/
  • Loading branch information
gkdn committed Sep 30, 2016
1 parent a61de06 commit 030a9a2
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 67 deletions.
12 changes: 7 additions & 5 deletions user/src/jsinterop/annotations/JsConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
import java.lang.annotation.Target;

/**
* JsConstructor marks a constructor that is the constructor function for the JavaScript
* type.
* <p>
* Note that there can only be one JsConstructor in a type; all other constructors must delegate
* to it.
* JsConstructor marks a constructor that will be translated into a JavaScript constructor function.
*
* <p>Due to ES6 class semantics, for non-native JsTypes only one JsConstructor is allowed to exist
* in the type which becomes the 'primary constructor'. All other constructors in the type must
* delegate to it. Subclasses of a type with JsConstructor should follow the same restriction with
* the exception that the primary constructor is not required to be marked as JsConstructor but
* still need to delegate to super primary constructor.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
Expand Down
32 changes: 18 additions & 14 deletions user/src/jsinterop/annotations/JsFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,26 @@
import java.lang.annotation.Target;

/**
* Marks a type containing a Single Abstract Method (SAM) as eligible for automatic conversion into
* a JavaScript function.
* <p>
* This enables lambda expressions to be passed directly to JavaScript as callbacks.
* <p>
* However there are some additional limitations that are imposed to make this practical and
* efficient:
* <li>A class may not implement more than one @JsFunction type. This restriction allows the
* compiler to construct a one-to-one mapping between the Java class and the generated JavaScript
* function and preserve referential equality.
* JsFunction marks a functional interface as being the definition of a JavaScript function.
*
* <p>There are some limitations exists on JsFunction to make them practical and efficient:
*
* <ul>
* <li>A JsFunction interface cannot extend any other interfaces.
* <li>A JsFunction interface cannot have defender methods.
* <li>A class that implements a @JsFunction type (directly or indirectly) cannot be a @JsType.
* <p>
* As a best practice, we also recommend marking @JsFunction interfaces with @FunctionalInterface
* <li>A class may not implement more than one JsFunction interface.
* <li>A class that implements a JsFunction type cannot be a {@link JsType} (directly or
* indirectly).
* <li>Fields and defender methods of the interfaces should be marked with {@link JsOverlay} and
* cannot be overridden by the implementations.
* </ul>
*
* <p>As a best practice, we also recommend marking JsFunction interfaces with FunctionalInterface
* to get improved checking in IDEs.
*
* <p><b>Instanceof and Castability:</b>
*
* <p>Instanceof and casting for JsFunction is effectively a JavaScript <tt>'typeof'</tt> check to
* determine if the instance is a function.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
Expand Down
9 changes: 5 additions & 4 deletions user/src/jsinterop/annotations/JsIgnore.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@

/**
* Marks a member to be ignored for JsInterop purposes.
* <p>
* This is particularly useful when {@link JsType} applied to a class and some members are needed to
* be ignored as they don't comply with restrictions (e.g. overloading) or shouldn't be exported.
*
* <p>This is particularly useful when {@link JsType} is applied to a class and some members need
* to be ignored as they don't comply with restrictions (e.g. overloading) or shouldn't be exported
* for other reasons.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface JsIgnore {
}
35 changes: 28 additions & 7 deletions user/src/jsinterop/annotations/JsOverlay.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,34 @@
import java.lang.annotation.Target;

/**
* JsOverlay is used to add new helper APIs to existing JavaScript types. This is achieved by adding
* the new method/field to a @JsType(isNative=true) and marking it with this annotation.
* <p>
* Note that the JsOverlay methods cannot be called from JavaScript, cannot override any existing
* methods and needs to be marked as final. This is because underneath, the original type is not
* modified and the method is simply turned into a static dispatch. Similarly, JsOverlay fields can
* only be compile time constants.
* JsOverlay is used to enhance Java API of the native JsTypes and JsFunctions so richer and more
* Java friendly abstractions could be provided.
*
* <pre>
* {@literal @}JsType(isNative=true)
* class Person {
* {@literal @}JsOverlay
* private static final Person NO_BODY = new Person();
*
* private String name;
* private String lastName;
*
* {@literal @}JsOverlay
* public String getFullName() {
* return (name + " " + lastName).trim();
* }
* }</pre>
*
* <p>Note that:
*
* <ul>
* <li> JsOverlay methods cannot override any existing methods.
* <li> JsOverlay methods should be effectively final.
* <li> JsOverlay methods cannot be called from JavaScript
* </ul>
*
* These restrictions are in place to avoid polymorphism because underneath the original type is not
* modified and the overlay fields/methods are simply turned into static dispatches.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
Expand Down
2 changes: 1 addition & 1 deletion user/src/jsinterop/annotations/JsPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
@Documented
public @interface JsPackage {
/**
* Namespace for the global JavaScript object.
* Namespace of the global JavaScript object.
*/
String GLOBAL = "<global>";

Expand Down
29 changes: 16 additions & 13 deletions user/src/jsinterop/annotations/JsProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@
/**
* JsProperty marks a field or method that is translated directly into a JavaScript property
* preserving its name.
* <p>
* If it is applied to a method, it will be treated as a property accessor. As a result, instead of
* translating method calls to JsProperty methods as method calls in JS, they will be translated as
* property lookups. When a JsProperty method implemented by a Java class, such methods will be
* generated as custom property setter and getter in JavaScript, hence the property access will
* trigger the execution of the matching getter or setter methods.
* <p>
* JsProperty follows JavaBean style naming convention to extract the default property name. If the
* JavaBean convention is not followed, the name should be set explicitly. For example:
*
* <p>If it is applied to a method, it will be treated as a property accessor. As a result, instead
* of translating method calls to JsProperty methods as method calls in JS, they will be translated
* as property lookups. When a JsProperty method implemented by a Java class, such methods will be
* generated as property accessor in JavaScript, hence the property access will trigger the
* execution of the matching getter or setter methods.
*
* <p>JsProperty follows JavaBean style naming convention to extract the default property name. If
* the JavaBean convention is not followed, the name should be set explicitly. For example:
*
* <ul>
* <li> {@code @JsProperty getX()} or {@code @JsProperty isX()} translates as <tt>this.x</tt>
* <li> {@code @JsProperty setX(int y)} translates as <tt>this.x=y</tt>
* </ul>
* <p>
* Note: In JavaScript, instance members are defined on the prototype and class members are defined
* on the constructor function of the type.
*
* <p>Note: In JavaScript, instance members are defined on the prototype and class members are
* defined on the constructor function of the type which mimics ES6 class style.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
Expand All @@ -48,9 +49,11 @@

/**
* Customizes the name of the member in generated JavaScript. If none is provided;
* <p>
*
* <ul>
* <li>if it is field, the simple Java name will be used.
* <li>if it is a method, the name will be generated based on JavaBean conventions.
* </ul>
*/
String name() default "<auto>";

Expand Down
52 changes: 29 additions & 23 deletions user/src/jsinterop/annotations/JsType.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,37 @@
* JsType is used to describe the JavaScript API of an object, either one that already exists from
* the external JavaScript environment, or one that will be accessible from the external JavaScript
* environment.
* <p>
* Marking an object with JsType is similar to marking each public member of the class with
*
* <p>Marking an object with JsType is similar to marking each public member of the class with
* {@link JsProperty}/{@link JsMethod}/{@link JsConstructor} respectively. In order for this to work
* correctly the JavaScript name needs to be unique for each member. Some unobvious ways to cause
* name collisions are;
* <p>
* <li>Having method or constructor overloads.
* <li>Using the same name for a method and a field.
* <li>Shadowing a field from parent.
* <p>
* A name collision needs to be avoided by providing a custom name (e.g. {@link JsProperty#name}) or
* by completely ignoring the member using {@link JsIgnore}.
* <p>
* If the JsType is marked as "native", then the type is considered as stub for an existing class
* that is available in native JavaScript. If it is concrete type, the subclass will use the
* designated type as super type opposed to the ordinary one (e.g. java.lang.Object).
* <p>
* Instanceof and Castability:
* <p>
* If the JsTypes is native then the generated code will try to mimic Javascript semantics.
* <li>If it is concrete native JsType then cast checks and instanceof checks will be delegated to
* the native JavaScript instanceof operator.
* <li>If it is an interface and marked as native, no checks will be performed.
* <p>
* All non-native JsTypes will follow regular Java semantics in terms of castability.
* name collisions are:
*
* <ul>
* <li>having method or constructor overloads
* <li>using the same name for a method and a field
* <li>shadowing a field from parent
* </ul>
*
* <p>Name collisions must be avoided by providing custom names (e.g. {@link JsProperty#name}) or by
* ignoring members using {@link JsIgnore}.
*
* <p>If the JsType is marked as "native" via {@link #isNative}, then the type is considered a stub
* for an existing class that is available in native JavaScript. Unlike non-native JsTypes, all
* members are considered {@link JsProperty}/{@link JsMethod}/{@link JsConstructor} unless they are
* explicitly marked with {@link JsOverlay}.
*
* <p><b>Instanceof and Castability:</b>
*
* <p>If the JsType is native, the generated code will try to mimic Javascript semantics.
*
* <p>All non-native JsTypes will follow regular Java semantics in terms of castability.
*
* <ul>
* <li>For concrete native JsTypes, cast checks and instanceof checks will be delegated to the
* native JavaScript instanceof operator.
* <li>For interface native JsTypes, instanceof is forbidden and casts to them always succeed.
* </ul>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
Expand Down

0 comments on commit 030a9a2

Please sign in to comment.