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

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

Go to download

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

There is a newer version: 2.7.1
Show newest version
/*
 * Factory.java July 2006
 *
 * Copyright (C) 2006, Niall Gallagher 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA  02111-1307  USA
 */

package org.simpleframework.xml.core;

import java.lang.reflect.Modifier;

import org.simpleframework.xml.strategy.Value;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;

/**
 * The Factory object provides a base class for factories 
 * used to produce field values from XML elements. The goal of this 
 * type of factory is to make use of the Strategy object
 * to determine the type of the field value. The strategy class must be 
 * assignable to the field class type, that is, it must extend it or
 * implement it if it represents an interface. If the strategy returns
 * a null Value then the subclass implementation determines 
 * the type used to populate the object field value.
 * 
 * @author Niall Gallagher
 */
abstract class Factory {
   
   /**
    * This is the context object used for the serialization process.
    */
   protected Context context;
   
   /**
    * This is used to translate all of the primitive type strings.
    */
   protected Support support;
   
   /**
    * This is the field type that the class must be assignable to.
    */
   protected Class field;        

   /**
    * Constructor for the Factory object. This is given 
    * the class type for the field that this factory will determine
    * the actual type for. The actual type must be assignable to the
    * field type to insure that any instance can be set. 
    * 
    * @param context the contextual object used by the persister
    * @param field this is the field type to determine the value of
    */
   protected Factory(Context context, Class field) {
      this.support = context.getSupport();
      this.context = context;           
      this.field = field;           
   }
   
   /**
    * This is used to create a default instance of the field type. It
    * is up to the subclass to determine how to best instantiate an
    * object of the field type that best suits. This is used when the
    * empty value is required or to create the default type instance.
    * 
    * @return a type which is used to instantiate the collection     
    */
   public Object getInstance() throws Exception {
      return field.newInstance();
   }

   /**
    * This is used to get a possible override from the provided node.
    * If the node provided is an element then this checks for a  
    * specific class override using the Strategy object.
    * If the strategy cannot resolve a class then this will return 
    * null. If the resolved Value is not assignable to 
    * the field then this will thrown an exception.
    * 
    * @param node this is the node used to search for the override
    * 
    * @return this returns null if no override type can be found
    * 
    * @throws Exception if the override type is not compatible
    */
   protected Value getOverride(InputNode node) throws Exception {
      Value value = getConversion(node);      

      if(value != null) { 
         Class type = value.getType();
     
         if(!isCompatible(field, type)) {
            throw new InstantiationException("Type %s is not compatible with %s", type, field);              
         }
      }         
      return value; 
   }
   
   /**
    * This method is used to set the override class within an element.
    * This delegates to the Strategy implementation, which
    * depending on the implementation may add an attribute of a child
    * element to describe the type of the object provided to this.
    * 
    * @param field this is the class of the field type being serialized
    * @param node the XML element that is to be given the details
    *
    * @throws Exception thrown if an error occurs within the strategy
    */
   public boolean setOverride(Class field, Object value, OutputNode node) throws Exception {
      if(!field.isPrimitive()) {
         return context.setOverride(field, value, node);
      }
      return false;
   }

   /**
    * This performs the conversion from the element node to a type. This
    * is where the Strategy object is consulted and asked
    * for a class that will represent the provided XML element. This will,
    * depending on the strategy implementation, make use of attributes
    * and/or elements to determine the type for the field.
    * 
    * @param node this is the element used to extract the override
    * 
    * @return this returns null if no override type can be found
    * 
    * @throws Exception thrown if the override class cannot be loaded    
    */ 
   public Value getConversion(InputNode node) throws Exception {
      return context.getOverride(field, node);
   }
   
   /**
    * This is used to determine whether the provided base class can be
    * assigned from the issued type. For an override to be compatible
    * with the field type an instance of the override type must be 
    * assignable to the field value. 
    * 
    * @param field this is the field value present the the object    
    * @param type this is the specialized type that will be assigned
    * 
    * @return true if the field type can be assigned the type value
    */
   public static boolean isCompatible(Class field, Class type) {
      if(field.isArray()) {
         field = field.getComponentType();
      }
      return field.isAssignableFrom(type);           
   }

   /**
    * This is used to determine whether the type given is instantiable,
    * that is, this determines if an instance of that type can be
    * created. If the type is an interface or an abstract class then 
    * this will return false.
    * 
    * @param type this is the type to check the modifiers of
    * 
    * @return false if the type is an interface or an abstract class
    */
   public static boolean isInstantiable(Class type) {
      int modifiers = type.getModifiers();

      if(Modifier.isAbstract(modifiers)) {
         return false;              
      }              
      return !Modifier.isInterface(modifiers);
   } 
}           




© 2015 - 2024 Weber Informatics LLC | Privacy Policy