Coverage Report - org.simpleframework.xml.core.Variable
 
Classes in this File Line Coverage Branch Coverage Complexity
Variable
44%
15/34
100%
2/2
1.242
Variable$Adapter
90%
18/20
100%
4/4
1.242
 
 1  
 /*
 2  
  * Variable.java December 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 java.lang.annotation.Annotation;
 22  
 
 23  
 import org.simpleframework.xml.strategy.Type;
 24  
 import org.simpleframework.xml.stream.InputNode;
 25  
 import org.simpleframework.xml.stream.OutputNode;
 26  
 import org.simpleframework.xml.stream.Position;
 27  
 
 28  
 /**
 29  
  * The <code>Variable</code> object is used to represent a variable 
 30  
  * for a method or field of a deserialized object. It has the value
 31  
  * for the field or method as well as the details from the annotation.
 32  
  * This is used by the <code>Collector</code> to populate an object
 33  
  * once all the values for that object have been collected. 
 34  
  * 
 35  
  * @author Niall Gallagher
 36  
  * 
 37  
  * @see org.simpleframework.xml.core.Collector
 38  
  */
 39  
 class Variable implements Label {
 40  
    
 41  
    /**
 42  
     * This is the object that has been deserialized from the XML.
 43  
     */
 44  
    private final Object value;
 45  
    
 46  
    /**
 47  
     * This contains the details for the annotated field or method.
 48  
     */
 49  
    private final Label label;
 50  
    
 51  
    /**
 52  
     * Constructor for the <code>Variable</code> object. This is used
 53  
     * to create an object that holds a deserialized value, as well as
 54  
     * the details of the annotated method or field it is to be set to.
 55  
     * This allows the value to be repeatedly deserialized.
 56  
     * 
 57  
     * @param label this is the label for the field or method used
 58  
     * @param value the deserialized object for the method or field
 59  
     */
 60  2495563
    public Variable(Label label, Object value) {
 61  2495563
       this.label = label;
 62  2495563
       this.value = value;
 63  2495563
    }
 64  
    
 65  
    /**
 66  
     * This is used to acquire the <code>Label</code> that the type
 67  
     * provided is represented by. Typically this will return the
 68  
     * same instance. However, in the case of unions this will
 69  
     * look for an individual label to match the type provided.
 70  
     * 
 71  
     * @param type this is the type to acquire the label for
 72  
     * 
 73  
     * @return this returns the label represented by this type
 74  
     */
 75  
    public Label getLabel(Class type) {
 76  0
       return this;
 77  
    }
 78  
    
 79  
    /**
 80  
     * This is used to acquire the <code>Type</code> that the type
 81  
     * provided is represented by. Typically this will return the
 82  
     * field or method represented by the label. However, in the 
 83  
     * case of unions this will provide an override type.
 84  
     * 
 85  
     * @param type this is the class to acquire the type for
 86  
     * 
 87  
     * @return this returns the type represented by this class
 88  
     */
 89  
    public Type getType(Class type) throws Exception {
 90  0
       return label.getType(type);
 91  
    }
 92  
    
 93  
    /**
 94  
     * This returns a <code>Collection</code> of element names. This
 95  
     * will typically contain both the name and path of the label. 
 96  
     * However, if this is a union it can contain many names and
 97  
     * paths. This method should never return null. 
 98  
     * 
 99  
     * @return this returns the names of each of the elements
 100  
     */
 101  
    public String[] getNames() throws Exception {
 102  0
       return label.getNames();
 103  
    }
 104  
    
 105  
    /**
 106  
     * This returns a <code>Collection</code> of element paths. This
 107  
     * will typically contain only the path of the label, which is
 108  
     * composed using the <code>Path</code> annotation and the name
 109  
     * of the label. However, if this is a union it can contain many 
 110  
     * paths. This method should never return null.
 111  
     * 
 112  
     * @return this returns the names of each of the elements
 113  
     */
 114  
    public String[] getPaths() throws Exception {
 115  749218
       return label.getPaths();
 116  
    }
 117  
    
 118  
    /**
 119  
     * This is used to acquire the value associated with the variable.
 120  
     * Once fully deserialized the value is used to set the value for 
 121  
     * a field or method of the object. This value can be repeatedly
 122  
     * read if the <code>Converter</code> is acquired a second time.
 123  
     * 
 124  
     * @return this returns the value that has been deserialized
 125  
     */
 126  
    public Object getValue() {
 127  2068951
       return value;
 128  
    }
 129  
    
 130  
    /**
 131  
     * This is used to acquire the <code>Decorator</code> for this.
 132  
     * A decorator is an object that adds various details to the
 133  
     * node without changing the overall structure of the node. For
 134  
     * example comments and namespaces can be added to the node with
 135  
     * a decorator as they do not affect the deserialization.
 136  
     * 
 137  
     * @return this returns the decorator associated with this
 138  
     */
 139  
    public Decorator getDecorator() throws Exception {
 140  0
       return label.getDecorator();
 141  
    }
 142  
    
 143  
    /**
 144  
     * This method returns a <code>Converter</code> which can be used to
 145  
     * convert an XML node into an object value and vice versa. The 
 146  
     * converter requires only the context object in order to perform
 147  
     * serialization or deserialization of the provided XML node.
 148  
     * 
 149  
     * @param context this is the context object for the serialization
 150  
     * 
 151  
     * @return this returns an object that is used for conversion
 152  
     */
 153  
    public Converter getConverter(Context context) throws Exception {
 154  249741
       Converter reader = label.getConverter(context);
 155  
       
 156  249741
       if(reader instanceof Adapter) {
 157  248585
          return reader;
 158  
       }
 159  1156
       return new Adapter(reader, label, value);
 160  
    }
 161  
    
 162  
    /**
 163  
     * This is used to provide a configured empty value used when the
 164  
     * annotated value is null. This ensures that XML can be created
 165  
     * with required details regardless of whether values are null or
 166  
     * not. It also provides a means for sensible default values.
 167  
     *
 168  
     * @param context this is the context object for the serialization
 169  
     * 
 170  
     * @return this returns the string to use for default values
 171  
     */
 172  
    public Object getEmpty(Context context) throws Exception {
 173  249681
       return label.getEmpty(context);
 174  
    }
 175  
    
 176  
    /**
 177  
     * This is used to acquire the contact object for this label. The 
 178  
     * contact retrieved can be used to set any object or primitive that
 179  
     * has been deserialized, and can also be used to acquire values to
 180  
     * be serialized in the case of object persistence. All contacts 
 181  
     * that are retrieved from this method will be accessible. 
 182  
     * 
 183  
     * @return returns the field that this label is representing
 184  
     */
 185  
    public Contact getContact() {
 186  2318138
       return label.getContact();
 187  
    }
 188  
    
 189  
    /**
 190  
     * This returns the dependent type for the annotation. This type
 191  
     * is the type other than the annotated field or method type that
 192  
     * the label depends on. For the <code>ElementList</code> and 
 193  
     * the <code>ElementArray</code> this is the component type that
 194  
     * is deserialized individually and inserted into the container. 
 195  
     * 
 196  
     * @return this is the type that the annotation depends on
 197  
     */
 198  
    public Type getDependent() throws Exception {
 199  0
       return label.getDependent();
 200  
    }
 201  
    
 202  
    /**
 203  
     * This is the key used to represent this label. The key is used
 204  
     * to store the parameter in hash containers. Typically the
 205  
     * key is generated from the paths associated with the label.
 206  
     * 
 207  
     * @return this is the key used to represent the label
 208  
     */
 209  
    public Object getKey() throws Exception {
 210  749159
       return label.getKey();
 211  
    }
 212  
    
 213  
    /**
 214  
     * This is used to either provide the entry value provided within
 215  
     * the annotation or compute a entry value. If the entry string
 216  
     * is not provided the the entry value is calculated as the type
 217  
     * of primitive the object is as a simplified class name.
 218  
     * 
 219  
     * @return this returns the name of the XML entry element used 
 220  
     */
 221  
    public String getEntry() throws Exception {
 222  0
       return label.getEntry();
 223  
    }
 224  
 
 225  
    /**
 226  
     * This is used to acquire the name of the element or attribute
 227  
     * that is used by the class schema. The name is determined by
 228  
     * checking for an override within the annotation. If it contains
 229  
     * a name then that is used, if however the annotation does not
 230  
     * specify a name the the field or method name is used instead.
 231  
     * 
 232  
     * @return returns the name that is used for the XML property
 233  
     */
 234  
    public String getName() throws Exception{
 235  0
       return label.getName();
 236  
    }
 237  
    
 238  
    /**
 239  
     * This acquires the annotation associated with this label. This
 240  
     * is typically the annotation acquired from the field or method.
 241  
     * However, in the case of unions this will return the actual
 242  
     * annotation within the union group that this represents.
 243  
     * 
 244  
     * @return this returns the annotation that this represents
 245  
     */
 246  
    public Annotation getAnnotation() {
 247  0
       return label.getAnnotation();
 248  
    }
 249  
    
 250  
    /**
 251  
     * This is used to acquire the path of the element or attribute
 252  
     * that is used by the class schema. The path is determined by
 253  
     * acquiring the XPath expression and appending the name of the
 254  
     * label to form a fully qualified path.
 255  
     * 
 256  
     * @return returns the path that is used for the XML property
 257  
     */
 258  
    public String getPath() throws Exception {
 259  0
       return label.getPath();
 260  
    }
 261  
    
 262  
    /**
 263  
     * This method is used to return an XPath expression that is 
 264  
     * used to represent the position of this label. If there is no
 265  
     * XPath expression associated with this then an empty path is
 266  
     * returned. This will never return a null expression.
 267  
     * 
 268  
     * @return the XPath expression identifying the location
 269  
     */
 270  
    public Expression getExpression() throws Exception {
 271  0
       return label.getExpression();
 272  
    }
 273  
    
 274  
    /**
 275  
     * This is used to acquire the name of the element or attribute
 276  
     * as taken from the annotation. If the element or attribute
 277  
     * explicitly specifies a name then that name is used for the
 278  
     * XML element or attribute used. If however no overriding name
 279  
     * is provided then the method or field is used for the name. 
 280  
     * 
 281  
     * @return returns the name of the annotation for the contact
 282  
     */
 283  
    public String getOverride() {
 284  0
       return label.getOverride();
 285  
    }
 286  
    
 287  
    /**
 288  
     * This acts as a convenience method used to determine the type of
 289  
     * the field this represents. This is used when an object is written
 290  
     * to XML. It determines whether a <code>class</code> attribute
 291  
     * is required within the serialized XML element, that is, if the
 292  
     * class returned by this is different from the actual value of the
 293  
     * object to be serialized then that type needs to be remembered.
 294  
     *  
 295  
     * @return this returns the type of the field class
 296  
     */
 297  
    public Class getType() {
 298  0
       return label.getType();
 299  
    }
 300  
    
 301  
    /**
 302  
     * This is used to determine whether the annotation requires it
 303  
     * and its children to be written as a CDATA block. This is done
 304  
     * when a primitive or other such element requires a text value
 305  
     * and that value needs to be encapsulated within a CDATA block.
 306  
     * 
 307  
     * @return this returns true if the element requires CDATA
 308  
     */
 309  
    public boolean isData() {
 310  0
       return label.isData();
 311  
    }
 312  
    
 313  
    /**
 314  
     * This is used to determine whether the label represents an
 315  
     * inline XML entity. The <code>ElementList</code> annotation
 316  
     * and the <code>Text</code> annotation represent inline 
 317  
     * items. This means that they contain no containing element
 318  
     * and so can not specify overrides or special attributes.
 319  
     * 
 320  
     * @return this returns true if the annotation is inline
 321  
     */
 322  
    public boolean isInline() {
 323  249740
       return label.isInline();
 324  
    }
 325  
    
 326  
    /**
 327  
     * This method is used to determine if the label represents an
 328  
     * attribute. This is used to style the name so that elements
 329  
     * are styled as elements and attributes are styled as required.
 330  
     * 
 331  
     * @return this is used to determine if this is an attribute
 332  
     */
 333  
    public boolean isAttribute() {
 334  0
       return label.isAttribute();
 335  
    }
 336  
    
 337  
    /**
 338  
     * This is used to determine if the label is a collection. If the
 339  
     * label represents a collection then any original assignment to
 340  
     * the field or method can be written to without the need to 
 341  
     * create a new collection. This allows obscure collections to be
 342  
     * used and also allows initial entries to be maintained.
 343  
     * 
 344  
     * @return true if the label represents a collection value
 345  
     */
 346  
    public boolean isCollection() {
 347  249682
       return label.isCollection();
 348  
    }
 349  
    
 350  
    /**
 351  
     * Determines whether the XML attribute or element is required. 
 352  
     * This ensures that if an XML element is missing from a document
 353  
     * that deserialization can continue. Also, in the process of
 354  
     * serialization, if a value is null it does not need to be 
 355  
     * written to the resulting XML document.
 356  
     * 
 357  
     * @return true if the label represents a some required data
 358  
     */
 359  
    public boolean isRequired() {
 360  0
       return label.isRequired();
 361  
    }
 362  
    
 363  
    /**
 364  
     * This is used to determine if the label represents text. If
 365  
     * a label represents text it typically does not have a name,
 366  
     * instead the empty string represents the name. Also text
 367  
     * labels can not exist with other text labels, or elements.
 368  
     * 
 369  
     * @return this returns true if this label represents text
 370  
     */
 371  
    public boolean isText() {
 372  0
       return label.isText();
 373  
    }
 374  
    
 375  
    /**
 376  
     * This is used to determine if an annotated list is a text 
 377  
     * list. A text list is a list of elements that also accepts
 378  
     * free text. Typically this will be an element list union that
 379  
     * will allow unstructured XML such as XHTML to be parsed.
 380  
     * 
 381  
     * @return returns true if the label represents a text list
 382  
     */
 383  
    public boolean isTextList() {
 384  0
       return label.isTextList();
 385  
    }
 386  
    
 387  
    /**
 388  
     * This is used to determine if this label is a union. If this
 389  
     * is true then this label represents a number of labels and
 390  
     * is simply a wrapper for these labels. 
 391  
     * 
 392  
     * @return this returns true if the label represents a union
 393  
     */
 394  
    public boolean isUnion() {
 395  0
       return label.isUnion();
 396  
    }
 397  
    
 398  
    /**
 399  
     * This is used to describe the annotation and method or field
 400  
     * that this label represents. This is used to provide error
 401  
     * messages that can be used to debug issues that occur when
 402  
     * processing a method. This should provide enough information
 403  
     * such that the problem can be isolated correctly. 
 404  
     * 
 405  
     * @return this returns a string representation of the label
 406  
     */
 407  
    public String toString() {
 408  0
       return label.toString();
 409  
    }
 410  
    
 411  
    /**
 412  
     * The <code>Adapter</code> object is used to call the repeater
 413  
     * with the original deserialized object. Using this object the
 414  
     * converter interface can be used to perform repeat reads for
 415  
     * the object. This must be given a <code>Repeater</code> in 
 416  
     * order to invoke the repeat read method.
 417  
     * 
 418  
     * @author Niall Gallagher
 419  
     */
 420  
    private static class Adapter implements Repeater {
 421  
       
 422  
       /**
 423  
        * This is the converter object used to perform a repeat read.
 424  
        */
 425  
       private final Converter reader;
 426  
       
 427  
       /**
 428  
        * This is the originally deserialized object value to use.
 429  
        */
 430  
       private final Object value;
 431  
       
 432  
       /**
 433  
        * This contains the details for the annotated field or method.
 434  
        */
 435  
       private final Label label;
 436  
       
 437  
       /**
 438  
        * Constructor for the <code>Adapter</code> object. This will
 439  
        * create an adapter between the converter an repeater such
 440  
        * that the reads will read from the XML to the original.
 441  
        * 
 442  
        * @param reader this is the converter object to be used      
 443  
        * @param value this is the originally deserialized object
 444  
        */
 445  1156
       public Adapter(Converter reader, Label label, Object value) {
 446  1156
          this.reader = reader;
 447  1156
          this.value = value;
 448  1156
          this.label = label;
 449  1156
       }
 450  
       
 451  
       /**
 452  
        * This <code>read</code> method will perform a read using the
 453  
        * provided object with the repeater. Reading with this method
 454  
        * ensures that any additional XML elements within the source
 455  
        * will be added to the value.
 456  
        * 
 457  
        *  @param node this is the node that contains the extra data
 458  
        *  
 459  
        *  @return this will return the original deserialized object
 460  
        */
 461  
       public Object read(InputNode node)throws Exception {
 462  1
          return read(node, value);
 463  
       }
 464  
       
 465  
       /**
 466  
        * This <code>read</code> method will perform a read using the
 467  
        * provided object with the repeater. Reading with this method
 468  
        * ensures that any additional XML elements within the source
 469  
        * will be added to the value.
 470  
        * 
 471  
        *  @param node this is the node that contains the extra data
 472  
        *  
 473  
        *  @return this will return the original deserialized object
 474  
        */
 475  
       public Object read(InputNode node, Object value) throws Exception {
 476  1118
          Position line = node.getPosition();
 477  1118
          String name = node.getName();         
 478  
          
 479  1118
          if(reader instanceof Repeater) {
 480  1117
             Repeater repeat = (Repeater) reader;
 481  
             
 482  1117
             return repeat.read(node, value);
 483  
          }
 484  1
          throw new PersistenceException("Element '%s' is already used with %s at %s", name, label, line);
 485  
       }
 486  
       
 487  
       /**
 488  
        * This <code>read</code> method will perform a read using the
 489  
        * provided object with the repeater. Reading with this method
 490  
        * ensures that any additional XML elements within the source
 491  
        * will be added to the value.
 492  
        * 
 493  
        *  @param node this is the node that contains the extra data
 494  
        *  
 495  
        *  @return this will return the original deserialized object
 496  
        */
 497  
       public boolean validate(InputNode node) throws Exception {
 498  38
          Position line = node.getPosition();
 499  38
          String name = node.getName();         
 500  
          
 501  38
          if(reader instanceof Repeater) {
 502  37
             Repeater repeat = (Repeater) reader;
 503  
             
 504  37
             return repeat.validate(node);
 505  
          }
 506  1
          throw new PersistenceException("Element '%s' declared twice at %s", name, line);
 507  
       }
 508  
       
 509  
       /**
 510  
        * This <code>write</code> method acts like any other write
 511  
        * in that it passes on the node and source object to write.
 512  
        * Typically this will not be used as the repeater object is
 513  
        * used for repeat reads of scattered XML elements.
 514  
        * 
 515  
        * @param node this is the node to write the data to
 516  
        * @param value this is the source object to be written
 517  
        */
 518  
       public void write(OutputNode node, Object value) throws Exception {
 519  0
          write(node, value);
 520  0
       }
 521  
    }
 522  
 }