Coverage Report - org.simpleframework.xml.strategy.ReadGraph
 
Classes in this File Line Coverage Branch Coverage Complexity
ReadGraph
93%
41/44
83%
15/18
3.143
 
 1  
 /*
 2  
  * ReadGraph.java April 2007
 3  
  *
 4  
  * Copyright (C) 2007, 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.strategy;
 20  
 
 21  
 import org.simpleframework.xml.stream.NodeMap;
 22  
 import org.simpleframework.xml.stream.Node;
 23  
 
 24  
 import java.util.HashMap;
 25  
 
 26  
 /**
 27  
  * The <code>ReadGraph</code> object is used to build a graph of the
 28  
  * objects that have been deserialized from the XML document. This is
 29  
  * required so that cycles in the object graph can be recreated such
 30  
  * that the deserialized object is an exact duplicate of the object
 31  
  * that was serialized. Objects are stored in the graph using unique
 32  
  * keys, which for this implementation are unique strings.
 33  
  * 
 34  
  * @author Niall Gallagher
 35  
  * 
 36  
  * @see org.simpleframework.xml.strategy.WriteGraph
 37  
  */
 38  
 class ReadGraph extends HashMap {
 39  
    
 40  
    /**
 41  
     * This is the class loader that is used to load the types used.
 42  
     */
 43  
    private final Loader loader;
 44  
    
 45  
    /**
 46  
     * This is used to represent the length of array object values.
 47  
     */
 48  
    private final String length;
 49  
    
 50  
    /**
 51  
     * This is the label used to mark the type of an object.
 52  
     */
 53  
    private final String label;
 54  
    
 55  
    /**
 56  
     * This is the attribute used to mark the identity of an object.
 57  
     */
 58  
    private final String mark;
 59  
    
 60  
    /**
 61  
     * This is the attribute used to refer to an existing instance.
 62  
     */
 63  
    private final String refer;
 64  
    
 65  
    /**
 66  
     * Constructor for the <code>ReadGraph</code> object. This is used
 67  
     * to create graphs that are used for reading objects from the XML
 68  
     * document. The specified strategy is used to acquire the names
 69  
     * of the special attributes used during the serialization.
 70  
     * 
 71  
     * @param contract this is the name scheme used by the strategy
 72  
     * @param loader this is the class loader to used for the graph 
 73  
     */
 74  1509
    public ReadGraph(Contract contract, Loader loader) {      
 75  1509
       this.refer = contract.getReference();
 76  1509
       this.mark = contract.getIdentity();
 77  1509
       this.length = contract.getLength();
 78  1509
       this.label = contract.getLabel();
 79  1509
       this.loader = loader;
 80  1509
    }
 81  
    
 82  
    /**
 83  
     * This is used to recover the object references from the document
 84  
     * using the special attributes specified. This allows the element
 85  
     * specified by the <code>NodeMap</code> to be used to discover
 86  
     * exactly which node in the object graph the element represents.
 87  
     * 
 88  
     * @param type the type of the field or method in the instance
 89  
     * @param node this is the XML element to be deserialized
 90  
     * 
 91  
     * @return this is used to return the type to acquire the value
 92  
     */
 93  
    public Value read(Type type, NodeMap node) throws Exception {
 94  26855
       Node entry = node.remove(label);
 95  26855
       Class expect = type.getType();
 96  
       
 97  26855
       if(expect.isArray()) {
 98  136
          expect = expect.getComponentType();
 99  
       }
 100  26855
       if(entry != null) {      
 101  1357
          String name = entry.getValue();
 102  1357
          expect = loader.load(name);
 103  
       }  
 104  26855
       return readInstance(type, expect, node); 
 105  
    }
 106  
    
 107  
    /**
 108  
     * This is used to recover the object references from the document
 109  
     * using the special attributes specified. This allows the element
 110  
     * specified by the <code>NodeMap</code> to be used to discover
 111  
     * exactly which node in the object graph the element represents.
 112  
     * 
 113  
     * @param type the type of the field or method in the instance
 114  
     * @param real this is the overridden type from the XML element
 115  
     * @param node this is the XML element to be deserialized
 116  
     * 
 117  
     * @return this is used to return the type to acquire the value
 118  
     */
 119  
    private Value readInstance(Type type, Class real, NodeMap node) throws Exception {      
 120  26855
       Node entry = node.remove(mark);
 121  
       
 122  26855
       if(entry == null) {
 123  4585
          return readReference(type, real, node);
 124  
       }      
 125  22270
       String key = entry.getValue();
 126  
       
 127  22270
       if(containsKey(key)) {
 128  0
          throw new CycleException("Element '%s' already exists", key);
 129  
       }
 130  22270
       return readValue(type, real, node, key);
 131  
    }
 132  
    
 133  
    /**
 134  
     * This is used to recover the object references from the document
 135  
     * using the special attributes specified. This allows the element
 136  
     * specified by the <code>NodeMap</code> to be used to discover
 137  
     * exactly which node in the object graph the element represents.
 138  
     * 
 139  
     * @param type the type of the field or method in the instance
 140  
     * @param real this is the overridden type from the XML element
 141  
     * @param node this is the XML element to be deserialized    
 142  
     * 
 143  
     * @return this is used to return the type to acquire the value
 144  
     */ 
 145  
    private Value readReference(Type type, Class real, NodeMap node) throws Exception {
 146  4585
       Node entry = node.remove(refer);
 147  
       
 148  4585
       if(entry == null) {
 149  385
          return readValue(type, real, node);
 150  
       }
 151  4200
       String key = entry.getValue();
 152  4200
       Object value = get(key); 
 153  
          
 154  4200
       if(!containsKey(key)) {        
 155  0
          throw new CycleException("Invalid reference '%s' found", key);
 156  
       }
 157  4200
       return new Reference(value, real);
 158  
    }
 159  
    
 160  
    /**
 161  
     * This is used to acquire the <code>Value</code> which can be used 
 162  
     * to represent the deserialized value. The type create cab be
 163  
     * added to the graph of created instances if the XML element has
 164  
     * an identification attribute, this allows cycles to be completed.
 165  
     *
 166  
     * @param type the type of the field or method in the instance
 167  
     * @param real this is the overridden type from the XML element
 168  
     * @param node this is the XML element to be deserialized    
 169  
     * 
 170  
     * @return this is used to return the type to acquire the value
 171  
     */
 172  
    private Value readValue(Type type, Class real, NodeMap node) throws Exception {      
 173  22655
       Class expect = type.getType();
 174  
       
 175  22655
       if(expect.isArray()) {
 176  112
          return readArray(type, real, node);
 177  
       }
 178  22543
       return new ObjectValue(real);
 179  
    }
 180  
    
 181  
    /**
 182  
     * This is used to acquire the <code>Value</code> which can be used 
 183  
     * to represent the deserialized value. The type create cab be
 184  
     * added to the graph of created instances if the XML element has
 185  
     * an identification attribute, this allows cycles to be completed.
 186  
     *
 187  
     * @param type the type of the field or method in the instance
 188  
     * @param real this is the overridden type from the XML element
 189  
     * @param node this is the XML element to be deserialized
 190  
     * @param key the key the instance is known as in the graph    
 191  
     * 
 192  
     * @return this is used to return the type to acquire the value
 193  
     */
 194  
    private Value readValue(Type type, Class real, NodeMap node, String key) throws Exception {
 195  22270
       Value value = readValue(type, real, node);
 196  
       
 197  22270
       if(key != null) {
 198  22270
          return new Allocate(value, this, key);
 199  
       }
 200  0
       return value;      
 201  
    }
 202  
    
 203  
    /**
 204  
     * This is used to acquire the <code>Value</code> which can be used 
 205  
     * to represent the deserialized value. The type create cab be
 206  
     * added to the graph of created instances if the XML element has
 207  
     * an identification attribute, this allows cycles to be completed.
 208  
     *
 209  
     * @param type the type of the field or method in the instance
 210  
     * @param real this is the overridden type from the XML element
 211  
     * @param node this is the XML element to be deserialized  
 212  
     * 
 213  
     * @return this is used to return the type to acquire the value
 214  
     */  
 215  
    private Value readArray(Type type, Class real, NodeMap node) throws Exception {
 216  112
       Node entry = node.remove(length);
 217  112
       int size = 0;
 218  
       
 219  112
       if(entry != null) {
 220  106
          String value = entry.getValue();
 221  106
          size = Integer.parseInt(value);
 222  
       }      
 223  112
       return new ArrayValue(real, size);      
 224  
    }
 225  
 }