Coverage Report - org.simpleframework.xml.core.PrimitiveValue
 
Classes in this File Line Coverage Branch Coverage Complexity
PrimitiveValue
94%
65/69
94%
32/34
3
 
 1  
 /*
 2  
  * PrimitiveValue.java July 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.core;
 20  
 
 21  
 import org.simpleframework.xml.strategy.Type;
 22  
 import org.simpleframework.xml.stream.InputNode;
 23  
 import org.simpleframework.xml.stream.OutputNode;
 24  
 import org.simpleframework.xml.stream.Style;
 25  
 
 26  
 /**
 27  
  * The <code>PrimitiveValue</code> is used to serialize a primitive 
 28  
  * value to and from a node. If a value name is provided in the 
 29  
  * annotation then this will serialize and deserialize that value 
 30  
  * with the given name, if the value is primitive and no name is
 31  
  * specified then the value is written inline, that is without any
 32  
  * enclosing XML element.
 33  
  * <pre>
 34  
  * 
 35  
  *    &lt;entry key="one"&gt;example one&lt;/entry&gt;
 36  
  *    &lt;entry key="two"&gt;example two&lt;/entry&gt;
 37  
  *    &lt;entry key="three"&gt;example three&lt;/entry&gt;    
 38  
  * 
 39  
  * </pre>
 40  
  * Allowing the value to be written as either an XML element or an
 41  
  * inline text value enables a more flexible means for representing 
 42  
  * the value. The only condition for having an inline value is that
 43  
  * the key is specified as an attribute in the annotation.
 44  
  * 
 45  
  * @author Niall Gallagher
 46  
  * 
 47  
  * @see org.simpleframework.xml.core.CompositeMap
 48  
  */
 49  
 class PrimitiveValue implements Converter {
 50  
    
 51  
    /**
 52  
     * The primitive factory used to resolve the primitive to a string.
 53  
     */
 54  
    private final PrimitiveFactory factory;
 55  
    
 56  
    /**
 57  
     * This is the context used to support the serialization process.
 58  
     */
 59  
    private final Context context;
 60  
    
 61  
    /**
 62  
     * The primitive converter used to read the value from the node.
 63  
     */
 64  
    private final Primitive root;
 65  
    
 66  
    /**
 67  
     * This is the style used to style the XML names for the value.
 68  
     */
 69  
    private final Style style;
 70  
    
 71  
    /**
 72  
     * The entry object contains the details on how to write the value.
 73  
     */
 74  
    private final Entry entry; 
 75  
    
 76  
    /**
 77  
     * Represents the primitive type the value is serialized to and from.
 78  
     */
 79  
    private final Type type;
 80  
    
 81  
    /**
 82  
     * Constructor for the <code>PrimitiveValue</code> object. This is 
 83  
     * used to create the value object which converts the map value to 
 84  
     * an instance of the value type. This can also resolve references. 
 85  
     * 
 86  
     * @param context this is the context object used for serialization
 87  
     * @param entry this is the entry object that describes entries
 88  
     * @param type this is the type that this converter deals with
 89  
     */   
 90  242
    public PrimitiveValue(Context context, Entry entry, Type type) {
 91  242
       this.factory = new PrimitiveFactory(context, type);
 92  242
       this.root = new Primitive(context, type);
 93  242
       this.style = context.getStyle();
 94  242
       this.context = context;
 95  242
       this.entry = entry;
 96  242
       this.type = type;
 97  242
    }
 98  
    
 99  
    /**
 100  
     * This method is used to read the value value from the node. The 
 101  
     * value read from the node is resolved using the template filter.
 102  
     * If the value value can not be found according to the annotation
 103  
     * attributes then an exception is thrown.
 104  
     * 
 105  
     * @param node this is the node to read the value object from
 106  
     * 
 107  
     * @return this returns the value deserialized from the node
 108  
     */ 
 109  
    public Object read(InputNode node) throws Exception {
 110  217
       Class expect = type.getType();
 111  217
       String name = entry.getValue();
 112  
       
 113  217
       if(!entry.isInline()) {
 114  159
          if(name == null) {
 115  123
             name = context.getName(expect);
 116  
          }
 117  159
          return readElement(node, name);
 118  
       }
 119  58
       return readAttribute(node, name);
 120  
    }
 121  
    
 122  
    /**
 123  
     * This method is used to read the value value from the node. The 
 124  
     * value read from the node is resolved using the template filter.
 125  
     * If the value value can not be found according to the annotation
 126  
     * attributes then an exception is thrown.
 127  
     * 
 128  
     * @param node this is the node to read the value object from
 129  
     * @param value this is the value to deserialize in to
 130  
     * 
 131  
     * @return this returns the value deserialized from the node
 132  
     * 
 133  
     * @throws Exception if value is not null an exception is thrown
 134  
     */ 
 135  
    public Object read(InputNode node, Object value) throws Exception {
 136  0
       Class expect = type.getType();
 137  
       
 138  0
       if(value != null) {
 139  0
          throw new PersistenceException("Can not read value of %s for %s", expect, entry);
 140  
       }
 141  0
       return read(node);
 142  
    }
 143  
    
 144  
    /**
 145  
     * This method is used to read the element value from the node. The 
 146  
     * value read from the node is resolved using the template filter.
 147  
     * If the value value can not be found according to the annotation
 148  
     * attributes then null is assumed and returned.
 149  
     * 
 150  
     * @param node this is the node to read the value object from
 151  
     * @param key this is the name of the value XML element
 152  
     * 
 153  
     * @return this returns the value deserialized from the node
 154  
     */ 
 155  
    private Object readElement(InputNode node, String key) throws Exception {
 156  159
       String name = style.getAttribute(key);
 157  159
       InputNode child = node.getNext(name);
 158  
       
 159  159
       if(child == null) {
 160  7
          return null;        
 161  
       }
 162  152
       return root.read(child);      
 163  
    }
 164  
    
 165  
    /**
 166  
     * This method is used to read the text value from the node. The 
 167  
     * value read from the node is resolved using the template filter.
 168  
     * If the value value can not be found according to the annotation
 169  
     * attributes then null is assumed and returned.
 170  
     * 
 171  
     * @param node this is the node to read the value object from
 172  
     * @param name this is the name of the value XML attribute, if any
 173  
     * 
 174  
     * @return this returns the value deserialized from the node
 175  
     */ 
 176  
    private Object readAttribute(InputNode node, String name) throws Exception {
 177  58
       if(name != null) {
 178  20
          name = style.getAttribute(name);
 179  20
          node = node.getAttribute(name);
 180  
       }       
 181  58
       if(node == null) {
 182  2
          return null;        
 183  
       }
 184  56
       return root.read(node);      
 185  
    }
 186  
    
 187  
    /**
 188  
     * This method is used to validate the value from the node. The 
 189  
     * value read from the node is resolved using the template filter.
 190  
     * If the value value can not be found according to the annotation
 191  
     * attributes then null is assumed and the node is valid.
 192  
     * 
 193  
     * @param node this is the node to read the value object from
 194  
     * 
 195  
     * @return this returns true if the primitive key is valid
 196  
     */ 
 197  
    public boolean validate(InputNode node) throws Exception {
 198  85
       Class expect = type.getType();
 199  85
       String name = entry.getValue();
 200  
       
 201  85
       if(!entry.isInline()) {
 202  62
          if(name == null) {
 203  50
             name = context.getName(expect);
 204  
          }
 205  62
          return validateElement(node, name);
 206  
       }
 207  23
       return validateAttribute(node, name);
 208  
    }
 209  
    
 210  
    /**
 211  
     * This method is used to validate the value from the node. The 
 212  
     * value read from the node is resolved using the template filter.
 213  
     * If the value value can not be found according to the annotation
 214  
     * attributes then null is assumed and the node is valid.
 215  
     *  
 216  
     * @param node this is the node to read the value object from
 217  
     * @param key this is the name of the node to be validated
 218  
     * 
 219  
     * @return this returns true if the primitive key is valid
 220  
     */    
 221  
    private boolean validateElement(InputNode node, String key) throws Exception {
 222  62
       String name = style.getAttribute(key);
 223  62
       InputNode child = node.getNext(name);
 224  
       
 225  62
       if(child == null) {
 226  13
          return true;        
 227  
       }
 228  49
       return root.validate(node);
 229  
    }
 230  
    
 231  
    /**
 232  
     * This method is used to validate the value from the node. The 
 233  
     * value read from the node is resolved using the template filter.
 234  
     * If the value value can not be found according to the annotation
 235  
     * attributes then null is assumed and the node is valid.
 236  
     *  
 237  
     * @param node this is the node to read the value object from
 238  
     * @param key this is the name of the node to be validated
 239  
     * 
 240  
     * @return this returns true if the primitive key is valid
 241  
     */    
 242  
    private boolean validateAttribute(InputNode node, String key) throws Exception {
 243  23
       if(key != null) {
 244  8
          key = style.getAttribute(key);
 245  8
          node = node.getNext(key);
 246  
       }
 247  23
       if(node == null) {
 248  8
          return true;        
 249  
       }
 250  15
       return root.validate(node);
 251  
    }
 252  
 
 253  
    /**
 254  
     * This method is used to write the value to the specified node.
 255  
     * The value written to the node can be an attribute or an element
 256  
     * depending on the annotation attribute values. This method will
 257  
     * maintain references for serialized elements.
 258  
     * 
 259  
     * @param node this is the node that the value is written to
 260  
     * @param item this is the item that is to be written
 261  
     */
 262  
    public void write(OutputNode node, Object item) throws Exception {
 263  432
       Class expect = type.getType();
 264  432
       String name = entry.getValue();
 265  
       
 266  432
       if(!entry.isInline()) {
 267  298
          if(name == null) {
 268  224
             name = context.getName(expect);
 269  
          } 
 270  298
          writeElement(node, item, name);
 271  
       } else {
 272  134
          writeAttribute(node, item, name);
 273  
       }
 274  432
    }
 275  
    
 276  
    /**
 277  
     * This method is used to write the value to the specified node.
 278  
     * The value written to the node can be an attribute or an element
 279  
     * depending on the annotation attribute values. This method will
 280  
     * maintain references for serialized elements.
 281  
     * 
 282  
     * @param node this is the node that the value is written to
 283  
     * @param item this is the item that is to be written
 284  
     * @param key this is the name of the element to be created
 285  
     */   
 286  
    private void writeElement(OutputNode node, Object item, String key) throws Exception {
 287  298
       String name = style.getAttribute(key);
 288  298
       OutputNode child = node.getChild(name);
 289  
 
 290  298
       if(item != null) {        
 291  276
          if(!isOverridden(child, item)) {
 292  271
             root.write(child, item);
 293  
          }
 294  
       }
 295  298
    }
 296  
    
 297  
    /**
 298  
     * This method is used to write the value to the specified node.
 299  
     * The value written to the node can be an attribute or an element
 300  
     * depending on the annotation attribute values. This method will
 301  
     * maintain references for serialized elements.
 302  
     * 
 303  
     * @param node this is the node that the value is written to
 304  
     * @param item this is the item that is to be written
 305  
     * @param key this is the name of the attribute to be created
 306  
     */   
 307  
    private void writeAttribute(OutputNode node, Object item, String key) throws Exception {
 308  134
       if(item != null) {
 309  119
          if(key != null) {
 310  47
             key = style.getAttribute(key);
 311  47
             node = node.setAttribute(key, null);
 312  
          }     
 313  119
          root.write(node, item);
 314  
       }
 315  134
    }
 316  
    
 317  
    /**
 318  
     * This is used to determine whether the specified value has been
 319  
     * overridden by the strategy. If the item has been overridden
 320  
     * then no more serialization is require for that value, this is
 321  
     * effectively telling the serialization process to stop writing.
 322  
     * 
 323  
     * @param node the node that a potential override is written to
 324  
     * @param value this is the object instance to be serialized
 325  
     * 
 326  
     * @return returns true if the strategy overrides the object
 327  
     */
 328  
    private boolean isOverridden(OutputNode node, Object value) throws Exception{
 329  276
       return factory.setOverride(type, value, node);
 330  
    }
 331  
 
 332  
 }