1.1 --- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Fri Apr 04 18:09:39 2014 +0200
1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Sat Apr 05 09:06:59 2014 +0200
1.3 @@ -155,13 +155,13 @@
1.4 private static BrwsrCtx onCallback;
1.5
1.6 @OnReceive(url="{url}")
1.7 - static void fetch(Person p, JSONik model) {
1.8 + static void fetch(JSONik model, Person p) {
1.9 model.setFetched(p);
1.10 onCallback = BrwsrCtx.findDefault(model.getClass());
1.11 }
1.12
1.13 @OnReceive(url="{url}", onError = "setMessage")
1.14 - static void fetchArray(Person[] p, JSONik model) {
1.15 + static void fetchArray(JSONik model, Person[] p) {
1.16 model.setFetchedCount(p.length);
1.17 model.setFetched(p[0]);
1.18 onCallback = BrwsrCtx.findDefault(model.getClass());
1.19 @@ -173,7 +173,7 @@
1.20 }
1.21
1.22 @OnReceive(url="{url}")
1.23 - static void fetchPeople(People p, JSONik model) {
1.24 + static void fetchPeople(JSONik model, People p) {
1.25 final int size = p.getInfo().size();
1.26 if (size > 0) {
1.27 model.setFetched(p.getInfo().get(0));
1.28 @@ -182,7 +182,7 @@
1.29 }
1.30
1.31 @OnReceive(url="{url}")
1.32 - static void fetchPeopleAge(People p, JSONik model) {
1.33 + static void fetchPeopleAge(JSONik model, People p) {
1.34 int sum = 0;
1.35 for (int a : p.getAge()) {
1.36 sum += a;
1.37 @@ -215,7 +215,7 @@
1.38 }
1.39
1.40 @OnReceive(url="{url}?callme={me}", jsonp = "me")
1.41 - static void fetchViaJSONP(Person p, JSONik model) {
1.42 + static void fetchViaJSONP(JSONik model, Person p) {
1.43 model.setFetched(p);
1.44 }
1.45
1.46 @@ -396,7 +396,7 @@
1.47 }
1.48
1.49 @OnReceive(url="{url}")
1.50 - static void fetchPeopleSex(People p, JSONik model) {
1.51 + static void fetchPeopleSex(JSONik model, People p) {
1.52 model.setFetchedCount(1);
1.53 model.getFetchedSex().addAll(p.getSex());
1.54 }
2.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java Fri Apr 04 18:09:39 2014 +0200
2.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java Sat Apr 05 09:06:59 2014 +0200
2.3 @@ -226,6 +226,17 @@
2.4 return JSON.read(context, modelClass, data);
2.5 }
2.6
2.7 + /** Initializes asynchronous JSON connection to specified URL. Delegates
2.8 + * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
2.9 + * with no extra parameters.
2.10 + */
2.11 + public void loadJSON(final int index,
2.12 + String urlBefore, String urlAfter, String method,
2.13 + final Object data
2.14 + ) {
2.15 + loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
2.16 + }
2.17 +
2.18 /** Initializes asynchronous JSON connection to specified URL. The
2.19 * method returns immediately and later does callback later.
2.20 *
2.21 @@ -237,20 +248,23 @@
2.22 * @param method method to use for connection to the server
2.23 * @param data string, number or a {@link Model} generated class to send to
2.24 * the server when doing a query
2.25 + * @param params extra params to pass back when calling
2.26 + * {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
2.27 + * @since 0.8.1
2.28 */
2.29 public void loadJSON(final int index,
2.30 String urlBefore, String urlAfter, String method,
2.31 - final Object data
2.32 + final Object data, final Object... params
2.33 ) {
2.34 class Rcvr extends RcvrJSON {
2.35 @Override
2.36 protected void onMessage(MsgEvnt msg) {
2.37 - type.onMessage(obj, index, 1, msg.getValues());
2.38 + type.onMessage(obj, index, 1, msg.getValues(), params);
2.39 }
2.40
2.41 @Override
2.42 protected void onError(MsgEvnt msg) {
2.43 - type.onMessage(obj, index, 2, msg.getException());
2.44 + type.onMessage(obj, index, 2, msg.getException(), params);
2.45 }
2.46 }
2.47 JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
2.48 @@ -546,7 +560,7 @@
2.49
2.50 /** Called to report results of asynchronous over-the-wire
2.51 * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
2.52 - * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)}.
2.53 + * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
2.54 *
2.55 * @param model the instance of the model class
2.56 * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
2.57 @@ -555,7 +569,28 @@
2.58 * @param data <code>null</code> or string, number or a {@link Model} class
2.59 * obtained to the server as a response
2.60 */
2.61 - protected abstract void onMessage(Model model, int index, int type, Object data);
2.62 + protected void onMessage(Model model, int index, int type, Object data) {
2.63 + onMessage(model, index, type, data, new Object[0]);
2.64 + }
2.65 +
2.66 + /** Called to report results of asynchronous over-the-wire
2.67 + * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
2.68 + * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
2.69 + *
2.70 + * @param model the instance of the model class
2.71 + * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
2.72 + * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
2.73 + * not all messages are applicable to all communication protocols (JSON has only 1 and 2).
2.74 + * @param data <code>null</code> or string, number or a {@link Model} class
2.75 + * obtained to the server as a response
2.76 + * @param params extra parameters as passed for example to
2.77 + * {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
2.78 + * method
2.79 + * @since 0.8.1
2.80 + */
2.81 + protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
2.82 + onMessage(model, index, type, data);
2.83 + }
2.84
2.85 //
2.86 // Various support methods the generated classes use
3.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Fri Apr 04 18:09:39 2014 +0200
3.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Sat Apr 05 09:06:59 2014 +0200
3.3 @@ -986,7 +986,7 @@
3.4 Element clazz, StringWriter body, String className,
3.5 List<? extends Element> enclosedElements, StringBuilder inType
3.6 ) {
3.7 - inType.append(" @Override public void onMessage(").append(className).append(" model, int index, int type, Object data) {\n");
3.8 + inType.append(" @Override public void onMessage(").append(className).append(" model, int index, int type, Object data, Object[] params) {\n");
3.9 inType.append(" switch (index) {\n");
3.10 int index = 0;
3.11 for (Element m : enclosedElements) {
3.12 @@ -1027,6 +1027,7 @@
3.13 }
3.14 int expectsList = 0;
3.15 List<String> args = new ArrayList<String>();
3.16 + List<String> params = new ArrayList<String>();
3.17 // first argument is model class
3.18 {
3.19 TypeMirror type = e.getParameters().get(0).asType();
3.20 @@ -1079,7 +1080,8 @@
3.21 }
3.22 }
3.23 String n = e.getSimpleName().toString();
3.24 - if ("WebSocket".equals(onR.method())) {
3.25 + final boolean isWebSocket = "WebSocket".equals(onR.method());
3.26 + if (isWebSocket) {
3.27 body.append(" /** Performs WebSocket communication. Call with <code>null</code> data parameter\n");
3.28 body.append(" * to open the connection (even if not required). Call with non-null data to\n");
3.29 body.append(" * send messages to server. Call again with <code>null</code> data to close the socket.\n");
3.30 @@ -1111,17 +1113,34 @@
3.31 if (dataMirror != null) {
3.32 body.append(sep).append(dataMirror.toString()).append(" data");
3.33 }
3.34 + for (int i = 2; i < e.getParameters().size(); i++) {
3.35 + if (isWebSocket) {
3.36 + error("@OnReceive(method=\"WebSocket\") can only have two arguments", e);
3.37 + return false;
3.38 + }
3.39 +
3.40 + VariableElement ve = e.getParameters().get(i);
3.41 + body.append(sep).append(ve.asType().toString()).append(" ").append(ve.getSimpleName());
3.42 + final String tp = ve.asType().toString();
3.43 + String btn = findBoxedType(tp);
3.44 + if (btn == null) {
3.45 + btn = tp;
3.46 + }
3.47 + args.add("(" + btn + ")params[" + (i - 2) + "]");
3.48 + params.add(ve.getSimpleName().toString());
3.49 + sep = ", ";
3.50 + }
3.51 }
3.52 body.append(") {\n");
3.53 boolean webSocket = onR.method().equals("WebSocket");
3.54 if (webSocket) {
3.55 - if (generateWSReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
3.56 + if (generateWSReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, params, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
3.57 return false;
3.58 }
3.59 body.append(" }\n");
3.60 body.append(" private Object ws_" + e.getSimpleName() + ";\n");
3.61 } else {
3.62 - if (generateJSONReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
3.63 + if (generateJSONReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, params, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
3.64 return false;
3.65 }
3.66 body.append(" }\n");
3.67 @@ -1133,7 +1152,7 @@
3.68 return true;
3.69 }
3.70
3.71 - private boolean generateJSONReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
3.72 + private boolean generateJSONReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, List<String> params, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
3.73 body.append(
3.74 " case " + index + ": {\n" +
3.75 " if (type == 2) { /* on error */\n" +
3.76 @@ -1199,11 +1218,14 @@
3.77 } else {
3.78 method.append(", null, null");
3.79 }
3.80 + for (String a : params) {
3.81 + method.append(", ").append(a);
3.82 + }
3.83 method.append(");\n");
3.84 return false;
3.85 }
3.86
3.87 - private boolean generateWSReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
3.88 + private boolean generateWSReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, List<String> params, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
3.89 body.append(
3.90 " case " + index + ": {\n" +
3.91 " if (type == 0) { /* on open */\n" +
3.92 @@ -1212,7 +1234,7 @@
3.93 String sep = "";
3.94 for (String arg : args) {
3.95 body.append(sep);
3.96 - if (arg.startsWith("arr")) {
3.97 + if (arg.startsWith("arr") || arg.startsWith("java.util.Array")) {
3.98 body.append("null");
3.99 } else {
3.100 body.append(arg);
3.101 @@ -1284,7 +1306,11 @@
3.102 method.append("= proto.wsOpen(" + index + ", ");
3.103 method.append(urlBefore).append(", data);\n");
3.104 method.append(" } else {\n");
3.105 - method.append(" proto.wsSend(this.ws_").append(e.getSimpleName()).append(", ").append(urlBefore).append(", data);\n");
3.106 + method.append(" proto.wsSend(this.ws_").append(e.getSimpleName()).append(", ").append(urlBefore).append(", data");
3.107 + for (String a : params) {
3.108 + method.append(", ").append(a);
3.109 + }
3.110 + method.append(");\n");
3.111 method.append(" }\n");
3.112 return false;
3.113 }
4.1 --- a/json/src/test/java/net/java/html/json/ModelProcessorTest.java Fri Apr 04 18:09:39 2014 +0200
4.2 +++ b/json/src/test/java/net/java/html/json/ModelProcessorTest.java Sat Apr 05 09:06:59 2014 +0200
4.3 @@ -341,6 +341,21 @@
4.4 res.assertError("Cannot have the name");
4.5 }
4.6
4.7 + @Test public void onWebSocketJustTwoArgs() throws IOException {
4.8 + Compile res = Compile.create("", "package x;\n"
4.9 + + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
4.10 + + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
4.11 + + "})\n"
4.12 + + "class UseOnReceive {\n"
4.13 + + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\", method=\"WebSocket\")\n"
4.14 + + " static void onMessage(MyModel model, String value, int arg) {\n"
4.15 + + " }\n"
4.16 + + "}\n"
4.17 + );
4.18 + res.assertErrors();
4.19 + res.assertError("only have two arg");
4.20 + }
4.21 +
4.22 @Test public void onErrorWouldHaveToBeStatic() throws IOException {
4.23 Compile res = Compile.create("", "package x;\n"
4.24 + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
5.1 --- a/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java Fri Apr 04 18:09:39 2014 +0200
5.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java Sat Apr 05 09:06:59 2014 +0200
5.3 @@ -54,7 +54,8 @@
5.4 */
5.5 @Model(className = "Employee", properties = {
5.6 @Property(name = "person", type = Person.class),
5.7 - @Property(name = "employer", type = Employer.class)
5.8 + @Property(name = "employer", type = Employer.class),
5.9 + @Property(name = "call", type = Call.class)
5.10 })
5.11 public class EmployeeImpl {
5.12 @OnReceive(url = "some/url")
5.13 @@ -62,8 +63,39 @@
5.14 e.setPerson(p);
5.15 }
5.16
5.17 + private static void callChangePers(Employee e) {
5.18 + Person per = new Person();
5.19 + e.changePersonalities(10, 3.14, "Ahoj", per);
5.20 + e.updatePersonalities("kuk", new Person(), 1, 2, "3", new Person());
5.21 + e.socketPersonalities("where", null);
5.22 + }
5.23 +
5.24 @OnReceive(url = "some/other/url")
5.25 - static void changePersonalities(Employee e, List<Person> p) {
5.26 + static void changePersonalities(Employee e, List<Person> data, int i, double d, String s, Person o) {
5.27 + e.setCall(new Call(i, d, s, o, data.toArray(new Person[0])));
5.28 + }
5.29 +
5.30 + @OnReceive(url = "{url}", method = "PUT", data = Person.class)
5.31 + static void updatePersonalities(Employee e, List<Person> p, int i, double d, String s, Person o) {
5.32 e.setPerson(p.get(0));
5.33 }
5.34 +
5.35 + @OnReceive(url = "{url}", method = "WebSocket", data = Person.class)
5.36 + static void socketPersonalities(Employee e, List<Person> p) {
5.37 + e.setPerson(p.get(0));
5.38 + }
5.39 + @OnReceive(url = "{url}", method = "WebSocket", data = Person.class)
5.40 + static void socketArrayPersonalities(Employee e, Person[] p) {
5.41 + e.setPerson(p[0]);
5.42 + }
5.43 +
5.44 + @Model(className="Call", properties = {
5.45 + @Property(name = "i", type=int.class),
5.46 + @Property(name = "d", type=double.class),
5.47 + @Property(name = "s", type=String.class),
5.48 + @Property(name = "p", type=Person.class),
5.49 + @Property(name = "data", type=Person.class, array = true)
5.50 + })
5.51 + static class CallModel {
5.52 + }
5.53 }
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/OnReceiveTest.java Sat Apr 05 09:06:59 2014 +0200
6.3 @@ -0,0 +1,112 @@
6.4 +/**
6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
6.6 + *
6.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6.8 + *
6.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
6.10 + * Other names may be trademarks of their respective owners.
6.11 + *
6.12 + * The contents of this file are subject to the terms of either the GNU
6.13 + * General Public License Version 2 only ("GPL") or the Common
6.14 + * Development and Distribution License("CDDL") (collectively, the
6.15 + * "License"). You may not use this file except in compliance with the
6.16 + * License. You can obtain a copy of the License at
6.17 + * http://www.netbeans.org/cddl-gplv2.html
6.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
6.19 + * specific language governing permissions and limitations under the
6.20 + * License. When distributing the software, include this License Header
6.21 + * Notice in each file and include the License file at
6.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
6.23 + * particular file as subject to the "Classpath" exception as provided
6.24 + * by Oracle in the GPL Version 2 section of the License file that
6.25 + * accompanied this code. If applicable, add the following below the
6.26 + * License Header, with the fields enclosed by brackets [] replaced by
6.27 + * your own identifying information:
6.28 + * "Portions Copyrighted [year] [name of copyright owner]"
6.29 + *
6.30 + * Contributor(s):
6.31 + *
6.32 + * The Original Software is NetBeans. The Initial Developer of the Original
6.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
6.34 + *
6.35 + * If you wish your version of this file to be governed by only the CDDL
6.36 + * or only the GPL Version 2, indicate your decision by adding
6.37 + * "[Contributor] elects to include this software in this distribution
6.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
6.39 + * single choice of license, a recipient has the option to distribute
6.40 + * your version of this file under either the CDDL, the GPL Version 2 or
6.41 + * to extend the choice of license to its licensees as provided above.
6.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
6.43 + * Version 2 license, then the option applies only if the new code is
6.44 + * made subject to such option by the copyright holder.
6.45 + */
6.46 +package org.netbeans.html.json.impl;
6.47 +
6.48 +import java.io.IOException;
6.49 +import java.io.InputStream;
6.50 +import java.util.HashMap;
6.51 +import java.util.Map;
6.52 +import net.java.html.BrwsrCtx;
6.53 +import net.java.html.json.Models;
6.54 +import net.java.html.json.Person;
6.55 +import org.apidesign.html.context.spi.Contexts;
6.56 +import org.apidesign.html.json.spi.JSONCall;
6.57 +import org.apidesign.html.json.spi.Transfer;
6.58 +import static org.testng.Assert.*;
6.59 +import org.testng.annotations.Test;
6.60 +
6.61 +/**
6.62 + *
6.63 + * @author Jaroslav Tulach <jtulach@netbeans.org>
6.64 + */
6.65 +public class OnReceiveTest {
6.66 + @Test public void performJSONCall() {
6.67 + MockTrans mt = new MockTrans();
6.68 + BrwsrCtx ctx = Contexts.newBuilder().register(Transfer.class, mt, 1).build();
6.69 +
6.70 + Employee e = Models.bind(new Employee(), ctx);
6.71 + e.setCall(null);
6.72 + Person p = new Person();
6.73 +
6.74 + mt.result = new HashMap<String, String>();
6.75 + mt.result.put("firstName", "Jarda");
6.76 + mt.result.put("lastName", "Tulach");
6.77 + e.changePersonalities(1, 2.0, "3", p);
6.78 + final Call c = e.getCall();
6.79 + assertNotNull(c, "A call has been made");
6.80 + assertEquals(c.getI(), 1);
6.81 + assertEquals(c.getD(), 2.0);
6.82 + assertEquals(c.getS(), "3");
6.83 + assertEquals(c.getP(), p);
6.84 + assertEquals(c.getData().size(), 1, "One result sent over wire");
6.85 + assertEquals(c.getData().get(0).getFirstName(), "Jarda");
6.86 + assertEquals(c.getData().get(0).getLastName(), "Tulach");
6.87 + }
6.88 +
6.89 +
6.90 + public static class MockTrans implements Transfer {
6.91 + Map<String,String> result;
6.92 +
6.93 + @Override
6.94 + public void extract(Object obj, String[] props, Object[] values) {
6.95 + assertTrue(obj instanceof Map, "It is a map: " + obj);
6.96 + Map<?,?> mt = (Map<?,?>) obj;
6.97 + for (int i = 0; i < props.length; i++) {
6.98 + values[i] = mt.get(props[i]);
6.99 + }
6.100 + }
6.101 +
6.102 + @Override
6.103 + public Object toJSON(InputStream is) throws IOException {
6.104 + throw new IOException();
6.105 + }
6.106 +
6.107 + @Override
6.108 + public void loadJSON(JSONCall call) {
6.109 + Object r = result;
6.110 + assertNotNull(r, "We need a reply!");
6.111 + result = null;
6.112 + call.notifySuccess(r);
6.113 + }
6.114 + }
6.115 +}
7.1 --- a/src/main/javadoc/overview.html Fri Apr 04 18:09:39 2014 +0200
7.2 +++ b/src/main/javadoc/overview.html Sat Apr 05 09:06:59 2014 +0200
7.3 @@ -78,6 +78,12 @@
7.4 <h3>What's New in Version 0.8?</h3>
7.5
7.6 <p>
7.7 + The first argument of method annotated by
7.8 + {@link net.java.html.json.OnReceive} annotation has to
7.9 + be the associated {@link net.java.html.json.Model model class}.
7.10 + </p>
7.11 +
7.12 + <p>
7.13 {@link net.java.html.json.OnReceive} annotation now accepts
7.14 {@link java.util.List} of data values as second argument
7.15 (previously required an array).