Few steps towards multi-method access that can also return plain text
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 09 May 2013 17:13:54 +0200
changeset 73f7e7223e94d4
parent 72 c00bc21c664a
child 74 b4d67c7a8d83
Few steps towards multi-method access that can also return plain text
json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
json/src/main/java/org/apidesign/html/json/impl/JSON.java
json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java
json/src/test/java/net/java/html/json/ModelProcessorTest.java
json/src/test/java/net/java/html/json/ModelTest.java
ko-fx/pom.xml
ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java
     1.1 --- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java	Thu May 09 12:47:26 2013 +0200
     1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java	Thu May 09 17:13:54 2013 +0200
     1.3 @@ -36,6 +36,7 @@
     1.4  @Model(className = "JSONik", properties = {
     1.5      @Property(name = "fetched", type = Person.class),
     1.6      @Property(name = "fetchedCount", type = int.class),
     1.7 +    @Property(name = "fetchedResponse", type = String.class),
     1.8      @Property(name = "fetchedSex", type = Sex.class, array = true)
     1.9  })
    1.10  public final class JSONTest {
    1.11 @@ -150,15 +151,15 @@
    1.12      @OnReceive(url="{url}", method = "PUT", data = Person.class)
    1.13      static void putPerson(JSONik model, String reply) {
    1.14          model.setFetchedCount(1);
    1.15 +        model.setFetchedResponse(reply);
    1.16      }
    1.17 -    /*
    1.18      @Http(@Http.Resource(
    1.19 -        content = "", 
    1.20 +        content = "$0\n$1", 
    1.21          path="/person.json", 
    1.22          mimeType = "text/plain",
    1.23 -        parameters = { }
    1.24 +        parameters = { "http.method", "http.requestBody" }
    1.25      ))
    1.26 -    @BrwsrTest public void putPeople() throws InterruptedException, Exception {
    1.27 +    @BrwsrTest public void putPeopleUsesRightMethod() throws InterruptedException, Exception {
    1.28          if (js == null) {
    1.29              orig = scriptElements();
    1.30              assert orig > 0 : "There should be some scripts on the page";
    1.31 @@ -175,10 +176,20 @@
    1.32          if (cnt == 0) {
    1.33              throw new InterruptedException();
    1.34          }
    1.35 -
    1.36 -        org.testng.Assert.fail("OK");
    1.37 +        String res = js.getFetchedResponse();
    1.38 +        int line = res.indexOf('\n');
    1.39 +        String msg;
    1.40 +        if (line >= 0) {
    1.41 +            msg = res.substring(0, line);
    1.42 +            res = res.substring(0, line);
    1.43 +        } else {
    1.44 +            msg = res;
    1.45 +        }
    1.46 +        
    1.47 +        assert "PUT".equals(res) : "Server was queried with PUT method: " + js.getFetchedResponse();
    1.48 +        
    1.49 +        assert msg.contains("Jarda") : "Data transferred to the server: " + msg;
    1.50      }
    1.51 -    */
    1.52      
    1.53      private static int scriptElements() throws Exception {
    1.54          return ((Number)Utils.executeScript("return window.document.getElementsByTagName('script').length;")).intValue();
     2.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSON.java	Thu May 09 12:47:26 2013 +0200
     2.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/JSON.java	Thu May 09 17:13:54 2013 +0200
     2.3 @@ -126,6 +126,9 @@
     2.4          return read(c, modelClazz, tr.toJSON((InputStream)data));
     2.5      }
     2.6      public static <T> T read(Context c, Class<T> modelClazz, Object data) {
     2.7 +        if (modelClazz == String.class) {
     2.8 +            return modelClazz.cast(data.toString());
     2.9 +        }
    2.10          for (int i = 0; i < 2; i++) {
    2.11              FromJSON<?> from = froms.get(modelClazz);
    2.12              if (from == null) {
     3.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Thu May 09 12:47:26 2013 +0200
     3.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Thu May 09 17:13:54 2013 +0200
     3.3 @@ -726,7 +726,10 @@
     3.4                  error("@OnReceive method should return void", e);
     3.5                  return false;
     3.6              }
     3.7 -            TypeMirror dataMirror = findDataSpecified(e, onR);
     3.8 +            if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) {
     3.9 +                error("JSONP works only with GET transport method", e);
    3.10 +            }
    3.11 +            String dataMirror = findDataSpecified(e, onR);
    3.12              if ("PUT".equals(onR.method()) && dataMirror == null) {
    3.13                  error("PUT method needs to specify a data() class", e);
    3.14                  return false;
    3.15 @@ -799,6 +802,9 @@
    3.16                          "') is not used in url attribute '" + onR.url() + "'", e
    3.17                      );
    3.18                  }
    3.19 +                if (dataMirror != null) {
    3.20 +                    body.append(sep).append(dataMirror.toString()).append(" data");
    3.21 +                }
    3.22              }
    3.23              body.append(") {\n");
    3.24              body.append("    final Object[] result = { null };\n");
    3.25 @@ -1181,7 +1187,16 @@
    3.26          }
    3.27      }
    3.28  
    3.29 -    private TypeMirror findDataSpecified(ExecutableElement e, OnReceive onR) {
    3.30 +    private String findDataSpecified(ExecutableElement e, OnReceive onR) {
    3.31 +        try {
    3.32 +            return onR.data().getName();
    3.33 +        } catch (MirroredTypeException ex) {
    3.34 +            String name = ex.getTypeMirror().toString();
    3.35 +            return "java.lang.Object".equals(name) ? null : name;
    3.36 +        } catch (Exception ex) {
    3.37 +            // fallback
    3.38 +        }
    3.39 +        
    3.40          AnnotationMirror found = null;
    3.41          for (AnnotationMirror am : e.getAnnotationMirrors()) {
    3.42              if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) {
    3.43 @@ -1196,8 +1211,14 @@
    3.44              ExecutableElement ee = entry.getKey();
    3.45              AnnotationValue av = entry.getValue();
    3.46              if (ee.getSimpleName().contentEquals("data")) {
    3.47 -                List<? extends Object> values = getAnnoValues(processingEnv, ee, found);
    3.48 -                return ee.asType();
    3.49 +                List<? extends Object> values = getAnnoValues(processingEnv, e, found);
    3.50 +                for (Object v : values) {
    3.51 +                    String sv = v.toString();
    3.52 +                    if (sv.startsWith("data = ") && sv.endsWith(".class")) {
    3.53 +                        return sv.substring(7, sv.length() - 6);
    3.54 +                    }
    3.55 +                }
    3.56 +                return "error";
    3.57              }
    3.58          }
    3.59          return null;
     4.1 --- a/json/src/test/java/net/java/html/json/ModelProcessorTest.java	Thu May 09 12:47:26 2013 +0200
     4.2 +++ b/json/src/test/java/net/java/html/json/ModelProcessorTest.java	Thu May 09 17:13:54 2013 +0200
     4.3 @@ -115,4 +115,35 @@
     4.4          fail("Needs an error message about missing data():\n" + c.getErrors());
     4.5          
     4.6      }
     4.7 +    
     4.8 +    
     4.9 +    @Test public void jsonNeedsToUseGet () throws Exception {
    4.10 +        String html = "<html><body>"
    4.11 +            + "</body></html>";
    4.12 +        String code = "package x.y.z;\n"
    4.13 +            + "import net.java.html.json.Model;\n"
    4.14 +            + "import net.java.html.json.Property;\n"
    4.15 +            + "import net.java.html.json.OnReceive;\n"
    4.16 +            + "@Model(className=\"XModel\", properties={\n"
    4.17 +            + "  @Property(name=\"prop\", type=long.class)\n"
    4.18 +            + "})\n"
    4.19 +            + "class X {\n"
    4.20 +            + "  @Model(className=\"PQ\", properties={})\n"
    4.21 +            + "  class PImpl {\n"
    4.22 +            + "  }\n"
    4.23 +            + "  @OnReceive(method=\"POST\", jsonp=\"callback\", url=\"whereever\")\n"
    4.24 +            + "  static void obtained(XModel m, PQ p) { }\n"
    4.25 +            + "}\n";
    4.26 +        
    4.27 +        Compile c = Compile.create(html, code);
    4.28 +        assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
    4.29 +        for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
    4.30 +            String msg = diagnostic.getMessage(Locale.ENGLISH);
    4.31 +            if (msg.contains("JSONP works only with GET")) {
    4.32 +                return;
    4.33 +            }
    4.34 +        }
    4.35 +        fail("Needs an error message about wrong method:\n" + c.getErrors());
    4.36 +        
    4.37 +    }
    4.38  }
     5.1 --- a/json/src/test/java/net/java/html/json/ModelTest.java	Thu May 09 12:47:26 2013 +0200
     5.2 +++ b/json/src/test/java/net/java/html/json/ModelTest.java	Thu May 09 17:13:54 2013 +0200
     5.3 @@ -166,7 +166,7 @@
     5.4      static void loadPeople(Modelik thiz, People p) {
     5.5          Modelik m = null;
     5.6          m.applyBindings();
     5.7 -        m.loadPeople("http", "apidesign.org", "query");
     5.8 +        m.loadPeople("http", "apidesign.org", "query", new Person(Context.EMPTY));
     5.9      }
    5.10  
    5.11      @OnReceive(url = "{protocol}://{host}?callback={back}&query={query}", jsonp = "back")
     6.1 --- a/ko-fx/pom.xml	Thu May 09 12:47:26 2013 +0200
     6.2 +++ b/ko-fx/pom.xml	Thu May 09 17:13:54 2013 +0200
     6.3 @@ -65,7 +65,7 @@
     6.4      <dependency>
     6.5        <groupId>org.apidesign.bck2brwsr</groupId>
     6.6        <artifactId>launcher.fx</artifactId>
     6.7 -      <version>${bck2brwsr.version}</version>
     6.8 +      <version>0.8-SNAPSHOT</version>
     6.9        <scope>test</scope>
    6.10      </dependency>
    6.11    </dependencies>
     7.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java	Thu May 09 12:47:26 2013 +0200
     7.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java	Thu May 09 17:13:54 2013 +0200
     7.3 @@ -94,6 +94,7 @@
     7.4              final URL u = new URL(base, url.replace(" ", "%20"));
     7.5              final PushbackInputStream is = new PushbackInputStream(u.openStream(), 1);
     7.6              boolean array = false;
     7.7 +            boolean string = false;
     7.8              if (call.isJSONP()) {
     7.9                  for (;;) {
    7.10                      int ch = is.read();
    7.11 @@ -114,13 +115,33 @@
    7.12                  int ch = is.read();
    7.13                  array = ch == '[';
    7.14                  is.unread(ch);
    7.15 +                if (!array && ch != '{') {
    7.16 +                    string = true;
    7.17 +                }
    7.18              }
    7.19 -            Reader r = new InputStreamReader(is, "UTF-8");
    7.20 +            try {
    7.21 +                if (string) {
    7.22 +                    throw new JSONException("");
    7.23 +                }
    7.24 +                Reader r = new InputStreamReader(is, "UTF-8");
    7.25  
    7.26 -            JSONTokener tok = new JSONTokener(r);
    7.27 -            Object obj = array ? new JSONArray(tok) : new JSONObject(tok);
    7.28 -            json = convertToArray(obj);
    7.29 -        } catch (JSONException | IOException ex) {
    7.30 +                JSONTokener tok = new JSONTokener(r);
    7.31 +                Object obj;
    7.32 +                obj = array ? new JSONArray(tok) : new JSONObject(tok);
    7.33 +                json = convertToArray(obj);
    7.34 +            } catch (JSONException ex) {
    7.35 +                Reader r = new InputStreamReader(is, "UTF-8");
    7.36 +                StringBuilder sb = new StringBuilder();
    7.37 +                for (;;) {
    7.38 +                    int ch = r.read();
    7.39 +                    if (ch == -1) {
    7.40 +                        break;
    7.41 +                    }
    7.42 +                    sb.append((char)ch);
    7.43 +                }
    7.44 +                json = sb.toString();
    7.45 +            }
    7.46 +        } catch (IOException ex) {
    7.47              error = ex;
    7.48              LOG.log(Level.WARNING, "Cannot connect to " + url, ex);
    7.49          } finally {