Coverage Report - org.simpleframework.xml.core.ParameterFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
ParameterFactory
93%
30/32
86%
19/22
3.182
ParameterFactory$ParameterBuilder
100%
13/13
100%
2/2
3.182
 
 1  
 /*
 2  
  * ParameterFactory.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.annotation.Annotation;
 22  
 import java.lang.reflect.Constructor;
 23  
 
 24  
 import org.simpleframework.xml.Attribute;
 25  
 import org.simpleframework.xml.Element;
 26  
 import org.simpleframework.xml.ElementArray;
 27  
 import org.simpleframework.xml.ElementList;
 28  
 import org.simpleframework.xml.ElementListUnion;
 29  
 import org.simpleframework.xml.ElementMap;
 30  
 import org.simpleframework.xml.ElementMapUnion;
 31  
 import org.simpleframework.xml.ElementUnion;
 32  
 import org.simpleframework.xml.Text;
 33  
 import org.simpleframework.xml.stream.Format;
 34  
 
 35  
 /**
 36  
  * The <code>ParameterFactory</code> object is used to create instances 
 37  
  * of the <code>Parameter</code> object. Each parameter created can be
 38  
  * used to validate against the annotated fields and methods to ensure
 39  
  * that the annotations are compatible. 
 40  
  * <p>
 41  
  * The <code>Parameter</code> objects created by this are selected
 42  
  * using the XML annotation type. If the annotation type is not known
 43  
  * the factory will throw an exception, otherwise a parameter instance
 44  
  * is created that will expose the properties of the annotation.
 45  
  * 
 46  
  * @author Niall Gallagher
 47  
  */
 48  
 class ParameterFactory {
 49  
 
 50  
    /**
 51  
     * This format contains the style which is used to create names.
 52  
     */
 53  
    private final Format format;
 54  
    
 55  
    /**
 56  
     * Constructor for the <code>ParameterFactory</code> object. This 
 57  
     * factory is used for creating parameters within a constructor.
 58  
     * Parameters can be annotated in the same way as methods or
 59  
     * fields, this object is used to create such parameters.
 60  
     * 
 61  
     * @param support this contains various support functions
 62  
     */
 63  3664
    public ParameterFactory(Support support) {
 64  3664
       this.format = support.getFormat();
 65  3664
    }
 66  
    
 67  
    /**
 68  
     * Creates a <code>Parameter</code> using the provided constructor
 69  
     * and the XML annotation. The parameter produced contains all 
 70  
     * information related to the constructor parameter. It knows the 
 71  
     * name of the XML entity, as well as the type. 
 72  
     * 
 73  
     * @param factory this is the constructor the parameter exists in
 74  
     * @param label represents the XML annotation for the contact
 75  
     * @param index the index of the parameter in the constructor
 76  
     * 
 77  
     * @return returns the parameter instantiated for the field
 78  
     */
 79  
    public Parameter getInstance(Constructor factory, Annotation label, int index) throws Exception {   
 80  561
       return getInstance(factory, label, null, index);
 81  
    }
 82  
    
 83  
    /**
 84  
     * Creates a <code>Parameter</code> using the provided constructor
 85  
     * and the XML annotation. The parameter produced contains all 
 86  
     * information related to the constructor parameter. It knows the 
 87  
     * name of the XML entity, as well as the type. 
 88  
     * 
 89  
     * @param factory this is the constructor the parameter exists in
 90  
     * @param label represents the XML annotation for the contact
 91  
     * @param entry this is the entry annotation for the parameter
 92  
     * @param index the index of the parameter in the constructor
 93  
     * 
 94  
     * @return returns the parameter instantiated for the field
 95  
     */
 96  
    public Parameter getInstance(Constructor factory, Annotation label, Annotation entry, int index) throws Exception {   
 97  595
       Constructor builder = getConstructor(label);    
 98  
       
 99  595
       if(entry != null) {
 100  34
          return (Parameter)builder.newInstance(factory, label, entry, format, index);
 101  
       }
 102  561
       return (Parameter)builder.newInstance(factory, label, format, index);
 103  
    }
 104  
     
 105  
     /**
 106  
      * Creates a constructor that is used to instantiate the parameter
 107  
      * used to represent the specified annotation. The constructor
 108  
      * created by this method takes three arguments, a constructor, 
 109  
      * an annotation, and the parameter index.
 110  
      * 
 111  
      * @param label the XML annotation representing the label
 112  
      * 
 113  
      * @return returns a constructor for instantiating the parameter 
 114  
      * 
 115  
      * @throws Exception thrown if the annotation is not supported
 116  
      */
 117  
     private Constructor getConstructor(Annotation label) throws Exception {
 118  595
       ParameterBuilder builder = getBuilder(label);
 119  595
       Constructor factory = builder.getConstructor();
 120  
       
 121  595
       if(!factory.isAccessible()) {
 122  595
          factory.setAccessible(true);
 123  
       }
 124  595
       return factory;
 125  
     }
 126  
     
 127  
     /**
 128  
      * Creates an entry that is used to select the constructor for the
 129  
      * parameter. Each parameter must implement a constructor that takes 
 130  
      * a constructor, and annotation, and the index of the parameter. If
 131  
      * the annotation is not know this method throws an exception.
 132  
      * 
 133  
      * @param label the XML annotation used to create the parameter
 134  
      * 
 135  
      * @return this returns the entry used to create a constructor
 136  
      */
 137  
     private ParameterBuilder getBuilder(Annotation label) throws Exception{      
 138  595
        if(label instanceof Element) {
 139  378
           return new ParameterBuilder(ElementParameter.class, Element.class);
 140  
        }
 141  217
        if(label instanceof ElementList) {
 142  32
           return new ParameterBuilder(ElementListParameter.class, ElementList.class);
 143  
        }
 144  185
        if(label instanceof ElementArray) {
 145  3
           return new ParameterBuilder(ElementArrayParameter.class, ElementArray.class);               
 146  
        }
 147  182
        if(label instanceof ElementMapUnion) {
 148  0
           return new ParameterBuilder(ElementMapUnionParameter.class, ElementMapUnion.class, ElementMap.class);
 149  
        }
 150  182
        if(label instanceof ElementListUnion) {
 151  8
           return new ParameterBuilder(ElementListUnionParameter.class, ElementListUnion.class, ElementList.class);
 152  
        }
 153  174
        if(label instanceof ElementUnion) {
 154  26
           return new ParameterBuilder(ElementUnionParameter.class, ElementUnion.class, Element.class);
 155  
        }
 156  148
        if(label instanceof ElementMap) {
 157  7
           return new ParameterBuilder(ElementMapParameter.class, ElementMap.class);
 158  
        }
 159  141
        if(label instanceof Attribute) {
 160  120
           return new ParameterBuilder(AttributeParameter.class, Attribute.class);
 161  
        }
 162  21
        if(label instanceof Text) {
 163  21
           return new ParameterBuilder(TextParameter.class, Text.class);
 164  
        }
 165  0
        throw new PersistenceException("Annotation %s not supported", label);
 166  
     }
 167  
     
 168  
     /**
 169  
      * The <code>ParameterBuilder<code> is used to create a constructor 
 170  
      * that can be used to instantiate the correct parameter for the 
 171  
      * XML annotation specified. The constructor requires three 
 172  
      * arguments, the constructor, the annotation, and the index.
 173  
      * 
 174  
      * @see java.lang.reflect.Constructor
 175  
      */
 176  
     private static class ParameterBuilder {
 177  
              
 178  
        /**
 179  
         * This is the entry that is used to create the parameter.
 180  
         */
 181  
        private final Class entry;
 182  
        
 183  
        /**       
 184  
         * This is the XML annotation type within the constructor.
 185  
         */
 186  
        private final Class label;
 187  
        
 188  
        /**
 189  
         * This is the parameter type that is to be instantiated.
 190  
         */
 191  
        private final Class type;
 192  
        
 193  
        /**
 194  
         * Constructor for the <code>PameterBuilder</code> object. This 
 195  
         * pairs the parameter type with the annotation argument used 
 196  
         * within the constructor. This allows constructor to be selected.
 197  
         * 
 198  
         * @param type this is the parameter type to be instantiated
 199  
         * @param label the type that is used within the constructor
 200  
         */
 201  
        public ParameterBuilder(Class type, Class label) {
 202  561
           this(type, label, null);
 203  561
        }
 204  
        
 205  
        /**
 206  
         * Constructor for the <code>PameterBuilder</code> object. This 
 207  
         * pairs the parameter type with the annotation argument used 
 208  
         * within the constructor. This allows constructor to be selected.
 209  
         * 
 210  
         * @param type this is the parameter type to be instantiated
 211  
         * @param label the type that is used within the constructor
 212  
         * @param entry this is the entry used to create the parameter
 213  
         */
 214  595
        public ParameterBuilder(Class type, Class label, Class entry) {
 215  595
           this.label = label;
 216  595
           this.entry = entry;
 217  595
           this.type = type;
 218  595
        }
 219  
        
 220  
        /**
 221  
         * Creates the constructor used to instantiate the label for
 222  
         * the XML annotation. The constructor returned will take two
 223  
         * arguments, a contact and the XML annotation type. 
 224  
         * 
 225  
         * @return returns the constructor for the label object
 226  
         */
 227  
        public Constructor getConstructor() throws Exception {
 228  595
           if(entry != null) {
 229  34
              return getConstructor(label, entry);
 230  
           }
 231  561
           return getConstructor(label);
 232  
        }
 233  
        
 234  
        /**
 235  
         * Creates the constructor used to instantiate the parameter
 236  
         * for the XML annotation. The constructor returned will take 
 237  
         * two arguments, a contact and the XML annotation type. 
 238  
         * 
 239  
         * @param label the type that is used within the constructor
 240  
         * 
 241  
         * @return returns the constructor for the parameter object
 242  
         */
 243  
        public Constructor getConstructor(Class label) throws Exception {
 244  561
           return getConstructor(Constructor.class, label, Format.class, int.class);
 245  
        }
 246  
        
 247  
        /**
 248  
         * Creates the constructor used to instantiate the parameter
 249  
         * for the XML annotation. The constructor returned will take 
 250  
         * two arguments, a contact and the XML annotation type. 
 251  
         * 
 252  
         * @param label the type that is used within the constructor
 253  
         * @param entry this is the entry used to create the parameter
 254  
         * 
 255  
         * @return returns the constructor for the parameter object
 256  
         */
 257  
        public Constructor getConstructor(Class label, Class entry) throws Exception {
 258  34
           return getConstructor(Constructor.class, label, entry, Format.class, int.class);
 259  
        }
 260  
        
 261  
        /**
 262  
         * Creates the constructor used to instantiate the parameter 
 263  
         * for the XML annotation. The constructor returned will take 
 264  
         * three arguments, a constructor, an annotation and a type.
 265  
         * 
 266  
         * @param types these are the arguments for the constructor
 267  
         * 
 268  
         * @return returns the constructor for the parameter object
 269  
         */
 270  
        private Constructor getConstructor(Class... types) throws Exception {
 271  595
           return type.getConstructor(types);
 272  
        }
 273  
     }
 274  
 }