Can callback @JavaScriptBody methods in the same class
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 29 Jun 2013 22:44:59 +0200
changeset 17154ac82353158
parent 169 d22f28c04cb7
child 172 a058550f8f1f
Can callback @JavaScriptBody methods in the same class
boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.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/org/apidesign/html/boot/impl/FnUtils.java	Wed Jun 26 18:18:21 2013 +0200
     1.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Sat Jun 29 22:44:59 2013 +0200
     1.3 @@ -29,6 +29,7 @@
     1.4  import java.util.Collections;
     1.5  import java.util.Enumeration;
     1.6  import java.util.List;
     1.7 +import java.util.Map;
     1.8  import org.apidesign.html.boot.spi.Fn;
     1.9  import org.objectweb.asm.Type;
    1.10  
    1.11 @@ -76,9 +77,9 @@
    1.12          };
    1.13      }
    1.14  
    1.15 -    static String callback(String body, ClassLoader loader) {
    1.16 +    static String callback(String body, ClassLoader loader, String ownName, Map<String,String> ownMethods) {
    1.17          try {
    1.18 -            return callbackImpl(body, loader);
    1.19 +            return callbackImpl(body, loader, ownName, ownMethods);
    1.20          } catch (ClassNotFoundException ex) {
    1.21              throw new IllegalStateException("Can't parse " + body, ex);
    1.22          } catch (NoSuchMethodException ex) {
    1.23 @@ -86,8 +87,9 @@
    1.24          }
    1.25      }
    1.26      
    1.27 -    private static String callbackImpl(String body, ClassLoader loader)
    1.28 -    throws ClassNotFoundException, NoSuchMethodException {
    1.29 +    private static String callbackImpl(
    1.30 +        String body, ClassLoader loader, String ownName, Map<String,String> ownMethods
    1.31 +    ) throws ClassNotFoundException, NoSuchMethodException {
    1.32          StringBuilder sb = new StringBuilder();
    1.33          int pos = 0;
    1.34          for (;;) {
    1.35 @@ -111,21 +113,36 @@
    1.36              String method = body.substring(colon4 + 2, sigBeg);
    1.37              String params = body.substring(sigBeg, sigEnd + 1);
    1.38              
    1.39 -            Class<?> clazz = Class.forName(fqn, false, loader);
    1.40 -            final Type[] argTps = Type.getArgumentTypes(params);
    1.41 -            Class<?>[] argCls = new Class<?>[argTps.length];
    1.42 -            for (int i = 0; i < argCls.length; i++) {
    1.43 -                argCls[i] = toClass(argTps[i], loader);
    1.44 +            if (fqn.equals(ownName.replace('/', '.'))) {
    1.45 +                if (!ownMethods.containsKey(method + params)) {
    1.46 +                    throw new IllegalStateException("Wrong refernece to " + method + params);
    1.47 +                }
    1.48 +                sb.append("['").append(method).append("(");
    1.49 +                final Type[] argTps = Type.getArgumentTypes(params);
    1.50 +                Class<?>[] argCls = new Class<?>[argTps.length];
    1.51 +                String sep = "";
    1.52 +                for (int i = 0; i < argCls.length; i++) {
    1.53 +                    sb.append(sep).append(toClass(argTps[i], loader).getName());
    1.54 +                    sep = ",";
    1.55 +                }
    1.56 +                sb.append(")']");
    1.57 +            } else {
    1.58 +                Class<?> clazz = Class.forName(fqn, false, loader);
    1.59 +                final Type[] argTps = Type.getArgumentTypes(params);
    1.60 +                Class<?>[] argCls = new Class<?>[argTps.length];
    1.61 +                for (int i = 0; i < argCls.length; i++) {
    1.62 +                    argCls[i] = toClass(argTps[i], loader);
    1.63 +                }
    1.64 +                Method m = clazz.getMethod(method, argCls);
    1.65 +
    1.66 +                sb.append("['").append(m.getName()).append("(");
    1.67 +                String sep = "";
    1.68 +                for (Class<?> pt : m.getParameterTypes()) {
    1.69 +                    sb.append(sep).append(pt.getName());
    1.70 +                    sep = ",";
    1.71 +                }
    1.72 +                sb.append(")']");
    1.73              }
    1.74 -            Method m = clazz.getMethod(method, argCls);
    1.75 -            
    1.76 -            sb.append("['").append(m.getName()).append("(");
    1.77 -            String sep = "";
    1.78 -            for (Class<?> pt : m.getParameterTypes()) {
    1.79 -                sb.append(sep).append(pt.getName());
    1.80 -                sep = ",";
    1.81 -            }
    1.82 -            sb.append(")']");
    1.83              
    1.84              pos = sigEnd + 1;
    1.85          }
     2.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java	Wed Jun 26 18:18:21 2013 +0200
     2.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java	Sat Jun 29 22:44:59 2013 +0200
     2.3 @@ -27,7 +27,9 @@
     2.4  import java.net.URL;
     2.5  import java.util.ArrayList;
     2.6  import java.util.Enumeration;
     2.7 +import java.util.HashMap;
     2.8  import java.util.List;
     2.9 +import java.util.Map;
    2.10  import org.objectweb.asm.AnnotationVisitor;
    2.11  import org.objectweb.asm.ClassReader;
    2.12  import org.objectweb.asm.ClassVisitor;
    2.13 @@ -93,11 +95,11 @@
    2.14                  is.close();
    2.15                  is = null;
    2.16                  ClassReader cr = new ClassReader(arr);
    2.17 -                FindInClass tst = new FindInClass(null);
    2.18 +                FindInClass tst = new FindInClass(null, new HashMap<String,String>());
    2.19                  cr.accept(tst, 0);
    2.20                  if (tst.found > 0) {
    2.21                      ClassWriter w = new ClassWriterEx(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    2.22 -                    FindInClass fic = new FindInClass(w);
    2.23 +                    FindInClass fic = new FindInClass(w, tst.methods);
    2.24                      cr.accept(fic, 0);
    2.25                      arr = w.toByteArray();
    2.26                  }
    2.27 @@ -130,9 +132,11 @@
    2.28      private final class FindInClass extends ClassVisitor {
    2.29          private String name;
    2.30          private int found;
    2.31 +        private final Map<String,String> methods;
    2.32          
    2.33 -        public FindInClass(ClassVisitor cv) {
    2.34 +        public FindInClass(ClassVisitor cv, Map<String,String> methods) {
    2.35              super(Opcodes.ASM4, cv);
    2.36 +            this.methods = methods;
    2.37          }
    2.38  
    2.39          @Override
    2.40 @@ -152,6 +156,9 @@
    2.41  
    2.42          @Override
    2.43          public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    2.44 +            int end = desc.indexOf(')');
    2.45 +            methods.put(name + desc.substring(0, end + 1), desc);
    2.46 +            
    2.47              return new FindInMethod(access, name, desc,
    2.48                  super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
    2.49              );
    2.50 @@ -402,7 +409,7 @@
    2.51                  public void visitEnd() {
    2.52                      if (body != null) {
    2.53                          generateJSBody(args, javacall ? 
    2.54 -                            FnUtils.callback(body, JsClassLoader.this) : 
    2.55 +                            FnUtils.callback(body, JsClassLoader.this, FindInClass.this.name, FindInClass.this.methods) : 
    2.56                              body
    2.57                          );
    2.58                      }
     3.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java	Wed Jun 26 18:18:21 2013 +0200
     3.2 +++ b/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java	Sat Jun 29 22:44:59 2013 +0200
     3.3 @@ -136,4 +136,15 @@
     3.4              throw ex.getTargetException();
     3.5          }
     3.6      }
     3.7 +    
     3.8 +    @Test public void callJavaScriptMethodOnOwnClass() throws Throwable {
     3.9 +        try {
    3.10 +            Object thiz = methodClass.newInstance();
    3.11 +            Method st = methodClass.getMethod("returnYourSelf", methodClass);
    3.12 +            assertEquals(st.invoke(null, thiz), thiz, "Returns this");
    3.13 +        } catch (InvocationTargetException ex) {
    3.14 +            throw ex.getTargetException();
    3.15 +        }
    3.16 +        
    3.17 +    }
    3.18  }
    3.19 \ No newline at end of file
     4.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java	Wed Jun 26 18:18:21 2013 +0200
     4.2 +++ b/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java	Sat Jun 29 22:44:59 2013 +0200
     4.3 @@ -72,4 +72,7 @@
     4.4      
     4.5      @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
     4.6      public static native int useExternalMul(int x, int y);
     4.7 +    
     4.8 +    @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.apidesign.html.boot.impl.JsMethods::getThis()()")
     4.9 +    public static native JsMethods returnYourSelf(JsMethods m);
    4.10  }