Coverage Report - org.simpleframework.xml.core.ExtractorFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
ExtractorFactory
94%
17/18
75%
6/8
1.556
ExtractorFactory$ElementExtractor
100%
12/12
100%
2/2
1.556
ExtractorFactory$ElementListExtractor
100%
9/9
N/A
1.556
ExtractorFactory$ElementMapExtractor
100%
9/9
N/A
1.556
ExtractorFactory$ExtractorBuilder
100%
6/6
N/A
1.556
 
 1  
 /*
 2  
  * ExtractorFactory.java March 2011
 3  
  *
 4  
  * Copyright (C) 2011, 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.Element;
 25  
 import org.simpleframework.xml.ElementList;
 26  
 import org.simpleframework.xml.ElementListUnion;
 27  
 import org.simpleframework.xml.ElementMap;
 28  
 import org.simpleframework.xml.ElementMapUnion;
 29  
 import org.simpleframework.xml.ElementUnion;
 30  
 import org.simpleframework.xml.stream.Format;
 31  
 
 32  
 /**
 33  
  * The <code>ExtractorFactory</code> is used to create an extractor 
 34  
  * object that can be used to build a label for each annotation in
 35  
  * the union group. In order to build an extractor the factory
 36  
  * requires the <code>Contact</code> and the union annotation.
 37  
  * Each extractor created by this factory can be used to extract
 38  
  * the constituent parts of each label defined in the union.
 39  
  * 
 40  
  * @author Niall Gallagher
 41  
  * 
 42  
  * @see org.simpleframework.xml.core.Extractor
 43  
  */
 44  
 class ExtractorFactory {   
 45  
 
 46  
    /**
 47  
     * This is the union annotation this creates extractors for.
 48  
     */
 49  
    private final Annotation label;
 50  
    
 51  
    /**
 52  
     * This is the contact that has been annotated as a union.
 53  
     */
 54  
    private final Contact contact;
 55  
    
 56  
    /**
 57  
     * The format used for each of the extractors instantiated.
 58  
     */
 59  
    private final Format format;
 60  
    
 61  
    /**
 62  
     * Constructor for the <code>ExtractorFactory</code> object. This
 63  
     * requires the contact that was annotated as a union and the
 64  
     * actual union annotation, which is used to build individual
 65  
     * labels based on the declarations.
 66  
     * 
 67  
     * @param contact this is the field or method annotated
 68  
     * @param label this is the union annotation to extract from
 69  
     * @param format this is the format used by the extractors
 70  
     */
 71  524
    public ExtractorFactory(Contact contact, Annotation label, Format format) {
 72  524
       this.contact = contact;
 73  524
       this.format = format;
 74  524
       this.label = label;
 75  524
    }
 76  
    
 77  
    /**
 78  
     * This is used to instantiate an <code>Extractor</code> based on
 79  
     * the union annotation provided. Each extractor provides a 
 80  
     * uniform interface to the constituent parts of the union.
 81  
     * 
 82  
     * @return this returns an extractor for the union
 83  
     */
 84  
    public Extractor getInstance() throws Exception {
 85  524
       return (Extractor)getInstance(label);     
 86  
    }
 87  
    
 88  
    /**
 89  
     * This is used to instantiate an <code>Extractor</code> based on
 90  
     * the union annotation provided. Each extractor provides a 
 91  
     * uniform interface to the constituent parts of the union.
 92  
     * 
 93  
     * @param label this is the union annotation to be used
 94  
     * 
 95  
     * @return this returns an extractor for the union
 96  
     */
 97  
    private Object getInstance(Annotation label) throws Exception {
 98  524
       ExtractorBuilder builder = getBuilder(label);
 99  524
       Constructor factory = builder.getConstructor();
 100  
       
 101  524
       if(!factory.isAccessible()) {
 102  524
          factory.setAccessible(true);
 103  
       }
 104  524
       return factory.newInstance(contact, label, format); 
 105  
    }
 106  
    
 107  
    /**
 108  
     * This returns a builder used to instantiate an extractor based
 109  
     * on a particular union annotation. If the annotation provided
 110  
     * does not represent a valid union an exception is thrown.
 111  
     * 
 112  
     * @param label this is the union annotation to build for
 113  
     * 
 114  
     * @return this returns a builder used to create an extractor
 115  
     */
 116  
    private ExtractorBuilder getBuilder(Annotation label) throws Exception {
 117  524
       if(label instanceof ElementUnion) {
 118  256
          return new ExtractorBuilder(ElementUnion.class, ElementExtractor.class);
 119  
       }
 120  268
       if(label instanceof ElementListUnion) {
 121  206
          return new ExtractorBuilder(ElementListUnion.class, ElementListExtractor.class);
 122  
       }
 123  62
       if(label instanceof ElementMapUnion) {
 124  62
          return new ExtractorBuilder(ElementMapUnion.class, ElementMapExtractor.class);
 125  
       }
 126  0
       throw new PersistenceException("Annotation %s is not a union", label);
 127  
    }
 128  
    
 129  
    /**
 130  
     * The <code>ExtractorBuilder</code> object is used to instantiate
 131  
     * an extractor based an a particular union annotation. Each 
 132  
     * builder has a known constructor signature which can be used to
 133  
     * reflectively instantiate the builder instance.
 134  
     * 
 135  
     * @author Niall Gallagher
 136  
     */
 137  524
    private static class ExtractorBuilder {
 138  
       
 139  
       /**
 140  
        * This is the union annotation to build the extractor for.
 141  
        */
 142  
       private final Class label;
 143  
       
 144  
       /**
 145  
        * This is the actual extractor that is to be instantianted.
 146  
        */
 147  
       private final Class type;
 148  
       
 149  
       /**
 150  
        * Constructor for the <code>ExtractorBuilder</code> object. This
 151  
        * requires the union annotation to instantiate the builder for.
 152  
        * Also, the actual builder type is required.
 153  
        * 
 154  
        * @param label this is the union annotation to be used
 155  
        * @param type this is the actual extractor implementation
 156  
        */
 157  524
       public ExtractorBuilder(Class label, Class type) {
 158  524
          this.label = label;
 159  524
          this.type = type;
 160  524
       }
 161  
       
 162  
       /**
 163  
        * Returns a <code>Constructor</code> that can be used to create
 164  
        * an extractor based on a known constructor signature. The 
 165  
        * provided constructor is then used to instantiated the object.
 166  
        * 
 167  
        * @return this returns the constructor for the extractor
 168  
        */
 169  
       private Constructor getConstructor() throws Exception {
 170  524
          return type.getConstructor(Contact.class, label, Format.class);
 171  
       }
 172  
    }
 173  
    
 174  
    /**
 175  
     * The <code>ElementExtractor</code> object is used extract the
 176  
     * constituent parts of the provided union annotation. This can
 177  
     * also be used to create a </code>Label</code> object for each
 178  
     * of the declared annotation for dynamic serialization.
 179  
     * 
 180  
     * @author Niall Gallagher
 181  
     */
 182  1908
    private static class ElementExtractor implements Extractor<Element> {
 183  
       
 184  
       /**
 185  
        * This is the contact that has been annotated as a union.
 186  
        */
 187  
       private final Contact contact;
 188  
       
 189  
       /**
 190  
        * This is the union annotation to extract the labels for.
 191  
        */
 192  
       private final ElementUnion union;
 193  
       
 194  
       /**
 195  
        * This is the format used to style the elements created.
 196  
        */
 197  
       private final Format format;
 198  
       
 199  
       /**
 200  
        * Constructor for the <code>ElementExtractor</code> object. This
 201  
        * is used to create an extractor that can be used to extract
 202  
        * the various labels used to serialize and deserialize objects.
 203  
        * 
 204  
        * @param contact this is the contact annotated as a union
 205  
        * @param union this is the union annotation to extract from
 206  
        * @param format this is the format used to style the elements
 207  
        */
 208  256
       public ElementExtractor(Contact contact, ElementUnion union, Format format) throws Exception {
 209  256
          this.contact = contact;
 210  256
          this.format = format;
 211  256
          this.union = union;
 212  256
       }
 213  
       
 214  
       /**
 215  
        * This is used to acquire each annotation that forms part of the
 216  
        * union group. Extracting the annotations in this way allows
 217  
        * the extractor to build a <code>Label</code> which can be used
 218  
        * to represent the annotation. Each label can then provide a
 219  
        * converter implementation to serialize objects.
 220  
        * 
 221  
        * @return this returns each annotation within the union group
 222  
        */
 223  
       public Element[] getAnnotations() {
 224  256
          return union.value();
 225  
       }
 226  
       
 227  
       /**
 228  
        * This creates a <code>Label</code> object used to represent the
 229  
        * annotation provided. Creating the label in this way ensures
 230  
        * that each union has access to the serialization methods 
 231  
        * defined for each type an XML element name.
 232  
        * 
 233  
        * @param element this is the annotation to create the label for
 234  
        * 
 235  
        * @return this is the label created for the annotation
 236  
        */
 237  
       public Label getLabel(Element element) {
 238  826
          return new ElementLabel(contact, element, format);
 239  
       }
 240  
       
 241  
       /**
 242  
        * Each annotation can provide a class which is used to determine
 243  
        * which label is used to serialize an object. This ensures that
 244  
        * the correct label is selected whenever serialization occurs.
 245  
        * 
 246  
        * @param element this is the annotation to extract the type for
 247  
        * 
 248  
        * @return this returns the class associated with the annotation
 249  
        */
 250  
       public Class getType(Element element) {
 251  826
          Class type = element.type();
 252  
          
 253  826
          if(type == void.class) {
 254  441
             return contact.getType();
 255  
          }
 256  385
          return type;
 257  
       }
 258  
    }
 259  
    
 260  
    /**
 261  
     * The <code>ElementListExtractor</code> object is used extract the
 262  
     * constituent parts of the provided union annotation. This can
 263  
     * also be used to create a </code>Label</code> object for each
 264  
     * of the declared annotation for dynamic serialization.
 265  
     * 
 266  
     * @author Niall Gallagher
 267  
     */
 268  1458
    private static class ElementListExtractor implements Extractor<ElementList>{
 269  
       
 270  
       /**
 271  
        * This is the contact that has been annotated as a union.
 272  
        */
 273  
       private final Contact contact;
 274  
       
 275  
       /**
 276  
        * This is the union annotation to extract the labels for.
 277  
        */
 278  
       private final ElementListUnion union;
 279  
       
 280  
       /**
 281  
        * This is the format used to style the elements for this.
 282  
        */
 283  
       private final Format format;
 284  
       
 285  
       /**
 286  
        * Constructor for the <code>ElementListExtractor</code> object. 
 287  
        * This is used to create an extractor that can be used to extract
 288  
        * the various labels used to serialize and deserialize objects.
 289  
        * 
 290  
        * @param contact this is the contact annotated as a union
 291  
        * @param union this is the union annotation to extract from
 292  
        * @param format this is the format used to style the elements
 293  
        */
 294  206
       public ElementListExtractor(Contact contact, ElementListUnion union, Format format) throws Exception {
 295  206
          this.contact = contact;
 296  206
          this.format = format;
 297  206
          this.union = union;
 298  206
       }
 299  
       
 300  
       /**
 301  
        * This is used to acquire each annotation that forms part of the
 302  
        * union group. Extracting the annotations in this way allows
 303  
        * the extractor to build a <code>Label</code> which can be used
 304  
        * to represent the annotation. Each label can then provide a
 305  
        * converter implementation to serialize objects.
 306  
        * 
 307  
        * @return this returns each annotation within the union group
 308  
        */
 309  
       public ElementList[] getAnnotations() {
 310  206
          return union.value();
 311  
       }
 312  
       
 313  
       /**
 314  
        * This creates a <code>Label</code> object used to represent the
 315  
        * annotation provided. Creating the label in this way ensures
 316  
        * that each union has access to the serialization methods 
 317  
        * defined for each type an XML element name.
 318  
        * 
 319  
        * @param element this is the annotation to create the label for
 320  
        * 
 321  
        * @return this is the label created for the annotation
 322  
        */
 323  
       public Label getLabel(ElementList element) {
 324  626
          return new ElementListLabel(contact, element, format);
 325  
       }
 326  
       
 327  
       /**
 328  
        * Each annotation can provide a class which is used to determine
 329  
        * which label is used to serialize an object. This ensures that
 330  
        * the correct label is selected whenever serialization occurs.
 331  
        * 
 332  
        * @param element this is the annotation to extract the type for
 333  
        * 
 334  
        * @return this returns the class associated with the annotation
 335  
        */
 336  
       public Class getType(ElementList element) {
 337  626
          return element.type();
 338  
       }
 339  
    }
 340  
    
 341  
    /**
 342  
     * The <code>ElementListExtractor</code> object is used extract the
 343  
     * constituent parts of the provided union annotation. This can
 344  
     * also be used to create a </code>Label</code> object for each
 345  
     * of the declared annotation for dynamic serialization.
 346  
     * 
 347  
     * @author Niall Gallagher
 348  
     */
 349  430
    private static class ElementMapExtractor implements Extractor<ElementMap>{
 350  
       
 351  
       /**
 352  
        * This is the contact that has been annotated as a union.
 353  
        */
 354  
       private final Contact contact;
 355  
       
 356  
       /**
 357  
        * This is the union annotation to extract the labels for.
 358  
        */
 359  
       private final ElementMapUnion union;
 360  
       
 361  
       /**
 362  
        * This is the format used to style the elements created.
 363  
        */
 364  
       private final Format format;
 365  
       
 366  
       /**
 367  
        * Constructor for the <code>ElementMapExtractor</code> object. 
 368  
        * This is used to create an extractor that can be used to extract
 369  
        * the various labels used to serialize and deserialize objects.
 370  
        * 
 371  
        * @param contact this is the contact annotated as a union
 372  
        * @param union this is the union annotation to extract from
 373  
        * @param format this is the format used to style elements
 374  
        */
 375  62
       public ElementMapExtractor(Contact contact, ElementMapUnion union, Format format) throws Exception {
 376  62
          this.contact = contact;
 377  62
          this.format = format;
 378  62
          this.union = union;
 379  62
       }
 380  
       
 381  
       /**
 382  
        * This is used to acquire each annotation that forms part of the
 383  
        * union group. Extracting the annotations in this way allows
 384  
        * the extractor to build a <code>Label</code> which can be used
 385  
        * to represent the annotation. Each label can then provide a
 386  
        * converter implementation to serialize objects.
 387  
        * 
 388  
        * @return this returns each annotation within the union group
 389  
        */
 390  
       public ElementMap[] getAnnotations() {
 391  62
          return union.value();
 392  
       }
 393  
       
 394  
       /**
 395  
        * This creates a <code>Label</code> object used to represent the
 396  
        * annotation provided. Creating the label in this way ensures
 397  
        * that each union has access to the serialization methods 
 398  
        * defined for each type an XML element name.
 399  
        * 
 400  
        * @param element this is the annotation to create the label for
 401  
        * 
 402  
        * @return this is the label created for the annotation
 403  
        */
 404  
       public Label getLabel(ElementMap element) {
 405  184
          return new ElementMapLabel(contact, element, format);
 406  
       }
 407  
       
 408  
       /**
 409  
        * Each annotation can provide a class which is used to determine
 410  
        * which label is used to serialize an object. This ensures that
 411  
        * the correct label is selected whenever serialization occurs.
 412  
        * 
 413  
        * @param element this is the annotation to extract the type for
 414  
        * 
 415  
        * @return this returns the class associated with the annotation
 416  
        */
 417  
       public Class getType(ElementMap element) {
 418  184
          return element.valueType();
 419  
       }
 420  
    }
 421  
 }