Coverage Report - org.simpleframework.xml.convert.RegistryStrategy
 
Classes in this File Line Coverage Branch Coverage Complexity
RegistryStrategy
100%
37/37
94%
17/18
2.333
 
 1  
 /*
 2  
  * RegistryStrategy.java January 2010
 3  
  *
 4  
  * Copyright (C) 2010, 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.convert;
 20  
 
 21  
 import java.util.Map;
 22  
 
 23  
 import org.simpleframework.xml.strategy.Strategy;
 24  
 import org.simpleframework.xml.strategy.TreeStrategy;
 25  
 import org.simpleframework.xml.strategy.Type;
 26  
 import org.simpleframework.xml.strategy.Value;
 27  
 import org.simpleframework.xml.stream.InputNode;
 28  
 import org.simpleframework.xml.stream.NodeMap;
 29  
 import org.simpleframework.xml.stream.OutputNode;
 30  
 
 31  
 /**
 32  
  * The <code>RegistryStrategy</code> object is used to intercept
 33  
  * the serialization process and delegate to custom converters. The
 34  
  * custom converters are resolved from a <code>Registry</code>
 35  
  * object, which is provided to the constructor. If there is no
 36  
  * binding for a particular object then serialization is delegated
 37  
  * to an internal strategy. All converters resolved by this are
 38  
  * instantiated once and cached internally for performance.
 39  
  * <p>
 40  
  * By default the <code>TreeStrategy</code> is used to perform the
 41  
  * normal serialization process should there be no class binding
 42  
  * specifying a converter to use. However, any implementation can
 43  
  * be used, including the <code>CycleStrategy</code>, which handles
 44  
  * cycles in the object graph. To specify the internal strategy to
 45  
  * use it can be provided in the constructor.
 46  
  * 
 47  
  * @author Niall Gallagher
 48  
  *
 49  
  * @see org.simpleframework.xml.convert.Registry
 50  
  */
 51  
 public class RegistryStrategy implements Strategy {
 52  
    
 53  
    /**
 54  
     * This is the registry that is used to resolve bindings.
 55  
     */
 56  
    private final Registry registry;
 57  
    
 58  
    /**
 59  
     * This is the strategy used if there is no bindings.
 60  
     */
 61  
    private final Strategy strategy;
 62  
    
 63  
    /**
 64  
     * Constructor for the <code>RegistryStrategy</code> object. This
 65  
     * is used to create a strategy that will intercept the normal
 66  
     * serialization process by searching for bindings within the
 67  
     * provided <code>Registry</code> instance.
 68  
     * 
 69  
     * @param registry this is the registry instance with bindings
 70  
     */
 71  
    public RegistryStrategy(Registry registry) {
 72  4
       this(registry, new TreeStrategy());
 73  4
    }
 74  
    
 75  
    /**
 76  
     * Constructor for the <code>RegistryStrategy</code> object. This
 77  
     * is used to create a strategy that will intercept the normal
 78  
     * serialization process by searching for bindings within the
 79  
     * provided <code>Registry</code> instance.
 80  
     * 
 81  
     * @param registry this is the registry instance with bindings
 82  
     * @param strategy this is the strategy to delegate to
 83  
     */
 84  8
    public RegistryStrategy(Registry registry, Strategy strategy){
 85  8
       this.registry = registry;
 86  8
       this.strategy = strategy;
 87  8
    }
 88  
    
 89  
    /**
 90  
     * This is used to read the <code>Value</code> which will be used 
 91  
     * to represent the deserialized object. If there is an binding
 92  
     * present then the value will contain an object instance. If it
 93  
     * does not then it is up to the internal strategy to determine 
 94  
     * what the returned value contains.
 95  
     * 
 96  
     * @param type this is the type that represents a method or field
 97  
     * @param node this is the node representing the XML element
 98  
     * @param map this is the session map that contain variables
 99  
     * 
 100  
     * @return the value representing the deserialized value
 101  
     */
 102  
    public Value read(Type type, NodeMap<InputNode> node, Map map) throws Exception {
 103  20
       Value value = strategy.read(type, node, map);
 104  
       
 105  20
       if(isReference(value)) {
 106  2
          return value;
 107  
       }
 108  18
       return read(type, node, value);
 109  
    }
 110  
   
 111  
    /**
 112  
     * This is used to read the <code>Value</code> which will be used 
 113  
     * to represent the deserialized object. If there is an binding
 114  
     * present then the value will contain an object instance. If it
 115  
     * does not then it is up to the internal strategy to determine 
 116  
     * what the returned value contains.
 117  
     * 
 118  
     * @param type this is the type that represents a method or field
 119  
     * @param node this is the node representing the XML element
 120  
     * @param value this is the value from the internal strategy
 121  
     * 
 122  
     * @return the value representing the deserialized value
 123  
     */   
 124  
    private Value read(Type type, NodeMap<InputNode> node, Value value) throws Exception {
 125  18
       Converter converter = lookup(type, value);
 126  18
       InputNode source = node.getNode();
 127  
       
 128  18
       if(converter != null) {
 129  7
          Object data = converter.read(source);
 130  
       
 131  7
          if(value != null) {
 132  5
             value.setValue(data);
 133  
          }
 134  7
          return new Reference(value, data);
 135  
       }
 136  11
       return value;
 137  
    }
 138  
    
 139  
    /**
 140  
     * This is used to serialize a representation of the object value
 141  
     * provided. If there is a <code>Registry</code> binding present
 142  
     * for the provided type then this will use the converter specified
 143  
     * to serialize a representation of the object. If however there
 144  
     * is no binding present then this will delegate to the internal 
 145  
     * strategy. This returns true if the serialization has completed.
 146  
     * 
 147  
     * @param type this is the type that represents the field or method
 148  
     * @param value this is the object instance to be serialized
 149  
     * @param node this is the XML element to be serialized to
 150  
     * @param map this is the session map used by the serializer
 151  
     * 
 152  
     * @return this returns true if it was serialized, false otherwise
 153  
     */
 154  
    public boolean write(Type type, Object value, NodeMap<OutputNode> node, Map map) throws Exception {
 155  52
       boolean reference = strategy.write(type, value, node, map);
 156  
       
 157  52
       if(!reference) {
 158  43
          return write(type, value, node);
 159  
       }
 160  9
       return reference;
 161  
    }
 162  
    
 163  
    /**
 164  
     * This is used to serialize a representation of the object value
 165  
     * provided. If there is a <code>Registry</code> binding present
 166  
     * for the provided type then this will use the converter specified
 167  
     * to serialize a representation of the object. If however there
 168  
     * is no binding present then this will delegate to the internal 
 169  
     * strategy. This returns true if the serialization has completed.
 170  
     * 
 171  
     * @param type this is the type that represents the field or method
 172  
     * @param value this is the object instance to be serialized
 173  
     * @param node this is the XML element to be serialized to
 174  
     * 
 175  
     * @return this returns true if it was serialized, false otherwise
 176  
     */
 177  
    private boolean write(Type type, Object value, NodeMap<OutputNode> node) throws Exception {
 178  43
       Converter converter = lookup(type, value);
 179  43
       OutputNode source = node.getNode();
 180  
       
 181  43
       if(converter != null) {
 182  16
          converter.write(source, value);
 183  16
          return true;
 184  
       }
 185  27
       return false;  
 186  
    }
 187  
    
 188  
    /**
 189  
     * This is used to acquire a <code>Converter</code> instance for 
 190  
     * the provided value object. The value object is used to resolve
 191  
     * the converter to use for the serialization process.
 192  
     * 
 193  
     * @param type this is the type representing the field or method
 194  
     * @param value this is the value that is to be serialized
 195  
     * 
 196  
     * @return this returns the converter instance that is matched
 197  
     */
 198  
    private Converter lookup(Type type, Value value) throws Exception {
 199  18
       Class real = type.getType();
 200  
       
 201  18
       if(value != null) {
 202  6
          real = value.getType();
 203  
       }
 204  18
       return registry.lookup(real);
 205  
    }
 206  
    
 207  
    /**
 208  
     * This is used to acquire a <code>Converter</code> instance for 
 209  
     * the provided object instance. The instance class is used to
 210  
     * resolve the converter to use for the serialization process.
 211  
     * 
 212  
     * @param type this is the type representing the field or method
 213  
     * @param value this is the value that is to be serialized
 214  
     * 
 215  
     * @return this returns the converter instance that is matched
 216  
     */
 217  
    private Converter lookup(Type type, Object value) throws Exception {
 218  43
       Class real = type.getType();
 219  
       
 220  43
       if(value != null) {
 221  43
          real = value.getClass();
 222  
       }
 223  43
       return registry.lookup(real);
 224  
    }
 225  
    
 226  
    /**
 227  
     * This is used to determine if the <code>Value</code> provided
 228  
     * represents a reference. If it does represent a reference then
 229  
     * this will return true, if it does not then this returns false.
 230  
     * 
 231  
     * @param value this is the value instance to be evaluated
 232  
     * 
 233  
     * @return this returns true if the value represents a reference
 234  
     */
 235  
    private boolean isReference(Value value) {
 236  20
       return value != null && value.isReference();
 237  
    }
 238  
 }