Coverage Report - org.simpleframework.xml.convert.AnnotationStrategy
 
Classes in this File Line Coverage Branch Coverage Complexity
AnnotationStrategy
100%
29/29
100%
14/14
2.429
 
 1  
 /*
 2  
  * AnnotationStrategy.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>AnnotationStrategy</code> object is used to intercept
 33  
  * the serialization process and delegate to custom converters. This
 34  
  * strategy uses the <code>Convert</code> annotation to specify the
 35  
  * converter to use for serialization and deserialization. If there
 36  
  * is no annotation present on the field or method representing the
 37  
  * object instance to be serialized then this acts as a transparent
 38  
  * proxy to an internal strategy.
 39  
  * <p>
 40  
  * By default the <code>TreeStrategy</code> is used to perform the
 41  
  * normal serialization process should there be no annotation
 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.strategy.TreeStrategy
 50  
  */
 51  
 public class AnnotationStrategy implements Strategy {
 52  
    
 53  
    /**
 54  
     * This is used to scan for an annotation and create a converter.
 55  
     */
 56  
    private final ConverterScanner scanner;
 57  
    
 58  
    /**
 59  
     * This is the strategy that is delegated to for serialization.
 60  
     */
 61  
    private final Strategy strategy;
 62  
    
 63  
    /**
 64  
     * Constructor for the <code>AnnotationStrategy</code> object. 
 65  
     * This creates a strategy that intercepts serialization on any
 66  
     * annotated method or field. If no annotation exists then this
 67  
     * delegates to an internal <code>TreeStrategy</code> object.
 68  
     */
 69  
    public AnnotationStrategy() {
 70  10
       this(new TreeStrategy());
 71  10
    }
 72  
    
 73  
    /**
 74  
     * Constructor for the <code>AnnotationStrategy</code> object. 
 75  
     * This creates a strategy that intercepts serialization on any
 76  
     * annotated method or field. If no annotation exists then this
 77  
     * will delegate to the <code>Strategy</code> provided.
 78  
     * 
 79  
     * @param strategy the internal strategy to delegate to
 80  
     */
 81  12
    public AnnotationStrategy(Strategy strategy) {
 82  12
       this.scanner = new ConverterScanner();
 83  12
       this.strategy = strategy;
 84  12
    }
 85  
    
 86  
    /**
 87  
     * This is used to read the <code>Value</code> which will be used 
 88  
     * to represent the deserialized object. If there is an annotation
 89  
     * present then the value will contain an object instance. If it
 90  
     * does not then it is up to the internal strategy to determine 
 91  
     * what the returned value contains.
 92  
     * 
 93  
     * @param type this is the type that represents a method or field
 94  
     * @param node this is the node representing the XML element
 95  
     * @param map this is the session map that contain variables
 96  
     * 
 97  
     * @return the value representing the deserialized value
 98  
     */
 99  
    public Value read(Type type, NodeMap<InputNode> node, Map map) throws Exception {
 100  34
       Value value = strategy.read(type, node, map);
 101  
       
 102  34
       if(isReference(value)) {
 103  2
          return value;
 104  
       }
 105  32
       return read(type, node, value);
 106  
    }
 107  
    
 108  
    /**
 109  
     * This is used to read the <code>Value</code> which will be used 
 110  
     * to represent the deserialized object. If there is an annotation
 111  
     * present then the value will contain an object instance. If it
 112  
     * does not then it is up to the internal strategy to determine 
 113  
     * what the returned value contains.
 114  
     * 
 115  
     * @param type this is the type that represents a method or field
 116  
     * @param node this is the node representing the XML element
 117  
     * @param value this is the value from the internal strategy
 118  
     * 
 119  
     * @return the value representing the deserialized value
 120  
     */
 121  
    private Value read(Type type, NodeMap<InputNode> node, Value value) throws Exception {
 122  32
       Converter converter = scanner.getConverter(type, value);
 123  32
       InputNode parent = node.getNode();
 124  
       
 125  32
       if(converter != null) {
 126  20
          Object data = converter.read(parent);
 127  
          
 128  20
          if(value != null) {
 129  6
             value.setValue(data);
 130  
          }
 131  20
          return new Reference(value, data);
 132  
       }
 133  12
       return value;
 134  
    }
 135  
    
 136  
    /**
 137  
     * This is used to serialize a representation of the object value
 138  
     * provided. If there is a <code>Convert</code> annotation present
 139  
     * on the provided type then this will use the converter specified
 140  
     * to serialize a representation of the object. If however there
 141  
     * is no annotation then this will delegate to the internal 
 142  
     * strategy. This returns true if the serialization has completed.
 143  
     * 
 144  
     * @param type this is the type that represents the field or method
 145  
     * @param value this is the object instance to be serialized
 146  
     * @param node this is the XML element to be serialized to
 147  
     * @param map this is the session map used by the serializer
 148  
     * 
 149  
     * @return this returns true if it was serialized, false otherwise
 150  
     */
 151  
    public boolean write(Type type, Object value, NodeMap<OutputNode> node, Map map) throws Exception {
 152  78
       boolean reference = strategy.write(type, value, node, map);
 153  
       
 154  78
       if(!reference) {
 155  71
          return write(type, value, node);
 156  
       }
 157  7
       return reference;
 158  
    }
 159  
    
 160  
    /**
 161  
     * This is used to serialize a representation of the object value
 162  
     * provided. If there is a <code>Convert</code> annotation present
 163  
     * on the provided type then this will use the converter specified
 164  
     * to serialize a representation of the object. If however there
 165  
     * is no annotation then this will delegate to the internal 
 166  
     * strategy. This returns true if the serialization has completed.
 167  
     * 
 168  
     * @param type this is the type that represents the field or method
 169  
     * @param value this is the object instance to be serialized
 170  
     * @param node this is the XML element to be serialized to
 171  
     * 
 172  
     * @return this returns true if it was serialized, false otherwise
 173  
     */
 174  
    private boolean write(Type type, Object value, NodeMap<OutputNode> node) throws Exception {
 175  71
       Converter converter = scanner.getConverter(type, value);
 176  71
       OutputNode parent = node.getNode();
 177  
       
 178  71
       if(converter != null) {
 179  37
          converter.write(parent, value);
 180  37
          return true;
 181  
       }
 182  34
       return false;
 183  
    }
 184  
    
 185  
    /**
 186  
     * This is used to determine if the <code>Value</code> provided
 187  
     * represents a reference. If it does represent a reference then
 188  
     * this will return true, if it does not then this returns false.
 189  
     * 
 190  
     * @param value this is the value instance to be evaluated
 191  
     * 
 192  
     * @return this returns true if the value represents a reference
 193  
     */
 194  
    private boolean isReference(Value value) {
 195  34
       return value != null && value.isReference();
 196  
    }
 197  
 }