View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2003 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   *
35   * Date Author Changes 04/21/2003 Keith Visco Created
36   */
37  
38  package org.exolab.castor.util;
39  
40  import java.lang.reflect.Constructor;
41  import java.lang.reflect.InvocationTargetException;
42  
43  import org.exolab.castor.core.exceptions.CastorIllegalStateException;
44  
45  /**
46   * The default implementation of ObjectFactory used for creating class instances
47   * 
48   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
49   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
50   * @see ObjectFactory
51   */
52  public class DefaultObjectFactory implements ObjectFactory {
53  
54    /**
55     * Creates a default instance of the given class.
56     *
57     * @param type the Class to create an instance of
58     * @return the new instance of the given class
59     */
60    public Object createInstance(Class type) throws IllegalAccessException, InstantiationException {
61      return createInstance(type, null, null);
62    } // -- createInstance
63  
64    /**
65     * Creates a default instance of the given class.
66     *
67     * @param type the Class to create an instance of
68     * @param args the array of arguments to pass to the Class constructor
69     * @return the new instance of the given class
70     */
71    public Object createInstance(Class type, Object[] args)
72        throws IllegalAccessException, InstantiationException {
73      return createInstance(type, null, args);
74    } // -- createInstance
75  
76    /**
77     * Creates a default instance of the given class.
78     *
79     * @param type the Class to create an instance of
80     * @param argTypes the Class types for each argument, used to find the correct constructor
81     * @param args the array of arguments to pass to the Class constructor
82     * @return the new instance of the given class
83     */
84    public Object createInstance(Class type, Class[] argTypes, Object[] args)
85        throws IllegalAccessException, InstantiationException {
86      if ((args == null) || (args.length == 0)) {
87        if (java.util.Date.class.isAssignableFrom(type)) {
88          return handleDates(type);
89        }
90        return type.newInstance();
91      }
92  
93      argTypes = checkArguments(argTypes, args);
94  
95      return instantiateUsingConstructor(type, argTypes, args);
96  
97    } // -- createInstance
98  
99    /**
100    * Create a new instance of the given type by calling a public constructor of this class, passing
101    * the given arguments to the constructor call.
102    * 
103    * @param type The class type to instantiate
104    * @param argTypes Argument types.
105    * @param args Arguments (to be used as parameters to the constructor class).
106    * @return An instance of the class type provided
107    * @throws InstantiationException If the given class type does not expose a constructor with the
108    *         given number of argument (types).
109    * @throws IllegalAccessException If the given constructor failed during invocation.
110    */
111   private Object instantiateUsingConstructor(Class type, Class[] argTypes, Object[] args)
112       throws InstantiationException, IllegalAccessException {
113     try {
114       Constructor cons = type.getConstructor(argTypes);
115       return cons.newInstance(args);
116     } catch (java.lang.NoSuchMethodException nsmx) {
117       String err = "unable to find matching public constructor for class: " + type.getName();
118       err += " with argument types: ";
119       for (int i = 0; i < argTypes.length; i++) {
120         if (i > 0)
121           err += ", ";
122         err += argTypes[i].getName();
123       }
124       throw new InstantiationException(err);
125     } catch (InvocationTargetException ite) {
126       throw new CastorIllegalStateException(ite.getMessage(), ite.getTargetException());
127     }
128   }
129 
130   /**
131    * Check the arguments (incl. argument types, if provided) for consistency, and deduce argument
132    * types if not provided.
133    * 
134    * @param argTypes Argumemnt types.
135    * @param args Arguments
136    * @return A class array for the argument types provided.
137    */
138   private Class[] checkArguments(Class[] argTypes, Object[] args) {
139     if (argTypes == null) {
140       argTypes = new Class[args.length];
141       for (int i = 0; i < args.length; i++) {
142         if (args[i] != null) {
143           argTypes[i] = args[i].getClass();
144         } else {
145           String err =
146               "null arguments to constructor not accepted " + "if the 'argTypes' array is null.";
147           throw new IllegalStateException(getClass().getName() + ": " + err);
148         }
149       }
150     } else if (argTypes.length != args.length) {
151       String err = "The argument type array must be the same length as argument value array.";
152       throw new IllegalArgumentException(getClass().getName() + ": " + err);
153     }
154     return argTypes;
155   }
156 
157 
158   /**
159    * Handles 'Date' types in a special way.
160    * 
161    * @param type The Class type
162    * @return A new instance of the type given
163    * @throws InstantiationException If the given class type cannot be successfully instantiated.
164    * @throws IllegalAccessException If the given constructor failed during invocation.
165    */
166   private Object handleDates(Class type) throws IllegalAccessException, InstantiationException {
167 
168     java.util.Date date = new java.util.Date();
169 
170     if (java.util.Date.class == type) {
171       return date;
172     } else if (java.sql.Date.class == type) {
173       long time = date.getTime();
174       return new java.sql.Date(time);
175     } else if (java.sql.Time.class == type) {
176       long time = date.getTime();
177       return new java.sql.Time(time);
178     } else if (java.sql.Timestamp.class == type) {
179       long time = date.getTime();
180       return new java.sql.Timestamp(time);
181     } else {
182       return type.newInstance();
183     }
184 
185   } // -- handleDates
186 
187 } // -- DefaultObjectFactory