Coverage Report - org.simpleframework.xml.core.CompositeMapUnion
 
Classes in this File Line Coverage Branch Coverage Complexity
CompositeMapUnion
98%
49/50
81%
13/16
2.286
 
 1  
 /*
 2  
  * CompositeMapUnion.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.util.Collections;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.simpleframework.xml.strategy.Type;
 25  
 import org.simpleframework.xml.stream.InputNode;
 26  
 import org.simpleframework.xml.stream.OutputNode;
 27  
 import org.simpleframework.xml.stream.Style;
 28  
 
 29  
 /**
 30  
  * The <code>CompositeMapUnion</code> object is used to act as a 
 31  
  * mediator for multiple converters associated with a particular union 
 32  
  * group. This will basically determine which <code>Converter</code> 
 33  
  * should be delegated to based on either the XML element name being read 
 34  
  * or the type of the instance object being written. Selection of the 
 35  
  * converter is done by consulting the <code>Group</code> of labels 
 36  
  * representing the union declaration.
 37  
  * 
 38  
  * @author Niall Gallagher
 39  
  */
 40  
 class CompositeMapUnion implements Repeater {
 41  
    
 42  
    /**
 43  
     * This contains the labels in the union group keyed by name.
 44  
     */
 45  
    private final LabelMap elements;
 46  
    
 47  
    /**
 48  
     * This is the path expression used to represent this union.
 49  
     */
 50  
    private final Expression path;
 51  
    
 52  
    /**
 53  
     * This is the current context used for the serialization.
 54  
     */
 55  
    private final Context context;
 56  
    
 57  
    /**
 58  
     * This contains the group of labels associated with the union.
 59  
     */
 60  
    private final Group group;
 61  
    
 62  
    /**
 63  
     * This is this style associated with the serialization context.
 64  
     */
 65  
    private final Style style;
 66  
    
 67  
    /**
 68  
     * This is the type field or method annotated as a union.
 69  
     */
 70  
    private final Type type;
 71  
 
 72  
    /**
 73  
     * Constructor for the <code>CompositeMapUnion</code> object. This
 74  
     * is used to create a converter that delegates to other associated
 75  
     * converters within the union group depending on the XML element
 76  
     * name being read or the instance type that is being written.
 77  
     * 
 78  
     * @param context this is the context used for the serialization
 79  
     * @param group this is the union group used for delegation
 80  
     * @param path this is the path expression representing this union
 81  
     * @param type this is the annotated field or method to be used
 82  
     */
 83  86
    public CompositeMapUnion(Context context, Group group, Expression path, Type type) throws Exception {
 84  86
       this.elements = group.getElements();
 85  86
       this.style = context.getStyle();
 86  86
       this.context = context;
 87  86
       this.group = group;
 88  86
       this.type = type;
 89  86
       this.path = path;
 90  86
    }
 91  
 
 92  
    /**
 93  
     * The <code>read</code> method uses the name of the XML element to
 94  
     * select a converter to be used to read the instance. Selection of
 95  
     * the converter is done by looking up the associated label from
 96  
     * the union group using the element name. Once the converter has
 97  
     * been selected it is used to read the instance.
 98  
     * 
 99  
     * @param node this is the XML element used to read the instance
 100  
     * 
 101  
     * @return this is the instance that has been read by this
 102  
     */
 103  
    public Object read(InputNode node) throws Exception {
 104  17
       String name = node.getName();
 105  17
       String element = path.getElement(name);
 106  17
       Label label = elements.get(element);
 107  17
       Converter converter = label.getConverter(context);
 108  
       
 109  17
       return converter.read(node);
 110  
    }
 111  
 
 112  
    /**
 113  
     * The <code>read</code> method uses the name of the XML element to
 114  
     * select a converter to be used to read the instance. Selection of
 115  
     * the converter is done by looking up the associated label from
 116  
     * the union group using the element name. Once the converter has
 117  
     * been selected it is used to read the instance.
 118  
     * 
 119  
     * @param node this is the XML element used to read the instance
 120  
     * @param value this is the value that is to be repeated
 121  
     * 
 122  
     * @return this is the instance that has been read by this
 123  
     */
 124  
    public Object read(InputNode node, Object value) throws Exception {
 125  21
       String name = node.getName();
 126  21
       String element = path.getElement(name);
 127  21
       Label label = elements.get(element);
 128  21
       Converter converter = label.getConverter(context);
 129  
       
 130  21
       return converter.read(node, value);
 131  
    }
 132  
    
 133  
    /**
 134  
     * The <code>validate</code> method is used to validate the XML
 135  
     * element provided using an associated class schema. The schema
 136  
     * is selected using the name of the XML element to acquire
 137  
     * the associated converter. Once the converter has been acquired
 138  
     * it is delegated to and validated against it.
 139  
     * 
 140  
     * @param node this is the input XML element to be validated
 141  
     * 
 142  
     * @return this returns true if the node validates 
 143  
     */
 144  
    public boolean validate(InputNode node) throws Exception {
 145  14
       String name = node.getName();
 146  14
       String element = path.getElement(name);
 147  14
       Label label = elements.get(element);
 148  14
       Converter converter = label.getConverter(context);
 149  
       
 150  14
       return converter.validate(node);
 151  
    }
 152  
    
 153  
    /**
 154  
     * The <code>write</code> method uses the name of the XML element to
 155  
     * select a converter to be used to write the instance. Selection of
 156  
     * the converter is done by looking up the associated label from
 157  
     * the union group using the instance type. Once the converter has
 158  
     * been selected it is used to write the instance.
 159  
     * 
 160  
     * @param node this is the XML element used to write the instance
 161  
     * @param source this is the value that is to be written
 162  
     */
 163  
    public void write(OutputNode node, Object source) throws Exception {               
 164  34
       Map map = (Map) source;
 165  
 
 166  34
       if(group.isInline()) {
 167  24
          if(!map.isEmpty()) {
 168  23
             write(node, map);
 169  1
          } else if(!node.isCommitted()){
 170  1
             node.remove();
 171  
          }
 172  
       } else {
 173  10
          write(node, map);
 174  
       }
 175  34
    }
 176  
 
 177  
    /**
 178  
     * The <code>write</code> method uses the name of the XML element to
 179  
     * select a converter to be used to write the instance. Selection of
 180  
     * the converter is done by looking up the associated label from
 181  
     * the union group using the instance type. Once the converter has
 182  
     * been selected it is used to write the instance.
 183  
     * 
 184  
     * @param node this is the XML element used to write the instance
 185  
     * @param map this is the value that is to be written
 186  
     */
 187  
    private void write(OutputNode node, Map map) throws Exception {
 188  33
       for(Object key : map.keySet()) {
 189  115
          Object item = map.get(key);
 190  
          
 191  115
          if(item != null) {
 192  115
             Class real = item.getClass();
 193  115
             Label label = group.getLabel(real);
 194  
             
 195  115
             if(label == null) {               
 196  0
                throw new UnionException("Value of %s not declared in %s with annotation %s", real, type, group);
 197  
             }
 198  115
             write(node, key, item, label);
 199  
          }
 200  115
       }
 201  33
    }
 202  
    
 203  
    /**
 204  
     * The <code>write</code> method uses the name of the XML element to
 205  
     * select a converter to be used to write the instance. Selection of
 206  
     * the converter is done by looking up the associated label from
 207  
     * the union group using the instance type. Once the converter has
 208  
     * been selected it is used to write the instance.
 209  
     * 
 210  
     * @param node this is the XML element used to write the instance
 211  
     * @param key this is the key associated with the item to write
 212  
     * @param item this is the value associated with the item to write
 213  
     * @param label this is the label to used to acquire the converter     
 214  
     */
 215  
    private void write(OutputNode node, Object key, Object item, Label label) throws Exception {  
 216  115
       Converter converter = label.getConverter(context);
 217  115
       Map map = Collections.singletonMap(key, item);
 218  
       
 219  115
       if(!label.isInline()) {
 220  20
          String name = label.getName();
 221  20
          String root = style.getElement(name);
 222  
         
 223  20
          if(!node.isCommitted()) {
 224  10
             node.setName(root);
 225  
          }
 226  
       }
 227  115
       converter.write(node, map);   
 228  115
    }
 229  
 }