Include properties from the union classes into the main model union
authorJaroslav Tulach <jaroslav.tulach@netbeans.org>
Wed, 29 Jan 2014 15:00:53 +0100
branchunion
changeset 503fabdf33e4cab
parent 502 d09a640f5a56
child 504 f21372e3b044
Include properties from the union classes into the main model
json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
json/src/test/java/net/java/html/json/MapModelTest.java
json/src/test/java/org/netbeans/html/json/impl/PlainEnumTest.java
     1.1 --- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java	Tue Jan 28 16:18:33 2014 +0100
     1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java	Wed Jan 29 15:00:53 2014 +0100
     1.3 @@ -114,6 +114,30 @@
     1.4          }
     1.5      }
     1.6      
     1.7 +    @KOTest public void showUnionStrings() throws Exception {
     1.8 +        Object exp = Utils.exposeHTML(KnockoutTest.class, 
     1.9 +            "<ul id='ones' data-bind='foreach: ones'>\n"
    1.10 +          + "  <li data-bind='text: $data'/>"
    1.11 +          + "</ul>"
    1.12 +          + "<ul id='twos' data-bind='foreach: twos'>\n"
    1.13 +          + "  <li data-bind='text: $data'/>"
    1.14 +          + "</ul>"
    1.15 +        );
    1.16 +        try {
    1.17 +            Union u = new Union(new Union.One("Hello", "All!"));
    1.18 +            Union m = Models.bind(u, newContext());
    1.19 +            m.applyBindings();
    1.20 +
    1.21 +            int ones = countChildren("ones");
    1.22 +            int twos = countChildren("twos");
    1.23 +
    1.24 +            assert ones == 2 : "Two from One: " + ones;
    1.25 +            assert twos == 0 : "None from Two: " + twos;
    1.26 +        } finally {
    1.27 +            Utils.exposeHTML(KnockoutTest.class, "");
    1.28 +        }
    1.29 +    }
    1.30 +    
    1.31      @KOTest public void modifyValueAssertChangeInModel() throws Exception {
    1.32          Object exp = Utils.exposeHTML(KnockoutTest.class, 
    1.33              "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
     2.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java	Tue Jan 28 16:18:33 2014 +0100
     2.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java	Wed Jan 29 15:00:53 2014 +0100
     2.3 @@ -352,8 +352,8 @@
     2.4                  + (functions.size() / 2) + ");\n");
     2.5          {
     2.6              for (int i = 0; i < propsGetSet.size(); i++) {
     2.7 -                w.append("      registerProperty(\"").append(propsGetSet.get(i).p0).append("\", ");
     2.8 -                w.append(i + ", " + (propsGetSet.get(i).p2 == null) + ");\n");
     2.9 +                w.append("      registerProperty(\"").append(propsGetSet.get(i).name).append("\", ");
    2.10 +                w.append(i + ", " + (propsGetSet.get(i).set == null) + ");\n");
    2.11              }
    2.12          }
    2.13          {
    2.14 @@ -366,8 +366,8 @@
    2.15          w.append("    @Override public void setValue(" + className + " data, int type, Object value) {\n");
    2.16          w.append("      switch (type) {\n");
    2.17          for (int i = 0; i < propsGetSet.size(); i++) {
    2.18 -            final String set = propsGetSet.get(i).p2;
    2.19 -            String tn = propsGetSet.get(i).p4;
    2.20 +            final String set = propsGetSet.get(i).set;
    2.21 +            String tn = propsGetSet.get(i).type;
    2.22              String btn = findBoxedType(tn);
    2.23              if (btn != null) {
    2.24                  tn = btn;
    2.25 @@ -381,7 +381,7 @@
    2.26          w.append("    @Override public Object getValue(" + className + " data, int type) {\n");
    2.27          w.append("      switch (type) {\n");
    2.28          for (int i = 0; i < propsGetSet.size(); i++) {
    2.29 -            final String get = propsGetSet.get(i).p1;
    2.30 +            final String get = propsGetSet.get(i).get;
    2.31              if (get != null) {
    2.32                  w.append("        case " + i + ": return data." + strip(get) + "();\n");
    2.33              }
    2.34 @@ -427,7 +427,7 @@
    2.35          w.append("    this(c);\n");
    2.36          int values = 0;
    2.37          for (int i = 0; i < propsGetSet.size(); i++) {
    2.38 -            Prprt p = findPrprt(props, propsGetSet.get(i).p0);
    2.39 +            Prprt p = findPrprt(props, propsGetSet.get(i).name);
    2.40              if (p == null) {
    2.41                  continue;
    2.42              }
    2.43 @@ -436,15 +436,15 @@
    2.44          w.append("    Object[] ret = new Object[" + values + "];\n");
    2.45          w.append("    proto.extract(json, new String[] {\n");
    2.46          for (int i = 0; i < propsGetSet.size(); i++) {
    2.47 -            Prprt p = findPrprt(props, propsGetSet.get(i).p0);
    2.48 +            Prprt p = findPrprt(props, propsGetSet.get(i).name);
    2.49              if (p == null) {
    2.50                  continue;
    2.51              }
    2.52 -            w.append("      \"").append(propsGetSet.get(i).p0).append("\",\n");
    2.53 +            w.append("      \"").append(propsGetSet.get(i).name).append("\",\n");
    2.54          }
    2.55          w.append("    }, ret);\n");
    2.56          for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i++) {
    2.57 -            final String pn = propsGetSet.get(i).p0;
    2.58 +            final String pn = propsGetSet.get(i).name;
    2.59              Prprt p = findPrprt(props, pn);
    2.60              if (p == null) {
    2.61                  continue;
    2.62 @@ -580,6 +580,46 @@
    2.63              if (!generateOperation(e, body, className, e.getEnclosedElements())) {
    2.64                  ok = false;
    2.65              }
    2.66 +            List<PropInfo> mergedProps = new ArrayList<PropInfo>(propsGetSet);
    2.67 +            for (Element ec : e.getEnclosedElements()) {
    2.68 +                if (ec.getKind() != ElementKind.ENUM_CONSTANT) {
    2.69 +                    continue;
    2.70 +                }
    2.71 +                Model em = ec.getAnnotation(Model.class);
    2.72 +                if (em == null) {
    2.73 +                    continue;
    2.74 +                }
    2.75 +                Prprt[] subProps = Prprt.wrap(processingEnv, ec, em.properties());
    2.76 +                for (Prprt prprt : subProps) {
    2.77 +                    PropInfo found = null;
    2.78 +                    for (PropInfo existing : mergedProps) {
    2.79 +                        if (existing.name.equals(prprt.name())) {
    2.80 +                            found = existing;
    2.81 +                            break;
    2.82 +                        }
    2.83 +                    }
    2.84 +                    if (found == null) {
    2.85 +                        final String tn = typeName(ec, prprt);
    2.86 +                        String[] gs = toGetSet(prprt.name(), tn, prprt.array());
    2.87 +                        String castTo;
    2.88 +
    2.89 +                        if (prprt.array()) {
    2.90 +                            castTo = "java.util.List";
    2.91 +                        } else {
    2.92 +                            castTo = tn;
    2.93 +                        }
    2.94 +                        found = new PropInfo(
    2.95 +                            prprt.name(),
    2.96 +                            gs[2],
    2.97 +                            gs[3],
    2.98 +                            gs[0],
    2.99 +                            castTo
   2.100 +                        );
   2.101 +                        mergedProps.add(found);
   2.102 +                    }
   2.103 +                    found.addModel(em);
   2.104 +                }
   2.105 +            }            
   2.106              FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
   2.107              w = new OutputStreamWriter(java.openOutputStream());
   2.108              try {
   2.109 @@ -702,12 +742,12 @@
   2.110                  }
   2.111                  w.append("  private static class Html4JavaType extends org.apidesign.html.json.spi.Proto.Type<").append(className).append("> {\n");
   2.112                  w.append("    private Html4JavaType() {\n      super(").append(className).append(".class, ").
   2.113 -                    append(inPckName(e)).append(".class, " + (propsGetSet.size()) + ", "
   2.114 +                    append(inPckName(e)).append(".class, " + (mergedProps.size()) + ", "
   2.115                      + (functions.size() / 2) + ");\n");
   2.116                  {
   2.117 -                    for (int i = 0; i < propsGetSet.size(); i++) {
   2.118 -                        w.append("      registerProperty(\"").append(propsGetSet.get(i).p0).append("\", ");
   2.119 -                        w.append(i + ", " + (propsGetSet.get(i).p2 == null) + ");\n");
   2.120 +                    for (int i = 0; i < mergedProps.size(); i++) {
   2.121 +                        w.append("      registerProperty(\"").append(mergedProps.get(i).name).append("\", ");
   2.122 +                        w.append(i + ", " + (mergedProps.get(i).set == null) + ");\n");
   2.123                      }
   2.124                  }
   2.125                  {
   2.126 @@ -719,25 +759,52 @@
   2.127                  w.append("    }\n");
   2.128                  w.append("    @Override public void setValue(" + className + " data, int type, Object value) {\n");
   2.129                  w.append("      switch (type) {\n");
   2.130 -                for (int i = 0; i < propsGetSet.size(); i++) {
   2.131 -                    final String set = propsGetSet.get(i).p2;
   2.132 -                    String tn = propsGetSet.get(i).p4;
   2.133 +                for (int i = 0; i < mergedProps.size(); i++) {
   2.134 +                    final PropInfo mp = mergedProps.get(i);
   2.135 +                    final String set = mp.set;
   2.136 +                    String tn = mp.type;
   2.137                      String btn = findBoxedType(tn);
   2.138                      if (btn != null) {
   2.139                          tn = btn;
   2.140                      }
   2.141                      if (set != null) {
   2.142 -                        w.append("        case " + i + ": data." + strip(set) + "(TYPE.extractValue(" + tn + ".class, value)); return;\n");
   2.143 +                        if (mp.models.isEmpty()) {
   2.144 +                            w.append("        case " + i + ": data." + strip(set) + "(TYPE.extractValue(" + tn + ".class, value)); return;\n");
   2.145 +                        } else {
   2.146 +                            w.append("        case " + i + ": {\n");
   2.147 +                            for (Model mdl : mp.models) {
   2.148 +                                w.append("          if (data.get" + mdl.className() + 
   2.149 +                                    "() != null) data.get" + mdl.className() + "()." + 
   2.150 +                                    strip(set) + "(TYPE.extractValue(" + tn + 
   2.151 +                                    ".class, value));\n"
   2.152 +                                );
   2.153 +                            }
   2.154 +                            w.append("          return;\n");
   2.155 +                            w.append("        }\n");
   2.156 +                        }
   2.157                      }
   2.158                  }
   2.159                  w.append("      }\n");
   2.160                  w.append("    }\n");
   2.161                  w.append("    @Override public Object getValue(" + className + " data, int type) {\n");
   2.162                  w.append("      switch (type) {\n");
   2.163 -                for (int i = 0; i < propsGetSet.size(); i++) {
   2.164 -                    final String get = propsGetSet.get(i).p1;
   2.165 +                for (int i = 0; i < mergedProps.size(); i++) {
   2.166 +                    final PropInfo mp = mergedProps.get(i);
   2.167 +                    final String get = mp.get;
   2.168                      if (get != null) {
   2.169 -                        w.append("        case " + i + ": return data." + strip(get) + "();\n");
   2.170 +                        if (mp.models.isEmpty()) {
   2.171 +                            w.append("        case " + i + ": return data." + strip(get) + "();\n");
   2.172 +                        } else {
   2.173 +                            w.append("        case " + i + ": {\n");
   2.174 +                            for (Model mdl : mp.models) {
   2.175 +                                w.append("          if (data.get" + mdl.className() + 
   2.176 +                                    "() != null) return data.get" + mdl.className() + "()." + 
   2.177 +                                    strip(get) + "();\n"
   2.178 +                                );
   2.179 +                            }
   2.180 +                            w.append("          return null;\n");
   2.181 +                            w.append("        }\n");
   2.182 +                        }
   2.183                      }
   2.184                  }
   2.185                  w.append("      }\n");
   2.186 @@ -782,7 +849,7 @@
   2.187                  w.append("  private final Object readUnion(Object json) {\n");
   2.188                  int values = 1;
   2.189                  for (int i = 0; i < propsGetSet.size(); i++) {
   2.190 -                    Prprt p = findPrprt(props, propsGetSet.get(i).p0);
   2.191 +                    Prprt p = findPrprt(props, propsGetSet.get(i).name);
   2.192                      if (p == null) {
   2.193                          continue;
   2.194                      }
   2.195 @@ -792,11 +859,11 @@
   2.196                  w.append("    proto.extract(json, new String[] {\n");
   2.197                  w.append("      \"").append(e.getSimpleName()).append("\",\n");
   2.198                  for (int i = 0; i < propsGetSet.size(); i++) {
   2.199 -                    Prprt p = findPrprt(props, propsGetSet.get(i).p0);
   2.200 +                    Prprt p = findPrprt(props, propsGetSet.get(i).name);
   2.201                      if (p == null) {
   2.202                          continue;
   2.203                      }
   2.204 -                    w.append("      \"").append(propsGetSet.get(i).p0).append("\",\n");
   2.205 +                    w.append("      \"").append(propsGetSet.get(i).name).append("\",\n");
   2.206                  }
   2.207                  w.append("    }, ret);\n");
   2.208                  w.append("    Object union;\n");
   2.209 @@ -812,7 +879,7 @@
   2.210                  w.append("      default: throw new IllegalStateException(ret[0].toString());\n");
   2.211                  w.append("    }\n" );
   2.212                  for (int i = 0, cnt = 1, prop = 0; i < propsGetSet.size(); i++) {
   2.213 -                    final String pn = propsGetSet.get(i).p0;
   2.214 +                    final String pn = propsGetSet.get(i).name;
   2.215                      Prprt p = findPrprt(props, pn);
   2.216                      if (p == null) {
   2.217                          continue;
   2.218 @@ -924,7 +991,7 @@
   2.219                  final PropInfo switchProp = new PropInfo(e.getSimpleName().toString(), null, null, null, null);
   2.220                  if (sharedProps.contains(switchProp)) {
   2.221                      ok = false;
   2.222 -                    error("Duplicated property " + switchProp.p0 + " due to enum switch", e);
   2.223 +                    error("Duplicated property " + switchProp.name + " due to enum switch", e);
   2.224                  } else {
   2.225                      sharedProps.add(switchProp);
   2.226                  }
   2.227 @@ -2351,26 +2418,28 @@
   2.228      }
   2.229  
   2.230      private static final class PropInfo {
   2.231 -        final String p0;
   2.232 -        final String p1;
   2.233 -        final String p2;
   2.234 +        final String name;
   2.235 +        final String get;
   2.236 +        final String set;
   2.237          final String p3;
   2.238 -        final String p4;
   2.239 +        final String type;
   2.240 +        final List<Model> models;
   2.241  
   2.242          PropInfo(
   2.243              String p1, String p2, Object p3, String p4, String p5
   2.244          ) {
   2.245 -            this.p0 = p1;
   2.246 -            this.p1 = p2;
   2.247 -            this.p2 = p3 == null ? null : p3.toString();
   2.248 +            this.name = p1;
   2.249 +            this.get = p2;
   2.250 +            this.set = p3 == null ? null : p3.toString();
   2.251              this.p3 = p4;
   2.252 -            this.p4 = p5;
   2.253 +            this.type = p5;
   2.254 +            models = new ArrayList<Model>();
   2.255          }
   2.256  
   2.257          @Override
   2.258          public int hashCode() {
   2.259              int hash = 7;
   2.260 -            hash = 19 * hash + (this.p0 != null ? this.p0.hashCode() : 0);
   2.261 +            hash = 19 * hash + (this.name != null ? this.name.hashCode() : 0);
   2.262              return hash;
   2.263          }
   2.264  
   2.265 @@ -2383,10 +2452,14 @@
   2.266                  return false;
   2.267              }
   2.268              final PropInfo other = (PropInfo) obj;
   2.269 -            if ((this.p0 == null) ? (other.p0 != null) : !this.p0.equals(other.p0)) {
   2.270 +            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
   2.271                  return false;
   2.272              }
   2.273              return true;
   2.274          }
   2.275 +
   2.276 +        private void addModel(Model em) {
   2.277 +            models.add(em);
   2.278 +        }
   2.279      } // end of PropInfo
   2.280  }
     3.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java	Tue Jan 28 16:18:33 2014 +0100
     3.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java	Wed Jan 29 15:00:53 2014 +0100
     3.3 @@ -188,7 +188,7 @@
     3.4          }
     3.5      }
     3.6      
     3.7 -    static final class MapTechnology 
     3.8 +    public static final class MapTechnology 
     3.9      implements Technology<Map<String,One>>, Transfer {
    3.10  
    3.11          @Override
     4.1 --- a/json/src/test/java/org/netbeans/html/json/impl/PlainEnumTest.java	Tue Jan 28 16:18:33 2014 +0100
     4.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/PlainEnumTest.java	Wed Jan 29 15:00:53 2014 +0100
     4.3 @@ -42,9 +42,14 @@
     4.4   */
     4.5  package org.netbeans.html.json.impl;
     4.6  
     4.7 +import java.util.Map;
     4.8 +import net.java.html.BrwsrCtx;
     4.9 +import net.java.html.json.MapModelTest;
    4.10  import net.java.html.json.Model;
    4.11  import net.java.html.json.Models;
    4.12  import net.java.html.json.Property;
    4.13 +import org.apidesign.html.context.spi.Contexts;
    4.14 +import org.apidesign.html.json.spi.Technology;
    4.15  import static org.testng.Assert.*;
    4.16  import org.testng.annotations.Test;
    4.17  
    4.18 @@ -130,4 +135,18 @@
    4.19          int next = json.indexOf('{', 1);
    4.20          assertEquals(next, -1, "No other {");
    4.21      }
    4.22 +    
    4.23 +    @Test public void unionOfProperties() {
    4.24 +        MapModelTest.MapTechnology mt = new MapModelTest.MapTechnology();
    4.25 +        BrwsrCtx ctx = Contexts.newBuilder().register(Technology.class, mt, 1).build();
    4.26 +
    4.27 +        Union on = new Union(new Union.B("9.9"), 11, 1.1);
    4.28 +        Union u = Models.bind(on, ctx);
    4.29 +        
    4.30 +        Map<?,?> map = (Map<?,?>)Models.toRaw(u);
    4.31 +        assertNotNull(map.get("x"), "Four properties: " + map);
    4.32 +        assertNotNull(map.get("y"), "Four properties: " + map);
    4.33 +        assertNotNull(map.get("ua"), "Four properties: " + map);
    4.34 +        assertNotNull(map.get("ub"), "Four properties: " + map);
    4.35 +    }
    4.36  }