Coverage Report - org.simpleframework.xml.core.Factory
 
Classes in this File Line Coverage Branch Coverage Complexity
Factory
88%
39/44
83%
20/24
2.7
 
 1  
 /*
 2  
  * Factory.java July 2006
 3  
  *
 4  
  * Copyright (C) 2006, 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.reflect.Modifier;
 22  
 
 23  
 import org.simpleframework.xml.strategy.Type;
 24  
 import org.simpleframework.xml.strategy.Value;
 25  
 import org.simpleframework.xml.stream.InputNode;
 26  
 import org.simpleframework.xml.stream.OutputNode;
 27  
 import org.simpleframework.xml.stream.Position;
 28  
 
 29  
 /**
 30  
  * The <code>Factory</code> object provides a base class for factories 
 31  
  * used to produce field values from XML elements. The goal of this 
 32  
  * type of factory is to make use of the <code>Strategy</code> object
 33  
  * to determine the type of the field value. The strategy class must be 
 34  
  * assignable to the field class type, that is, it must extend it or
 35  
  * implement it if it represents an interface. If the strategy returns
 36  
  * a null <code>Value</code> then the subclass implementation determines 
 37  
  * the type used to populate the object field value.
 38  
  * 
 39  
  * @author Niall Gallagher
 40  
  */
 41  
 abstract class Factory {
 42  
    
 43  
    /**
 44  
     * This is the context object used for the serialization process.
 45  
     */
 46  
    protected Context context;
 47  
    
 48  
    /**
 49  
     * This is used to translate all of the primitive type strings.
 50  
     */
 51  
    protected Support support;
 52  
    
 53  
    /**
 54  
     * This is the class override to used when instantiating objects.
 55  
     */
 56  
    protected Class override;
 57  
    
 58  
    /**
 59  
     * This is the field type that the class must be assignable to.
 60  
     */
 61  
    protected Type type;  
 62  
 
 63  
    /**
 64  
     * Constructor for the <code>Factory</code> object. This is given 
 65  
     * the class type for the field that this factory will determine
 66  
     * the actual type for. The actual type must be assignable to the
 67  
     * field type to insure that any instance can be set. 
 68  
     * 
 69  
     * @param context the contextual object used by the persister
 70  
     * @param type this is the property representing the field 
 71  
     */
 72  
    protected Factory(Context context, Type type) {
 73  3140594
       this(context, type, null);
 74  3140594
    }
 75  
    
 76  
    /**
 77  
     * Constructor for the <code>Factory</code> object. This is given 
 78  
     * the class type for the field that this factory will determine
 79  
     * the actual type for. The actual type must be assignable to the
 80  
     * field type to insure that any instance can be set. 
 81  
     * 
 82  
     * @param context the contextual object used by the persister
 83  
     * @param type this is the property representing the field 
 84  
     * @param override this is the override used for this factory
 85  
     */
 86  4076096
    protected Factory(Context context, Type type, Class override) {
 87  4076096
       this.support = context.getSupport();
 88  4076096
       this.override = override;
 89  4076096
       this.context = context; 
 90  4076096
       this.type = type;
 91  4076096
    }
 92  
    
 93  
    /**
 94  
     * This is used to extract the type this factory is using. Each
 95  
     * factory represents a specific class, which it instantiates if
 96  
     * required. This method provides the represented class.
 97  
     * 
 98  
     * @return this returns the class represented by the factory
 99  
     */
 100  
    public Class getType() {
 101  1899760
       if(override != null) {
 102  105
          return override;
 103  
       }
 104  1899655
       return type.getType();
 105  
    }
 106  
    
 107  
    /**
 108  
     * This is used to create a default instance of the field type. It
 109  
     * is up to the subclass to determine how to best instantiate an
 110  
     * object of the field type that best suits. This is used when the
 111  
     * empty value is required or to create the default type instance.
 112  
     * 
 113  
     * @return a type which is used to instantiate the collection     
 114  
     */
 115  
    public Object getInstance() throws Exception {
 116  0
       Class type = getType();
 117  
       
 118  0
       if(!isInstantiable(type)) {
 119  0
          throw new InstantiationException("Type %s can not be instantiated", type);
 120  
       }
 121  0
       return type.newInstance();
 122  
    }
 123  
 
 124  
    /**
 125  
     * This is used to get a possible override from the provided node.
 126  
     * If the node provided is an element then this checks for a  
 127  
     * specific class override using the <code>Strategy</code> object.
 128  
     * If the strategy cannot resolve a class then this will return 
 129  
     * null. If the resolved <code>Value</code> is not assignable to 
 130  
     * the field then this will thrown an exception.
 131  
     * 
 132  
     * @param node this is the node used to search for the override
 133  
     * 
 134  
     * @return this returns null if no override type can be found
 135  
     * 
 136  
     * @throws Exception if the override type is not compatible
 137  
     */
 138  
    protected Value getOverride(InputNode node) throws Exception {
 139  1802414
       Value value = getConversion(node);      
 140  
 
 141  1802413
       if(value != null) {
 142  97190
          Position line = node.getPosition();
 143  97190
          Class proposed = value.getType();
 144  97190
          Class expect = getType();
 145  
      
 146  97190
          if(!isCompatible(expect, proposed)) {
 147  3
             throw new InstantiationException("Incompatible %s for %s at %s", proposed, type, line);              
 148  
          }
 149  
       }         
 150  1802410
       return value; 
 151  
    }
 152  
    
 153  
    /**
 154  
     * This method is used to set the override class within an element.
 155  
     * This delegates to the <code>Strategy</code> implementation, which
 156  
     * depending on the implementation may add an attribute of a child
 157  
     * element to describe the type of the object provided to this.
 158  
     * 
 159  
     * @param type this is the class of the field type being serialized
 160  
     * @param node the XML element that is to be given the details
 161  
     *
 162  
     * @throws Exception thrown if an error occurs within the strategy
 163  
     */
 164  
    public boolean setOverride(Type type, Object value, OutputNode node) throws Exception {
 165  420978
       Class expect = type.getType();
 166  
       
 167  420978
       if(expect.isPrimitive()) {
 168  2379
          type = getPrimitive(type, expect);
 169  
       }
 170  420978
       return context.setOverride(type, value, node);
 171  
    }
 172  
    
 173  
    /**
 174  
     * This is used to convert the <code>Type</code> provided as an 
 175  
     * overridden type. Overriding the type in this way ensures that if
 176  
     * a primitive type, represented as a boxed object, is given to a
 177  
     * strategy then the strategy will see a match in the types used.
 178  
     * 
 179  
     * @param type this is the field or method that is a primitive
 180  
     * @param expect this is the boxed object type to be converted
 181  
     * 
 182  
     * @return this returns a type representing the boxed type
 183  
     */
 184  
    private Type getPrimitive(Type type, Class expect) throws Exception {      
 185  2379
       Class convert = support.getPrimitive(expect);
 186  
       
 187  2379
       if(convert != expect) {
 188  2379
          return new OverrideType(type, convert);
 189  
       }
 190  0
       return type;
 191  
    }
 192  
 
 193  
    /**
 194  
     * This performs the conversion from the element node to a type. This
 195  
     * is where the <code>Strategy</code> object is consulted and asked
 196  
     * for a class that will represent the provided XML element. This will,
 197  
     * depending on the strategy implementation, make use of attributes
 198  
     * and/or elements to determine the type for the field.
 199  
     * 
 200  
     * @param node this is the element used to extract the override
 201  
     * 
 202  
     * @return this returns null if no override type can be found
 203  
     * 
 204  
     * @throws Exception thrown if the override class cannot be loaded    
 205  
     */ 
 206  
    public Value getConversion(InputNode node) throws Exception {
 207  1802414
       Value value = context.getOverride(type, node);
 208  
       
 209  1802413
       if(value != null && override != null) {
 210  38
          Class proposed = value.getType();
 211  
      
 212  38
          if(!isCompatible(override, proposed)) {
 213  26
             return new OverrideValue(value, override);
 214  
          }
 215  
       }
 216  1802387
       return value;
 217  
    }
 218  
    
 219  
    /**
 220  
     * This is used to determine whether the provided base class can be
 221  
     * assigned from the issued type. For an override to be compatible
 222  
     * with the field type an instance of the override type must be 
 223  
     * assignable to the field value. 
 224  
     * 
 225  
     * @param expect this is the field value present the the object    
 226  
     * @param type this is the specialized type that will be assigned
 227  
     * 
 228  
     * @return true if the field type can be assigned the type value
 229  
     */
 230  
    public static boolean isCompatible(Class expect, Class type) {
 231  97228
       if(expect.isArray()) {
 232  205
          expect = expect.getComponentType();
 233  
       }
 234  97228
       return expect.isAssignableFrom(type);           
 235  
    }
 236  
 
 237  
    /**
 238  
     * This is used to determine whether the type given is instantiable,
 239  
     * that is, this determines if an instance of that type can be
 240  
     * created. If the type is an interface or an abstract class then 
 241  
     * this will return false.
 242  
     * 
 243  
     * @param type this is the type to check the modifiers of
 244  
     * 
 245  
     * @return false if the type is an interface or an abstract class
 246  
     */
 247  
    public static boolean isInstantiable(Class type) {
 248  777543
       int modifiers = type.getModifiers();
 249  
 
 250  777543
       if(Modifier.isAbstract(modifiers)) {
 251  212
          return false;              
 252  
       }              
 253  777331
       return !Modifier.isInterface(modifiers);
 254  
    } 
 255  
 }