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