This is an automated email from the ASF dual-hosted git repository.

jtulach pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans-html4j.git


The following commit(s) were added to refs/heads/master by this push:
     new 7cb1712  Allow additional registrations of properties and functions 
into a Proto.Type
7cb1712 is described below

commit 7cb171279dbb1fbb81c2c7c1781d3f9efc64a130
Author: Jaroslav Tulach <[email protected]>
AuthorDate: Mon Oct 29 15:51:04 2018 +0100

    Allow additional registrations of properties and functions into a Proto.Type
---
 .../org/netbeans/html/json/impl/SimpleList.java    |  18 +-
 .../java/org/netbeans/html/json/spi/Proto.java     |  63 ++++---
 .../java/org/netbeans/html/json/spi/ProtoTest.java | 198 +++++++++++++++++++++
 3 files changed, 253 insertions(+), 26 deletions(-)

diff --git a/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java 
b/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
index 0950c7e..566397c 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
@@ -239,9 +239,9 @@ public class SimpleList<E> implements List<E> {
         }
     }
 
-    private void ensureAccess(int reqSize) {
+    private int ensureAccess(int reqSize) {
         if (reqSize < size) {
-            return;
+            return size;
         }
 
         int newSize = arr == null ? 0 : arr.length;
@@ -257,6 +257,11 @@ public class SimpleList<E> implements List<E> {
         }
 
         arr = newArr;
+        return reqSize;
+    }
+
+    private void ensureSize(int newSize) {
+        this.size = ensureAccess(newSize);
     }
 
     @Override
@@ -404,6 +409,15 @@ public class SimpleList<E> implements List<E> {
         return sb.toString();
     }
 
+    public static void ensureSize(List<?> list, int size) {
+        if (list instanceof SimpleList) {
+            ((SimpleList<?>) list).ensureSize(size);
+            return;
+        }
+        while (list.size() < size) {
+            list.add(null);
+        }
+    }
 
     private final class Sub implements List<E> {
         private final int from;
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Proto.java 
b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
index d54cf58..dfa1ab7 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/Proto.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
@@ -18,6 +18,7 @@
  */
 package org.netbeans.html.json.spi;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import net.java.html.BrwsrCtx;
@@ -32,6 +33,7 @@ import org.netbeans.html.json.impl.JSONList;
 import org.netbeans.html.json.impl.PropertyBindingAccessor;
 import org.netbeans.html.json.impl.RcvrJSON;
 import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
+import org.netbeans.html.json.impl.SimpleList;
 
 /** Object associated with one instance of a model generated by the
  * {@link Model} annotation. Contains methods the generated class can
@@ -141,7 +143,7 @@ public final class Proto {
         });
     }
 
-    /** Whenever model changes a propertyit should notify the
+    /** Whenever model changes a property it should notify the
      * associated technology. Either by calling this method
      * (if the new value is known and different to the old one) or
      * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
@@ -486,17 +488,19 @@ public final class Proto {
     final Bindings initBindings(Object originalObject) {
         if (ko == null) {
             Bindings b = Bindings.apply(context);
-            PropertyBinding[] pb = new 
PropertyBinding[type.propertyNames.length];
+            PropertyBinding[] pb = new PropertyBinding[type.properties.size()];
             for (int i = 0; i < pb.length; i++) {
-                pb[i] = b.registerProperty(
-                    type.propertyNames[i], i, obj, type, type.propertyType[i]
-                );
+                final PropertyInfo info = (PropertyInfo) 
type.properties.get(i);
+                if (info != null) {
+                    pb[i] = b.registerProperty(info.name, i, obj, type, 
info.type);
+                }
             }
-            FunctionBinding[] fb = new FunctionBinding[type.functions.length];
+            FunctionBinding[] fb = new FunctionBinding[type.functions.size()];
             for (int i = 0; i < fb.length; i++) {
-                fb[i] = FunctionBinding.registerFunction(
-                    type.functions[i], i, obj, type
-                );
+                final String fnName = (String) type.functions.get(i);
+                if (fnName != null) {
+                    fb[i] = FunctionBinding.registerFunction(fnName, i, obj, 
type);
+                }
             }
             ko = b;
             b.finish(obj, originalObject, pb, fb);
@@ -519,6 +523,16 @@ public final class Proto {
         return observers;
     }
 
+    private static class PropertyInfo {
+        final String name;
+        final byte type;
+
+        PropertyInfo(String name, byte type) {
+            this.name = name;
+            this.type = type;
+        }
+    }
+
     /** Functionality used by the code generated by annotation
      * processor for the {@link net.java.html.json.Model} annotation.
      *
@@ -526,10 +540,9 @@ public final class Proto {
      * @since 0.7
      */
     public static abstract class Type<Model> {
-        private final Class<? extends Model> clazz;
-        private final String[] propertyNames;
-        private final byte[] propertyType;
-        private final String[] functions;
+        final Class<? extends Model> clazz;
+        final java.util.List<PropertyInfo> properties;
+        final java.util.List<String> functions;
 
         /** Constructor for subclasses generated by the annotation processor
          * associated with {@link net.java.html.json.Model} annotation.
@@ -543,9 +556,8 @@ public final class Proto {
             Class<? extends Model> clazz, Class<?> modelFor, int properties, 
int functions
         ) {
             this.clazz = clazz;
-            this.propertyNames = new String[properties];
-            this.propertyType = new byte[properties];
-            this.functions = new String[functions];
+            this.properties = SimpleList.asList(new PropertyInfo[properties]);
+            this.functions = SimpleList.asList(new String[functions]);
             JSON.register(clazz, this);
         }
 
@@ -557,9 +569,7 @@ public final class Proto {
          * @param readOnly is the property read only?
          */
         protected final void registerProperty(String name, int index, boolean 
readOnly) {
-            assert propertyNames[index] == null;
-            propertyNames[index] = name;
-            propertyType[index] = (byte) (readOnly ? 1 : 0);
+            registerProperty(name, index, readOnly, false);
         }
 
         /** Registers property for the type. It is expected each index
@@ -569,6 +579,9 @@ public final class Proto {
          * {@link Property#mutable() non-mutable} property. On the other
          * hand, a <code>readOnly</code> property can change its value,
          * but not via a setter - just like {@link ComputedProperty}.
+         * <p>
+         * This method isn't synchronized. Synchronization is up to the
+         * caller.
          *
          * @param name name of the property
          * @param index index of the property
@@ -579,9 +592,10 @@ public final class Proto {
         protected final void registerProperty(
             String name, int index, boolean readOnly, boolean constant
         ) {
-            assert propertyNames[index] == null;
-            propertyNames[index] = name;
-            propertyType[index] = (byte) ((readOnly ? 1 : 0) | (constant ? 2 : 
0));
+            SimpleList.ensureSize(properties, index + 1);
+            assert properties.get(index) == null;
+            byte t = (byte) ((readOnly ? 1 : 0) | (constant ? 2 : 0));
+            properties.set(index, new PropertyInfo(name, t));
         }
 
         /** Registers function of given name at given index.
@@ -590,8 +604,9 @@ public final class Proto {
          * @param index name of the type
          */
         protected final void registerFunction(String name, int index) {
-            assert functions[index] == null;
-            functions[index] = name;
+            SimpleList.ensureSize(functions, index + 1);
+            assert functions.get(index) == null;
+            functions.set(index, name);
         }
 
         /** Creates new proto-object for given {@link Model} class bound to
diff --git a/json/src/test/java/org/netbeans/html/json/spi/ProtoTest.java 
b/json/src/test/java/org/netbeans/html/json/spi/ProtoTest.java
new file mode 100644
index 0000000..89ed6ab
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/spi/ProtoTest.java
@@ -0,0 +1,198 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.html.json.spi;
+
+import java.util.Map;
+import java.util.TreeMap;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import org.testng.annotations.Test;
+
+
+public class ProtoTest implements Technology.BatchInit<Object> {
+
+    private Object applyBindings;
+    private FunctionBinding[] functions;
+    private PropertyBinding[] properties;
+    private Object valueHasMutatedData;
+    private String valueHasMutatedName;
+
+    public ProtoTest() {
+    }
+
+    @Override
+    public Object wrapModel(Object model, PropertyBinding[] propArr, 
FunctionBinding[] funcArr) {
+        this.properties = propArr;
+        this.functions = funcArr;
+        return model;
+    }
+
+    @Override
+    public Object wrapModel(Object model) {
+        throw new UnsupportedOperationException("wrapModel");
+    }
+
+    @Override
+    public <M> M toModel(Class<M> modelClass, Object data) {
+        throw new UnsupportedOperationException("toModel");
+    }
+
+    @Override
+    public void bind(PropertyBinding b, Object model, Object data) {
+        throw new UnsupportedOperationException("bind");
+    }
+
+    @Override
+    public void valueHasMutated(Object data, String propertyName) {
+        this.valueHasMutatedData = data;
+        this.valueHasMutatedName = propertyName;
+    }
+
+    @Override
+    public void expose(FunctionBinding fb, Object model, Object d) {
+        throw new UnsupportedOperationException("expose");
+    }
+
+    @Override
+    public void applyBindings(Object data) {
+        this.applyBindings = data;
+    }
+
+    @Override
+    public Object wrapArray(Object[] arr) {
+        throw new UnsupportedOperationException("wrapArray");
+    }
+
+    @Override
+    public void runSafe(Runnable r) {
+        throw new UnsupportedOperationException("runSafe");
+    }
+
+    static final class MyObj {
+        final Proto proto;
+        final Map<Integer, Object> values;
+
+        MyObj(MyType type, BrwsrCtx ctx) {
+            this.proto = type.createProto(this, ctx);
+            this.values = new TreeMap<Integer, Object>();
+        }
+    }
+
+    static final class MyType extends Proto.Type<MyObj> {
+
+        MyType() {
+            super(MyObj.class, MyObj.class, 0, 0);
+        }
+
+
+
+        @Override
+        protected void setValue(MyObj model, int index, Object value) {
+            model.values.put(index, value);
+        }
+
+        @Override
+        protected Object getValue(MyObj model, int index) {
+            return model.values.get(index);
+        }
+
+        @Override
+        protected void call(MyObj model, int index, Object data, Object event) 
throws Exception {
+            throw new UnsupportedOperationException("call");
+        }
+
+        @Override
+        protected MyObj cloneTo(MyObj model, BrwsrCtx ctx) {
+            throw new UnsupportedOperationException("cloneTo");
+        }
+
+        @Override
+        protected MyObj read(BrwsrCtx c, Object json) {
+            throw new UnsupportedOperationException("read");
+        }
+
+        @Override
+        protected void onChange(MyObj model, int index) {
+            throw new UnsupportedOperationException("onChange");
+        }
+
+        @Override
+        protected Proto protoFor(Object object) {
+            if (object instanceof MyObj) {
+                return ((MyObj) object).proto;
+            }
+            return null;
+        }
+    }
+
+    @Test
+    public void registerPropertiesIncrementally() {
+        BrwsrCtx ctx = Contexts.newBuilder().register(Technology.class, this, 
100).build();
+        MyType type = new MyType();
+        MyObj obj = new MyObj(type, ctx);
+        type.registerProperty("33", 1, false, false);
+        type.registerProperty("44", 2, false, false);
+
+        obj.proto.applyBindings();
+
+        assertEquals(properties.length, 3, "Three properties");
+        assertNull(properties[0], "First one is empty");
+        assertNotNull(properties[1]);
+        assertNotNull(properties[2]);
+
+        type.setValue(obj, 1, "zero");
+        type.setValue(obj, 2, "one");
+
+        Object zero = type.getValue(obj, 1);
+        Object one = type.getValue(obj, 2);
+
+        assertEquals(zero, "zero");
+        assertEquals(one, "one");
+
+        assertNull(valueHasMutatedName);
+        obj.values.put(1, "nil");
+        obj.proto.valueHasMutated("33", "zero", "nil");
+        assertEquals(valueHasMutatedName, "33");
+        assertEquals(valueHasMutatedData, obj);
+
+        Object nil = type.getValue(obj, 1);
+        assertEquals(nil, "nil");
+    }
+
+    @Test
+    public void registerFunctionsIncrementally() {
+        BrwsrCtx ctx = Contexts.newBuilder().register(Technology.class, this, 
100).build();
+        MyType type = new MyType();
+        MyObj obj = new MyObj(type, ctx);
+        type.registerFunction("fifth", 5);
+
+        obj.proto.applyBindings();
+
+        assertEquals(6, functions.length);
+        assertNull(functions[0]);
+        assertNull(functions[1]);
+        assertNull(functions[2]);
+        assertNull(functions[3]);
+        assertNull(functions[4]);
+        assertNotNull(functions[5]);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to