Coverage Report - org.simpleframework.xml.core.FieldContact
 
Classes in this File Line Coverage Branch Coverage Complexity
FieldContact
100%
30/30
100%
12/12
1.4
 
 1  
 /*
 2  
  * FieldContact.java April 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  
 import java.lang.reflect.Field;
 23  
 import java.lang.reflect.Modifier;
 24  
 
 25  
 import org.simpleframework.xml.util.Cache;
 26  
 import org.simpleframework.xml.util.ConcurrentCache;
 27  
 
 28  
 /**
 29  
  * The <code>FieldContact</code> object is used to act as a contact
 30  
  * for a field within an object. This allows a value to be set on an
 31  
  * object field during deserialization and acquired from the same
 32  
  * field during serialization.
 33  
  *
 34  
  * @author Niall Gallagher
 35  
  *
 36  
  * @see org.simpleframework.xml.core.FieldScanner
 37  
  */ 
 38  
 class FieldContact implements Contact {
 39  
    
 40  
    /**
 41  
     * This cache contains the annotations present on the field.
 42  
     */
 43  
    private final Cache<Annotation> cache; 
 44  
    
 45  
    /**
 46  
     * This is the list of annotations associated with the field.
 47  
     */
 48  
    private final Annotation[] list;
 49  
    
 50  
    /**
 51  
     * This is the label that marks the field within the object.
 52  
     */           
 53  
    private final Annotation label;
 54  
    
 55  
    /**
 56  
     * This represents the field within the schema class object.
 57  
     */ 
 58  
    private final Field field;
 59  
    
 60  
    /**
 61  
     * This is the name for this contact as taken from the field.
 62  
     */
 63  
    private final String name;
 64  
    
 65  
    /**
 66  
     * This is the modifiers for the field that this represents.
 67  
     */
 68  
    private final int modifier;
 69  
    
 70  
    /**
 71  
     * Constructor for the <code>FieldContact</code> object. This is 
 72  
     * used as a point of contact for a field within a schema class.
 73  
     * Values can be read and written directly to the field with this.
 74  
     *
 75  
     * @param field this is the field that is the point of contact
 76  
     * @param label this is the annotation that is used by the field
 77  
     * @param list this is the list of annotations on the field
 78  
     */ 
 79  3538
    public FieldContact(Field field, Annotation label, Annotation[] list) {
 80  3538
       this.cache = new ConcurrentCache<Annotation>();
 81  3538
       this.modifier = field.getModifiers();
 82  3538
       this.name = field.getName();
 83  3538
       this.label = label;
 84  3538
       this.field = field;
 85  3538
       this.list = list;
 86  3538
    } 
 87  
    
 88  
    /**
 89  
     * This is used to determine if the annotated contact is for a
 90  
     * read only variable. A read only variable is a field that
 91  
     * can be set from within the constructor such as a blank final
 92  
     * variable. It can also be a method with no set counterpart.
 93  
     * 
 94  
     * @return this returns true if the contact is a constant one
 95  
     */
 96  
    public boolean isReadOnly() {
 97  7880
       return !isStatic() && isFinal();
 98  
    }
 99  
    
 100  
    /**
 101  
     * This is used to determine if the annotated contact is for a
 102  
     * static field or method. A static field or method is one that
 103  
     * contains the "static" keyword. Any static final fields will
 104  
     * be read only and does not require any matching annotation.
 105  
     * 
 106  
     * @return this returns true if the contact is a static one
 107  
     */
 108  
    public boolean isStatic() {
 109  7880
       return Modifier.isStatic(modifier);
 110  
    }
 111  
    
 112  
    /**
 113  
     * This is used to identify annotated methods are fields that
 114  
     * can not be modified. Such field will require that there is 
 115  
     * a constructor that can have the value injected in to it.
 116  
     * 
 117  
     * @return this returns true if the field or method is final
 118  
     */
 119  
    public boolean isFinal() {
 120  2074366
       return Modifier.isFinal(modifier); 
 121  
    }
 122  
 
 123  
    /**
 124  
     * This will provide the contact type. The contact type is the
 125  
     * class that is to be set and get on the object. This represents
 126  
     * the return type for the get and the parameter for the set.
 127  
     *
 128  
     * @return this returns the type that this contact represents
 129  
     */
 130  
    public Class getType() {
 131  10104992
       return field.getType();
 132  
    }
 133  
    
 134  
    /**
 135  
     * This provides the dependent class for the contact. This will
 136  
     * actually represent a generic type for the actual type. For
 137  
     * contacts that use a <code>Collection</code> type this will
 138  
     * be the generic type parameter for that collection.
 139  
     * 
 140  
     * @return this returns the dependent type for the contact
 141  
     */
 142  
    public Class getDependent() {
 143  209
       return Reflector.getDependent(field);
 144  
    }
 145  
    
 146  
    /**
 147  
     * This provides the dependent classes for the contact. This will
 148  
     * typically represent a generic types for the actual type. For
 149  
     * contacts that use a <code>Map</code> type this will be the 
 150  
     * generic type parameter for that map type declaration.
 151  
     * 
 152  
     * @return this returns the dependent type for the contact
 153  
     */
 154  
    public Class[] getDependents() {
 155  747
       return Reflector.getDependents(field);
 156  
    }
 157  
    
 158  
    /**
 159  
     * This is the class that declares the contact. The declaring
 160  
     * class is where the field represented been defined. This will
 161  
     * typically be a class rather than an interface.
 162  
     * 
 163  
     * @return this returns the class the contact is declared within
 164  
     */
 165  
    public Class getDeclaringClass() {
 166  3463
       return field.getDeclaringClass();
 167  
    }
 168  
    
 169  
    /**
 170  
     * This is used to acquire the name of the field. This will return
 171  
     * the name of the field which can then be used to determine the 
 172  
     * XML attribute or element the contact represents. This ensures
 173  
     * that the name provided string is internalized for performance.  
 174  
     * 
 175  
     *  @return this returns the name of the field represented
 176  
     */
 177  
    public String getName() {
 178  7534
       return name;
 179  
    }
 180  
 
 181  
    /**
 182  
     * This is the annotation associated with the point of contact.
 183  
     * This will be an XML annotation that describes how the contact
 184  
     * should be serialized and deserialized from the object.
 185  
     *
 186  
     * @return this provides the annotation associated with this
 187  
     */
 188  
    public Annotation getAnnotation() {
 189  12359
       return label;
 190  
    }
 191  
    
 192  
    /**
 193  
     * This is the annotation associated with the point of contact.
 194  
     * This will be an XML annotation that describes how the contact
 195  
     * should be serialized and deserialized from the object.
 196  
     * 
 197  
     * @param type this is the type of the annotation to acquire
 198  
     *
 199  
     * @return this provides the annotation associated with this
 200  
     */
 201  
    public <T extends Annotation> T getAnnotation(Class<T> type) {
 202  16818
       if(type == label.annotationType()) {
 203  59
          return (T) label;
 204  
       }
 205  16759
       return getCache(type);
 206  
    }
 207  
    
 208  
    /**
 209  
     * This is the annotation associated with the point of contact.
 210  
     * This will be an XML annotation that describes how the contact
 211  
     * should be serialized and deserialized from the object.
 212  
     * 
 213  
     * @param type this is the type of the annotation to acquire
 214  
     *
 215  
     * @return this provides the annotation associated with this
 216  
     */
 217  
    private <T extends Annotation> T getCache(Class<T> type) {
 218  16759
       if(cache.isEmpty()) {
 219  7170
          for(Annotation entry : list) {
 220  3515
             Class key = entry.annotationType();
 221  3515
             cache.cache(key, entry);
 222  
          }
 223  
       }
 224  16759
       return (T)cache.fetch(type);
 225  
    }
 226  
 
 227  
    /**
 228  
     * This is used to set the specified value on the provided object.
 229  
     * The value provided must be an instance of the contact class so
 230  
     * that it can be set without a runtime class compatibility error.
 231  
     *
 232  
     * @param source this is the object to set the value on
 233  
     * @param value this is the value that is to be set on the object
 234  
     */ 
 235  
    public void set(Object source, Object value) throws Exception {
 236  2066510
       if(!isFinal()) {
 237  2066507
          field.set(source, value);
 238  
       }
 239  2066510
    }
 240  
 
 241  
    /**
 242  
     * This is used to get the specified value on the provided object.
 243  
     * The value returned from this method will be an instance of the
 244  
     * contact class type. If the returned object is of a different
 245  
     * type then the serialization process will fail.
 246  
     *
 247  
     * @param source this is the object to acquire the value from
 248  
     *
 249  
     * @return this is the value that is acquired from the object
 250  
     */
 251  
    public Object get(Object source) throws Exception {
 252  700713
       return field.get(source);
 253  
    }
 254  
    
 255  
    /**
 256  
     * This is used to describe the contact as it exists within the
 257  
     * owning class. It is used to provide error messages that can
 258  
     * be used to debug issues that occur when processing a contact.
 259  
     * The string provided is the generic field string.
 260  
     * 
 261  
     * @return this returns a string representation of the contact
 262  
     */
 263  
    public String toString() {
 264  147
       return String.format("field '%s' %s", getName(), field.toString());
 265  
    }
 266  
 }