Coverage Report - javax.faces.component.behavior._AjaxBehaviorDeltaStateHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
_AjaxBehaviorDeltaStateHelper
0%
0/157
0%
0/92
2.73
_AjaxBehaviorDeltaStateHelper$InternalDeltaListMap
0%
0/8
N/A
2.73
_AjaxBehaviorDeltaStateHelper$InternalList
0%
0/19
0%
0/10
2.73
_AjaxBehaviorDeltaStateHelper$InternalMap
0%
0/25
0%
0/10
2.73
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package javax.faces.component.behavior;
 20  
 
 21  
 import javax.el.ValueExpression;
 22  
 import javax.faces.component.StateHelper;
 23  
 import javax.faces.component.StateHolder;
 24  
 import javax.faces.component.UIComponentBase;
 25  
 import javax.faces.context.FacesContext;
 26  
 import java.io.Serializable;
 27  
 import java.util.ArrayList;
 28  
 import java.util.Collection;
 29  
 import java.util.HashMap;
 30  
 import java.util.Iterator;
 31  
 import java.util.List;
 32  
 import java.util.Map;
 33  
 
 34  
 /**
 35  
  * Delta state helper to deal with the ajax
 36  
  * behavior delta states, cross ported
 37  
  * from our generic delta state, due to limitations
 38  
  * in the spec (sorry for the somewhat dirty code here maybe
 39  
  * we can unify both implementations by isolating a common protected interface)
 40  
  *
 41  
  * @since 2.0
 42  
  */
 43  
 class _AjaxBehaviorDeltaStateHelper<A extends AjaxBehavior> implements StateHelper
 44  
 {
 45  
     /**
 46  
      * We need to hold a component instance because:
 47  
      * <p/>
 48  
      * - The component is the one who knows if we are on initial or delta mode
 49  
      * - eval assume calls to component.ValueExpression
 50  
      */
 51  
     private A _target;
 52  
 
 53  
     /**
 54  
      * This map holds the full current state
 55  
      */
 56  
     private Map<Serializable, Object> _fullState;
 57  
 
 58  
     /**
 59  
      * This map only keep track of delta changes to be saved
 60  
      */
 61  
     private Map<Serializable, Object> _deltas;
 62  
 
 63  
     /**
 64  
      * This map keep track of StateHolder keys, to be saved when
 65  
      * saveState is called.
 66  
      */
 67  
     //private Set<Serializable> _stateHolderKeys;
 68  
 
 69  0
     private boolean _transient = false;
 70  
 
 71  
     public _AjaxBehaviorDeltaStateHelper(A component)
 72  
     {
 73  0
         super();
 74  0
         this._target = component;
 75  0
         _fullState = new HashMap<Serializable, Object>();
 76  0
         _deltas = null;
 77  
         //_stateHolderKeys = new HashSet<Serializable>();
 78  0
     }
 79  
 
 80  
     /**
 81  
      * Used to create delta map on demand
 82  
      *
 83  
      * @return
 84  
      */
 85  
     private boolean _createDeltas()
 86  
     {
 87  0
         if (isInitialStateMarked())
 88  
         {
 89  0
             if (_deltas == null)
 90  
             {
 91  0
                 _deltas = new HashMap<Serializable, Object>(2);
 92  
             }
 93  0
             return true;
 94  
         }
 95  
 
 96  0
         return false;
 97  
     }
 98  
 
 99  
     protected boolean isInitialStateMarked()
 100  
     {
 101  0
         return _target.initialStateMarked();
 102  
     }
 103  
 
 104  
     public void add(Serializable key, Object value)
 105  
     {
 106  0
         if (_createDeltas())
 107  
         {
 108  
             //Track delta case
 109  0
             Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
 110  
                     .get(key);
 111  0
             if (deltaListMapValues == null)
 112  
             {
 113  0
                 deltaListMapValues = new InternalDeltaListMap<Object, Boolean>(
 114  
                         3);
 115  0
                 _deltas.put(key, deltaListMapValues);
 116  
             }
 117  0
             deltaListMapValues.put(value, Boolean.TRUE);
 118  
         }
 119  
 
 120  
         //Handle change on full map
 121  0
         List<Object> fullListValues = (List<Object>) _fullState.get(key);
 122  0
         if (fullListValues == null)
 123  
         {
 124  0
             fullListValues = new InternalList<Object>(3);
 125  0
             _fullState.put(key, fullListValues);
 126  
         }
 127  0
         fullListValues.add(value);
 128  0
     }
 129  
 
 130  
     public Object eval(Serializable key)
 131  
     {
 132  0
         Object returnValue = _fullState.get(key);
 133  0
         if (returnValue != null)
 134  
         {
 135  0
             return returnValue;
 136  
         }
 137  0
         ValueExpression expression = _target.getValueExpression(key
 138  
                 .toString());
 139  0
         if (expression != null)
 140  
         {
 141  0
             return expression.getValue(FacesContext.getCurrentInstance()
 142  
                     .getELContext());
 143  
         }
 144  0
         return null;
 145  
     }
 146  
 
 147  
     public Object eval(Serializable key, Object defaultValue)
 148  
     {
 149  0
         Object returnValue = _fullState.get(key);
 150  0
         if (returnValue != null)
 151  
         {
 152  0
             return returnValue;
 153  
         }
 154  0
         ValueExpression expression = _target.getValueExpression(key
 155  
                 .toString());
 156  0
         if (expression != null)
 157  
         {
 158  0
             return expression.getValue(FacesContext.getCurrentInstance()
 159  
                     .getELContext());
 160  
         }
 161  0
         return defaultValue;
 162  
     }
 163  
 
 164  
     public Object get(Serializable key)
 165  
     {
 166  0
         return _fullState.get(key);
 167  
     }
 168  
 
 169  
     public Object put(Serializable key, Object value)
 170  
     {
 171  0
         Object returnValue = null;
 172  0
         if (_createDeltas())
 173  
         {
 174  0
             if (_deltas.containsKey(key))
 175  
             {
 176  0
                 returnValue = _deltas.put(key, value);
 177  0
                 _fullState.put(key, value);
 178  
             }
 179  
             else
 180  
             {
 181  0
                 _deltas.put(key, value);
 182  0
                 returnValue = _fullState.put(key, value);
 183  
             }
 184  
         }
 185  
         else
 186  
         {
 187  
             /*
 188  
             if (value instanceof StateHolder)
 189  
             {
 190  
                 _stateHolderKeys.add(key);
 191  
             }
 192  
             */
 193  0
             returnValue = _fullState.put(key, value);
 194  
         }
 195  0
         return returnValue;
 196  
     }
 197  
 
 198  
     public Object put(Serializable key, String mapKey, Object value)
 199  
     {
 200  0
         boolean returnSet = false;
 201  0
         Object returnValue = null;
 202  0
         if (_createDeltas())
 203  
         {
 204  
             //Track delta case
 205  0
             Map<String, Object> mapValues = (Map<String, Object>) _deltas
 206  
                     .get(key);
 207  0
             if (mapValues == null)
 208  
             {
 209  0
                 mapValues = new InternalMap<String, Object>();
 210  0
                 _deltas.put(key, mapValues);
 211  
             }
 212  0
             if (mapValues.containsKey(mapKey))
 213  
             {
 214  0
                 returnValue = mapValues.put(mapKey, value);
 215  0
                 returnSet = true;
 216  
             }
 217  
             else
 218  
             {
 219  0
                 mapValues.put(mapKey, value);
 220  
             }
 221  
         }
 222  
 
 223  
         //Handle change on full map
 224  0
         Map<String, Object> mapValues = (Map<String, Object>) _fullState
 225  
                 .get(key);
 226  0
         if (mapValues == null)
 227  
         {
 228  0
             mapValues = new InternalMap<String, Object>();
 229  0
             _fullState.put(key, mapValues);
 230  
         }
 231  0
         if (returnSet)
 232  
         {
 233  0
             mapValues.put(mapKey, value);
 234  
         }
 235  
         else
 236  
         {
 237  0
             returnValue = mapValues.put(mapKey, value);
 238  
         }
 239  0
         return returnValue;
 240  
     }
 241  
 
 242  
     public Object remove(Serializable key)
 243  
     {
 244  0
         Object returnValue = null;
 245  0
         if (_createDeltas())
 246  
         {
 247  0
             if (_deltas.containsKey(key))
 248  
             {
 249  
                 // Keep track of the removed values using key/null pair on the delta map
 250  0
                 returnValue = _deltas.put(key, null);
 251  0
                 _fullState.remove(key);
 252  
             }
 253  
             else
 254  
             {
 255  
                 // Keep track of the removed values using key/null pair on the delta map
 256  0
                 _deltas.put(key, null);
 257  0
                 returnValue = _fullState.remove(key);
 258  
             }
 259  
         }
 260  
         else
 261  
         {
 262  0
             returnValue = _fullState.remove(key);
 263  
         }
 264  0
         return returnValue;
 265  
     }
 266  
 
 267  
     public Object remove(Serializable key, Object valueOrKey)
 268  
     {
 269  
         // Comment by lu4242 : The spec javadoc says if it is a Collection
 270  
         // or Map deal with it. But the intention of this method is work
 271  
         // with add(?,?) and put(?,?,?), this ones return instances of
 272  
         // InternalMap and InternalList to prevent mixing, so to be
 273  
         // consistent we'll cast to those classes here.
 274  
 
 275  0
         Object collectionOrMap = _fullState.get(key);
 276  0
         Object returnValue = null;
 277  0
         if (collectionOrMap instanceof InternalMap)
 278  
         {
 279  0
             if (_createDeltas())
 280  
             {
 281  0
                 returnValue = _removeValueOrKeyFromMap(_deltas, key,
 282  
                         valueOrKey, true);
 283  0
                 _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
 284  
             }
 285  
             else
 286  
             {
 287  0
                 returnValue = _removeValueOrKeyFromMap(_fullState, key,
 288  
                         valueOrKey, false);
 289  
             }
 290  
         }
 291  0
         else if (collectionOrMap instanceof InternalList)
 292  
         {
 293  0
             if (_createDeltas())
 294  
             {
 295  0
                 returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
 296  
                         key, valueOrKey);
 297  0
                 _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
 298  
             }
 299  
             else
 300  
             {
 301  0
                 returnValue = _removeValueOrKeyFromCollection(_fullState, key,
 302  
                         valueOrKey);
 303  
             }
 304  
         }
 305  0
         return returnValue;
 306  
     }
 307  
 
 308  
     private static Object _removeValueOrKeyFromCollectionDelta(
 309  
             Map<Serializable, Object> stateMap, Serializable key,
 310  
             Object valueOrKey)
 311  
     {
 312  0
         Object returnValue = null;
 313  0
         Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
 314  0
         if (c != null)
 315  
         {
 316  0
             if (c.containsKey(valueOrKey))
 317  
             {
 318  0
                 returnValue = valueOrKey;
 319  
             }
 320  0
             c.put(valueOrKey, Boolean.FALSE);
 321  
         }
 322  0
         return returnValue;
 323  
     }
 324  
 
 325  
     private static Object _removeValueOrKeyFromCollection(
 326  
             Map<Serializable, Object> stateMap, Serializable key,
 327  
             Object valueOrKey)
 328  
     {
 329  0
         Object returnValue = null;
 330  0
         Collection c = (Collection) stateMap.get(key);
 331  0
         if (c != null)
 332  
         {
 333  0
             if (c.remove(valueOrKey))
 334  
             {
 335  0
                 returnValue = valueOrKey;
 336  
             }
 337  0
             if (c.isEmpty())
 338  
             {
 339  0
                 stateMap.remove(key);
 340  
             }
 341  
         }
 342  0
         return returnValue;
 343  
     }
 344  
 
 345  
     private static Object _removeValueOrKeyFromMap(
 346  
             Map<Serializable, Object> stateMap, Serializable key,
 347  
             Object valueOrKey, boolean delta)
 348  
     {
 349  0
         if (valueOrKey == null)
 350  
         {
 351  0
             return null;
 352  
         }
 353  
 
 354  0
         Object returnValue = null;
 355  0
         Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
 356  0
         if (map != null)
 357  
         {
 358  0
             if (delta)
 359  
             {
 360  
                 // Keep track of the removed values using key/null pair on the delta map
 361  0
                 returnValue = map.put((String) valueOrKey, null);
 362  
             }
 363  
             else
 364  
             {
 365  0
                 returnValue = map.remove(valueOrKey);
 366  
             }
 367  
 
 368  0
             if (map.isEmpty())
 369  
             {
 370  
                 //stateMap.remove(key);
 371  0
                 stateMap.put(key, null);
 372  
             }
 373  
         }
 374  0
         return returnValue;
 375  
     }
 376  
 
 377  
     public boolean isTransient()
 378  
     {
 379  0
         return _transient;
 380  
     }
 381  
 
 382  
     /**
 383  
      * Serializing cod
 384  
      * the serialized data structure consists of key value pairs unless the value itself is an internal array
 385  
      * or a map in case of an internal array or map the value itself is another array with its initial value
 386  
      * myfaces.InternalArray, myfaces.internalMap
 387  
      * <p/>
 388  
      * the internal Array is then mapped to another array
 389  
      * <p/>
 390  
      * the internal Map again is then mapped to a map with key value pairs
 391  
      */
 392  
 
 393  
     public Object saveState(FacesContext context)
 394  
     {
 395  0
         Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
 396  
 
 397  0
         if (serializableMap == null || serializableMap.size() == 0)
 398  
         {
 399  0
             return null;
 400  
         }
 401  
 
 402  
         /*
 403  
         int stateHolderKeyCount = 0;
 404  
         if (isInitalStateMarked())
 405  
         {
 406  
             for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
 407  
             {
 408  
                 Serializable key = it.next();
 409  
                 if (!_deltas.containsKey(key))
 410  
                 {
 411  
                     stateHolderKeyCount++;
 412  
                 }
 413  
             }
 414  
         }*/
 415  
 
 416  
         Map.Entry<Serializable, Object> entry;
 417  
         //entry == key, value, key, value
 418  0
         Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
 419  
         //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount];
 420  
 
 421  0
         Iterator<Map.Entry<Serializable, Object>> it = serializableMap.entrySet().iterator();
 422  0
         int cnt = 0;
 423  0
         while (it.hasNext())
 424  
         {
 425  0
             entry = it.next();
 426  0
             retArr[cnt] = entry.getKey();
 427  
 
 428  0
             Object value = entry.getValue();
 429  
 
 430  
             // The condition in which the call to saveAttachedState
 431  
             // is to handle List, StateHolder or non Serializable instances.
 432  
             // we check it here, to prevent unnecessary calls.
 433  0
             if (value instanceof StateHolder ||
 434  
                     value instanceof List ||
 435  
                     !(value instanceof Serializable))
 436  
             {
 437  0
                 Object savedValue = UIComponentBase.saveAttachedState(context,
 438  
                         value);
 439  0
                 retArr[cnt + 1] = savedValue;
 440  0
             }
 441  
             else
 442  
             {
 443  0
                 retArr[cnt + 1] = value;
 444  
             }
 445  0
             cnt += 2;
 446  0
         }
 447  
 
 448  
         /*
 449  
         if (isInitalStateMarked())
 450  
         {
 451  
             for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
 452  
             {
 453  
                 Serializable key = it2.next();
 454  
                 if (!_deltas.containsKey(key))
 455  
                 {
 456  
                     retArr[cnt] = key;
 457  
                     Object value = _fullState.get(key);
 458  
                     if (value instanceof PartialStateHolder)
 459  
                     {
 460  
                         //Could contain delta, save it as _AttachedDeltaState
 461  
                         PartialStateHolder holder = (PartialStateHolder) value;
 462  
                         if (holder.isTransient())
 463  
                         {
 464  
                             retArr[cnt + 1] = null;
 465  
                         }
 466  
                         else
 467  
                         {
 468  
                             retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
 469  
                         }
 470  
                     }
 471  
                     else
 472  
                     {
 473  
                         //Save everything
 474  
                         retArr[cnt + 1] = UIComponentBase.saveAttachedState(context, _fullState.get(key));
 475  
                     }
 476  
                     cnt += 2;
 477  
                 }
 478  
             }
 479  
         }
 480  
         */
 481  0
         return retArr;
 482  
     }
 483  
 
 484  
 
 485  
     public void restoreState(FacesContext context, Object state)
 486  
     {
 487  0
         if (state == null)
 488  
         {
 489  0
             return;
 490  
         }
 491  
 
 492  0
         Object[] serializedState = (Object[]) state;
 493  
 
 494  0
         for (int cnt = 0; cnt < serializedState.length; cnt += 2)
 495  
         {
 496  0
             Serializable key = (Serializable) serializedState[cnt];
 497  
 
 498  0
             Object savedValue = UIComponentBase.restoreAttachedState(context,
 499  
                     serializedState[cnt + 1]);
 500  
 
 501  0
             if (isInitialStateMarked())
 502  
             {
 503  0
                 if (savedValue instanceof InternalDeltaListMap)
 504  
                 {
 505  0
                     for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
 506  
                             .entrySet())
 507  
                     {
 508  0
                         boolean addOrRemove = mapEntry.getValue();
 509  0
                         if (addOrRemove)
 510  
                         {
 511  
                             //add
 512  0
                             this.add(key, mapEntry.getKey());
 513  
                         }
 514  
                         else
 515  
                         {
 516  
                             //remove
 517  0
                             this.remove(key, mapEntry.getKey());
 518  
                         }
 519  0
                     }
 520  
                 }
 521  0
                 else if (savedValue instanceof InternalMap)
 522  
                 {
 523  0
                     for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
 524  
                             .entrySet())
 525  
                     {
 526  0
                         this.put(key, mapEntry.getKey(), mapEntry.getValue());
 527  0
                     }
 528  
                 }
 529  
                 /*
 530  
                 else if (savedValue instanceof _AttachedDeltaWrapper)
 531  
                 {
 532  
                     _AttachedStateWrapper wrapper = (_AttachedStateWrapper) savedValue;
 533  
                     //Restore delta state
 534  
                     ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
 535  
                     //Add this key as StateHolder key
 536  
                     _stateHolderKeys.add(key);
 537  
                 }
 538  
                 */
 539  
                 else
 540  
                 {
 541  0
                     put(key, savedValue);
 542  
                 }
 543  
             }
 544  
             else
 545  
             {
 546  0
                 put(key, savedValue);
 547  
             }
 548  
         }
 549  0
     }
 550  
 
 551  
     public void setTransient(boolean transientValue)
 552  
     {
 553  0
         _transient = transientValue;
 554  0
     }
 555  
 
 556  
     //We use our own data structures just to make sure
 557  
     //nothing gets mixed up internally
 558  
     static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
 559  
     {
 560  
         public InternalMap()
 561  
         {
 562  0
             super();
 563  0
         }
 564  
 
 565  
         public InternalMap(int initialCapacity, float loadFactor)
 566  
         {
 567  0
             super(initialCapacity, loadFactor);
 568  0
         }
 569  
 
 570  
         public InternalMap(Map<? extends K, ? extends V> m)
 571  
         {
 572  0
             super(m);
 573  0
         }
 574  
 
 575  
         public InternalMap(int initialSize)
 576  
         {
 577  0
             super(initialSize);
 578  0
         }
 579  
 
 580  
         public boolean isTransient()
 581  
         {
 582  0
             return false;
 583  
         }
 584  
 
 585  
         public void setTransient(boolean newTransientValue)
 586  
         {
 587  
             // No op
 588  0
         }
 589  
 
 590  
         public void restoreState(FacesContext context, Object state)
 591  
         {
 592  0
             Object[] listAsMap = (Object[]) state;
 593  0
             for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
 594  
             {
 595  0
                 this.put((K) listAsMap[cnt], (V) UIComponentBase
 596  
                         .restoreAttachedState(context, listAsMap[cnt + 1]));
 597  
             }
 598  0
         }
 599  
 
 600  
         public Object saveState(FacesContext context)
 601  
         {
 602  0
             int cnt = 0;
 603  0
             Object[] mapArr = new Object[this.size() * 2];
 604  0
             for (Map.Entry<K, V> entry : this.entrySet())
 605  
             {
 606  0
                 mapArr[cnt] = entry.getKey();
 607  0
                 Object value = entry.getValue();
 608  
 
 609  0
                 if (value instanceof StateHolder ||
 610  
                         value instanceof List ||
 611  
                         !(value instanceof Serializable))
 612  
                 {
 613  0
                     mapArr[cnt + 1] = UIComponentBase.saveAttachedState(context, value);
 614  
                 }
 615  
                 else
 616  
                 {
 617  0
                     mapArr[cnt + 1] = value;
 618  
                 }
 619  0
                 cnt += 2;
 620  0
             }
 621  0
             return mapArr;
 622  
         }
 623  
     }
 624  
 
 625  
     /**
 626  
      * Map used to keep track of list changes
 627  
      */
 628  
     static class InternalDeltaListMap<K, V> extends InternalMap<K, V>
 629  
     {
 630  
 
 631  
         public InternalDeltaListMap()
 632  
         {
 633  0
             super();
 634  0
         }
 635  
 
 636  
         public InternalDeltaListMap(int initialCapacity, float loadFactor)
 637  
         {
 638  0
             super(initialCapacity, loadFactor);
 639  0
         }
 640  
 
 641  
         public InternalDeltaListMap(int initialSize)
 642  
         {
 643  0
             super(initialSize);
 644  0
         }
 645  
 
 646  
         public InternalDeltaListMap(Map<? extends K, ? extends V> m)
 647  
         {
 648  0
             super(m);
 649  0
         }
 650  
     }
 651  
 
 652  
     static class InternalList<T> extends ArrayList<T> implements StateHolder
 653  
     {
 654  
         public InternalList()
 655  
         {
 656  0
             super();
 657  0
         }
 658  
 
 659  
         public InternalList(Collection<? extends T> c)
 660  
         {
 661  0
             super(c);
 662  0
         }
 663  
 
 664  
         public InternalList(int initialSize)
 665  
         {
 666  0
             super(initialSize);
 667  0
         }
 668  
 
 669  
         public boolean isTransient()
 670  
         {
 671  0
             return false;
 672  
         }
 673  
 
 674  
         public void setTransient(boolean newTransientValue)
 675  
         {
 676  0
         }
 677  
 
 678  
         public void restoreState(FacesContext context, Object state)
 679  
         {
 680  0
             Object[] listAsArr = (Object[]) state;
 681  
             //since all other options would mean dual iteration
 682  
             //we have to do it the hard way
 683  0
             for (Object elem : listAsArr)
 684  
             {
 685  0
                 add((T) UIComponentBase.restoreAttachedState(context, elem));
 686  
             }
 687  0
         }
 688  
 
 689  
         public Object saveState(FacesContext context)
 690  
         {
 691  0
             Object[] values = new Object[size()];
 692  0
             for (int i = 0; i < size(); i++)
 693  
             {
 694  0
                 Object value = get(i);
 695  
 
 696  0
                 if (value instanceof StateHolder ||
 697  
                         value instanceof List ||
 698  
                         !(value instanceof Serializable))
 699  
                 {
 700  0
                     values[i] = UIComponentBase.saveAttachedState(context, value);
 701  
                 }
 702  
                 else
 703  
                 {
 704  0
                     values[i] = value;
 705  
                 }
 706  
             }
 707  0
             return values;
 708  
         }
 709  
     }
 710  
 }