Coverage Report - org.simpleframework.xml.transform.Transformer
 
Classes in this File Line Coverage Branch Coverage Complexity
Transformer
96%
24/25
91%
11/12
2.5
 
 1  
 /*
 2  
  * Transformer.java May 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.transform;
 20  
 
 21  
 import java.util.Map;
 22  
 
 23  
 import org.simpleframework.xml.util.Cache;
 24  
 import org.simpleframework.xml.util.ConcurrentCache;
 25  
 
 26  
 /**
 27  
  * The <code>Transformer</code> object is used to convert strings to
 28  
  * and from object instances. This is used during the serialization
 29  
  * and deserialization process to transform types from the Java class
 30  
  * libraries, as well as other types which do not contain XML schema
 31  
  * annotations. Typically this will be used to transform primitive
 32  
  * types to and from strings, such as <code>int</code> values.
 33  
  * <pre>
 34  
  * 
 35  
  *    &#64;Element
 36  
  *    private String[] value;
 37  
  *    
 38  
  * </pre>
 39  
  * For example taking the above value the array of strings needs to 
 40  
  * be converted in to a single string value that can be inserted in 
 41  
  * to the element in such a way that in can be read later. In this
 42  
  * case the serialized value of the string array would be as follows.
 43  
  * <pre>
 44  
  * 
 45  
  *    &lt;value&gt;one, two, three&lt;/value&gt;
 46  
  * 
 47  
  * </pre>
 48  
  * Here each non-null string is inserted in to a comma separated  
 49  
  * list of values, which can later be deserialized. Just to note the
 50  
  * above array could be annotated with <code>ElementList</code> just
 51  
  * as easily, in which case each entry would have its own element.
 52  
  * The choice of which annotation to use is up to the developer. A
 53  
  * more obvious benefit to transformations like this can be seen for
 54  
  * values annotated with the <code>Attribute</code> annotation.
 55  
  * 
 56  
  * @author Niall Gallagher
 57  
  */
 58  
 public class Transformer {
 59  
 
 60  
    /**
 61  
     * This is used to cache all transforms matched to a given type.
 62  
     */
 63  
    private final Cache<Transform> cache;
 64  
    
 65  
    /**
 66  
     * This is used to cache the types that to not have a transform.
 67  
     */ 
 68  
    private final Cache<Object> error;
 69  
 
 70  
    /**
 71  
     * This is used to perform the matching of types to transforms.
 72  
     */
 73  
    private final Matcher matcher;
 74  
    
 75  
    /**
 76  
     * Constructor for the <code>Transformer</code> object. This is
 77  
     * used to create a transformer which will transform specified
 78  
     * types using transforms loaded from the class path. Transforms
 79  
     * are matched to types using the specified matcher object.
 80  
     * 
 81  
     * @param matcher this is used to match types to transforms
 82  
     */
 83  974
    public Transformer(Matcher matcher) {  
 84  974
       this.cache = new ConcurrentCache<Transform>();
 85  974
       this.error = new ConcurrentCache<Object>();
 86  974
       this.matcher = new DefaultMatcher(matcher);
 87  974
    }
 88  
    
 89  
    /**
 90  
     * This method is used to convert the string value given to an
 91  
     * appropriate representation. This is used when an object is
 92  
     * being deserialized from the XML document and the value for
 93  
     * the string representation is required.
 94  
     * 
 95  
     * @param value this is the string representation of the value
 96  
     * @param type this is the type to convert the string value to
 97  
     * 
 98  
     * @return this returns an appropriate instanced to be used
 99  
     */
 100  
    public Object read(String value, Class type) throws Exception {
 101  1714149
       Transform transform = lookup(type);
 102  
 
 103  1714149
       if(transform == null) {
 104  0
          throw new TransformException("Transform of %s not supported", type);
 105  
       }      
 106  1714149
       return transform.read(value);
 107  
    }
 108  
    
 109  
    /**
 110  
     * This method is used to convert the provided value into an XML
 111  
     * usable format. This is used in the serialization process when
 112  
     * there is a need to convert a field value in to a string so 
 113  
     * that that value can be written as a valid XML entity.
 114  
     * 
 115  
     * @param value this is the value to be converted to a string
 116  
     * @param type this is the type to convert to a string value
 117  
     * 
 118  
     * @return this is the string representation of the given value
 119  
     */
 120  
    public String write(Object value, Class type) throws Exception {
 121  526219
       Transform transform = lookup(type);
 122  
 
 123  526219
       if(transform == null) {
 124  1
          throw new TransformException("Transform of %s not supported", type);
 125  
       }
 126  526218
       return transform.write(value);
 127  
    }
 128  
 
 129  
    /**
 130  
     * This method is used to determine if the type specified can be
 131  
     * transformed. This will use the <code>Matcher</code> to find a
 132  
     * suitable transform, if one exists then this returns true, if
 133  
     * not then this returns false. This is used during serialization
 134  
     * to determine how to convert a field or method parameter. 
 135  
     *
 136  
     * @param type the type to determine whether its transformable
 137  
     * 
 138  
     * @return true if the type specified can be transformed by this
 139  
     */ 
 140  
    public boolean valid(Class type) throws Exception {   
 141  1181093
       return lookup(type) != null;
 142  
    }
 143  
 
 144  
    /**
 145  
     * This method is used to acquire a <code>Transform</code> for 
 146  
     * the the specified type. If there is no transform for the type
 147  
     * then this will return null. Once acquired once the transform
 148  
     * is cached so that subsequent lookups will be performed faster.
 149  
     *
 150  
     * @param type the type to determine whether its transformable
 151  
     *
 152  
     * @return this will return a transform for the specified type
 153  
     */ 
 154  
    private Transform lookup(Class type) throws Exception {
 155  3421461
       if(!error.contains(type)) {
 156  2251402
          Transform transform = cache.fetch(type);            
 157  
    
 158  2251402
          if(transform != null) {
 159  2247230
             return transform;
 160  
          }          
 161  4172
          return match(type);
 162  
       }
 163  1170059
       return null;
 164  
    }
 165  
 
 166  
    /**
 167  
     * This method is used to acquire a <code>Transform</code> for 
 168  
     * the the specified type. If there is no transform for the type
 169  
     * then this will return null. Once acquired once the transform
 170  
     * is cached so that subsequent lookups will be performed faster.
 171  
     *
 172  
     * @param type the type to determine whether its transformable
 173  
     *
 174  
     * @return this will return a transform for the specified type
 175  
     */ 
 176  
    private Transform match(Class type) throws Exception {
 177  4172
       Transform transform = matcher.match(type);
 178  
       
 179  4172
       if(transform != null) {
 180  1764
          cache.cache(type, transform);
 181  
       } else {
 182  2408
          error.cache(type, this);               
 183  
       }
 184  4172
       return transform;
 185  
    }
 186  
 }