Coverage Report - org.simpleframework.xml.core.MethodContact
 
Classes in this File Line Coverage Branch Coverage Complexity
MethodContact
94%
33/35
90%
9/10
1.467
 
 1  
 /*
 2  
  * MethodContact.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.Method;
 23  
 
 24  
 /**
 25  
  * The <code>MethodContact</code> object is acts as a contact that
 26  
  * can set and get data to and from an object using methods. This 
 27  
  * requires a get method and a set method that share the same class
 28  
  * type for the return and parameter respectively.
 29  
  *
 30  
  * @author Niall Gallagher
 31  
  *
 32  
  * @see org.simpleframework.xml.core.MethodScanner
 33  
  */ 
 34  
 class MethodContact implements Contact {
 35  
    
 36  
    /**
 37  
     * This is the label that marks both the set and get methods.
 38  
     */         
 39  
    private Annotation label;
 40  
    
 41  
    /**
 42  
     * This is the set method which is used to set the value.
 43  
     */ 
 44  
    private MethodPart set;
 45  
    
 46  
    /**
 47  
     * This is the get method which is used to get the value.
 48  
     */
 49  
    private MethodPart get;
 50  
 
 51  
    /**
 52  
     * This is the dependent types as taken from the get method.
 53  
     */
 54  
    private Class[] items;
 55  
    
 56  
    /**
 57  
     * This represents the declaring class for this method.
 58  
     */
 59  
    private Class owner;
 60  
    
 61  
    /**
 62  
     * This is the dependent type as taken from the get method.
 63  
     */
 64  
    private Class item;
 65  
    
 66  
    /**
 67  
     * This is the type associated with this point of contact.
 68  
     */ 
 69  
    private Class type; 
 70  
    
 71  
    /**
 72  
     * This represents the name of the method for this contact.
 73  
     */
 74  
    private String name;
 75  
    
 76  
    /**
 77  
     * Constructor for the <code>MethodContact</code> object. This is
 78  
     * used to compose a point of contact that makes use of a get and
 79  
     * set method on a class. The specified methods will be invoked
 80  
     * during the serialization process to get and set values.
 81  
     *
 82  
     * @param get this forms the get method for the object
 83  
     */ 
 84  
    public MethodContact(MethodPart get) {
 85  40
       this(get, null);
 86  40
    }
 87  
    
 88  
    /**
 89  
     * Constructor for the <code>MethodContact</code> object. This is
 90  
     * used to compose a point of contact that makes use of a get and
 91  
     * set method on a class. The specified methods will be invoked
 92  
     * during the serialization process to get and set values.
 93  
     *
 94  
     * @param get this forms the get method for the object
 95  
     * @param set this forms the get method for the object 
 96  
     */ 
 97  323
    public MethodContact(MethodPart get, MethodPart set) {
 98  323
       this.owner = get.getDeclaringClass();
 99  323
       this.label = get.getAnnotation();   
 100  323
       this.items = get.getDependents();
 101  323
       this.item = get.getDependent();
 102  323
       this.type = get.getType();   
 103  323
       this.name = get.getName();
 104  323
       this.set = set;
 105  323
       this.get = get;
 106  323
    }  
 107  
    
 108  
    /**
 109  
     * This is used to determine if the annotated contact is for a
 110  
     * read only variable. A read only variable is a field that
 111  
     * can be set from within the constructor such as a blank final
 112  
     * variable. It can also be a method with no set counterpart.
 113  
     * 
 114  
     * @return this returns true if the contact is a constant one
 115  
     */
 116  
    public boolean isReadOnly() {
 117  383
       return set == null;
 118  
    }
 119  
    
 120  
    /**
 121  
     * This returns the get part of the method. Acquiring separate
 122  
     * parts of the method ensures that method parts can be inherited
 123  
     * easily between types as overriding either part of a property.
 124  
     * 
 125  
     * @return this returns the get part of the method contact
 126  
     */
 127  
    public MethodPart getRead() {
 128  107
       return get;
 129  
    }
 130  
    
 131  
    /**
 132  
     * This returns the set part of the method. Acquiring separate
 133  
     * parts of the method ensures that method parts can be inherited
 134  
     * easily between types as overriding either part of a property.
 135  
     * 
 136  
     * @return this returns the set part of the method contact
 137  
     */
 138  
    public MethodPart getWrite() {
 139  107
       return set;
 140  
    }
 141  
    
 142  
    /**
 143  
     * This is the annotation associated with the point of contact.
 144  
     * This will be an XML annotation that describes how the contact
 145  
     * should be serialized and deserialized from the object.
 146  
     *
 147  
     * @return this provides the annotation associated with this
 148  
     */
 149  
    public Annotation getAnnotation() {
 150  619
       return label;
 151  
    }
 152  
    
 153  
    /**
 154  
     * This is the annotation associated with the point of contact.
 155  
     * This will be an XML annotation that describes how the contact
 156  
     * should be serialized and deserialized from the object.
 157  
     * 
 158  
     * @param type this is the type of the annotation to acquire
 159  
     *
 160  
     * @return this provides the annotation associated with this
 161  
     */
 162  
    public <T extends Annotation> T getAnnotation(Class<T> type) {
 163  744
       T result = get.getAnnotation(type);
 164  
       
 165  744
       if(type == label.annotationType()) {
 166  17
          return (T) label;
 167  
       }
 168  727
       if(result == null && set != null) {        
 169  486
          return set.getAnnotation(type);
 170  
       }
 171  241
       return result;
 172  
    }
 173  
 
 174  
    /**
 175  
     * This will provide the contact type. The contact type is the
 176  
     * class that is to be set and get on the object. This represents
 177  
     * the return type for the get and the parameter for the set.
 178  
     *
 179  
     * @return this returns the type that this contact represents
 180  
     */
 181  
    public Class getType() {
 182  2634
       return type;
 183  
    }
 184  
    
 185  
    /**
 186  
     * This provides the dependent class for the contact. This will
 187  
     * actually represent a generic type for the actual type. For
 188  
     * contacts that use a <code>Collection</code> type this will
 189  
     * be the generic type parameter for that collection.
 190  
     * 
 191  
     * @return this returns the dependent type for the contact
 192  
     */
 193  
    public Class getDependent() {
 194  12
       return item;
 195  
    }
 196  
    
 197  
    /**
 198  
     * This provides the dependent classes for the contact. This will
 199  
     * typically represent a generic types for the actual type. For
 200  
     * contacts that use a <code>Map</code> type this will be the 
 201  
     * generic type parameter for that map type declaration.
 202  
     * 
 203  
     * @return this returns the dependent type for the contact
 204  
     */
 205  
    public Class[] getDependents() {
 206  0
       return items;
 207  
    } 
 208  
    
 209  
    /**
 210  
     * This is the class that declares the contact. The declaring
 211  
     * class is where the method represented has been defined. This 
 212  
     * will typically be a class rather than an interface.
 213  
     * 
 214  
     * @return this returns the class the contact is declared within
 215  
     */
 216  
    public Class getDeclaringClass() {
 217  174
       return owner;
 218  
    }
 219  
    
 220  
    /**
 221  
     * This is used to acquire the name of the method. This returns
 222  
     * the name of the method without the get, set or is prefix that
 223  
     * represents the Java Bean method type. Also this decapitalizes
 224  
     * the resulting name. The result is used to represent the XML
 225  
     * attribute of element within the class schema represented.
 226  
     * 
 227  
     *  @return this returns the name of the method represented
 228  
     */
 229  
    public String getName() {
 230  402
       return name;
 231  
    }   
 232  
 
 233  
    /**
 234  
     * This is used to set the specified value on the provided object.
 235  
     * The value provided must be an instance of the contact class so
 236  
     * that it can be set without a runtime class compatibility error.
 237  
     *
 238  
     * @param source this is the object to set the value on
 239  
     * @param value this is the value that is to be set on the object
 240  
     */    
 241  
    public void set(Object source, Object value) throws Exception{
 242  175
       Method method = get.getMethod();
 243  175
       Class type = method.getDeclaringClass();
 244  
       
 245  175
       if(set == null) {
 246  0
          throw new MethodException("Property '%s' is read only in %s", name, type);
 247  
       }
 248  175
       set.getMethod().invoke(source, value);
 249  175
    }
 250  
    
 251  
    /**
 252  
     * This is used to get the specified value on the provided object.
 253  
     * The value returned from this method will be an instance of the
 254  
     * contact class type. If the returned object is of a different
 255  
     * type then the serialization process will fail.
 256  
     *
 257  
     * @param source this is the object to acquire the value from
 258  
     *
 259  
     * @return this is the value that is acquired from the object
 260  
     */ 
 261  
    public Object get(Object source) throws Exception {
 262  383
       return get.getMethod().invoke(source);
 263  
    }
 264  
    
 265  
    /**
 266  
     * This is used to describe the contact as it exists within the
 267  
     * owning class. It is used to provide error messages that can
 268  
     * be used to debug issues that occur when processing a contact.
 269  
     * The string provided contains both the set and get methods.
 270  
     * 
 271  
     * @return this returns a string representation of the contact
 272  
     */
 273  
    public String toString() {
 274  9
       return String.format("method '%s'", name);
 275  
    }
 276  
 }