Coverage Report - org.simpleframework.xml.core.PrimitiveList
 
Classes in this File Line Coverage Branch Coverage Complexity
PrimitiveList
90%
40/44
77%
14/18
3.125
 
 1  
 /*
 2  
  * PrimitiveList.java July 2006
 3  
  *
 4  
  * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * 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, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 15  
  * implied. See the License for the specific language governing 
 16  
  * permissions and limitations under the License.
 17  
  */
 18  
 
 19  
 package org.simpleframework.xml.core;
 20  
 
 21  
 import java.util.Collection;
 22  
 
 23  
 import org.simpleframework.xml.strategy.Type;
 24  
 import org.simpleframework.xml.stream.InputNode;
 25  
 import org.simpleframework.xml.stream.OutputNode;
 26  
 
 27  
 /**
 28  
  * The <code>PrimitiveList</code> object is used to convert an element
 29  
  * list to a collection of element entries. This in effect performs a 
 30  
  * serialization and deserialization of primitive entry elements for 
 31  
  * the collection object. On serialization each objects type must be 
 32  
  * checked against the XML annotation entry so that it is serialized
 33  
  * in a form that can be deserialized. 
 34  
  * <pre>
 35  
  *
 36  
  *    &lt;list&gt;
 37  
  *       &lt;entry&gt;example one&lt;/entry&gt;
 38  
  *       &lt;entry&gt;example two&lt;/entry&gt;
 39  
  *       &lt;entry&gt;example three&lt;/entry&gt;
 40  
  *       &lt;entry&gt;example four&lt;/entry&gt;
 41  
  *    &lt;/list&gt;
 42  
  * 
 43  
  * </pre>
 44  
  * For the above XML element list the element <code>entry</code> is
 45  
  * used to wrap the primitive string value. This wrapping XML element 
 46  
  * is configurable and defaults to the lower case string for the name
 47  
  * of the class it represents. So, for example, if the primitive type
 48  
  * is an <code>int</code> the enclosing element will be called int.
 49  
  * 
 50  
  * @author Niall Gallagher
 51  
  *
 52  
  * @see org.simpleframework.xml.core.Primitive
 53  
  * @see org.simpleframework.xml.ElementList
 54  
  */ 
 55  
 class PrimitiveList implements Converter {
 56  
 
 57  
    /**
 58  
     * This factory is used to create a suitable collection list.
 59  
     */         
 60  
    private final CollectionFactory factory;
 61  
 
 62  
    /**
 63  
     * This performs the serialization of the primitive element.
 64  
     */ 
 65  
    private final Primitive root;
 66  
       
 67  
    /**
 68  
     * This is the name that each array element is wrapped with.
 69  
     */
 70  
    private final String parent;
 71  
    
 72  
    /**
 73  
     * This is the type of object that will be held within the list.
 74  
     */
 75  
    private final Type entry;
 76  
                  
 77  
    /**
 78  
     * Constructor for the <code>PrimitiveList</code> object. This is
 79  
     * given the list type and entry type to be used. The list type is
 80  
     * the <code>Collection</code> implementation that deserialized
 81  
     * entry objects are inserted into. 
 82  
     * 
 83  
     * @param context this is the context object used for serialization
 84  
     * @param type this is the collection type for the list used
 85  
     * @param entry the primitive type to be stored within the list
 86  
     * @param parent this is the name to wrap the list element with 
 87  
     */    
 88  158
    public PrimitiveList(Context context, Type type, Type entry, String parent) {
 89  158
       this.factory = new CollectionFactory(context, type); 
 90  158
       this.root = new Primitive(context, entry);          
 91  158
       this.parent = parent;
 92  158
       this.entry = entry;
 93  158
    }
 94  
 
 95  
    /**
 96  
     * This <code>read</code> method will read the XML element list from
 97  
     * the provided node and deserialize its children as entry types.
 98  
     * This will deserialize each entry type as a primitive value. In
 99  
     * order to do this the parent string provided forms the element.
 100  
     * 
 101  
     * @param node this is the XML element that is to be deserialized
 102  
     * 
 103  
     * @return this returns the item to attach to the object contact
 104  
     */ 
 105  
    public Object read(InputNode node) throws Exception{
 106  41
       Instance type = factory.getInstance(node);
 107  41
       Object list = type.getInstance();
 108  
       
 109  41
       if(!type.isReference()) {
 110  41
          return populate(node, list);
 111  
       }
 112  0
       return list;
 113  
    }
 114  
    
 115  
    /**
 116  
     * This <code>read</code> method will read the XML element map from
 117  
     * the provided node and deserialize its children as entry types.
 118  
     * Each entry type must contain a key and value so that the entry 
 119  
     * can be inserted in to the map as a pair. If either the key or 
 120  
     * value is composite it is read as a root object, which means its
 121  
     * <code>Root</code> annotation must be present and the name of the
 122  
     * object element must match that root element name.
 123  
     * 
 124  
     * @param node this is the XML element that is to be deserialized
 125  
     * @param result this is the map object that is to be populated
 126  
     * 
 127  
     * @return this returns the item to attach to the object contact
 128  
     */
 129  
    public Object read(InputNode node, Object result) throws Exception {
 130  9
       Instance type = factory.getInstance(node);
 131  
       
 132  9
       if(type.isReference()) {
 133  0
          return type.getInstance();
 134  
       }
 135  9
       type.setInstance(result);
 136  
       
 137  9
       if(result != null) {
 138  9
          return populate(node, result);
 139  
       }
 140  0
       return result;
 141  
    }
 142  
    
 143  
    /**
 144  
     * This <code>populate</code> method wll read the XML element list 
 145  
     * from the provided node and deserialize its children as entry types.
 146  
     * This will deserialize each entry type as a primitive value. In
 147  
     * order to do this the parent string provided forms the element.
 148  
     * 
 149  
     * @param node this is the XML element that is to be deserialized
 150  
     * @param result this is the collection that is to be populated
 151  
     * 
 152  
     * @return this returns the item to attach to the object contact
 153  
     */ 
 154  
    private Object populate(InputNode node, Object result) throws Exception {
 155  50
       Collection list = (Collection) result;                 
 156  
       
 157  
       while(true) {
 158  151
          InputNode next = node.getNext();
 159  
         
 160  151
          if(next == null) {
 161  50
             return list;
 162  
          }
 163  101
          list.add(root.read(next));
 164  101
       }
 165  
    }
 166  
    
 167  
    /**
 168  
     * This <code>validate</code> method wll validate the XML element list 
 169  
     * from the provided node and validate its children as entry types.
 170  
     * This will validate each entry type as a primitive value. In order 
 171  
     * to do this the parent string provided forms the element.
 172  
     * 
 173  
     * @param node this is the XML element that is to be deserialized
 174  
     * 
 175  
     * @return true if the element matches the XML schema class given 
 176  
     */ 
 177  
    public boolean validate(InputNode node) throws Exception{
 178  17
       Instance value = factory.getInstance(node);
 179  
       
 180  17
       if(!value.isReference()) {
 181  17
          Object result = value.setInstance(null);
 182  17
          Class expect = value.getType();
 183  
             
 184  17
          return validate(node, expect);
 185  
       }
 186  0
       return true;      
 187  
 
 188  
    }
 189  
    
 190  
    /**
 191  
     * This <code>validate</code> method will validate the XML element list 
 192  
     * from the provided node and validate its children as entry types.
 193  
     * This will validate each entry type as a primitive value. In order 
 194  
     * to do this the parent string provided forms the element.
 195  
     * 
 196  
     * @param node this is the XML element that is to be deserialized
 197  
     * @param type this is the type to validate against the input node
 198  
     * 
 199  
     * @return true if the element matches the XML schema class given 
 200  
     */ 
 201  
    private boolean validate(InputNode node, Class type) throws Exception {
 202  
       while(true) {
 203  50
          InputNode next = node.getNext();
 204  
         
 205  50
          if(next == null) {
 206  17
             return true;
 207  
          }
 208  33
          root.validate(next);
 209  33
       }
 210  
    }     
 211  
 
 212  
    /**
 213  
     * This <code>write</code> method will write the specified object
 214  
     * to the given XML element as as list entries. Each entry within
 215  
     * the given list must be assignable to the given primitive type.
 216  
     * This will deserialize each entry type as a primitive value. In
 217  
     * order to do this the parent string provided forms the element.
 218  
     * 
 219  
     * @param source this is the source object array to be serialized 
 220  
     * @param node this is the XML element container to be populated
 221  
     */ 
 222  
    public void write(OutputNode node, Object source) throws Exception {
 223  92
       Collection list = (Collection) source;                
 224  
       
 225  92
       for(Object item : list) {
 226  203
          if(item != null) {
 227  179
             OutputNode child = node.getChild(parent);         
 228  
 
 229  179
             if(!isOverridden(child, item)) { 
 230  155
                root.write(child, item);
 231  
             }
 232  203
          }
 233  
       }
 234  92
    }
 235  
    
 236  
    /**
 237  
     * This is used to determine whether the specified value has been
 238  
     * overridden by the strategy. If the item has been overridden
 239  
     * then no more serialization is require for that value, this is
 240  
     * effectively telling the serialization process to stop writing.
 241  
     * 
 242  
     * @param node the node that a potential override is written to
 243  
     * @param value this is the object instance to be serialized
 244  
     * 
 245  
     * @return returns true if the strategy overrides the object
 246  
     */
 247  
    private boolean isOverridden(OutputNode node, Object value) throws Exception{
 248  179
       return factory.setOverride(entry, value, node);
 249  
    }
 250  
 }