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