1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Fri Apr 05 10:41:07 2013 +0200
1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Fri Apr 05 12:43:17 2013 +0200
1.3 @@ -73,4 +73,26 @@
1.4 private static Object getProperty(Object object, String property) {
1.5 return null;
1.6 }
1.7 +
1.8 + @JavaScriptBody(args = { "url", "arr", "callback" }, body = ""
1.9 + + "var request = new XMLHttpRequest();\n"
1.10 + + "request.open('GET', url, true);\n"
1.11 + + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n"
1.12 + + "request.onreadystatechange = function() {\n"
1.13 + + " if (this.readyState!==4) return;\n"
1.14 + + " arr[0] = eval('(' + this.response + ')');\n"
1.15 + + " callback.run__V();\n"
1.16 + + "};"
1.17 + + "request.send();"
1.18 + )
1.19 + public static native void loadJSON(
1.20 + String url, Object[] jsonResult, Runnable whenDone
1.21 + );
1.22 +
1.23 + public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
1.24 + for (int i = 0; i < props.length; i++) {
1.25 + values[i] = getProperty(jsonObject, props[i]);
1.26 + }
1.27 + }
1.28 +
1.29 }
2.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Fri Apr 05 10:41:07 2013 +0200
2.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Fri Apr 05 12:43:17 2013 +0200
2.3 @@ -34,6 +34,7 @@
2.4 import javax.annotation.processing.AbstractProcessor;
2.5 import javax.annotation.processing.Completion;
2.6 import javax.annotation.processing.Completions;
2.7 +import javax.annotation.processing.Messager;
2.8 import javax.annotation.processing.Processor;
2.9 import javax.annotation.processing.RoundEnvironment;
2.10 import javax.annotation.processing.SupportedAnnotationTypes;
2.11 @@ -57,6 +58,7 @@
2.12 import org.apidesign.bck2brwsr.htmlpage.api.Model;
2.13 import org.apidesign.bck2brwsr.htmlpage.api.On;
2.14 import org.apidesign.bck2brwsr.htmlpage.api.OnFunction;
2.15 +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive;
2.16 import org.apidesign.bck2brwsr.htmlpage.api.Page;
2.17 import org.apidesign.bck2brwsr.htmlpage.api.Property;
2.18 import org.openide.util.lookup.ServiceProvider;
2.19 @@ -71,6 +73,7 @@
2.20 "org.apidesign.bck2brwsr.htmlpage.api.Model",
2.21 "org.apidesign.bck2brwsr.htmlpage.api.Page",
2.22 "org.apidesign.bck2brwsr.htmlpage.api.OnFunction",
2.23 + "org.apidesign.bck2brwsr.htmlpage.api.OnReceive",
2.24 "org.apidesign.bck2brwsr.htmlpage.api.On"
2.25 })
2.26 public final class PageProcessor extends AbstractProcessor {
2.27 @@ -103,6 +106,10 @@
2.28 return processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, pkg, name).openInputStream();
2.29 }
2.30 }
2.31 +
2.32 + private Messager err() {
2.33 + return processingEnv.getMessager();
2.34 + }
2.35
2.36 private boolean processModel(Element e) {
2.37 boolean ok = true;
2.38 @@ -135,18 +142,64 @@
2.39 w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n");
2.40 w.append("import org.apidesign.bck2brwsr.core.JavaScriptOnly;\n");
2.41 w.append("final class ").append(className).append(" implements Cloneable {\n");
2.42 - w.append(" private Object json;\n");
2.43 w.append(" private boolean locked;\n");
2.44 w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
2.45 w.append(body.toString());
2.46 w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
2.47 w.append(" public ").append(className).append("() {\n");
2.48 + w.append(" intKnckt();\n");
2.49 + w.append(" };\n");
2.50 + w.append(" private void intKnckt() {\n");
2.51 w.append(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(this, ");
2.52 writeStringArray(propsGetSet, w);
2.53 w.append(", ");
2.54 writeStringArray(functions, w);
2.55 w.append(" );\n");
2.56 w.append(" };\n");
2.57 + w.append(" ").append(className).append("(Object json) {\n");
2.58 + int values = 0;
2.59 + for (int i = 0; i < propsGetSet.size(); i += 4) {
2.60 + if (propsGetSet.get(i + 2) == null) {
2.61 + continue;
2.62 + }
2.63 + values++;
2.64 + }
2.65 + w.append(" Object[] ret = new Object[" + values + "];\n");
2.66 + w.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.extractJSON(json, new String[] {\n");
2.67 + for (int i = 0; i < propsGetSet.size(); i += 4) {
2.68 + if (propsGetSet.get(i + 2) == null) {
2.69 + continue;
2.70 + }
2.71 + w.append(" \"").append(propsGetSet.get(i)).append("\",\n");
2.72 + }
2.73 + w.append(" }, ret);\n");
2.74 + for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 4) {
2.75 + if (propsGetSet.get(i + 2) == null) {
2.76 + continue;
2.77 + }
2.78 + boolean[] isModel = { false };
2.79 + boolean[] isEnum = { false };
2.80 + String type = checkType(m.properties()[prop++], isModel, isEnum);
2.81 + w.append(" this.prop_").append(propsGetSet.get(i)).append(" = ");
2.82 + boolean close = false;
2.83 + if (isEnum[0]) {
2.84 +// w.append(type).append(".valueOf((String)");
2.85 +// close = true;
2.86 + w.append("null;\n");
2.87 + continue;
2.88 + } else {
2.89 + w.append('(').append(type).append(')');
2.90 + }
2.91 + w.append("ret[" + cnt++ + "]");
2.92 + if (close) {
2.93 + w.append(");\n");
2.94 + } else {
2.95 + w.append(";\n");
2.96 + }
2.97 +
2.98 + }
2.99 + w.append(" intKnckt();\n");
2.100 + w.append(" };\n");
2.101 writeToString(m.properties(), w);
2.102 writeClone(className, m.properties(), w);
2.103 w.append("}\n");
2.104 @@ -154,7 +207,7 @@
2.105 w.close();
2.106 }
2.107 } catch (IOException ex) {
2.108 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e);
2.109 + err().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e);
2.110 return false;
2.111 }
2.112 return ok;
2.113 @@ -173,7 +226,7 @@
2.114 pp = ProcessPage.readPage(is);
2.115 is.close();
2.116 } catch (IOException iOException) {
2.117 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't read " + p.xhtml() + " as " + iOException.getMessage(), e);
2.118 + err().printMessage(Diagnostic.Kind.ERROR, "Can't read " + p.xhtml() + " as " + iOException.getMessage(), e);
2.119 ok = false;
2.120 pp = null;
2.121 }
2.122 @@ -197,6 +250,9 @@
2.123 if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
2.124 ok = false;
2.125 }
2.126 + if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) {
2.127 + ok = false;
2.128 + }
2.129
2.130 FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
2.131 w = new OutputStreamWriter(java.openOutputStream());
2.132 @@ -237,7 +293,7 @@
2.133 w.close();
2.134 }
2.135 } catch (IOException ex) {
2.136 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e);
2.137 + err().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e);
2.138 return false;
2.139 }
2.140 return ok;
2.141 @@ -283,24 +339,24 @@
2.142 if (oc != null) {
2.143 for (String id : oc.id()) {
2.144 if (pp == null) {
2.145 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " not found in HTML page.");
2.146 + err().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " not found in HTML page.");
2.147 ok = false;
2.148 continue;
2.149 }
2.150 if (pp.tagNameForId(id) == null) {
2.151 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method);
2.152 + err().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method);
2.153 ok = false;
2.154 continue;
2.155 }
2.156 ExecutableElement ee = (ExecutableElement)method;
2.157 CharSequence params = wrapParams(ee, id, className, "ev", null);
2.158 if (!ee.getModifiers().contains(Modifier.STATIC)) {
2.159 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee);
2.160 + err().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee);
2.161 ok = false;
2.162 continue;
2.163 }
2.164 if (ee.getModifiers().contains(Modifier.PRIVATE)) {
2.165 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method can't be private", ee);
2.166 + err().printMessage(Diagnostic.Kind.ERROR, "@On method can't be private", ee);
2.167 ok = false;
2.168 continue;
2.169 }
2.170 @@ -553,7 +609,7 @@
2.171 if (!isModel[0] && !"java.lang.String".equals(ret) && !isEnum[0]) {
2.172 String bt = findBoxedType(ret);
2.173 if (bt == null) {
2.174 - processingEnv.getMessager().printMessage(
2.175 + err().printMessage(
2.176 Diagnostic.Kind.ERROR,
2.177 "Only primitive types supported in the mapping. Not " + ret,
2.178 where
2.179 @@ -604,7 +660,7 @@
2.180 sb.append('"');
2.181 sep = ", ";
2.182 }
2.183 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
2.184 + err().printMessage(Diagnostic.Kind.ERROR,
2.185 propName + " is not one of known properties: " + sb
2.186 , e
2.187 );
2.188 @@ -634,19 +690,19 @@
2.189 continue;
2.190 }
2.191 if (!e.getModifiers().contains(Modifier.STATIC)) {
2.192 - processingEnv.getMessager().printMessage(
2.193 + err().printMessage(
2.194 Diagnostic.Kind.ERROR, "@OnFunction method needs to be static", e
2.195 );
2.196 return false;
2.197 }
2.198 if (e.getModifiers().contains(Modifier.PRIVATE)) {
2.199 - processingEnv.getMessager().printMessage(
2.200 + err().printMessage(
2.201 Diagnostic.Kind.ERROR, "@OnFunction method cannot be private", e
2.202 );
2.203 return false;
2.204 }
2.205 if (e.getReturnType().getKind() != TypeKind.VOID) {
2.206 - processingEnv.getMessager().printMessage(
2.207 + err().printMessage(
2.208 Diagnostic.Kind.ERROR, "@OnFunction method should return void", e
2.209 );
2.210 return false;
2.211 @@ -664,6 +720,100 @@
2.212 return true;
2.213 }
2.214
2.215 + private boolean generateReceive(
2.216 + Element clazz, StringWriter body, String className,
2.217 + List<? extends Element> enclosedElements, List<String> functions
2.218 + ) {
2.219 + for (Element m : enclosedElements) {
2.220 + if (m.getKind() != ElementKind.METHOD) {
2.221 + continue;
2.222 + }
2.223 + ExecutableElement e = (ExecutableElement)m;
2.224 + OnReceive onR = e.getAnnotation(OnReceive.class);
2.225 + if (onR == null) {
2.226 + continue;
2.227 + }
2.228 + if (!e.getModifiers().contains(Modifier.STATIC)) {
2.229 + err().printMessage(
2.230 + Diagnostic.Kind.ERROR, "@OnReceive method needs to be static", e
2.231 + );
2.232 + return false;
2.233 + }
2.234 + if (e.getModifiers().contains(Modifier.PRIVATE)) {
2.235 + err().printMessage(
2.236 + Diagnostic.Kind.ERROR, "@OnReceive method cannot be private", e
2.237 + );
2.238 + return false;
2.239 + }
2.240 + if (e.getReturnType().getKind() != TypeKind.VOID) {
2.241 + err().printMessage(
2.242 + Diagnostic.Kind.ERROR, "@OnReceive method should return void", e
2.243 + );
2.244 + return false;
2.245 + }
2.246 + String modelClass = null;
2.247 + List<String> args = new ArrayList<>();
2.248 + {
2.249 + for (VariableElement ve : e.getParameters()) {
2.250 + if (ve.asType().toString().equals(className)) {
2.251 + args.add(className + ".this");
2.252 + } else if (isModel(ve.asType())) {
2.253 + if (modelClass != null) {
2.254 + err().printMessage(Diagnostic.Kind.ERROR, "There can be only one model class among arguments", e);
2.255 + } else {
2.256 + modelClass = ve.asType().toString();
2.257 + args.add("new " + modelClass + "(value)");
2.258 + }
2.259 + }
2.260 + }
2.261 + }
2.262 + String n = e.getSimpleName().toString();
2.263 + body.append("public void ").append(n).append("(");
2.264 + StringBuilder assembleURL = new StringBuilder();
2.265 + {
2.266 + String sep = "";
2.267 + for (String p : findParamNames(e, onR.url(), assembleURL)) {
2.268 + body.append(sep);
2.269 + body.append("String ").append(p);
2.270 + sep = ", ";
2.271 + }
2.272 + }
2.273 + body.append(") {\n");
2.274 + body.append(" final Object[] result = { null };\n");
2.275 + body.append(
2.276 + " class ProcessResult implements Runnable {\n" +
2.277 + " @Override\n" +
2.278 + " public void run() {\n" +
2.279 + " Object value = result[0];\n" +
2.280 + " if (value instanceof Object[]) {\n" +
2.281 + " throw new IllegalStateException(\"Array value: \" + value);\n" +
2.282 + " } else {\n ");
2.283 + {
2.284 + body.append(clazz.getSimpleName()).append(".").append(n).append("(");
2.285 + String sep = "";
2.286 + for (String arg : args) {
2.287 + body.append(sep);
2.288 + body.append(arg);
2.289 + sep = ", ";
2.290 + }
2.291 + body.append(");\n");
2.292 + }
2.293 + body.append(
2.294 + " }\n" +
2.295 + " }\n" +
2.296 + " }\n"
2.297 + );
2.298 + body.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.loadJSON(\n ");
2.299 + body.append(assembleURL);
2.300 + body.append(", result, new ProcessResult()\n );\n");
2.301 +// body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
2.302 +// body.append(wrapParams(e, null, className, "ev", "data"));
2.303 +// body.append(");\n");
2.304 + body.append("}\n");
2.305 + }
2.306 + return true;
2.307 + }
2.308 +
2.309 private CharSequence wrapParams(
2.310 ExecutableElement ee, String id, String className, String evName, String dataName
2.311 ) {
2.312 @@ -716,7 +866,7 @@
2.313 params.append(className).append(".this");
2.314 continue;
2.315 }
2.316 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
2.317 + err().printMessage(Diagnostic.Kind.ERROR,
2.318 "@On method can only accept String named 'id' or " + className + " arguments",
2.319 ee
2.320 );
2.321 @@ -835,4 +985,29 @@
2.322 }
2.323 return ret;
2.324 }
2.325 +
2.326 + private Iterable<String> findParamNames(Element e, String url, StringBuilder assembleURL) {
2.327 + List<String> params = new ArrayList<>();
2.328 +
2.329 + for (int pos = 0; ;) {
2.330 + int next = url.indexOf('{', pos);
2.331 + if (next == -1) {
2.332 + assembleURL.append('"')
2.333 + .append(url.substring(pos))
2.334 + .append('"');
2.335 + return params;
2.336 + }
2.337 + int close = url.indexOf('}', next);
2.338 + if (close == -1) {
2.339 + err().printMessage(Diagnostic.Kind.ERROR, "Unbalanced '{' and '}' in " + url, e);
2.340 + return params;
2.341 + }
2.342 + final String paramName = url.substring(next + 1, close);
2.343 + params.add(paramName);
2.344 + assembleURL.append('"')
2.345 + .append(url.substring(pos, next))
2.346 + .append("\" + ").append(paramName).append(" + ");
2.347 + pos = close + 1;
2.348 + }
2.349 + }
2.350 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnReceive.java Fri Apr 05 12:43:17 2013 +0200
3.3 @@ -0,0 +1,41 @@
3.4 +/**
3.5 + * Back 2 Browser Bytecode Translator
3.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.7 + *
3.8 + * This program is free software: you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License as published by
3.10 + * the Free Software Foundation, version 2 of the License.
3.11 + *
3.12 + * This program is distributed in the hope that it will be useful,
3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.15 + * GNU General Public License for more details.
3.16 + *
3.17 + * You should have received a copy of the GNU General Public License
3.18 + * along with this program. Look for COPYING file in the top folder.
3.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
3.20 + */
3.21 +package org.apidesign.bck2brwsr.htmlpage.api;
3.22 +
3.23 +import java.lang.annotation.ElementType;
3.24 +import java.lang.annotation.Retention;
3.25 +import java.lang.annotation.RetentionPolicy;
3.26 +import java.lang.annotation.Target;
3.27 +
3.28 +/** Static methods in classes annotated by {@link Model} or {@link Page}
3.29 + * can be marked by this annotation establish a JSON communication point.
3.30 + * The associated model page then gets new method to invoke a network
3.31 + * connection
3.32 + *
3.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
3.34 + */
3.35 +@Retention(RetentionPolicy.SOURCE)
3.36 +@Target(ElementType.METHOD)
3.37 +public @interface OnReceive {
3.38 + /** The URL to connect to. Can contain variable names surrounded by '{' and '}'.
3.39 + * Those parameters will then become variables of the associated method.
3.40 + *
3.41 + * @return the (possibly parametrized) url to connect to
3.42 + */
3.43 + String url();
3.44 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypesTest.java Fri Apr 05 12:43:17 2013 +0200
4.3 @@ -0,0 +1,52 @@
4.4 +/**
4.5 + * Back 2 Browser Bytecode Translator
4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.7 + *
4.8 + * This program is free software: you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License as published by
4.10 + * the Free Software Foundation, version 2 of the License.
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details.
4.16 + *
4.17 + * You should have received a copy of the GNU General Public License
4.18 + * along with this program. Look for COPYING file in the top folder.
4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
4.20 + */
4.21 +package org.apidesign.bck2brwsr.htmlpage;
4.22 +
4.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
4.24 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
4.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
4.26 +import org.testng.annotations.Factory;
4.27 +
4.28 +/**
4.29 + *
4.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.31 + */
4.32 +public class ConvertTypesTest {
4.33 + @JavaScriptBody(args = { }, body = "var json = new Object();"
4.34 + + "json.firstName = 'son';\n"
4.35 + + "json.lastName = 'dj';\n"
4.36 + + "json.sex = 'MALE';\n"
4.37 + + "return json;"
4.38 + )
4.39 + private static native Object createJSON();
4.40 +
4.41 + @BrwsrTest
4.42 + public void testConvertToPeople() {
4.43 + final Object o = createJSON();
4.44 +
4.45 + Person p = new Person(o);
4.46 +
4.47 + assert "son".equals(p.getFirstName()) : "First name: " + p.getFirstName();
4.48 + assert "dj".equals(p.getLastName()) : "Last name: " + p.getLastName();
4.49 +// assert Sex.MALE.equals(p.getSex()) : "Sex: " + p.getSex();
4.50 + }
4.51 +
4.52 + @Factory public static Object[] create() {
4.53 + return VMTest.create(ConvertTypesTest.class);
4.54 + }
4.55 +}
4.56 \ No newline at end of file
5.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java Fri Apr 05 10:41:07 2013 +0200
5.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java Fri Apr 05 12:43:17 2013 +0200
5.3 @@ -18,16 +18,26 @@
5.4 package org.apidesign.bck2brwsr.htmlpage;
5.5
5.6 import java.util.Iterator;
5.7 +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive;
5.8 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
5.9 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
5.10 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
5.11 +import org.apidesign.bck2brwsr.vmtest.Http;
5.12 +import org.apidesign.bck2brwsr.vmtest.VMTest;
5.13 import org.json.JSONException;
5.14 import org.json.JSONObject;
5.15 import org.json.JSONTokener;
5.16 import org.testng.annotations.Test;
5.17 import static org.testng.Assert.*;
5.18 +import org.testng.annotations.Factory;
5.19
5.20 /** Need to verify that models produce reasonable JSON objects.
5.21 *
5.22 * @author Jaroslav Tulach <jtulach@netbeans.org>
5.23 */
5.24 +@Page(xhtml = "Empty.html", className = "JSONik", properties = {
5.25 + @Property(name = "fetched", type = PersonImpl.class)
5.26 +})
5.27 public class JSONTest {
5.28
5.29 @Test public void personToString() throws JSONException {
5.30 @@ -108,4 +118,60 @@
5.31 assertEquals(o.getJSONArray("nicknames").getString(1), n2);
5.32 assertEquals(o.getJSONArray("age").getInt(1), 73);
5.33 }
5.34 +
5.35 +
5.36 + @OnReceive(url="/{url}")
5.37 + static void fetch(Person p, JSONik model) {
5.38 + model.setFetched(p);
5.39 + throw new IllegalStateException("Got him: " + p);
5.40 + }
5.41 +
5.42 + @Http(@Http.Resource(
5.43 + content = "{'firstName': 'Sitar', 'sex': 'MALE'}",
5.44 + path="/person.json",
5.45 + mimeType = "application/json"
5.46 + ))
5.47 + @BrwsrTest public void loadAndParseJSON() {
5.48 + JSONik js = new JSONik();
5.49 + js.applyBindings();
5.50 +
5.51 + js.fetch("person.json");
5.52 +
5.53 + Person p = null;
5.54 + for (int i = 0; i < 10000000; i++) {
5.55 + if (js.getFetched() != null) {
5.56 + p = js.getFetched();
5.57 + }
5.58 + }
5.59 + assert p != null : "We should get our person back: " + p;
5.60 + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
5.61 + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
5.62 + }
5.63 +
5.64 + @Http(@Http.Resource(
5.65 + content = "[{'firstName': 'Sitar', 'sex': 'MALE'}]",
5.66 + path="/person.json",
5.67 + mimeType = "application/json"
5.68 + ))
5.69 + @BrwsrTest public void loadAndParseJSONArray() {
5.70 + JSONik js = new JSONik();
5.71 + js.applyBindings();
5.72 +
5.73 + js.fetch("person.json");
5.74 +
5.75 + Person p = null;
5.76 + for (int i = 0; i < 10000000; i++) {
5.77 + if (js.getFetched() != null) {
5.78 + p = js.getFetched();
5.79 + }
5.80 + }
5.81 + assert p != null : "We should get our person back: " + p;
5.82 + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
5.83 + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
5.84 + }
5.85 +
5.86 + @Factory public static Object[] create() {
5.87 + return VMTest.create(JSONTest.class);
5.88 + }
5.89 +
5.90 }