All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simpleframework.xml.core.CompositeListUnion Maven / Gradle / Ivy

Go to download

Simple is a high performance XML serialization and configuration framework for Java

The newest version!
/*
 * CompositeListUnion.java March 2011
 *
 * Copyright (C) 2011, Niall Gallagher 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.
 */

package org.simpleframework.xml.core;

import java.util.Collection;
import java.util.Collections;

import org.simpleframework.xml.strategy.Type;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;
import org.simpleframework.xml.stream.Style;

/**
 * The CompositeListUnion object is used to act as a 
 * mediator for multiple converters associated with a particular union 
 * group. This will basically determine which Converter 
 * should be delegated to based on either the XML element name being read 
 * or the type of the instance object being written. Selection of the 
 * converter is done by consulting the Group of labels 
 * representing the union declaration.
 * 
 * @author Niall Gallagher
 */
class CompositeListUnion implements Repeater {
   
   /**
    * This contains the labels in the union group keyed by name.
    */
   private final LabelMap elements;
   
   /**
    * This is the path expression used to represent this union.
    */
   private final Expression path;
   
   /**
    * This is the current context used for the serialization.
    */
   private final Context context;
   
   /**
    * This contains the group of labels associated with the union.
    */
   private final Group group;
   
   /**
    * This is this style associated with the serialization context.
    */
   private final Style style;
   
   /**
    * This is the type field or method annotated as a union.
    */
   private final Type type;

   /**
    * Constructor for the CompositeListUnion object. This
    * is used to create a converter that delegates to other associated
    * converters within the union group depending on the XML element
    * name being read or the instance type that is being written.
    * 
    * @param context this is the context used for the serialization
    * @param group this is the union group used for delegation
    * @param path this is the path expression representing this union
    * @param type this is the annotated field or method to be used
    */
   public CompositeListUnion(Context context, Group group, Expression path, Type type) throws Exception {
      this.elements = group.getElements();
      this.style = context.getStyle();
      this.context = context;
      this.group = group;
      this.type = type;
      this.path = path;
   }

   /**
    * The read method uses the name of the XML element to
    * select a converter to be used to read the instance. Selection of
    * the converter is done by looking up the associated label from
    * the union group using the element name. Once the converter has
    * been selected it is used to read the instance.
    * 
    * @param node this is the XML element used to read the instance
    * 
    * @return this is the instance that has been read by this
    */
   public Object read(InputNode node) throws Exception {
      Label text = group.getText();
      
      if(text == null) {
         return readElement(node);
      } 
      return readText(node);
   }
   
   /**
    * The readElement method uses the name of the element 
    * to select a converter to be used to read the instance. Selection 
    * of the converter is done by looking up the associated label from
    * the union group using the element name. Once the converter has
    * been selected it is used to read the instance.
    * 
    * @param node this is the XML element used to read the instance
    * 
    * @return this is the instance that has been read by this
    */
   private Object readElement(InputNode node) throws Exception {
      String name = node.getName();
      String element = path.getElement(name);
      Label label = elements.get(element);
      Converter converter = label.getConverter(context);
   
      return converter.read(node);
   }
   
   /**
    * The readText method is used to read free text from
    * between the declared elements and add them to a list. Consuming
    * free text in this manner enables an element list union to parse
    * unstructured XML such as XHTML.
    * 
    * @param node this is the node to consume the free text from
    * 
    * @return this returns the list with the text added to it
    */
   private Object readText(InputNode node) throws Exception {
      Label text = group.getText();
      Converter converter = text.getConverter(context);
      
      return converter.read(node);
   }

   /**
    * The read method uses the name of the XML element to
    * select a converter to be used to read the instance. Selection 
    * of the converter is done by looking up the associated label from
    * the union group using the element name. Once the converter has
    * been selected it is used to read the instance.
    * 
    * @param node this is the XML element used to read the instance
    * @param value this is the value that is to be repeated
    * 
    * @return this is the instance that has been read by this
    */
   public Object read(InputNode node, Object value) throws Exception {
      Object result = readElement(node, value);
      Label text = group.getText();
     
      if(text != null) {
         return readText(node, value);
      }
      return result;
   }
   
   /**
    * The readElement method uses the name of the element 
    * to select a converter to be used to read the instance. Selection 
    * of the converter is done by looking up the associated label from
    * the union group using the element name. Once the converter has
    * been selected it is used to read the instance.
    * 
    * @param node this is the XML element used to read the instance
    * @param value this is the value that is to be repeated
    * 
    * @return this is the instance that has been read by this
    */
   private Object readElement(InputNode node, Object value) throws Exception {
      String name = node.getName();
      String element = path.getElement(name);
      Label label = elements.get(element);
      Converter converter = label.getConverter(context);
      
      return converter.read(node, value);
   }
   
   /**
    * The readText method is used to read free text from
    * between the declared elements and add them to a list. Consuming
    * free text in this manner enables an element list union to parse
    * unstructured XML such as XHTML.
    * 
    * @param node this is the node to consume the free text from
    * @param value this is the value that is to be repeated
    * 
    * @return this returns the list with the text added to it
    */
   private Object readText(InputNode node, Object value) throws Exception {
      Label label = group.getText();
      Converter converter = label.getConverter(context);
      InputNode parent = node.getParent();
      
      return converter.read(parent, value);
   }
   
   /**
    * The validate method is used to validate the XML
    * element provided using an associated class schema. The schema
    * is selected using the name of the XML element to acquire
    * the associated converter. Once the converter has been acquired
    * it is delegated to and validated against it.
    * 
    * @param node this is the input XML element to be validated
    * 
    * @return this returns true if the node validates 
    */
   public boolean validate(InputNode node) throws Exception {
      String name = node.getName();
      String element = path.getElement(name);
      Label label = elements.get(element);
      Converter converter = label.getConverter(context);
      
      return converter.validate(node);
   }
   
   /**
    * The write method uses the name of the XML element to
    * select a converter to be used to write the instance. Selection of
    * the converter is done by looking up the associated label from
    * the union group using the instance type. Once the converter has
    * been selected it is used to write the instance.
    * 
    * @param source this is the source collection to be serialized 
    * @param node this is the XML element container to be populated
    */ 
   public void write(OutputNode node, Object source) throws Exception {
      Collection list = (Collection) source;                  
      
      if(group.isInline()) {
         if(!list.isEmpty()) {
            write(node, list);
         } else if(!node.isCommitted()){
            node.remove();
         }
      } else {
         write(node, list);
      }
   }

   /**
    * The write method uses the name of the XML element to
    * select a converter to be used to write the instance. Selection of
    * the converter is done by looking up the associated label from
    * the union group using the instance type. Once the converter has
    * been selected it is used to write the instance.
    * 
    * @param node this is the XML element used to write the instance
    * @param list this is the value that is to be written
    */
   private void write(OutputNode node, Collection list) throws Exception {     
      for(Object item : list) {
         if(item != null) {
            Class real = item.getClass();
            Label label = group.getLabel(real);
            
            if(label == null) {          
               throw new UnionException("Entry of %s not declared in %s with annotation %s", real, type, group);
            }
            write(node, item, label);
         }
      }
   }
      
   /**
    * The write method uses the name of the XML element to
    * select a converter to be used to write the instance. Selection of
    * the converter is done by looking up the associated label from
    * the union group using the instance type. Once the converter has
    * been selected it is used to write the instance.
    * 
    * @param node this is the XML element used to write the instance
    * @param item this is the individual list entry to be serialized
    * @param label this is the label to used to acquire the converter     
    */
   private void write(OutputNode node, Object item, Label label) throws Exception {
      Converter converter = label.getConverter(context);
      Collection list = Collections.singleton(item);

      if(!label.isInline()) {
         String name = label.getName();
         String root = style.getElement(name);
        
         if(!node.isCommitted()) {
            node.setName(root);
         }
      }
      converter.write(node, list);    
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy