All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simpleframework.xml.strategy.ReadGraph Maven / Gradle / Ivy

Go to download

Simple is a high performance XML serialization and configuration framework for Java

There is a newer version: 2.7.1
Show newest version
/*
 * ReadGraph.java April 2007
 *
 * Copyright (C) 2007, Niall Gallagher 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 */

package org.simpleframework.xml.strategy;

import org.simpleframework.xml.stream.NodeMap;
import org.simpleframework.xml.stream.Node;

import java.util.HashMap;

/**
 * The ReadGraph object is used to build a graph of the
 * objects that have been deserialized from the XML document. This is
 * required so that cycles in the object graph can be recreated such
 * that the deserialized object is an exact duplicate of the object
 * that was serialized. Objects are stored in the graph using unique
 * keys, which for this implementation are unique strings.
 * 
 * @author Niall Gallagher
 * 
 * @see org.simpleframework.xml.strategy.WriteGraph
 */
class ReadGraph extends HashMap {
   
   /**
    * This is the class loader that is used to load the types used.
    */
   private ClassLoader loader;
   
   /**
    * This is used to represent the length of array object values.
    */
   private String length;
   
   /**
    * This is the label used to mark the type of an object.
    */
   private String label;
   
   /**
    * This is the attribute used to mark the identity of an object.
    */
   private String mark;
   
   /**
    * This is the attribute used to refer to an existing instance.
    */
   private String refer;
   
   /**
    * Constructor for the ReadGraph object. This is used
    * to create graphs that are used for reading objects from the XML
    * document. The specified strategy is used to acquire the names
    * of the special attributes used during the serialization.
    * 
    * @param contract this is the name scheme used by the strategy
    * @param loader this is the class loader to used for the graph 
    */
   public ReadGraph(Contract contract, ClassLoader loader) {      
      this.refer = contract.getReference();
      this.mark = contract.getIdentity();
      this.length = contract.getLength();
      this.label = contract.getLabel();
      this.loader = loader;
   }
   
   /**
    * This is used to recover the object references from the document
    * using the special attributes specified. This allows the element
    * specified by the NodeMap to be used to discover
    * exactly which node in the object graph the element represents.
    * 
    * @param field the type of the field or method in the instance
    * @param node this is the XML element to be deserialized
    * 
    * @return this is used to return the type to acquire the value
    */
   public Value getElement(Class field, NodeMap node) throws Exception {
      Node entry = node.remove(label);
      Class type = field;
      
      if(field.isArray()) {
         type = field.getComponentType();
      }
      if(entry != null) {      
         String name = entry.getValue();
         type = loader.loadClass(name);
      }  
      return getInstance(field, type, node); 
   }
   
   /**
    * This is used to recover the object references from the document
    * using the special attributes specified. This allows the element
    * specified by the NodeMap to be used to discover
    * exactly which node in the object graph the element represents.
    * 
    * @param field the type of the field or method in the instance
    * @param real this is the overridden type from the XML element
    * @param node this is the XML element to be deserialized
    * 
    * @return this is used to return the type to acquire the value
    */
   private Value getInstance(Class field, Class real, NodeMap node) throws Exception {      
      Node entry = node.remove(mark);
      
      if(entry == null) {
         return getReference(field, real, node);
      }      
      String key = entry.getValue();
      
      if(containsKey(key)) {
         throw new CycleException("Element '%s' already exists", key);
      }
      return getValue(field, real, node, key);
   }
   
   /**
    * This is used to recover the object references from the document
    * using the special attributes specified. This allows the element
    * specified by the NodeMap to be used to discover
    * exactly which node in the object graph the element represents.
    * 
    * @param field the type of the field or method in the instance
    * @param real this is the overridden type from the XML element
    * @param node this is the XML element to be deserialized    
    * 
    * @return this is used to return the type to acquire the value
    */ 
   private Value getReference(Class field, Class real, NodeMap node) throws Exception {
      Node entry = node.remove(refer);
      
      if(entry == null) {
         return getValue(field, real, node);
      }
      String key = entry.getValue();
      Object value = get(key); 
         
      if(!containsKey(key)) {        
         throw new CycleException("Invalid reference '%s' found", key);
      }
      return new Reference(value, real);
   }
   
   /**
    * This is used to acquire the Value which can be used 
    * to represent the deserialized value. The type create cab be
    * added to the graph of created instances if the XML element has
    * an identification attribute, this allows cycles to be completed.
    *
    * @param field the type of the field or method in the instance
    * @param real this is the overridden type from the XML element
    * @param node this is the XML element to be deserialized    
    * 
    * @return this is used to return the type to acquire the value
    */
   private Value getValue(Class field, Class real, NodeMap node) throws Exception {      
      if(field.isArray()) {
         return getArray(field, real, node);
      }
      return new ObjectValue(real);
   }
   
   /**
    * This is used to acquire the Value which can be used 
    * to represent the deserialized value. The type create cab be
    * added to the graph of created instances if the XML element has
    * an identification attribute, this allows cycles to be completed.
    *
    * @param field the type of the field or method in the instance
    * @param real this is the overridden type from the XML element
    * @param node this is the XML element to be deserialized
    * @param key the key the instance is known as in the graph    
    * 
    * @return this is used to return the type to acquire the value
    */
   private Value getValue(Class field, Class real, NodeMap node, String key) throws Exception {
      Value type = getValue(field, real, node);
      
      if(key != null) {
         return new Allocate(type, this, key);
      }
      return type;      
   }
   
   /**
    * This is used to acquire the Value which can be used 
    * to represent the deserialized value. The type create cab be
    * added to the graph of created instances if the XML element has
    * an identification attribute, this allows cycles to be completed.
    *
    * @param field the type of the field or method in the instance
    * @param real this is the overridden type from the XML element
    * @param node this is the XML element to be deserialized  
    * 
    * @return this is used to return the type to acquire the value
    */  
   private Value getArray(Class field, Class real, NodeMap node) throws Exception {
      Node entry = node.remove(length);
      int size = 0;
      
      if(entry != null) {
         String value = entry.getValue();
         size = Integer.parseInt(value);
      }      
      return new ArrayValue(real, size);      
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy