1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Fri Mar 22 17:03:32 2013 +0100
1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Mar 25 11:50:36 2013 +0100
1.3 @@ -55,6 +55,7 @@
1.4 import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
1.5 import org.apidesign.bck2brwsr.htmlpage.api.Model;
1.6 import org.apidesign.bck2brwsr.htmlpage.api.On;
1.7 +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
1.8 import org.apidesign.bck2brwsr.htmlpage.api.Page;
1.9 import org.apidesign.bck2brwsr.htmlpage.api.Property;
1.10 import org.openide.util.lookup.ServiceProvider;
1.11 @@ -68,6 +69,7 @@
1.12 @SupportedAnnotationTypes({
1.13 "org.apidesign.bck2brwsr.htmlpage.api.Model",
1.14 "org.apidesign.bck2brwsr.htmlpage.api.Page",
1.15 + "org.apidesign.bck2brwsr.htmlpage.api.OnFunction",
1.16 "org.apidesign.bck2brwsr.htmlpage.api.On"
1.17 })
1.18 public final class PageProcessor extends AbstractProcessor {
1.19 @@ -164,6 +166,7 @@
1.20 try {
1.21 StringWriter body = new StringWriter();
1.22 List<String> propsGetSet = new ArrayList<>();
1.23 + List<String> functions = new ArrayList<>();
1.24 Map<String, Collection<String>> propsDeps = new HashMap<>();
1.25 if (!generateComputedProperties(body, p.properties(), e.getEnclosedElements(), propsGetSet, propsDeps)) {
1.26 ok = false;
1.27 @@ -171,6 +174,9 @@
1.28 if (!generateProperties(e, body, p.properties(), propsGetSet, propsDeps)) {
1.29 ok = false;
1.30 }
1.31 + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
1.32 + ok = false;
1.33 + }
1.34
1.35 FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
1.36 w = new OutputStreamWriter(java.openOutputStream());
1.37 @@ -208,6 +214,13 @@
1.38 }
1.39 sep = ",\n";
1.40 }
1.41 + w.write("\n }, new String[] {\n");
1.42 + sep = "";
1.43 + for (String n : functions) {
1.44 + w.write(sep);
1.45 + w.write(n);
1.46 + sep = ",\n";
1.47 + }
1.48 w.write("\n });\n return this;\n}\n");
1.49
1.50 w.write("public void triggerEvent(Element e, OnEvent ev) {\n");
1.51 @@ -275,46 +288,7 @@
1.52 continue;
1.53 }
1.54 ExecutableElement ee = (ExecutableElement)method;
1.55 - StringBuilder params = new StringBuilder();
1.56 - {
1.57 - boolean first = true;
1.58 - for (VariableElement ve : ee.getParameters()) {
1.59 - if (!first) {
1.60 - params.append(", ");
1.61 - }
1.62 - first = false;
1.63 - if (ve.asType() == stringType) {
1.64 - if (ve.getSimpleName().contentEquals("id")) {
1.65 - params.append('"').append(id).append('"');
1.66 - continue;
1.67 - }
1.68 - params.append("org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString(ev, \"");
1.69 - params.append(ve.getSimpleName().toString());
1.70 - params.append("\")");
1.71 - continue;
1.72 - }
1.73 - if (processingEnv.getTypeUtils().getPrimitiveType(TypeKind.DOUBLE) == ve.asType()) {
1.74 - params.append("org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble(ev, \"");
1.75 - params.append(ve.getSimpleName().toString());
1.76 - params.append("\")");
1.77 - continue;
1.78 - }
1.79 - String rn = ve.asType().toString();
1.80 - int last = rn.lastIndexOf('.');
1.81 - if (last >= 0) {
1.82 - rn = rn.substring(last + 1);
1.83 - }
1.84 - if (rn.equals(className)) {
1.85 - params.append(className).append(".this");
1.86 - continue;
1.87 - }
1.88 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
1.89 - "@On method can only accept String named 'id' or " + className + " arguments",
1.90 - ee
1.91 - );
1.92 - return false;
1.93 - }
1.94 - }
1.95 + CharSequence params = wrapParams(ee, id, className, "ev", null);
1.96 if (!ee.getModifiers().contains(Modifier.STATIC)) {
1.97 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee);
1.98 ok = false;
1.99 @@ -659,4 +633,105 @@
1.100 e = e.getEnclosingElement();
1.101 }
1.102 }
1.103 +
1.104 + private boolean generateFunctions(
1.105 + Element clazz, StringWriter body, String className,
1.106 + List<? extends Element> enclosedElements, List<String> functions
1.107 + ) {
1.108 + for (Element m : enclosedElements) {
1.109 + if (m.getKind() != ElementKind.METHOD) {
1.110 + continue;
1.111 + }
1.112 + ExecutableElement e = (ExecutableElement)m;
1.113 + OnFunction onF = e.getAnnotation(OnFunction.class);
1.114 + if (onF == null) {
1.115 + continue;
1.116 + }
1.117 + if (!e.getModifiers().contains(Modifier.STATIC)) {
1.118 + processingEnv.getMessager().printMessage(
1.119 + Diagnostic.Kind.ERROR, "@OnFunction method needs to be static", e
1.120 + );
1.121 + return false;
1.122 + }
1.123 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
1.124 + processingEnv.getMessager().printMessage(
1.125 + Diagnostic.Kind.ERROR, "@OnFunction method cannot be private", e
1.126 + );
1.127 + return false;
1.128 + }
1.129 + if (e.getReturnType().getKind() != TypeKind.VOID) {
1.130 + processingEnv.getMessager().printMessage(
1.131 + Diagnostic.Kind.ERROR, "@OnFunction method should return void", e
1.132 + );
1.133 + return false;
1.134 + }
1.135 + String n = e.getSimpleName().toString();
1.136 + body.append("private void ").append(n).append("(Object data, Object ev) {\n");
1.137 + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
1.138 + body.append(wrapParams(e, null, className, "ev", "data"));
1.139 + body.append(");\n");
1.140 + body.append("}\n");
1.141 +
1.142 + functions.add('\"' + n + '\"');
1.143 + functions.add('\"' + n + "__VLjava_lang_Object_2Ljava_lang_Object_2" + '\"');
1.144 + }
1.145 + return true;
1.146 + }
1.147 +
1.148 + private CharSequence wrapParams(
1.149 + ExecutableElement ee, String id, String className, String evName, String dataName
1.150 + ) {
1.151 + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
1.152 + StringBuilder params = new StringBuilder();
1.153 + boolean first = true;
1.154 + for (VariableElement ve : ee.getParameters()) {
1.155 + if (!first) {
1.156 + params.append(", ");
1.157 + }
1.158 + first = false;
1.159 + String toCall = null;
1.160 + if (ve.asType() == stringType) {
1.161 + if (ve.getSimpleName().contentEquals("id")) {
1.162 + params.append('"').append(id).append('"');
1.163 + continue;
1.164 + }
1.165 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString";
1.166 + }
1.167 + if (ve.asType().getKind() == TypeKind.DOUBLE) {
1.168 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble";
1.169 + }
1.170 + if (ve.asType().getKind() == TypeKind.INT) {
1.171 + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt";
1.172 + }
1.173 +
1.174 + if (toCall != null) {
1.175 + params.append(toCall).append('(');
1.176 + if (dataName != null && ve.getSimpleName().contentEquals("data")) {
1.177 + params.append(dataName);
1.178 + params.append(", null");
1.179 + } else {
1.180 + params.append(evName);
1.181 + params.append(", \"");
1.182 + params.append(ve.getSimpleName().toString());
1.183 + params.append("\"");
1.184 + }
1.185 + params.append(")");
1.186 + continue;
1.187 + }
1.188 + String rn = ve.asType().toString();
1.189 + int last = rn.lastIndexOf('.');
1.190 + if (last >= 0) {
1.191 + rn = rn.substring(last + 1);
1.192 + }
1.193 + if (rn.equals(className)) {
1.194 + params.append(className).append(".this");
1.195 + continue;
1.196 + }
1.197 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
1.198 + "@On method can only accept String named 'id' or " + className + " arguments",
1.199 + ee
1.200 + );
1.201 + }
1.202 + return params;
1.203 + }
1.204 }