Support for calling static Java methods from JavaScript
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 11 Jul 2013 21:26:28 +0200
changeset 191f48398ae1418
parent 190 c53532068a03
child 192 db8dcc30da25
Support for calling static Java methods from JavaScript
boot/src/main/java/net/java/html/js/JavaScriptBody.java
boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java
boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java
boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java
boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java
     1.1 --- a/boot/src/main/java/net/java/html/js/JavaScriptBody.java	Thu Jul 11 21:10:18 2013 +0200
     1.2 +++ b/boot/src/main/java/net/java/html/js/JavaScriptBody.java	Thu Jul 11 21:26:28 2013 +0200
     1.3 @@ -59,6 +59,8 @@
     1.4       * This is the syntax one can use to call <code>run()</code> 
     1.5       * method of {@link Runnable}:
     1.6       * <pre>r.@java.lang.Runnable::run()()</pre>.
     1.7 +     * One can also call static methods. Just use:
     1.8 +     * <pre>var ten = @java.lang.Integer::parseInt(Ljava/lang/String;)("10")</pre>
     1.9       * 
    1.10       * @return true, if the script should be scanned for special callback
    1.11       *   syntax
     2.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Thu Jul 11 21:10:18 2013 +0200
     2.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Thu Jul 11 21:26:28 2013 +0200
     2.3 @@ -82,7 +82,10 @@
     2.4              ) {
     2.5                  StringBuilder sb = new StringBuilder();
     2.6                  sb.append("vm.").append(mangle(fqn, method, params));
     2.7 -                sb.append("(").append(ident);
     2.8 +                sb.append("(");
     2.9 +                if (ident != null) {
    2.10 +                    sb.append(ident);
    2.11 +                }
    2.12                  return sb;
    2.13              }
    2.14  
     3.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java	Thu Jul 11 21:10:18 2013 +0200
     3.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java	Thu Jul 11 21:26:28 2013 +0200
     3.3 @@ -245,7 +245,10 @@
     3.4                  if (m.getReturnType().getKind() != TypeKind.VOID) {
     3.5                      source.append("return ");
     3.6                  }
     3.7 -                if (!isStatic) {
     3.8 +                if (isStatic) {
     3.9 +                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
    3.10 +                    source.append('.');
    3.11 +                } else {
    3.12                      source.append("self.");
    3.13                  }
    3.14                  source.append(m.getSimpleName());
     4.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java	Thu Jul 11 21:10:18 2013 +0200
     4.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java	Thu Jul 11 21:26:28 2013 +0200
     4.3 @@ -33,7 +33,8 @@
     4.4              int next = body.indexOf(".@", pos);
     4.5              if (next == -1) {
     4.6                  sb.append(body.substring(pos));
     4.7 -                return sb.toString();
     4.8 +                body = sb.toString();
     4.9 +                break;
    4.10              }
    4.11              int ident = next;
    4.12              while (ident > 0) {
    4.13 @@ -64,6 +65,38 @@
    4.14              }
    4.15              pos = paramBeg + 1;
    4.16          }
    4.17 +        pos = 0;
    4.18 +        sb = null;
    4.19 +        for (;;) {
    4.20 +            int next = body.indexOf("@", pos);
    4.21 +            if (next == -1) {
    4.22 +                if (sb == null) {
    4.23 +                    return body;
    4.24 +                }
    4.25 +                sb.append(body.substring(pos));
    4.26 +                return sb.toString();
    4.27 +            }
    4.28 +            if (sb == null) {
    4.29 +                sb = new StringBuilder();
    4.30 +            }
    4.31 +            
    4.32 +            sb.append(body.substring(pos, next));
    4.33 +            
    4.34 +            int sigBeg = body.indexOf('(', next);
    4.35 +            int sigEnd = body.indexOf(')', sigBeg);
    4.36 +            int colon4 = body.indexOf("::", next);
    4.37 +            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
    4.38 +                throw new IllegalStateException("Malformed body " + body);
    4.39 +            }
    4.40 +            String fqn = body.substring(next + 1, colon4);
    4.41 +            String method = body.substring(colon4 + 2, sigBeg);
    4.42 +            String params = body.substring(sigBeg, sigEnd + 1);
    4.43 +
    4.44 +            int paramBeg = body.indexOf('(', sigEnd + 1);
    4.45 +            
    4.46 +            sb.append(callMethod(null, fqn, method, params));
    4.47 +            pos = paramBeg + 1;
    4.48 +        }
    4.49      }
    4.50  
    4.51      protected abstract CharSequence callMethod(
     5.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java	Thu Jul 11 21:10:18 2013 +0200
     5.2 +++ b/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java	Thu Jul 11 21:26:28 2013 +0200
     5.3 @@ -145,6 +145,15 @@
     5.4          } catch (InvocationTargetException ex) {
     5.5              throw ex.getTargetException();
     5.6          }
     5.7 -        
     5.8 +    }
     5.9 +    
    5.10 +    @Test public void callStaticJavaMethod() throws Throwable {
    5.11 +        Method st = methodClass.getMethod("staticCallback", int.class, int.class);
    5.12 +        assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
    5.13 +    }
    5.14 +
    5.15 +    @Test public void callStaticStringParamMethod() throws Throwable {
    5.16 +        Method st = methodClass.getMethod("parseInt", String.class);
    5.17 +        assertEquals(st.invoke(null, "42"), 42, "Meaning of JavaScript?");
    5.18      }
    5.19  }
    5.20 \ No newline at end of file
     6.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java	Thu Jul 11 21:10:18 2013 +0200
     6.2 +++ b/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java	Thu Jul 11 21:26:28 2013 +0200
     6.3 @@ -54,7 +54,7 @@
     6.4          return false;
     6.5      }
     6.6      
     6.7 -    @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()()")
     6.8 +    @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();")
     6.9      public static native void callback(Runnable r);
    6.10      
    6.11      @JavaScriptBody(args = { "at", "arr" }, javacall = true, body =
    6.12 @@ -73,6 +73,12 @@
    6.13      @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
    6.14      public static native int useExternalMul(int x, int y);
    6.15      
    6.16 -    @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.apidesign.html.boot.impl.JsMethods::getThis()()")
    6.17 +    @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.apidesign.html.boot.impl.JsMethods::getThis()();")
    6.18      public static native JsMethods returnYourSelf(JsMethods m);
    6.19 +    
    6.20 +    @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.apidesign.html.boot.impl.JsMethods::useExternalMul(II)(x, y);")
    6.21 +    public static native int staticCallback(int x, int y);
    6.22 +
    6.23 +    @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);")
    6.24 +    public static native int parseInt(String v);
    6.25  }