Coverage Report - org.simpleframework.xml.load.CompositeInlineMap
 
Classes in this File Line Coverage Branch Coverage Complexity
CompositeInlineMap
86%
42/49
89%
8/9
0
 
 1  
 /*
 2  
  * CompositeInlineMap.java July 2007
 3  
  *
 4  
  * Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net>
 5  
  *
 6  
  * This library is free software; you can redistribute it and/or
 7  
  * modify it under the terms of the GNU Lesser General Public
 8  
  * License as published by the Free Software Foundation.
 9  
  *
 10  
  * This library is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  
  * GNU Lesser General Public License for more details.
 14  
  *
 15  
  * You should have received a copy of the GNU Lesser General 
 16  
  * Public License along with this library; if not, write to the 
 17  
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 18  
  * Boston, MA  02111-1307  USA
 19  
  */
 20  
 
 21  
 package org.simpleframework.xml.load;
 22  
 
 23  
 import org.simpleframework.xml.stream.InputNode;
 24  
 import org.simpleframework.xml.stream.OutputNode;
 25  
 import java.util.Map;
 26  
 
 27  
 /**
 28  
  * The <code>CompositeMap</code> is used to serialize and deserialize
 29  
  * maps to and from a source XML document. The structure of the map in
 30  
  * the XML format is determined by the annotation. Keys can be either
 31  
  * attributes or elements, and values can be inline. This can perform
 32  
  * serialization and deserialization of the key and value objects 
 33  
  * whether the object types are primitive or composite.
 34  
  * <pre>
 35  
  * 
 36  
  *    &lt;map&gt;
 37  
  *       &lt;entry key='1'&gt;           
 38  
  *          &lt;value&gt;one&lt;/value&gt;
 39  
  *       &lt;/entry&gt;
 40  
  *       &lt;entry key='2'&gt;
 41  
  *          &lt;value&gt;two&lt;/value&gt;
 42  
  *       &lt;/entry&gt;      
 43  
  *    &lt;/map&gt;
 44  
  *    
 45  
  * </pre>
 46  
  * For the above XML element map the element <code>entry</code> is 
 47  
  * used to wrap the key and value such that they can be grouped. This
 48  
  * element does not represent any real object. The names of each of
 49  
  * the XML elements serialized and deserialized can be configured.
 50  
  *  
 51  
  * @author Niall Gallagher
 52  
  * 
 53  
  * @see org.simpleframework.xml.load.Entry
 54  
  */
 55  
 class CompositeInlineMap implements Repeater {
 56  
       
 57  
    /**
 58  
     * The factory used to create suitable map object instances.
 59  
     */
 60  
    private final MapFactory factory;
 61  
    
 62  
    /**
 63  
     * This is the type that the value objects are instances of. 
 64  
     */
 65  
    private final Converter value;
 66  
    
 67  
    /**
 68  
     * This is the name of the entry wrapping the key and value.
 69  
     */
 70  
    private final Converter key;  
 71  
    
 72  
    /**
 73  
     * The entry object contains the details on how to write the map.
 74  
     */
 75  
    private final Entry entry;
 76  
     
 77  
    /**
 78  
     * Constructor for the <code>CompositeMap</code> object. This will
 79  
     * create a converter that is capable of writing map objects to 
 80  
     * and from XML. The resulting XML is configured by an annotation
 81  
     * such that key values can attributes and values can be inline. 
 82  
     * 
 83  
     * @param root this is the root context for the serialization
 84  
     * @param entry this provides configuration for the resulting XML
 85  
     * @param type this is the map type that is to be converted
 86  
     */
 87  12
    public CompositeInlineMap(Source root, Entry entry, Class type) throws Exception {
 88  12
       this.factory = new MapFactory(root, type);
 89  12
       this.value = entry.getValue(root);
 90  12
       this.key = entry.getKey(root);
 91  12
       this.entry = entry;
 92  12
    }
 93  
 
 94  
    /**
 95  
     * This <code>read</code> method will read the XML element map from
 96  
     * the provided node and deserialize its children as entry types.
 97  
     * Each entry type must contain a key and value so that the entry 
 98  
     * can be inserted in to the map as a pair. If either the key or 
 99  
     * value is composite it is read as a root object, which means its
 100  
     * <code>Root</code> annotation must be present and the name of the
 101  
     * object element must match that root element name.
 102  
     * 
 103  
     * @param node this is the XML element that is to be deserialized
 104  
     * 
 105  
     * @return this returns the item to attach to the object contact
 106  
     */
 107  
    public Object read(InputNode node) throws Exception{
 108  1
       Object value = factory.getInstance();
 109  1
       Map table = (Map) value;
 110  
       
 111  1
       if(table != null) {
 112  1
          return read(node, table);
 113  
       }
 114  0
       return null;
 115  
    }
 116  
    
 117  
    /**
 118  
     * This <code>read</code> method will read the XML element map from
 119  
     * the provided node and deserialize its children as entry types.
 120  
     * Each entry type must contain a key and value so that the entry 
 121  
     * can be inserted in to the map as a pair. If either the key or 
 122  
     * value is composite it is read as a root object, which means its
 123  
     * <code>Root</code> annotation must be present and the name of the
 124  
     * object element must match that root element name.
 125  
     * 
 126  
     * @param node this is the XML element that is to be deserialized
 127  
     * 
 128  
     * @return this returns the item to attach to the object contact
 129  
     */
 130  
    public Object read(InputNode node, Object value) throws Exception {
 131  0
       Map map = (Map) value;
 132  
       
 133  0
       if(map != null) {
 134  0
          return read(node, map);
 135  
       }
 136  0
       return read(node);
 137  
    }
 138  
    
 139  
    /**
 140  
     * This <code>read</code> method will read the XML element map from
 141  
     * the provided node and deserialize its children as entry types.
 142  
     * Each entry type must contain a key and value so that the entry 
 143  
     * can be inserted in to the map as a pair. If either the key or 
 144  
     * value is composite it is read as a root object, which means its
 145  
     * <code>Root</code> annotation must be present and the name of the
 146  
     * object element must match that root element name.
 147  
     * 
 148  
     * @param node this is the XML element that is to be deserialized
 149  
     * @param table this is the map object that is to be populated
 150  
     * 
 151  
     * @return this returns the item to attach to the object contact
 152  
     */
 153  
    private Object read(InputNode node, Map map) throws Exception {
 154  1
       InputNode from = node.getParent();
 155  1
       String name = node.getName();                
 156  
 
 157  5
       while(node != null) {         
 158  4
          Object index = key.read(node);
 159  4
          Object item = value.read(node);
 160  
             
 161  4
          if(map != null) {
 162  4
             map.put(index, item);
 163  
          }
 164  4
          node = from.getNext(name);
 165  4
       }
 166  1
       return map;
 167  
    }
 168  
    
 169  
    /**
 170  
     * This <code>read</code> method will read the XML element map from
 171  
     * the provided node and deserialize its children as entry types.
 172  
     * Each entry type must contain a key and value so that the entry 
 173  
     * can be inserted in to the map as a pair. If either the key or 
 174  
     * value is composite it is read as a root object, which means its
 175  
     * <code>Root</code> annotation must be present and the name of the
 176  
     * object element must match that root element name.
 177  
     * 
 178  
     * @param node this is the XML element that is to be deserialized
 179  
     * 
 180  
     * @return this returns the item to attach to the object contact
 181  
     */
 182  
    public boolean validate(InputNode node) throws Exception{
 183  4
       InputNode from = node.getParent();
 184  4
       String name = node.getName();                
 185  
       
 186  18
       while(node != null) {
 187  14
          if(!key.validate(node)) {
 188  0
             return false;
 189  
          }
 190  14
          if(!value.validate(node)) {
 191  0
             return false;
 192  
          }
 193  14
          node = from.getNext(name);
 194  14
       }
 195  4
       return true;
 196  
    }
 197  
    
 198  
    /**
 199  
     * This <code>write</code> method will write the key value pairs
 200  
     * within the provided map to the specified XML node. This will 
 201  
     * write each entry type must contain a key and value so that
 202  
     * the entry can be deserialized in to the map as a pair. If the
 203  
     * key or value object is composite it is read as a root object 
 204  
     * so its <code>Root</code> annotation must be present.
 205  
     * 
 206  
     * @param node this is the node the map is to be written to
 207  
     * @param source this is the source map that is to be written 
 208  
     */
 209  
    public void write(OutputNode node, Object source) throws Exception {               
 210  4
       OutputNode parent = node.getParent();      
 211  4
       Map table = (Map) source;
 212  
       
 213  4
       if(!node.isCommitted()) {
 214  4
          node.remove();
 215  
       }
 216  4
       write(parent, table);
 217  4
    }
 218  
    
 219  
    /**
 220  
     * This <code>write</code> method will write the key value pairs
 221  
     * within the provided map to the specified XML node. This will 
 222  
     * write each entry type must contain a key and value so that
 223  
     * the entry can be deserialized in to the map as a pair. If the
 224  
     * key or value object is composite it is read as a root object 
 225  
     * so its <code>Root</code> annotation must be present.
 226  
     * 
 227  
     * @param node this is the node the map is to be written to
 228  
     * @param map this is the source map that is to be written 
 229  
     */
 230  
    public void write(OutputNode node, Map map) throws Exception {   
 231  7
       String name = entry.getEntry();
 232  
       
 233  7
       for(Object index : map.keySet()) {
 234  20
          OutputNode next = node.getChild(name);
 235  20
          Object item = map.get(index);            
 236  
          
 237  20
          key.write(next, index);            
 238  20
          value.write(next, item);                  
 239  20
       }
 240  7
    }
 241  
 }