wrapping arrays and providing setter and getter in PropertyBinding
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 22 Apr 2013 21:12:16 +0200
changeset 17b3a45f840583
parent 16 fc6bdb2a2b98
child 18 e4fc249046cf
wrapping arrays and providing setter and getter in PropertyBinding
json/src/main/java/net/java/html/json/Context.java
json/src/main/java/org/apidesign/html/json/impl/Bindings.java
json/src/main/java/org/apidesign/html/json/impl/JSONList.java
json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java
json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java
json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java
json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java
json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java
json/src/main/java/org/apidesign/html/json/spi/Technology.java
json/src/test/java/net/java/html/json/MapModelTest.java
json/src/test/java/net/java/html/json/ModelTest.java
json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java
     1.1 --- a/json/src/main/java/net/java/html/json/Context.java	Mon Apr 22 16:14:52 2013 +0200
     1.2 +++ b/json/src/main/java/net/java/html/json/Context.java	Mon Apr 22 21:12:16 2013 +0200
     1.3 @@ -80,5 +80,10 @@
     1.4          @Override
     1.5          public void applyBindings(Object data) {
     1.6          }
     1.7 +
     1.8 +        @Override
     1.9 +        public Object wrapArray(Object[] arr) {
    1.10 +            return arr;
    1.11 +        }
    1.12      }
    1.13  }
     2.1 --- a/json/src/main/java/org/apidesign/html/json/impl/Bindings.java	Mon Apr 22 16:14:52 2013 +0200
     2.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/Bindings.java	Mon Apr 22 21:12:16 2013 +0200
     2.3 @@ -24,6 +24,7 @@
     2.4  import java.util.List;
     2.5  import org.apidesign.html.json.spi.PropertyBinding;
     2.6  import net.java.html.json.Context;
     2.7 +import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
     2.8  import org.apidesign.html.json.spi.FunctionBinding;
     2.9  import org.apidesign.html.json.spi.Technology;
    2.10  
    2.11 @@ -35,31 +36,36 @@
    2.12      private final Data data;
    2.13      private final Technology<Data> bp;
    2.14  
    2.15 -    public Bindings(Data data, Technology<Data> bp) {
    2.16 +    private Bindings(Data data, Technology<Data> bp) {
    2.17          this.data = data;
    2.18          this.bp = bp;
    2.19      }
    2.20      
    2.21 -    public static Bindings<?> apply(Context c, Object model, String[] propsAndGetters, String[] functions) {
    2.22 +    public <M> PropertyBinding registerProperty(String propName, M model, SetAndGet<M> access, boolean readOnly) {
    2.23 +        PropertyBinding pb = PropertyBindingAccessor.create(new PBData<>(propName, model, access, readOnly));
    2.24 +        bp.bind(pb, model, data);
    2.25 +        return pb;
    2.26 +    }
    2.27 +    
    2.28 +    public static Bindings<?> apply(Context c, Object model, String[] functions) {
    2.29          Technology<?> bp = ContextAccessor.findTechnology(c);
    2.30 -        return apply(bp, model, propsAndGetters, functions);
    2.31 +        return apply(bp, model, null, functions);
    2.32      }
    2.33      
    2.34      private static <Data> Bindings<Data> apply(
    2.35          Technology<Data> bp, Object model, 
    2.36 -        String[] propsAndGetters, String[] methodsAndSignatures
    2.37 +        PropertyBinding[] propBindings, String[] methodsAndSignatures
    2.38      ) {
    2.39          Data d = bp.wrapModel(model);
    2.40          
    2.41 -        List<String> arr = Arrays.asList(propsAndGetters);
    2.42 -        for (int i = 0; i < propsAndGetters.length; i += 4) {
    2.43 -            PropertyBinding pb = PropertyBindingAccessor.create(
    2.44 -                arr.subList(i, i + 4)
    2.45 -            );
    2.46 -            bp.bind(pb, model, d);
    2.47 +        if (propBindings != null) {
    2.48 +            for (int i = 0; i < propBindings.length; i++) {
    2.49 +                PropertyBinding pb = propBindings[i];
    2.50 +                bp.bind(pb, model, d);
    2.51 +            }
    2.52          }
    2.53 -
    2.54 -        arr = Arrays.asList(methodsAndSignatures);
    2.55 +        
    2.56 +        List<String> arr = Arrays.asList(methodsAndSignatures);
    2.57          for (int i = 0; i < methodsAndSignatures.length; i += 2) {
    2.58              FunctionBinding fb = PropertyBindingAccessor.createFunction(arr.subList(i, i + 2));
    2.59              bp.expose(fb, model, d);
    2.60 @@ -80,4 +86,8 @@
    2.61      public void applyBindings() {
    2.62          bp.applyBindings(data);
    2.63      }
    2.64 +
    2.65 +    Object wrapArray(Object[] arr) {
    2.66 +        return bp.wrapArray(arr);
    2.67 +    }
    2.68  }
     3.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSONList.java	Mon Apr 22 16:14:52 2013 +0200
     3.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/JSONList.java	Mon Apr 22 21:12:16 2013 +0200
     3.3 @@ -162,20 +162,12 @@
     3.4          return ko;
     3.5      }
     3.6  
     3.7 -    @Override
     3.8 -    public boolean equals(Object o) {
     3.9 -        if (o instanceof WrapperObject) {
    3.10 -            ((WrapperObject)o).setRealObject(koData());
    3.11 -        }
    3.12 -        return super.equals(o);
    3.13 -    }
    3.14 -
    3.15 -    private Object[] koData() {
    3.16 +    public Object koData() {
    3.17          Object[] arr = toArray();
    3.18          for (int i = 0; i < arr.length; i++) {
    3.19              arr[i] = WrapperObject.find(arr[i]);
    3.20          }
    3.21 -        return arr;
    3.22 +        return model.wrapArray(arr);
    3.23      }
    3.24      
    3.25  }
     4.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Mon Apr 22 16:14:52 2013 +0200
     4.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Mon Apr 22 21:12:16 2013 +0200
     4.3 @@ -197,15 +197,44 @@
     4.4                  w.append("  };\n");
     4.5                  w.append("  private org.apidesign.html.json.impl.Bindings intKnckt() {\n");
     4.6                  w.append("    if (ko != null) return ko;\n");
     4.7 -                w.append("    return ko = org.apidesign.html.json.impl.Bindings.apply(context, this, ");
     4.8 -                writeStringArray(propsGetSet, w);
     4.9 -                w.append(", ");
    4.10 +                w.append("    ko = org.apidesign.html.json.impl.Bindings.apply(context, this, ");
    4.11                  writeStringArray(functions, w);
    4.12                  w.append("    );\n");
    4.13 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
    4.14 +                    w.append("    ko.registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
    4.15 +                    w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + ");\n");
    4.16 +                }
    4.17 +                w.append("    return ko;\n");
    4.18                  w.append("  };\n");
    4.19 +                w.append("  private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + "> {\n");
    4.20 +                w.append("    private final int type;\n");
    4.21 +                w.append("    P(int t) { type = t; };\n");
    4.22 +                w.append("    public void setValue(" + className + " data, Object value) {\n");
    4.23 +                w.append("      switch (type) {\n");
    4.24 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
    4.25 +                    final String set = propsGetSet.get(i + 2);
    4.26 +                    final String tn = propsGetSet.get(i + 4);
    4.27 +                    if (set != null) {
    4.28 +                        w.append("        case " + (i / 5) + ": data." + strip(set) + "((" + tn + ")value); return;\n");
    4.29 +                    }
    4.30 +                }
    4.31 +                w.append("      }\n");
    4.32 +                w.append("    }\n");
    4.33 +                w.append("    public Object getValue(" + className + " data) {\n");
    4.34 +                w.append("      switch (type) {\n");
    4.35 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
    4.36 +                    final String get = propsGetSet.get(i + 1);
    4.37 +                    if (get != null) {
    4.38 +                        w.append("        case " + (i / 5) + ": return data." + strip(get) + "();\n");
    4.39 +                    }
    4.40 +                }
    4.41 +                w.append("      }\n");
    4.42 +                w.append("      throw new UnsupportedOperationException();\n");
    4.43 +                w.append("    }\n");
    4.44 +                w.append("  }\n");
    4.45                  w.append("  ").append(className).append("(Object json) {\n");
    4.46                  int values = 0;
    4.47 -                for (int i = 0; i < propsGetSet.size(); i += 4) {
    4.48 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
    4.49                      Prprt p = findPrprt(props, propsGetSet.get(i));
    4.50                      if (p == null) {
    4.51                          continue;
    4.52 @@ -214,7 +243,7 @@
    4.53                  }
    4.54                  w.append("    Object[] ret = new Object[" + values + "];\n");
    4.55                  w.append("    org.apidesign.html.json.impl.JSON.extract(json, new String[] {\n");
    4.56 -                for (int i = 0; i < propsGetSet.size(); i += 4) {
    4.57 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
    4.58                      Prprt p = findPrprt(props, propsGetSet.get(i));
    4.59                      if (p == null) {
    4.60                          continue;
    4.61 @@ -222,7 +251,7 @@
    4.62                      w.append("      \"").append(propsGetSet.get(i)).append("\",\n");
    4.63                  }
    4.64                  w.append("    }, ret);\n");
    4.65 -                for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 4) {
    4.66 +                for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) {
    4.67                      final String pn = propsGetSet.get(i);
    4.68                      Prprt p = findPrprt(props, pn);
    4.69                      if (p == null) {
    4.70 @@ -307,7 +336,8 @@
    4.71              final String tn;
    4.72              tn = typeName(where, p);
    4.73              String[] gs = toGetSet(p.name(), tn, p.array());
    4.74 -
    4.75 +            String castTo;
    4.76 +            
    4.77              if (p.array()) {
    4.78                  w.write("private org.apidesign.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.apidesign.html.json.impl.JSONList<" + tn + ">(\""
    4.79                      + p.name() + "\"");
    4.80 @@ -331,13 +361,15 @@
    4.81                      w.write("}})");
    4.82                  }
    4.83                  w.write(";\n");
    4.84 -                
    4.85 +            
    4.86 +                castTo = "java.util.List";
    4.87                  w.write("public java.util.List<" + tn + "> " + gs[0] + "() {\n");
    4.88                  w.write("  if (locked) throw new IllegalStateException();\n");
    4.89                  w.write("  prop_" + p.name() + ".assign(this.intKnckt());\n");
    4.90                  w.write("  return prop_" + p.name() + ";\n");
    4.91                  w.write("}\n");
    4.92              } else {
    4.93 +                castTo = tn;
    4.94                  w.write("private " + tn + " prop_" + p.name() + ";\n");
    4.95                  w.write("public " + tn + " " + gs[0] + "() {\n");
    4.96                  w.write("  if (locked) throw new IllegalStateException();\n");
    4.97 @@ -369,6 +401,7 @@
    4.98              props.add(gs[2]);
    4.99              props.add(gs[3]);
   4.100              props.add(gs[0]);
   4.101 +            props.add(castTo);
   4.102          }
   4.103          return ok;
   4.104      }
   4.105 @@ -440,6 +473,7 @@
   4.106              props.add(gs[2]);
   4.107              props.add(null);
   4.108              props.add(gs[0]);
   4.109 +            props.add(tn);
   4.110          }
   4.111          
   4.112          return ok;
   4.113 @@ -1094,6 +1128,15 @@
   4.114          return ret;
   4.115      }
   4.116      
   4.117 +    private static String strip(String s) {
   4.118 +        int indx = s.indexOf("__");
   4.119 +        if (indx >= 0) {
   4.120 +            return s.substring(0, indx);
   4.121 +        } else {
   4.122 +            return s;
   4.123 +        }
   4.124 +    }
   4.125 +    
   4.126      private static class Prprt {
   4.127          private final Element e;
   4.128          private final AnnotationMirror tm;
     5.1 --- a/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java	Mon Apr 22 16:14:52 2013 +0200
     5.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java	Mon Apr 22 21:12:16 2013 +0200
     5.3 @@ -47,16 +47,39 @@
     5.4          }
     5.5      }
     5.6  
     5.7 -    protected abstract PropertyBinding newBinding(List<String> params);
     5.8 +    protected abstract <M> PropertyBinding newBinding(PBData<M> d);
     5.9      protected abstract FunctionBinding newFunction(List<String> params);
    5.10      
    5.11 -    static PropertyBinding create(
    5.12 -        List<String> params
    5.13 -    ) {
    5.14 -        return DEFAULT.newBinding(params);
    5.15 +    static <M> PropertyBinding create(PBData<M> d) {
    5.16 +        return DEFAULT.newBinding(d);
    5.17      }
    5.18      static FunctionBinding createFunction(List<String> subList) {
    5.19          return DEFAULT.newFunction(subList);
    5.20      }
    5.21  
    5.22 +    public static final class PBData<M> {
    5.23 +        public final String name;
    5.24 +        public final M model;
    5.25 +        public final SetAndGet<M> access;
    5.26 +        public final boolean readOnly;
    5.27 +
    5.28 +        public PBData(String name, M model, SetAndGet<M> access, boolean readOnly) {
    5.29 +            this.name = name;
    5.30 +            this.model = model;
    5.31 +            this.access = access;
    5.32 +            this.readOnly = readOnly;
    5.33 +        }
    5.34 +
    5.35 +        public void setValue(Object v) {
    5.36 +            access.setValue(model, v);
    5.37 +        }
    5.38 +
    5.39 +        public Object getValue() {
    5.40 +            return access.getValue(model);
    5.41 +        }
    5.42 +
    5.43 +        public boolean isReadOnly() {
    5.44 +            return readOnly;
    5.45 +        }
    5.46 +    }
    5.47  }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java	Mon Apr 22 21:12:16 2013 +0200
     6.3 @@ -0,0 +1,33 @@
     6.4 +/**
     6.5 + * HTML via Java(tm) Language Bindings
     6.6 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     6.7 + *
     6.8 + * This program is free software: you can redistribute it and/or modify
     6.9 + * it under the terms of the GNU General Public License as published by
    6.10 + * the Free Software Foundation, version 2 of the License.
    6.11 + *
    6.12 + * This program is distributed in the hope that it will be useful,
    6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.15 + * GNU General Public License for more details. apidesign.org
    6.16 + * designates this particular file as subject to the
    6.17 + * "Classpath" exception as provided by apidesign.org
    6.18 + * in the License file that accompanied this code.
    6.19 + *
    6.20 + * You should have received a copy of the GNU General Public License
    6.21 + * along with this program. Look for COPYING file in the top folder.
    6.22 + * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
    6.23 + */
    6.24 +
    6.25 +package org.apidesign.html.json.impl;
    6.26 +
    6.27 +import org.apidesign.html.json.spi.PropertyBinding;
    6.28 +
    6.29 +/** A way to implement a {@link PropertyBinding}.
    6.30 + *
    6.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    6.32 + */
    6.33 +public interface SetAndGet<Data> {
    6.34 +    public void setValue(Data data, Object value);
    6.35 +    public Object getValue(Data data);
    6.36 +}
     7.1 --- a/json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java	Mon Apr 22 16:14:52 2013 +0200
     7.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java	Mon Apr 22 21:12:16 2013 +0200
     7.3 @@ -37,6 +37,13 @@
     7.4      
     7.5      
     7.6      public static Object find(Object model) {
     7.7 +        if (model == null) {
     7.8 +            return null;
     7.9 +        }
    7.10 +        if (model instanceof JSONList) {
    7.11 +            return ((JSONList<?>)model).koData();
    7.12 +        }
    7.13 +        
    7.14          WrapperObject ro = new WrapperObject();
    7.15          model.equals(ro);
    7.16          return ro.ko;
     8.1 --- a/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Mon Apr 22 16:14:52 2013 +0200
     8.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Mon Apr 22 21:12:16 2013 +0200
     8.3 @@ -22,6 +22,8 @@
     8.4  
     8.5  import java.util.List;
     8.6  import org.apidesign.html.json.impl.PropertyBindingAccessor;
     8.7 +import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
     8.8 +import org.apidesign.html.json.impl.WrapperObject;
     8.9  
    8.10  /** Describes a property when one is asked to 
    8.11   * bind it 
    8.12 @@ -29,17 +31,17 @@
    8.13   * @author Jaroslav Tulach <jtulach@netbeans.org>
    8.14   */
    8.15  public final class PropertyBinding {
    8.16 -    private final List<String> params;
    8.17 +    private final PBData<?> data;
    8.18      
    8.19 -    private PropertyBinding(List<String> p) {
    8.20 -        this.params = p;
    8.21 +    private PropertyBinding(PBData<?> p) {
    8.22 +        this.data = p;
    8.23      }
    8.24  
    8.25      static {
    8.26          new PropertyBindingAccessor() {
    8.27              @Override
    8.28 -            protected PropertyBinding newBinding(List<String> params) {
    8.29 -                return new PropertyBinding(params);
    8.30 +            protected <M> PropertyBinding newBinding(PBData<M> d) {
    8.31 +                return new PropertyBinding(d);
    8.32              }
    8.33  
    8.34              @Override
    8.35 @@ -50,27 +52,20 @@
    8.36      }
    8.37  
    8.38      public String getPropertyName() {
    8.39 -        return params.get(0);
    8.40 +        return data.name;
    8.41 +    }
    8.42 +
    8.43 +    public void setValue(Object v) {
    8.44 +        data.setValue(v);
    8.45      }
    8.46      
    8.47 -    public String getGetterName() {
    8.48 -        final String g = params.get(1);
    8.49 -        int end = g.indexOf("__");
    8.50 -        if (end == -1) {
    8.51 -            end = g.length();
    8.52 -        }
    8.53 -        return g.substring(0, end);
    8.54 +    public Object getValue() {
    8.55 +        Object v = data.getValue();
    8.56 +        Object r = WrapperObject.find(v);
    8.57 +        return r == null ? v : r;
    8.58      }
    8.59 -
    8.60 -    public String getSetterName() {
    8.61 -        final String g = params.get(2);
    8.62 -        if (g == null) {
    8.63 -            return null;
    8.64 -        }
    8.65 -        int end = g.indexOf("__");
    8.66 -        if (end == -1) {
    8.67 -            end = g.length();
    8.68 -        }
    8.69 -        return g.substring(0, end);
    8.70 +    
    8.71 +    public boolean isReadOnly() {
    8.72 +        return data.isReadOnly();
    8.73      }
    8.74  }
     9.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Technology.java	Mon Apr 22 16:14:52 2013 +0200
     9.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Technology.java	Mon Apr 22 21:12:16 2013 +0200
     9.3 @@ -61,4 +61,12 @@
     9.4       * @param data the data to apply
     9.5       */
     9.6      public void applyBindings(Data data);
     9.7 +
     9.8 +    /** Some technologies may require wrapping a Java array into a special
     9.9 +     * object. In such case they may return it from this method.
    9.10 +     * 
    9.11 +     * @param arr original array
    9.12 +     * @return wrapped array
    9.13 +     */
    9.14 +    public Object wrapArray(Object[] arr);
    9.15  }
    10.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java	Mon Apr 22 16:14:52 2013 +0200
    10.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java	Mon Apr 22 21:12:16 2013 +0200
    10.3 @@ -56,6 +56,7 @@
    10.4          assertEquals(v.getClass(), One.class, "It is instance of One");
    10.5          One o = (One)v;
    10.6          assertEquals(o.changes, 1, "One change so far");
    10.7 +        assertFalse(o.pb.isReadOnly(), "Mutable property");
    10.8          
    10.9          assertEquals(o.get(), "Jarda", "Value should be in the map");
   10.10          
   10.11 @@ -65,6 +66,17 @@
   10.12          assertEquals(o.changes, 2, "Snd change");
   10.13      }
   10.14      
   10.15 +    @Test public void derivedProperty() throws Exception {
   10.16 +        Person p = new Person(c);
   10.17 +        
   10.18 +        Map m = (Map)WrapperObject.find(p);
   10.19 +        Object v = m.get("fullName");
   10.20 +        assertNotNull(v, "Value should be in the map");
   10.21 +        assertEquals(v.getClass(), One.class, "It is instance of One");
   10.22 +        One o = (One)v;
   10.23 +        assertTrue(o.pb.isReadOnly(), "Mutable property");
   10.24 +    }
   10.25 +    
   10.26      @Test public void changeSex() {
   10.27          Person p = new Person(c);
   10.28          p.setFirstName("Trans");
   10.29 @@ -79,30 +91,18 @@
   10.30  
   10.31      private static final class One {
   10.32          int changes;
   10.33 -        private final Method getter;
   10.34 -        private final Object model;
   10.35 -        private final Method setter;
   10.36 +        final PropertyBinding pb;
   10.37      
   10.38 -        One(Object m, String get, String set) throws NoSuchMethodException {
   10.39 -            this.model = m;
   10.40 -            if (get != null) {
   10.41 -                this.getter = m.getClass().getMethod(get);
   10.42 -            } else {
   10.43 -                this.getter = null;
   10.44 -            }
   10.45 -            if (set != null) {
   10.46 -                this.setter = m.getClass().getMethod(set, this.getter.getReturnType());
   10.47 -            } else {
   10.48 -                this.setter = null;
   10.49 -            }
   10.50 +        One(Object m, PropertyBinding pb) throws NoSuchMethodException {
   10.51 +            this.pb = pb;
   10.52          }
   10.53          
   10.54          Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   10.55 -            return getter.invoke(model);
   10.56 +            return pb.getValue();
   10.57          }
   10.58          
   10.59          void set(Object v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   10.60 -            setter.invoke(model, v);
   10.61 +            pb.setValue(v);
   10.62          }
   10.63      }
   10.64      
   10.65 @@ -124,7 +124,7 @@
   10.66          @Override
   10.67          public void bind(PropertyBinding b, Object model, Map<String, One> data) {
   10.68              try {
   10.69 -                One o = new One(model, b.getGetterName(), b.getSetterName());
   10.70 +                One o = new One(model, b);
   10.71                  data.put(b.getPropertyName(), o);
   10.72              } catch (NoSuchMethodException ex) {
   10.73                  throw new IllegalStateException(ex);
   10.74 @@ -134,7 +134,7 @@
   10.75          @Override
   10.76          public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
   10.77              try {
   10.78 -                data.put(fb.getFunctionName(), new One(model, null, null));
   10.79 +                data.put(fb.getFunctionName(), new One(model, null));
   10.80              } catch (NoSuchMethodException ex) {
   10.81                  throw new IllegalStateException(ex);
   10.82              }
   10.83 @@ -143,5 +143,10 @@
   10.84          @Override
   10.85          public void applyBindings(Map<String, One> data) {
   10.86          }
   10.87 +
   10.88 +        @Override
   10.89 +        public Object wrapArray(Object[] arr) {
   10.90 +            return arr;
   10.91 +        }
   10.92      }
   10.93  }
    11.1 --- a/json/src/test/java/net/java/html/json/ModelTest.java	Mon Apr 22 16:14:52 2013 +0200
    11.2 +++ b/json/src/test/java/net/java/html/json/ModelTest.java	Mon Apr 22 21:12:16 2013 +0200
    11.3 @@ -256,5 +256,10 @@
    11.4          @Override
    11.5          public void applyBindings(Object data) {
    11.6          }
    11.7 +
    11.8 +        @Override
    11.9 +        public Object wrapArray(Object[] arr) {
   11.10 +            return arr;
   11.11 +        }
   11.12      }
   11.13  }
    12.1 --- a/json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java	Mon Apr 22 16:14:52 2013 +0200
    12.2 +++ b/json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java	Mon Apr 22 21:12:16 2013 +0200
    12.3 @@ -20,6 +20,8 @@
    12.4   */
    12.5  package org.apidesign.html.json.impl;
    12.6  
    12.7 +import java.util.HashMap;
    12.8 +import java.util.Map;
    12.9  import net.java.html.json.Context;
   12.10  import net.java.html.json.People;
   12.11  import net.java.html.json.Person;
   12.12 @@ -29,6 +31,7 @@
   12.13  import org.apidesign.html.json.spi.PropertyBinding;
   12.14  import org.apidesign.html.json.spi.Technology;
   12.15  import static org.testng.Assert.*;
   12.16 +import org.testng.annotations.BeforeMethod;
   12.17  import org.testng.annotations.Test;
   12.18  
   12.19  /**
   12.20 @@ -36,9 +39,15 @@
   12.21   * @author Jaroslav Tulach <jtulach@netbeans.org>
   12.22   */
   12.23  public class JSONListTest implements Technology<Object> {
   12.24 +    private boolean replaceArray;
   12.25 +    private final Map<String,PropertyBinding> bindings = new HashMap<>();
   12.26      
   12.27      public JSONListTest() {
   12.28      }
   12.29 +    
   12.30 +    @BeforeMethod public void clear() {
   12.31 +        replaceArray = false;
   12.32 +    }
   12.33  
   12.34      @Test public void testConvertorOnAnObject() {
   12.35          Context c = ContextBuilder.create().withTechnology(this).build();
   12.36 @@ -62,13 +71,45 @@
   12.37          
   12.38          People people = new People(c);
   12.39          people.getInfo().add(p);
   12.40 -
   12.41 -        Object real = WrapperObject.find(people.getInfo());
   12.42 +        
   12.43 +        PropertyBinding pb = bindings.get("info");
   12.44 +        assertNotNull(pb, "Binding for info found");
   12.45 +        
   12.46 +        Object real = pb.getValue();
   12.47          assertTrue(real instanceof Object[], "It is an array: " + real);
   12.48          Object[] arr = (Object[])real;
   12.49          assertEquals(arr.length, 1, "Size is one");
   12.50          assertEquals(this, arr[0], "I am the right model");
   12.51      }
   12.52 +    
   12.53 +    @Test public void testConvertorOnAnArrayWithWrapper() {
   12.54 +        this.replaceArray = true;
   12.55 +        Context c = ContextBuilder.create().withTechnology(this).build();
   12.56 +        
   12.57 +        Person p = new Person(c);
   12.58 +        p.setFirstName("1");
   12.59 +        p.setLastName("2");
   12.60 +        p.setSex(Sex.MALE);
   12.61 +        
   12.62 +        People people = new People(c);
   12.63 +        people.getInfo().add(p);
   12.64 +
   12.65 +        Object real = WrapperObject.find(people.getInfo());
   12.66 +        assertEquals(real, this, "I am the model of the array");
   12.67 +    }
   12.68 +
   12.69 +    @Test public void bindingsOnArray() {
   12.70 +        this.replaceArray = true;
   12.71 +        Context c = ContextBuilder.create().withTechnology(this).build();
   12.72 +        
   12.73 +        People p = new People(c);
   12.74 +        p.getAge().add(30);
   12.75 +        
   12.76 +        PropertyBinding pb = bindings.get("age");
   12.77 +        assertNotNull(pb, "There is a binding for age list");
   12.78 +        
   12.79 +        assertEquals(pb.getValue(), this, "I am the model of the array");
   12.80 +    }
   12.81  
   12.82      @Override
   12.83      public Object wrapModel(Object model) {
   12.84 @@ -77,6 +118,7 @@
   12.85  
   12.86      @Override
   12.87      public void bind(PropertyBinding b, Object model, Object data) {
   12.88 +        bindings.put(b.getPropertyName(), b);
   12.89      }
   12.90  
   12.91      @Override
   12.92 @@ -90,5 +132,10 @@
   12.93      @Override
   12.94      public void applyBindings(Object data) {
   12.95      }
   12.96 +
   12.97 +    @Override
   12.98 +    public Object wrapArray(Object[] arr) {
   12.99 +        return replaceArray ? this : arr;
  12.100 +    }
  12.101      
  12.102  }