FX Web View can finally call run() on non-public implementations of Runnable
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 11 Jul 2013 17:58:45 +0200
changeset 1885f3b1d7fafec
parent 187 9fed4172ad33
child 189 5c78e49bd297
FX Web View can finally call run() on non-public implementations of Runnable
boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.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/main/java/org/apidesign/html/boot/impl/JsClassLoader.java
     1.1 --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java	Thu Jul 11 16:39:39 2013 +0200
     1.2 +++ b/boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java	Thu Jul 11 17:58:45 2013 +0200
     1.3 @@ -38,7 +38,7 @@
     1.4      @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();")
     1.5      private static native void callback(Runnable r);
     1.6  
     1.7 -    public static class R implements Runnable {
     1.8 +    private static class R implements Runnable {
     1.9          int cnt;
    1.10  
    1.11          @Override
     2.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Thu Jul 11 16:39:39 2013 +0200
     2.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Thu Jul 11 17:58:45 2013 +0200
     2.3 @@ -23,7 +23,6 @@
     2.4  import java.io.InputStream;
     2.5  import java.io.InputStreamReader;
     2.6  import java.io.Reader;
     2.7 -import java.lang.reflect.Method;
     2.8  import java.net.URL;
     2.9  import java.util.ArrayList;
    2.10  import java.util.Collections;
    2.11 @@ -83,44 +82,10 @@
    2.12              protected CharSequence callMethod(
    2.13                  String ident, String fqn, String method, String params
    2.14              ) {
    2.15 -                try {
    2.16 -                    StringBuilder sb = new StringBuilder();
    2.17 -                    sb.append(ident);
    2.18 -                    if (fqn.equals(ownName.replace('/', '.'))) {
    2.19 -                        if (!ownMethods.containsKey(method + params)) {
    2.20 -                            throw new IllegalStateException("Wrong reference to " + method + params);
    2.21 -                        }
    2.22 -                        sb.append("['").append(method).append("(");
    2.23 -                        final Type[] argTps = Type.getArgumentTypes(params);
    2.24 -                        Class<?>[] argCls = new Class<?>[argTps.length];
    2.25 -                        String sep = "";
    2.26 -                        for (int i = 0; i < argCls.length; i++) {
    2.27 -                            sb.append(sep).append(toClass(argTps[i], loader).getName());
    2.28 -                            sep = ",";
    2.29 -                        }
    2.30 -                        sb.append(")']");
    2.31 -                    } else {
    2.32 -                        Class<?> clazz = Class.forName(fqn, false, loader);
    2.33 -                        final Type[] argTps = Type.getArgumentTypes(params);
    2.34 -                        Class<?>[] argCls = new Class<?>[argTps.length];
    2.35 -                        for (int i = 0; i < argCls.length; i++) {
    2.36 -                            argCls[i] = toClass(argTps[i], loader);
    2.37 -                        }
    2.38 -                        Method m = clazz.getMethod(method, argCls);
    2.39 -                        sb.append("['").append(m.getName()).append("(");
    2.40 -                        String sep = "";
    2.41 -                        for (Class<?> pt : m.getParameterTypes()) {
    2.42 -                            sb.append(sep).append(pt.getName());
    2.43 -                            sep = ",";
    2.44 -                        }
    2.45 -                        sb.append(")']");
    2.46 -                    }
    2.47 -                    return sb;
    2.48 -                } catch (ClassNotFoundException ex) {
    2.49 -                    throw new IllegalStateException("Can't parse " + body, ex);
    2.50 -                } catch (NoSuchMethodException ex) {
    2.51 -                    throw new IllegalStateException("Can't parse " + body, ex);
    2.52 -                }
    2.53 +                StringBuilder sb = new StringBuilder();
    2.54 +                sb.append("vm.").append(mangle(fqn, method, params));
    2.55 +                sb.append("(").append(ident);
    2.56 +                return sb;
    2.57              }
    2.58  
    2.59          }.parse(body);
    2.60 @@ -145,26 +110,4 @@
    2.61              throw new IllegalStateException("Can't execute " + resource, ex);
    2.62          } 
    2.63      }
    2.64 -    static Class<?> toClass(final Type t, ClassLoader loader) throws ClassNotFoundException {
    2.65 -        if (t == Type.INT_TYPE) {
    2.66 -            return Integer.TYPE;
    2.67 -        } else if (t == Type.VOID_TYPE) {
    2.68 -            return Void.TYPE;
    2.69 -        } else if (t == Type.BOOLEAN_TYPE) {
    2.70 -            return Boolean.TYPE;
    2.71 -        } else if (t == Type.BYTE_TYPE) {
    2.72 -            return Byte.TYPE;
    2.73 -        } else if (t == Type.CHAR_TYPE) {
    2.74 -            return Character.TYPE;
    2.75 -        } else if (t == Type.SHORT_TYPE) {
    2.76 -            return Short.TYPE;
    2.77 -        } else if (t == Type.DOUBLE_TYPE) {
    2.78 -            return Double.TYPE;
    2.79 -        } else if (t == Type.FLOAT_TYPE) {
    2.80 -            return Float.TYPE;
    2.81 -        } else if (t == Type.LONG_TYPE) {
    2.82 -            return Long.TYPE;
    2.83 -        }
    2.84 -        return Class.forName(t.getClassName(), false, loader);
    2.85 -    }
    2.86  }
     3.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java	Thu Jul 11 16:39:39 2013 +0200
     3.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java	Thu Jul 11 17:58:45 2013 +0200
     3.3 @@ -22,7 +22,6 @@
     3.4  
     3.5  import java.io.IOException;
     3.6  import java.io.Writer;
     3.7 -import java.util.ArrayList;
     3.8  import java.util.Collections;
     3.9  import java.util.HashMap;
    3.10  import java.util.HashSet;
    3.11 @@ -145,7 +144,7 @@
    3.12                      continue;
    3.13                  }
    3.14                  if (m.getSimpleName().contentEquals(method)) {
    3.15 -                    String paramTypes = findParamTypes((ExecutableElement)m, true);
    3.16 +                    String paramTypes = findParamTypes((ExecutableElement)m);
    3.17                      if (paramTypes.equals(params)) {
    3.18                          found = (ExecutableElement) m;
    3.19                          break;
    3.20 @@ -170,18 +169,16 @@
    3.21                      mangledOnes = new TreeMap<String, ExecutableElement>();
    3.22                      javacalls.put(findPkg(e), mangledOnes);
    3.23                  }
    3.24 -                String mangled = JsCallback.mangle(fqn, method, findParamTypes(found, false));
    3.25 +                String mangled = JsCallback.mangle(fqn, method, findParamTypes(found));
    3.26                  mangledOnes.put(mangled, found);
    3.27              }
    3.28              return "";
    3.29          }
    3.30  
    3.31 -        private String findParamTypes(ExecutableElement method, boolean surround) {
    3.32 +        private String findParamTypes(ExecutableElement method) {
    3.33              ExecutableType t = (ExecutableType) method.asType();
    3.34              StringBuilder sb = new StringBuilder();
    3.35 -            if (surround) {
    3.36 -                sb.append('(');
    3.37 -            }
    3.38 +            sb.append('(');
    3.39              for (TypeMirror tm : t.getParameterTypes()) {
    3.40                  if (tm.getKind().isPrimitive()) {
    3.41                      switch (tm.getKind()) {
    3.42 @@ -206,9 +203,7 @@
    3.43                      sb.append(';');
    3.44                  }
    3.45              }
    3.46 -            if (surround) {
    3.47 -                sb.append(')');
    3.48 -            }
    3.49 +            sb.append(')');
    3.50              return sb.toString();
    3.51          }
    3.52      }
    3.53 @@ -219,8 +214,8 @@
    3.54              Map<String, ExecutableElement> map = pkgEn.getValue();
    3.55              StringBuilder source = new StringBuilder();
    3.56              source.append("package ").append(pkgName).append(";\n");
    3.57 -            source.append("final class $JsCallbacks$ {\n");
    3.58 -            source.append("  public static final $JsCallbacks$ VM = new $JsCallbacks$();\n");
    3.59 +            source.append("public final class $JsCallbacks$ {\n");
    3.60 +            source.append("  static final $JsCallbacks$ VM = new $JsCallbacks$();\n");
    3.61              source.append("  private $JsCallbacks$() {}\n");
    3.62              for (Map.Entry<String, ExecutableElement> entry : map.entrySet()) {
    3.63                  final String mangled = entry.getKey();
     4.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java	Thu Jul 11 16:39:39 2013 +0200
     4.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java	Thu Jul 11 17:58:45 2013 +0200
     4.3 @@ -36,9 +36,12 @@
     4.4                  return sb.toString();
     4.5              }
     4.6              int ident = next;
     4.7 -            while (ident > 0 && Character.isJavaIdentifierPart(body.charAt(--ident))) {
     4.8 +            while (ident > 0) {
     4.9 +                if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
    4.10 +                    ident++;
    4.11 +                    break;
    4.12 +                }
    4.13              }
    4.14 -            ident++;
    4.15              String refId = body.substring(ident, next);
    4.16              
    4.17              sb.append(body.substring(pos, ident));
    4.18 @@ -52,9 +55,14 @@
    4.19              String fqn = body.substring(next + 2, colon4);
    4.20              String method = body.substring(colon4 + 2, sigBeg);
    4.21              String params = body.substring(sigBeg, sigEnd + 1);
    4.22 +
    4.23 +            int paramBeg = body.indexOf('(', sigEnd + 1);
    4.24              
    4.25              sb.append(callMethod(refId, fqn, method, params));
    4.26 -            pos = sigEnd + 1;
    4.27 +            if (body.charAt(paramBeg + 1) != (')')) {
    4.28 +                sb.append(",");
    4.29 +            }
    4.30 +            pos = paramBeg + 1;
    4.31          }
    4.32      }
    4.33  
    4.34 @@ -63,6 +71,12 @@
    4.35      );
    4.36  
    4.37      static String mangle(String fqn, String method, String params) {
    4.38 +        if (params.startsWith("(")) {
    4.39 +            params = params.substring(1);
    4.40 +        }
    4.41 +        if (params.endsWith(")")) {
    4.42 +            params = params.substring(0, params.length() - 1);
    4.43 +        }
    4.44          return 
    4.45              replace(fqn) + "__" + replace(method) + "__" + replace(params);
    4.46      }
     5.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java	Thu Jul 11 16:39:39 2013 +0200
     5.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java	Thu Jul 11 17:58:45 2013 +0200
     5.3 @@ -225,11 +225,14 @@
     5.4                  super.visitLdcInsn(body);
     5.5                  super.visitIntInsn(Opcodes.SIPUSH, args.size());
     5.6                  super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
     5.7 +                boolean needsVM = false;
     5.8                  for (int i = 0; i < args.size(); i++) {
     5.9 -                    String name = args.get(i);
    5.10 +                    assert !needsVM;
    5.11 +                    String argName = args.get(i);
    5.12 +                    needsVM = "vm".equals(argName);
    5.13                      super.visitInsn(Opcodes.DUP);
    5.14                      super.visitIntInsn(Opcodes.BIPUSH, i);
    5.15 -                    super.visitLdcInsn(name);
    5.16 +                    super.visitLdcInsn(argName);
    5.17                      super.visitInsn(Opcodes.AASTORE);
    5.18                  }
    5.19                  super.visitMethodInsn(Opcodes.INVOKESTATIC, 
    5.20 @@ -327,6 +330,15 @@
    5.21                  SignatureReader sr = new SignatureReader(desc);
    5.22                  sr.accept(sv);
    5.23                  
    5.24 +                if (needsVM) {
    5.25 +                    FindInMethod.super.visitInsn(Opcodes.DUP);
    5.26 +                    FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
    5.27 +                    int lastSlash = FindInClass.this.name.lastIndexOf('/');
    5.28 +                    String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
    5.29 +                    FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
    5.30 +                    FindInMethod.super.visitInsn(Opcodes.AASTORE);
    5.31 +                }
    5.32 +                
    5.33                  super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
    5.34                      "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
    5.35                  );
    5.36 @@ -408,10 +420,11 @@
    5.37                  @Override
    5.38                  public void visitEnd() {
    5.39                      if (body != null) {
    5.40 -                        generateJSBody(args, javacall ? 
    5.41 -                            FnUtils.callback(body, JsClassLoader.this, FindInClass.this.name, FindInClass.this.methods) : 
    5.42 -                            body
    5.43 -                        );
    5.44 +                        if (javacall) {
    5.45 +                            body = FnUtils.callback(body, JsClassLoader.this, FindInClass.this.name, FindInClass.this.methods);
    5.46 +                            args.add("vm");
    5.47 +                        }
    5.48 +                        generateJSBody(args, body);
    5.49                      }
    5.50                  }
    5.51              }