Coverage Report - org.simpleframework.xml.core.DetailScanner
 
Classes in this File Line Coverage Branch Coverage Complexity
DetailScanner
98%
83/84
81%
31/38
1.679
 
 1  
 /*
 2  
  * DetailScanner.java July 2012
 3  
  *
 4  
  * Copyright (C) 2012, 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  
 import java.lang.reflect.Constructor;
 23  
 import java.lang.reflect.Method;
 24  
 import java.lang.reflect.Field;
 25  
 import java.lang.reflect.Modifier;
 26  
 import java.util.LinkedList;
 27  
 import java.util.List;
 28  
 
 29  
 import org.simpleframework.xml.Default;
 30  
 import org.simpleframework.xml.DefaultType;
 31  
 import org.simpleframework.xml.Namespace;
 32  
 import org.simpleframework.xml.NamespaceList;
 33  
 import org.simpleframework.xml.Order;
 34  
 import org.simpleframework.xml.Root;
 35  
 
 36  
 /**
 37  
  * The <code>DetailScanner</code> is used to scan a class for methods
 38  
  * and fields as well as annotations. Scanning a type in this way 
 39  
  * ensures that all its details can be extracted and cached in one
 40  
  * place. This greatly improves performance on platforms that do not
 41  
  * cache reflection well, like Android. 
 42  
  * 
 43  
  * @author Niall Gallagher
 44  
  */
 45  
 class DetailScanner implements Detail {
 46  
    
 47  
    /**
 48  
     * This contains a list of methods that are extracted for this.
 49  
     */
 50  
    private List<MethodDetail> methods;
 51  
    
 52  
    /**
 53  
     * This contains a list of fields that are extracted for this.
 54  
     */
 55  
    private List<FieldDetail> fields;
 56  
    
 57  
    /**
 58  
     * This represents the namespace list declared on the type.
 59  
     */
 60  
    private NamespaceList declaration;
 61  
    
 62  
    /**
 63  
     * This represents the namespace annotation declared on the type.
 64  
     */
 65  
    private Namespace namespace;
 66  
    
 67  
    /**
 68  
     * This represents all the annotations declared for the type.
 69  
     */
 70  
    private Annotation[] labels;
 71  
    
 72  
    /**
 73  
     * This represents the default access type declared or the type.
 74  
     */
 75  
    private DefaultType access;
 76  
    
 77  
    /**
 78  
     * This is the order annotation that is declared for the type.
 79  
     */
 80  
    private Order order;
 81  
    
 82  
    /**
 83  
     * This is the root annotation that is declared for the type.
 84  
     */
 85  
    private Root root;
 86  
    
 87  
    /**
 88  
     * This is the type that is represented by this instance.
 89  
     */
 90  
    private Class type;
 91  
    
 92  
    /**
 93  
     * This represents the name of the type used for XML elements.
 94  
     */
 95  
    private String name;
 96  
    
 97  
    /**
 98  
     * This is used to determine if the default type is required.
 99  
     */
 100  
    private boolean required;
 101  
    
 102  
    /**
 103  
     * This is used to determine if strict XML parsing is done.
 104  
     */
 105  
    private boolean strict;
 106  
    
 107  
    /**
 108  
     * Constructor for the <code>DetailScanner</code> object. This is
 109  
     * used to create a detail object from a type. All of the methods
 110  
     * fields and annotations are extracted so that they can be used
 111  
     * many times over without the need to process them again.
 112  
     * 
 113  
     * @param type this is the type to scan for various details
 114  
     */
 115  4332
    public DetailScanner(Class type) {
 116  4332
       this.methods = new LinkedList<MethodDetail>();
 117  4332
       this.fields = new LinkedList<FieldDetail>();
 118  4332
       this.labels = type.getDeclaredAnnotations();
 119  4332
       this.strict = true;
 120  4332
       this.type = type;
 121  4332
       this.scan(type);
 122  4332
    }
 123  
 
 124  
    /**
 125  
     * This is used to determine if the generated annotations are
 126  
     * required or not. By default generated parameters are required.
 127  
     * Setting this to false means that null values are accepted
 128  
     * by all defaulted fields or methods depending on the type.
 129  
     * 
 130  
     * @return this is used to determine if defaults are required
 131  
     */
 132  
    public boolean isRequired() {
 133  6818
       return required;
 134  
    }
 135  
      
 136  
    /**
 137  
     * This method is used to determine whether strict mappings are
 138  
     * required. Strict mapping means that all labels in the class
 139  
     * schema must match the XML elements and attributes in the
 140  
     * source XML document. When strict mapping is disabled, then
 141  
     * XML elements and attributes that do not exist in the schema
 142  
     * class will be ignored without breaking the parser.
 143  
     *
 144  
     * @return true if strict parsing is enabled, false otherwise
 145  
     */ 
 146  
    public boolean isStrict() {
 147  24
       return strict;
 148  
    }
 149  
    
 150  
    /**
 151  
     * This is used to determine whether this detail represents a
 152  
     * primitive type. A primitive type is any type that does not
 153  
     * extend <code>Object</code>, examples are int, long and double.
 154  
     * 
 155  
     * @return this returns true if no XML annotations were found
 156  
     */
 157  
    public boolean isPrimitive() {
 158  3660
       return type.isPrimitive();
 159  
    }
 160  
    
 161  
    /**
 162  
     * This is used to determine if the class is an inner class. If
 163  
     * the class is a inner class and not static then this returns
 164  
     * false. Only static inner classes can be instantiated using
 165  
     * reflection as they do not require a "this" argument.
 166  
     * 
 167  
     * @return this returns true if the class is a static inner
 168  
     */
 169  
    public boolean isInstantiable() {
 170  2389
       int modifiers = type.getModifiers();
 171  
        
 172  2389
       if(Modifier.isStatic(modifiers)) {
 173  1615
          return true;
 174  
       }
 175  774
       return !type.isMemberClass();       
 176  
    }
 177  
    
 178  
    /**
 179  
     * This returns the <code>Root</code> annotation for the class.
 180  
     * The root determines the type of deserialization that is to
 181  
     * be performed and also contains the name of the root element. 
 182  
     * 
 183  
     * @return this returns the name of the object being scanned
 184  
     */
 185  
    public Root getRoot() {
 186  3338
       return root;
 187  
    }
 188  
    
 189  
    /**
 190  
     * This returns the name of the class processed by this scanner.
 191  
     * The name is either the name as specified in the last found
 192  
     * <code>Root</code> annotation, or if a name was not specified
 193  
     * within the discovered root then the Java Bean class name of
 194  
     * the last class annotated with a root annotation.
 195  
     * 
 196  
     * @return this returns the name of the object being scanned
 197  
     */
 198  
    public String getName() {
 199  461856
       return name;
 200  
    }
 201  
    
 202  
    /**
 203  
     * This returns the type represented by this detail. The type is
 204  
     * the class that has been scanned for annotations, methods and
 205  
     * fields. All super types of this are represented in the detail.
 206  
     * 
 207  
     * @return the type that this detail object represents
 208  
     */
 209  
    public Class getType() {
 210  948924
       return type;
 211  
    }
 212  
    
 213  
    /**
 214  
     * This returns the order annotation used to determine the order
 215  
     * of serialization of attributes and elements. The order is a
 216  
     * class level annotation that can be used only once per class
 217  
     * XML schema. If none exists then this will return null.
 218  
     *  of the class processed by this scanner.
 219  
     * 
 220  
     * @return this returns the name of the object being scanned
 221  
     */
 222  
    public Order getOrder() {
 223  3389
       return order;
 224  
    }
 225  
    
 226  
    /**
 227  
     * This returns the <code>Default</code> annotation access type
 228  
     * that has been specified by this. If no default annotation has
 229  
     * been declared on the type then this will return null.
 230  
     * 
 231  
     * @return this returns the default access type for this type
 232  
     */
 233  
    public DefaultType getAccess() {
 234  6802
       return access;
 235  
    }
 236  
    
 237  
    /**
 238  
     * This returns the <code>Namespace</code> annotation that was
 239  
     * declared on the type. If no annotation has been declared on the
 240  
     * type this will return null as not belonging to any.
 241  
     * 
 242  
     * @return this returns the namespace this type belongs to, if any
 243  
     */
 244  
    public Namespace getNamespace() {
 245  5773
       return namespace;
 246  
    }
 247  
    
 248  
    /**
 249  
     * This returns the <code>NamespaceList</code> annotation that was
 250  
     * declared on the type. A list of namespaces are used to simply 
 251  
     * declare the namespaces without specifically making the type
 252  
     * belong to any of the declared namespaces.
 253  
     * 
 254  
     * @return this returns the namespace declarations, if any
 255  
     */
 256  
    public NamespaceList getNamespaceList() {
 257  3400
       return declaration;
 258  
    }
 259  
    
 260  
    /**
 261  
     * This returns a list of the methods that belong to this type. 
 262  
     * The methods here do not include any methods from the super
 263  
     * types and simply provides a means of caching method data.
 264  
     * 
 265  
     * @return returns the list of methods declared for the type
 266  
     */
 267  
    public List<MethodDetail> getMethods() {
 268  10211
       return methods;
 269  
    }
 270  
    
 271  
    /**
 272  
     * This returns a list of the fields that belong to this type. 
 273  
     * The fields here do not include any fields from the super
 274  
     * types and simply provides a means of caching method data.
 275  
     * 
 276  
     * @return returns the list of fields declared for the type
 277  
     */
 278  
    public List<FieldDetail> getFields() {
 279  6788
       return fields;
 280  
    }
 281  
    
 282  
    /**
 283  
     * This returns the annotations that have been declared for this
 284  
     * type. It is preferable to acquire the declared annotations
 285  
     * from this method as they are cached. Older versions of some
 286  
     * runtime environments, particularly Android, are slow at this.
 287  
     * 
 288  
     * @return this returns the annotations associated with this
 289  
     */
 290  
    public Annotation[] getAnnotations() {
 291  0
       return labels;
 292  
    }
 293  
 
 294  
    /**
 295  
     * This returns the constructors that have been declared for this
 296  
     * type. It is preferable to acquire the declared constructors
 297  
     * from this method as they are cached. Older versions of some
 298  
     * runtime environments, particularly Android, are slow at this.
 299  
     * 
 300  
     * @return this returns the constructors associated with this
 301  
     */
 302  
    public Constructor[] getConstructors() {
 303  2389
       return type.getDeclaredConstructors();
 304  
    }
 305  
    
 306  
    /**
 307  
     * This is used to acquire the super type for the class that is
 308  
     * represented by this detail. If the super type for the class
 309  
     * is <code>Object</code> then this will return null.
 310  
     * 
 311  
     * @return returns the super type for this class or null
 312  
     */
 313  
    public Class getSuper() {
 314  10191
       Class base = type.getSuperclass();
 315  
       
 316  10191
       if(base == Object.class) {
 317  6366
          return null;
 318  
       }
 319  3825
       return base;
 320  
    }
 321  
    
 322  
    /**
 323  
     * This method is used to scan the type for all of its annotations
 324  
     * as well as its methods and fields. Everything that is scanned 
 325  
     * is cached within the instance to ensure that it can be reused
 326  
     * when ever an object of this type is to be scanned.
 327  
     * 
 328  
     * @param type this is the type to scan for details
 329  
     */
 330  
    private void scan(Class type) {
 331  4332
       methods(type);
 332  4332
       fields(type);
 333  4332
       extract(type);
 334  4332
    }
 335  
    
 336  
    /**
 337  
     * This method is used to extract the annotations associated with
 338  
     * the type. Annotations extracted include the <code>Root</code> 
 339  
     * annotation and the <code>Namespace</code> annotation as well as
 340  
     * other annotations that are used to describe the type.
 341  
     * 
 342  
     * @param type this is the type to extract the annotations from
 343  
     */
 344  
    private void extract(Class type) {
 345  6016
       for(Annotation label : labels) {
 346  1684
          if(label instanceof Namespace) {
 347  50
             namespace(label);
 348  
          }
 349  1684
          if(label instanceof NamespaceList) {
 350  22
             scope(label);
 351  
          }
 352  1684
          if(label instanceof Root) {
 353  1405
             root(label);
 354  
          }
 355  1684
          if(label instanceof Order) {
 356  30
             order(label);
 357  
          }
 358  1684
          if(label instanceof Default) {
 359  168
             access(label);
 360  
          }
 361  
       }
 362  4332
    }
 363  
    
 364  
    /**
 365  
     * This is used to scan the type for its declared methods. Scanning
 366  
     * of the methods in this way allows the detail to prepare a cache
 367  
     * that can be used to acquire the methods and the associated
 368  
     * annotations. This improves performance on some platforms.
 369  
     * 
 370  
     * @param type this is the type to scan for declared annotations
 371  
     */
 372  
    private void methods(Class type) {
 373  4332
       Method[] list = type.getDeclaredMethods();
 374  
       
 375  80297
       for(Method method : list) {
 376  75965
          MethodDetail detail = new MethodDetail(method);
 377  75965
          methods.add(detail);
 378  
       }
 379  4332
    }
 380  
    
 381  
    /**
 382  
     * This is used to scan the type for its declared fields. Scanning
 383  
     * of the fields in this way allows the detail to prepare a cache
 384  
     * that can be used to acquire the fields and the associated
 385  
     * annotations. This improves performance on some platforms.
 386  
     * 
 387  
     * @param type this is the type to scan for declared annotations
 388  
     */
 389  
    private void fields(Class type) {
 390  4332
       Field[] list = type.getDeclaredFields();
 391  
       
 392  18240
       for(Field field : list) {
 393  13908
          FieldDetail detail = new FieldDetail(field);
 394  13908
          fields.add(detail);
 395  
       }
 396  4332
    }
 397  
 
 398  
    /**
 399  
     * This is used to set the optional <code>Root</code> annotation for
 400  
     * the class. The root can only be set once, so if a super type also
 401  
     * has a root annotation define it must be ignored. 
 402  
     *
 403  
     * @param label this is the label used to define the root
 404  
     */    
 405  
    private void root(Annotation label) {
 406  1405
       if(label != null) {
 407  1405
          Root value = (Root)label;
 408  1405
          String real = type.getSimpleName();
 409  1405
          String text = real;
 410  
 
 411  1405
          if(value != null) {
 412  1405
             text = value.name();
 413  
 
 414  1405
             if(isEmpty(text)) {
 415  863
                text = Reflector.getName(real);
 416  
             }      
 417  1405
             strict = value.strict();
 418  1405
             root = value;
 419  1405
             name = text;  
 420  
          }
 421  
       }
 422  1405
    }
 423  
    
 424  
    /**
 425  
     * This method is used to determine if a root annotation value is
 426  
     * an empty value. Rather than determining if a string is empty
 427  
     * be comparing it to an empty string this method allows for the
 428  
     * value an empty string represents to be changed in future.
 429  
     * 
 430  
     * @param value this is the value to determine if it is empty
 431  
     * 
 432  
     * @return true if the string value specified is an empty value
 433  
     */
 434  
    private boolean isEmpty(String value) {
 435  1405
       return value.length() == 0;
 436  
    }
 437  
    
 438  
    /**
 439  
     * This is used to set the optional <code>Order</code> annotation for
 440  
     * the class. The order can only be set once, so if a super type also
 441  
     * has a order annotation define it must be ignored. 
 442  
     * 
 443  
     * @param label this is the label used to define the order
 444  
     */
 445  
    private void order(Annotation label) {
 446  30
       if(label != null) {
 447  30
          order = (Order)label;
 448  
       }
 449  30
    }
 450  
    
 451  
    /**
 452  
     * This is used to set the optional <code>Default</code> annotation for
 453  
     * the class. The default can only be set once, so if a super type also
 454  
     * has a default annotation define it must be ignored. 
 455  
     * 
 456  
     * @param label this is the label used to define the defaults
 457  
     */
 458  
    private void access(Annotation label) {
 459  168
       if(label != null) {
 460  168
          Default value = (Default)label;
 461  
          
 462  168
          required = value.required();
 463  168
          access = value.value();
 464  
       }
 465  168
    }
 466  
    
 467  
    /**
 468  
     * This is use to scan for <code>Namespace</code> annotations on
 469  
     * the class. Once a namespace has been located then it is used to
 470  
     * populate the internal namespace decorator. This can then be used
 471  
     * to decorate any output node that requires it.
 472  
     * 
 473  
     * @param label the XML annotation to scan for the namespace
 474  
     */
 475  
    private void namespace(Annotation label) {
 476  50
       if(label != null) {
 477  50
          namespace = (Namespace)label;
 478  
       }
 479  50
    }
 480  
    
 481  
    /**
 482  
     * This is use to scan for <code>NamespaceList</code> annotations 
 483  
     * on the class. Once a namespace list has been located then it is 
 484  
     * used to populate the internal namespace decorator. This can then 
 485  
     * be used to decorate any output node that requires it.
 486  
     * 
 487  
     * @param label the XML annotation to scan for namespace lists
 488  
     */
 489  
    private void scope(Annotation label) {
 490  22
       if(label != null) {
 491  22
          declaration = (NamespaceList)label;
 492  
       }
 493  22
    }
 494  
    
 495  
    /**
 496  
     * This is used to return a string representation of the detail. 
 497  
     * The string returned from this is the same that is returned
 498  
     * from the <code>toString</code> of the type represented. 
 499  
     * 
 500  
     * @return this returns the string representation of the type
 501  
     */
 502  
    public String toString() {
 503  10
       return type.toString();
 504  
    }
 505  
 }