rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 19 Mar 2016 10:31:13 +0100
changeset 1889 e1953d8b8338
parent 772 d382dacfd73f
child 1907 f5be41227c81
permissions -rw-r--r--
Support for default attributes of annotations
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.emul.reflect;
    19 
    20 import java.lang.annotation.Annotation;
    21 import java.lang.reflect.Method;
    22 import java.lang.reflect.Modifier;
    23 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    24 
    25 /**
    26  *
    27  * @author Jaroslav Tulach <jtulach@netbeans.org>
    28  */
    29 public final class AnnotationImpl implements Annotation {
    30     private final Class<? extends Annotation> type;
    31 
    32     public AnnotationImpl(Class<? extends Annotation> type) {
    33         this.type = type;
    34     }
    35     
    36     public Class<? extends Annotation> annotationType() {
    37         return type;
    38     }
    39 
    40     @JavaScriptBody(args = { "a", "n", "arr", "values" }, body = ""
    41         + "function r(anno, val, prop, m) {\n"
    42         + "  var v = val[prop];\n"
    43         + "  if (typeof v === 'undefined') {\n"
    44         + "    var cls = anno.fld_org_apidesign_bck2brwsr_emul_reflect_AnnotationImpl_type.cnstr;\n"
    45         + "    try { throw 'x'; } catch (errr) {};\n"
    46         + "    v = cls.prototype[m]();\n"
    47         + "  }\n"
    48         + "  return v;\n"
    49         + "}\n"
    50         + "function f(val, prop, clazz, m) {\n"
    51         + "  return function() {\n"
    52         + "    if (clazz == null) return r(this, val, prop, m);\n"
    53         + "    if (clazz.isArray__Z()) {\n"
    54         + "      var valarr = r(this, val, prop, m);\n"
    55         + "      var cmp = clazz.getComponentType__Ljava_lang_Class_2();\n"
    56         + "      var retarr = vm.java_lang_reflect_Array(false).newInstance__Ljava_lang_Object_2Ljava_lang_Class_2I(cmp, valarr.length);\n"
    57         + "      for (var i = 0; i < valarr.length; i++) {\n"
    58         + "        retarr[i] = CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(cmp, valarr[i]);\n"
    59         + "      }\n"
    60         + "      return retarr;\n"
    61         + "    }\n"
    62         + "    return CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(clazz, r(this, val, prop, m));\n"
    63         + "  };\n"
    64         + "}\n"
    65         + "for (var i = 0; i < arr.length; i += 3) {\n"
    66         + "  var m = arr[i];\n"
    67         + "  var p = arr[i + 1];\n"
    68         + "  var c = arr[i + 2];\n"
    69         + "  a[m] = f(values, p, c, m);\n"
    70         + "}\n"
    71         + "a['$instOf_' + n] = true;\n"
    72         + "return a;"
    73     )
    74     private static native <T extends Annotation> T create(
    75         AnnotationImpl a, String n, Object[] methodsAndProps, Object values
    76     );
    77     
    78     private static Object c(Class<? extends Annotation> a, Object v) {
    79         return create(a, v);
    80     }
    81     
    82     public static <T extends Annotation> T create(Class<T> annoClass, Object values) {
    83         return create(new AnnotationImpl(annoClass), 
    84             annoClass.getName().replace('.', '_'), 
    85             findProps(annoClass), values
    86         );
    87     }
    88 
    89     public static Annotation[] create(Object anno) {
    90         String[] names = findNames(anno);
    91         Annotation[] ret = new Annotation[names.length];
    92         for (int i = 0; i < names.length; i++) {
    93             String annoNameSlash = names[i].substring(1, names[i].length() - 1);
    94             Class<? extends Annotation> annoClass;
    95             try {
    96                 annoClass = (Class<? extends Annotation>)Class.forName(annoNameSlash.replace('/', '.'));
    97             } catch (ClassNotFoundException ex) {
    98                 throw new IllegalStateException("Can't find annotation class " + annoNameSlash);
    99             }
   100             ret[i] = create(
   101                 new AnnotationImpl(annoClass), 
   102                 annoNameSlash.replace('/', '_'),
   103                 findProps(annoClass),
   104                 findData(anno, names[i])
   105             );
   106         }
   107         return ret;
   108     }
   109     @JavaScriptBody(args = "anno", body =
   110           "var arr = new Array();"
   111         + "var props = Object.getOwnPropertyNames(anno);\n"
   112         + "for (var i = 0; i < props.length; i++) {\n"
   113         + "  var p = props[i];\n"
   114         + "  arr.push(p);"
   115         + "}"
   116         + "return arr;"
   117     )
   118     private static native String[] findNames(Object anno);
   119 
   120     @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];")
   121     private static native Object findData(Object anno, String p);
   122 
   123     private static Object[] findProps(Class<?> annoClass) {
   124         final Method[] marr = MethodImpl.findMethods(annoClass, Modifier.PUBLIC);
   125         Object[] arr = new Object[marr.length * 3];
   126         int pos = 0;
   127         for (Method m : marr) {
   128             arr[pos++] = MethodImpl.toSignature(m);
   129             arr[pos++] = m.getName();
   130             final Class<?> rt = m.getReturnType();
   131             if (rt.isArray()) {
   132                 arr[pos++] = rt.getComponentType().isAnnotation() ? rt : null;
   133             } else {
   134                 arr[pos++] = rt.isAnnotation() ? rt : null;
   135             }
   136         }
   137         return arr;
   138     }
   139 }