Coverage Report - org.simpleframework.xml.core.CollectionFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
CollectionFactory
93%
30/32
90%
18/20
4
 
 1  
 /*
 2  
  * CollectionFactory.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.util.ArrayList;
 22  
 import java.util.Collection;
 23  
 import java.util.HashSet;
 24  
 import java.util.TreeSet;
 25  
 
 26  
 import org.simpleframework.xml.strategy.Type;
 27  
 import org.simpleframework.xml.strategy.Value;
 28  
 import org.simpleframework.xml.stream.InputNode;
 29  
 
 30  
 /**
 31  
  * The <code>CollectionFactory</code> is used to create collection
 32  
  * instances that are compatible with the field type. This performs
 33  
  * resolution of the collection class by firstly consulting the
 34  
  * specified <code>Strategy</code> implementation. If the strategy
 35  
  * cannot resolve the collection class then this will select a type
 36  
  * from the Java Collections framework, if a compatible one exists.
 37  
  * 
 38  
  * @author Niall Gallagher
 39  
  */ 
 40  
 class CollectionFactory extends Factory {
 41  
 
 42  
    /**
 43  
     * Constructor for the <code>CollectionFactory</code> object. This
 44  
     * is given the field type as taken from the owning object. The
 45  
     * given type is used to determine the collection instance created.
 46  
     * 
 47  
     * @param context this is the context associated with this factory
 48  
     * @param type this is the class for the owning object
 49  
     */
 50  
    public CollectionFactory(Context context, Type type) {
 51  167278
       super(context, type);           
 52  167278
    }
 53  
    
 54  
    /**
 55  
     * Creates a collection that is determined from the field type. 
 56  
     * This is used for the <code>ElementList</code> to get a
 57  
     * collection that does not have any overrides. This must be
 58  
     * done as the inline list does not contain an outer element.
 59  
     * 
 60  
     * @return a type which is used to instantiate the collection     
 61  
     */
 62  
    @Override
 63  
    public Object getInstance() throws Exception {
 64  122
       Class expect = getType();
 65  122
       Class real = expect;
 66  
 
 67  122
       if(!isInstantiable(real)) {
 68  108
          real = getConversion(expect);   
 69  
       }
 70  122
       if(!isCollection(real)) {
 71  0
          throw new InstantiationException("Invalid collection %s for %s", expect, type);
 72  
       }
 73  122
       return real.newInstance();
 74  
    }
 75  
    
 76  
    /**
 77  
     * Creates the collection to use. The <code>Strategy</code> object
 78  
     * is consulted for the collection class, if one is not resolved
 79  
     * by the strategy implementation or if the collection resolved is
 80  
     * abstract then the Java Collections framework is consulted.
 81  
     * 
 82  
     * @param node this is the input node representing the list
 83  
     * 
 84  
     * @return this is the collection instantiated for the field
 85  
     */         
 86  
    public Instance getInstance(InputNode node) throws Exception {
 87  71321
       Value value = getOverride(node);
 88  71317
       Class expect = getType();
 89  
      
 90  71317
       if(value != null) {              
 91  71256
          return getInstance(value);
 92  
       }
 93  61
       if(!isInstantiable(expect)) {
 94  34
          expect = getConversion(expect);
 95  
       }
 96  60
       if(!isCollection(expect)) {
 97  1
          throw new InstantiationException("Invalid collection %s for %s", expect, type);
 98  
       }
 99  59
       return context.getInstance(expect);         
 100  
    }     
 101  
 
 102  
    /**
 103  
     * This creates a <code>Collection</code> instance from the type
 104  
     * provided. If the type provided is abstract or an interface then
 105  
     * this can promote the type to a collection type that can be 
 106  
     * instantiated. This is done by asking the type to convert itself.
 107  
     * 
 108  
     * @param value the type used to instantiate the collection
 109  
     * 
 110  
     * @return this returns a compatible collection instance 
 111  
     */
 112  
    public Instance getInstance(Value value) throws Exception {
 113  71256
       Class expect = value.getType();
 114  
 
 115  71256
       if(!isInstantiable(expect)) {
 116  19
          expect = getConversion(expect);
 117  
       }
 118  71255
       if(!isCollection(expect)) {
 119  0
          throw new InstantiationException("Invalid collection %s for %s", expect, type);              
 120  
       }
 121  71255
       return new ConversionInstance(context, value, expect);         
 122  
    }  
 123  
 
 124  
    /**
 125  
     * This is used to convert the provided type to a collection type
 126  
     * from the Java Collections framework. This will check to see if
 127  
     * the type is a <code>List</code> or <code>Set</code> and return
 128  
     * an <code>ArrayList</code> or <code>HashSet</code> type. If no
 129  
     * suitable match can be found this throws an exception.
 130  
     * 
 131  
     * @param require this is the type that is to be converted
 132  
     * 
 133  
     * @return a collection that is assignable to the provided type
 134  
     */   
 135  
    public Class getConversion(Class require) throws Exception {
 136  161
       if(require.isAssignableFrom(ArrayList.class)) {
 137  156
          return ArrayList.class;
 138  
       }
 139  5
       if(require.isAssignableFrom(HashSet.class)) {
 140  2
          return HashSet.class;                 
 141  
       }
 142  3
       if(require.isAssignableFrom(TreeSet.class)) {
 143  1
          return TreeSet.class;              
 144  
       }       
 145  2
       throw new InstantiationException("Cannot instantiate %s for %s", require, type);
 146  
    }
 147  
 
 148  
    /**
 149  
     * This determines whether the type provided is a collection type.
 150  
     * If the type is assignable to a <code>Collection</code> then 
 151  
     * this returns true, otherwise this returns false.
 152  
     * 
 153  
     * @param type given to determine whether it is a collection  
 154  
     * 
 155  
     * @return true if the provided type is a collection type
 156  
     */
 157  
    private boolean isCollection(Class type) {
 158  71437
       return Collection.class.isAssignableFrom(type);           
 159  
    }
 160  
 }