json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 790 30f20d9c0986
child 920 117b732d42d0
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
jaroslav@9
     1
/**
jaroslav@358
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jaroslav@9
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jaroslav@9
     5
 *
jaroslav@358
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@358
     7
 * Other names may be trademarks of their respective owners.
jaroslav@9
     8
 *
jaroslav@358
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@358
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@358
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@358
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@358
    13
 * License. You can obtain a copy of the License at
jaroslav@358
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@358
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@358
    16
 * specific language governing permissions and limitations under the
jaroslav@358
    17
 * License.  When distributing the software, include this License Header
jaroslav@358
    18
 * Notice in each file and include the License file at
jaroslav@358
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@358
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@358
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@358
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@358
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@358
    24
 * your own identifying information:
jaroslav@358
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@358
    26
 *
jaroslav@358
    27
 * Contributor(s):
jaroslav@358
    28
 *
jaroslav@358
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jaroslav@551
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jaroslav@358
    31
 *
jaroslav@358
    32
 * If you wish your version of this file to be governed by only the CDDL
jaroslav@358
    33
 * or only the GPL Version 2, indicate your decision by adding
jaroslav@358
    34
 * "[Contributor] elects to include this software in this distribution
jaroslav@358
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jaroslav@358
    36
 * single choice of license, a recipient has the option to distribute
jaroslav@358
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jaroslav@358
    38
 * to extend the choice of license to its licensees as provided above.
jaroslav@358
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jaroslav@358
    40
 * Version 2 license, then the option applies only if the new code is
jaroslav@358
    41
 * made subject to such option by the copyright holder.
jaroslav@9
    42
 */
jtulach@787
    43
package org.netbeans.html.json.impl;
jaroslav@9
    44
jtulach@787
    45
import java.io.IOException;
jtulach@787
    46
import java.io.InputStream;
jtulach@787
    47
import java.lang.reflect.InvocationTargetException;
jtulach@787
    48
import java.util.HashMap;
jtulach@777
    49
import java.util.List;
jtulach@773
    50
import java.util.Map;
jaroslav@110
    51
import net.java.html.BrwsrCtx;
jtulach@787
    52
import net.java.html.json.ComputedProperty;
jtulach@787
    53
import net.java.html.json.Model;
jtulach@787
    54
import net.java.html.json.Models;
jtulach@787
    55
import net.java.html.json.Property;
jtulach@838
    56
import org.netbeans.html.context.spi.Contexts;
jtulach@838
    57
import org.netbeans.html.json.spi.FunctionBinding;
jtulach@838
    58
import org.netbeans.html.json.spi.JSONCall;
jtulach@838
    59
import org.netbeans.html.json.spi.PropertyBinding;
jtulach@838
    60
import org.netbeans.html.json.spi.Technology;
jtulach@838
    61
import org.netbeans.html.json.spi.Transfer;
jtulach@773
    62
import static org.testng.Assert.*;
jaroslav@9
    63
import org.testng.annotations.BeforeMethod;
jaroslav@9
    64
import org.testng.annotations.Test;
jaroslav@9
    65
jaroslav@9
    66
/**
jaroslav@9
    67
 *
jtulach@790
    68
 * @author Jaroslav Tulach
jaroslav@9
    69
 */
jtulach@773
    70
public class DeepChangeTest {
jaroslav@9
    71
    private MapTechnology t;
jaroslav@110
    72
    private BrwsrCtx c;
jaroslav@9
    73
jaroslav@9
    74
    @BeforeMethod public void initTechnology() {
jaroslav@9
    75
        t = new MapTechnology();
jaroslav@110
    76
        c = Contexts.newBuilder().register(Technology.class, t, 1).
jaroslav@110
    77
            register(Transfer.class, t, 1).build();
jaroslav@9
    78
    }
jaroslav@9
    79
    
jtulach@773
    80
    @Model(className = "MyX", properties = {
jtulach@773
    81
        @Property(name = "one", type = MyY.class),
jtulach@773
    82
        @Property(name = "all", type = MyY.class, array = true)
jtulach@773
    83
    })
jtulach@773
    84
    static class X {
jtulach@787
    85
        @ComputedProperty @Transitive(deep = true) 
jtulach@773
    86
        static String oneName(MyY one) {
jtulach@773
    87
            return one.getValue();
jtulach@773
    88
        }
jtulach@788
    89
        @ComputedProperty
jtulach@775
    90
        static String sndName(MyY one) {
jtulach@775
    91
            return one.getValue().toUpperCase();
jtulach@775
    92
        }
jtulach@787
    93
        @ComputedProperty @Transitive(deep = false) 
jtulach@776
    94
        static String noName(MyY one) {
jtulach@776
    95
            return one.getValue().toUpperCase();
jtulach@776
    96
        }
jtulach@787
    97
        @ComputedProperty @Transitive(deep = true) 
jtulach@775
    98
        static String thrdName(MyY one) {
jtulach@775
    99
            return "X" + one.getCount();
jtulach@775
   100
        }
jtulach@777
   101
        
jtulach@788
   102
        @ComputedProperty
jtulach@777
   103
        static String allNames(List<MyY> all) {
jtulach@777
   104
            StringBuilder sb = new StringBuilder();
jtulach@777
   105
            for (MyY y : all) {
jtulach@777
   106
                sb.append(y.getValue());
jtulach@777
   107
            }
jtulach@777
   108
            return sb.toString();
jtulach@777
   109
        }
jtulach@777
   110
jtulach@787
   111
        @ComputedProperty @Transitive(deep = true)
jtulach@777
   112
        static String firstFromNames(List<MyY> all) {
jtulach@780
   113
            for (MyY y : all) {
jtulach@780
   114
                if (y != null && y.getValue() != null) {
jtulach@780
   115
                    return y.getValue();
jtulach@780
   116
                }
jtulach@777
   117
            }
jtulach@777
   118
            return null;
jtulach@777
   119
        }
jtulach@773
   120
    }
jtulach@773
   121
    @Model(className = "MyY", properties = {
jtulach@775
   122
        @Property(name = "value", type = String.class),
jtulach@775
   123
        @Property(name = "count", type = int.class)
jtulach@773
   124
    })
jtulach@773
   125
    static class Y {
jtulach@773
   126
    }
jtulach@778
   127
    @Model(className = "MyOverall", properties = {
jtulach@778
   128
        @Property(name = "x", type = MyX.class)
jtulach@778
   129
    })
jtulach@778
   130
    static class Overall {
jtulach@787
   131
        @ComputedProperty @Transitive(deep = true) 
jtulach@778
   132
        static String valueAccross(MyX x) {
jtulach@778
   133
            return x.getFirstFromNames();
jtulach@778
   134
        }
jtulach@778
   135
    }
jtulach@773
   136
    
jtulach@774
   137
    @Test public void isTransitiveChangeNotifiedProperly() throws Exception {
jtulach@773
   138
        MyX p = Models.bind(
jtulach@775
   139
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@773
   140
        ), c).applyBindings();
jaroslav@9
   141
        
jaroslav@450
   142
        Map m = (Map)Models.toRaw(p);
jtulach@773
   143
        Object v = m.get("oneName");
jaroslav@9
   144
        assertNotNull(v, "Value should be in the map");
jaroslav@9
   145
        assertEquals(v.getClass(), One.class, "It is instance of One");
jaroslav@9
   146
        One o = (One)v;
jtulach@773
   147
        assertEquals(o.changes, 0, "No changes so far");
jtulach@773
   148
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@773
   149
        assertEquals(o.get(), "Ahoj");
jtulach@773
   150
jtulach@773
   151
        p.getOne().setValue("Nazdar");
jtulach@773
   152
        
jtulach@773
   153
        assertEquals(o.get(), "Nazdar");
jaroslav@9
   154
        assertEquals(o.changes, 1, "One change so far");
jaroslav@9
   155
    }
jtulach@775
   156
    
jtulach@777
   157
    @Test public void isTransitiveChangeInArrayNotifiedProperly() throws Exception {
jtulach@777
   158
        MyX p = Models.bind(
jtulach@777
   159
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@777
   160
        ), c).applyBindings();
jtulach@777
   161
        
jtulach@777
   162
        Map m = (Map)Models.toRaw(p);
jtulach@777
   163
        Object v = m.get("allNames");
jtulach@777
   164
        assertNotNull(v, "Value should be in the map");
jtulach@777
   165
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@777
   166
        One o = (One)v;
jtulach@777
   167
        assertEquals(o.changes, 0, "No changes so far");
jtulach@777
   168
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@777
   169
        assertEquals(o.get(), "HiHello");
jtulach@777
   170
jtulach@777
   171
        p.getAll().get(0).setValue("Nazdar");
jtulach@777
   172
        
jtulach@777
   173
        assertEquals(o.get(), "NazdarHello");
jtulach@777
   174
        assertEquals(o.changes, 1, "One change so far");
jtulach@777
   175
    }
jtulach@779
   176
jtulach@779
   177
    @Test public void addingIntoArray() throws Exception {
jtulach@779
   178
        MyX p = Models.bind(
jtulach@779
   179
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@779
   180
        ), c).applyBindings();
jtulach@779
   181
        
jtulach@779
   182
        Map m = (Map)Models.toRaw(p);
jtulach@779
   183
        Object v = m.get("allNames");
jtulach@779
   184
        assertNotNull(v, "Value should be in the map");
jtulach@779
   185
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@779
   186
        One o = (One)v;
jtulach@779
   187
        assertEquals(o.changes, 0, "No changes so far");
jtulach@779
   188
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@779
   189
        assertEquals(o.get(), "HiHello");
jtulach@779
   190
jtulach@779
   191
        MyY y = new MyY("Cus", 1);
jtulach@779
   192
        p.getAll().add(y);
jtulach@779
   193
        
jtulach@779
   194
        assertEquals(o.changes, 1, "One change so far");
jtulach@779
   195
        assertEquals(o.get(), "HiHelloCus");
jtulach@779
   196
        
jtulach@779
   197
        y.setValue("Nazdar");
jtulach@779
   198
        
jtulach@779
   199
        assertEquals(o.changes, 2, "2nd change so far");
jtulach@779
   200
        assertEquals(o.get(), "HiHelloNazdar");
jtulach@779
   201
        
jtulach@780
   202
        y.setValue("Zdravim");
jtulach@780
   203
jtulach@780
   204
        assertEquals(o.changes, 3, "3rd change so far");
jtulach@780
   205
        assertEquals(o.get(), "HiHelloZdravim");
jtulach@779
   206
    }
jtulach@777
   207
    
jtulach@777
   208
    @Test public void firstChangeInArrayNotifiedProperly() throws Exception {
jtulach@777
   209
        MyX p = Models.bind(
jtulach@777
   210
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@777
   211
        ), c).applyBindings();
jtulach@777
   212
        
jtulach@777
   213
        Map m = (Map)Models.toRaw(p);
jtulach@777
   214
        Object v = m.get("firstFromNames");
jtulach@777
   215
        assertNotNull(v, "Value should be in the map");
jtulach@777
   216
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@777
   217
        One o = (One)v;
jtulach@777
   218
        assertEquals(o.changes, 0, "No changes so far");
jtulach@777
   219
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@777
   220
        assertEquals(o.get(), "Hi");
jtulach@777
   221
jtulach@777
   222
        p.getAll().get(0).setValue("Nazdar");
jtulach@777
   223
        
jtulach@777
   224
        assertEquals(o.get(), "Nazdar");
jtulach@777
   225
        assertEquals(o.changes, 1, "One change so far");
jtulach@777
   226
    }
jtulach@778
   227
    
jtulach@780
   228
    @Test public void firstChangeInArrayToNull() throws Exception {
jtulach@780
   229
        MyX p = Models.bind(
jtulach@780
   230
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@780
   231
        ), c).applyBindings();
jtulach@780
   232
        
jtulach@780
   233
        Map m = (Map)Models.toRaw(p);
jtulach@780
   234
        Object v = m.get("firstFromNames");
jtulach@780
   235
        assertNotNull(v, "Value should be in the map");
jtulach@780
   236
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@780
   237
        One o = (One)v;
jtulach@780
   238
        assertEquals(o.changes, 0, "No changes so far");
jtulach@780
   239
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@780
   240
        assertEquals(o.get(), "Hi");
jtulach@780
   241
jtulach@780
   242
        p.getAll().get(0).setValue(null);
jtulach@780
   243
        
jtulach@780
   244
        assertEquals(o.get(), "Hello");
jtulach@780
   245
        assertEquals(o.changes, 1, "One change so far");
jtulach@780
   246
        
jtulach@780
   247
        p.getAll().get(0).setValue("Nazdar");
jtulach@780
   248
jtulach@780
   249
        assertEquals(o.get(), "Nazdar");
jtulach@780
   250
        assertEquals(o.changes, 2, "2nd change so far");
jtulach@780
   251
    }
jtulach@780
   252
    
jtulach@778
   253
    @Test public void firstChangeInArrayNotifiedTransitively() throws Exception {
jtulach@778
   254
        MyOverall p = Models.bind(
jtulach@778
   255
            new MyOverall(new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999))
jtulach@778
   256
        ), c).applyBindings();
jtulach@778
   257
        
jtulach@778
   258
        Map m = (Map)Models.toRaw(p);
jtulach@778
   259
        Object v = m.get("valueAccross");
jtulach@778
   260
        assertNotNull(v, "Value should be in the map");
jtulach@778
   261
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@778
   262
        One o = (One)v;
jtulach@778
   263
        assertEquals(o.changes, 0, "No changes so far");
jtulach@778
   264
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@778
   265
        assertEquals(o.get(), "Hi");
jtulach@778
   266
jtulach@778
   267
        p.getX().getAll().get(0).setValue("Nazdar");
jtulach@778
   268
        
jtulach@778
   269
        assertEquals(o.get(), "Nazdar");
jtulach@778
   270
        assertEquals(o.changes, 1, "One change so far");
jtulach@778
   271
    }
jtulach@778
   272
    
jtulach@777
   273
    @Test public void secondChangeInArrayIgnored() throws Exception {
jtulach@777
   274
        MyX p = Models.bind(
jtulach@777
   275
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@777
   276
        ), c).applyBindings();
jtulach@777
   277
        
jtulach@777
   278
        Map m = (Map)Models.toRaw(p);
jtulach@777
   279
        Object v = m.get("firstFromNames");
jtulach@777
   280
        assertNotNull(v, "Value should be in the map");
jtulach@777
   281
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@777
   282
        One o = (One)v;
jtulach@777
   283
        assertEquals(o.changes, 0, "No changes so far");
jtulach@777
   284
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@777
   285
        assertEquals(o.get(), "Hi");
jtulach@777
   286
jtulach@777
   287
        p.getAll().get(1).setValue("Nazdar");
jtulach@777
   288
        
jtulach@777
   289
        assertEquals(o.get(), "Hi");
jtulach@777
   290
        assertEquals(o.changes, 0, "No change so far");
jtulach@777
   291
    }
jtulach@777
   292
    
jtulach@777
   293
    @Test public void changeInArraySizeNeedsToBeRecomputed() throws Exception {
jtulach@777
   294
        MyX p = Models.bind(
jtulach@777
   295
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@777
   296
        ), c).applyBindings();
jtulach@777
   297
        
jtulach@777
   298
        Map m = (Map)Models.toRaw(p);
jtulach@777
   299
        Object v = m.get("firstFromNames");
jtulach@777
   300
        assertNotNull(v, "Value should be in the map");
jtulach@777
   301
        assertEquals(v.getClass(), One.class, "It is instance of One");
jtulach@777
   302
        One o = (One)v;
jtulach@777
   303
        assertEquals(o.changes, 0, "No changes so far");
jtulach@777
   304
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@777
   305
        assertEquals(o.get(), "Hi");
jtulach@777
   306
jtulach@777
   307
        p.getAll().remove(1);
jtulach@777
   308
        
jtulach@777
   309
        assertEquals(o.get(), "Hi");
jtulach@777
   310
        assertEquals(o.changes, 1, "This required a change");
jtulach@777
   311
    }
jtulach@777
   312
    
jtulach@775
   313
    @Test public void doublePropertyChangeNotified() throws Exception {
jtulach@775
   314
        MyX p = Models.bind(
jtulach@775
   315
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@775
   316
        ), c).applyBindings();
jtulach@775
   317
        
jtulach@775
   318
        Map m = (Map)Models.toRaw(p);
jtulach@775
   319
        Object v = m.get("oneName");
jtulach@775
   320
        assertNotNull(v, "Value should be in the map");
jtulach@775
   321
        Object v2 = m.get("sndName");
jtulach@775
   322
        assertNotNull(v2, "Value2 should be in the map");
jtulach@775
   323
        One o = (One)v;
jtulach@775
   324
        One o2 = (One)v2;
jtulach@775
   325
        assertEquals(o.changes, 0, "No changes so far");
jtulach@775
   326
        assertEquals(o2.changes, 0, "No changes so far");
jtulach@775
   327
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@775
   328
        assertEquals(o.get(), "Ahoj");
jtulach@775
   329
        assertEquals(o2.get(), "AHOJ");
jtulach@775
   330
jtulach@775
   331
        p.getOne().setValue("Nazdar");
jtulach@775
   332
        
jtulach@775
   333
        assertEquals(o.get(), "Nazdar");
jtulach@775
   334
        assertEquals(o.changes, 1, "One change so far");
jtulach@775
   335
        assertEquals(o2.changes, 1, "One change so far");
jtulach@775
   336
        assertEquals(o2.get(), "NAZDAR");
jtulach@775
   337
    }
jtulach@775
   338
    
jtulach@775
   339
    @Test public void onlyAffectedPropertyChangeNotified() throws Exception {
jtulach@775
   340
        MyX p = Models.bind(
jtulach@775
   341
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@775
   342
        ), c).applyBindings();
jtulach@775
   343
        
jtulach@775
   344
        Map m = (Map)Models.toRaw(p);
jtulach@775
   345
        Object v = m.get("oneName");
jtulach@775
   346
        assertNotNull(v, "Value should be in the map");
jtulach@775
   347
        Object v2 = m.get("thrdName");
jtulach@775
   348
        assertNotNull(v2, "Value2 should be in the map");
jtulach@775
   349
        One o = (One)v;
jtulach@775
   350
        One o2 = (One)v2;
jtulach@775
   351
        assertEquals(o.changes, 0, "No changes so far");
jtulach@775
   352
        assertEquals(o2.changes, 0, "No changes so far");
jtulach@775
   353
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@775
   354
        assertEquals(o.get(), "Ahoj");
jtulach@775
   355
        assertEquals(o2.get(), "X0");
jtulach@775
   356
jtulach@775
   357
        p.getOne().setCount(10);
jtulach@775
   358
        
jtulach@775
   359
        assertEquals(o.get(), "Ahoj");
jtulach@775
   360
        assertEquals(o.changes, 0, "Still no change");
jtulach@775
   361
        assertEquals(o2.changes, 1, "One change so far");
jtulach@775
   362
        assertEquals(o2.get(), "X10");
jtulach@775
   363
    }
jtulach@776
   364
    
jtulach@776
   365
    @Test public void onlyDeepPropsAreNotified() throws Exception {
jtulach@776
   366
        MyX p = Models.bind(
jtulach@776
   367
            new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
jtulach@776
   368
        ), c).applyBindings();
jtulach@776
   369
        
jtulach@776
   370
        Map m = (Map)Models.toRaw(p);
jtulach@776
   371
        Object v = m.get("oneName");
jtulach@776
   372
        assertNotNull(v, "Value should be in the map");
jtulach@776
   373
        Object v2 = m.get("noName");
jtulach@776
   374
        assertNotNull(v2, "Value2 should be in the map");
jtulach@776
   375
        One o = (One)v;
jtulach@776
   376
        One o2 = (One)v2;
jtulach@776
   377
        assertEquals(o.changes, 0, "No changes so far");
jtulach@776
   378
        assertEquals(o2.changes, 0, "No changes so far");
jtulach@776
   379
        assertTrue(o.pb.isReadOnly(), "Derived property");
jtulach@776
   380
        assertEquals(o.get(), "Ahoj");
jtulach@778
   381
        assertEquals(o2.get(), "AHOJ");
jtulach@776
   382
jtulach@776
   383
        p.getOne().setValue("Nazdar");
jtulach@776
   384
        
jtulach@776
   385
        assertEquals(o.get(), "Nazdar");
jtulach@776
   386
        assertEquals(o.changes, 1, "One change so far");
jtulach@776
   387
        assertEquals(o2.changes, 0, "This change is not noticed");
jtulach@776
   388
        assertEquals(o2.get(), "NAZDAR", "but property value changes when computed");
jtulach@776
   389
    }
jtulach@787
   390
jtulach@787
   391
    static final class One {
jtulach@787
   392
jtulach@787
   393
        int changes;
jtulach@787
   394
        final PropertyBinding pb;
jtulach@787
   395
        final FunctionBinding fb;
jtulach@787
   396
jtulach@787
   397
        One(Object m, PropertyBinding pb) throws NoSuchMethodException {
jtulach@787
   398
            this.pb = pb;
jtulach@787
   399
            this.fb = null;
jtulach@787
   400
        }
jtulach@787
   401
jtulach@787
   402
        One(Object m, FunctionBinding fb) throws NoSuchMethodException {
jtulach@787
   403
            this.pb = null;
jtulach@787
   404
            this.fb = fb;
jtulach@787
   405
        }
jtulach@787
   406
jtulach@787
   407
        Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
jtulach@787
   408
            return pb.getValue();
jtulach@787
   409
        }
jtulach@787
   410
jtulach@787
   411
        void set(Object v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
jtulach@787
   412
            pb.setValue(v);
jtulach@787
   413
        }
jtulach@787
   414
    }
jtulach@787
   415
jtulach@787
   416
    static final class MapTechnology
jtulach@787
   417
            implements Technology<Map<String, One>>, Transfer {
jtulach@787
   418
jtulach@787
   419
        @Override
jtulach@787
   420
        public Map<String, One> wrapModel(Object model) {
jtulach@787
   421
            return new HashMap<String, One>();
jtulach@787
   422
        }
jtulach@787
   423
jtulach@787
   424
        @Override
jtulach@787
   425
        public void valueHasMutated(Map<String, One> data, String propertyName) {
jtulach@787
   426
            One p = data.get(propertyName);
jtulach@787
   427
            if (p != null) {
jtulach@787
   428
                p.changes++;
jtulach@787
   429
            }
jtulach@787
   430
        }
jtulach@787
   431
jtulach@787
   432
        @Override
jtulach@787
   433
        public void bind(PropertyBinding b, Object model, Map<String, One> data) {
jtulach@787
   434
            try {
jtulach@787
   435
                One o = new One(model, b);
jtulach@787
   436
                data.put(b.getPropertyName(), o);
jtulach@787
   437
            } catch (NoSuchMethodException ex) {
jtulach@787
   438
                throw new IllegalStateException(ex);
jtulach@787
   439
            }
jtulach@787
   440
        }
jtulach@787
   441
jtulach@787
   442
        @Override
jtulach@787
   443
        public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
jtulach@787
   444
            try {
jtulach@787
   445
                data.put(fb.getFunctionName(), new One(model, fb));
jtulach@787
   446
            } catch (NoSuchMethodException ex) {
jtulach@787
   447
                throw new IllegalStateException(ex);
jtulach@787
   448
            }
jtulach@787
   449
        }
jtulach@787
   450
jtulach@787
   451
        @Override
jtulach@787
   452
        public void applyBindings(Map<String, One> data) {
jtulach@787
   453
        }
jtulach@787
   454
jtulach@787
   455
        @Override
jtulach@787
   456
        public Object wrapArray(Object[] arr) {
jtulach@787
   457
            return arr;
jtulach@787
   458
        }
jtulach@787
   459
jtulach@787
   460
        @Override
jtulach@787
   461
        public void extract(Object obj, String[] props, Object[] values) {
jtulach@787
   462
            Map<?, ?> map = obj instanceof Map ? (Map<?, ?>) obj : null;
jtulach@787
   463
            for (int i = 0; i < Math.min(props.length, values.length); i++) {
jtulach@787
   464
                if (map == null) {
jtulach@787
   465
                    values[i] = null;
jtulach@787
   466
                } else {
jtulach@787
   467
                    values[i] = map.get(props[i]);
jtulach@787
   468
                    if (values[i] instanceof One) {
jtulach@787
   469
                        values[i] = ((One) values[i]).pb.getValue();
jtulach@787
   470
                    }
jtulach@787
   471
                }
jtulach@787
   472
            }
jtulach@787
   473
        }
jtulach@787
   474
jtulach@787
   475
        @Override
jtulach@787
   476
        public void loadJSON(JSONCall call) {
jtulach@787
   477
            call.notifyError(new UnsupportedOperationException());
jtulach@787
   478
        }
jtulach@787
   479
jtulach@787
   480
        @Override
jtulach@787
   481
        public <M> M toModel(Class<M> modelClass, Object data) {
jtulach@787
   482
            return modelClass.cast(data);
jtulach@787
   483
        }
jtulach@787
   484
jtulach@787
   485
        @Override
jtulach@787
   486
        public Object toJSON(InputStream is) throws IOException {
jtulach@787
   487
            throw new IOException();
jtulach@787
   488
        }
jtulach@787
   489
jtulach@787
   490
        @Override
jtulach@787
   491
        public void runSafe(Runnable r) {
jtulach@787
   492
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
jtulach@787
   493
        }
jtulach@787
   494
    }
jtulach@776
   495
    
jaroslav@9
   496
}