KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > beans > Statement


1 /*
2  * @(#)Statement.java 1.32 05/05/29
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package java.beans;
8
9 import java.lang.reflect.AccessibleObject JavaDoc;
10 import java.lang.reflect.Array JavaDoc;
11 import java.lang.reflect.Constructor JavaDoc;
12 import java.lang.reflect.InvocationTargetException JavaDoc;
13 import java.lang.reflect.Method JavaDoc;
14
15 import com.sun.beans.ObjectHandler;
16 import sun.reflect.misc.MethodUtil;
17
18 /**
19  * A <code>Statement</code> object represents a primitive statement
20  * in which a single method is applied to a target and
21  * a set of arguments - as in <code>"a.setFoo(b)"</code>.
22  * Note that where this example uses names
23  * to denote the target and its argument, a statement
24  * object does not require a name space and is constructed with
25  * the values themselves.
26  * The statement object associates the named method
27  * with its environment as a simple set of values:
28  * the target and an array of argument values.
29  *
30  * @since 1.4
31  *
32  * @version 1.32 05/29/05
33  * @author Philip Milne
34  */

35 public class Statement {
36
37     private static Object JavaDoc[] emptyArray = new Object JavaDoc[]{};
38
39     static ExceptionListener JavaDoc defaultExceptionListener = new ExceptionListener JavaDoc() {
40         public void exceptionThrown(Exception JavaDoc e) {
41             System.err.println(e);
42             // e.printStackTrace();
43
System.err.println("Continuing ...");
44         }
45     };
46
47     Object JavaDoc target;
48     String JavaDoc methodName;
49     Object JavaDoc[] arguments;
50
51     /**
52      * Creates a new <code>Statement</code> object with a <code>target</code>,
53      * <code>methodName</code> and <code>arguments</code> as per the parameters.
54      *
55      * @param target The target of this statement.
56      * @param methodName The methodName of this statement.
57      * @param arguments The arguments of this statement. If <code>null</code> then an empty array will be used.
58      *
59      */

60     public Statement(Object JavaDoc target, String JavaDoc methodName, Object JavaDoc[] arguments) {
61     this.target = target;
62         this.methodName = methodName;
63         this.arguments = (arguments == null) ? emptyArray : arguments;
64     }
65
66     /**
67      * Returns the target of this statement.
68      *
69      * @return The target of this statement.
70      */

71     public Object JavaDoc getTarget() {
72         return target;
73     }
74
75     /**
76      * Returns the name of the method.
77      *
78      * @return The name of the method.
79      */

80     public String JavaDoc getMethodName() {
81         return methodName;
82     }
83
84     /**
85      * Returns the arguments of this statement.
86      *
87      * @return the arguments of this statement.
88      */

89     public Object JavaDoc[] getArguments() {
90         return arguments;
91     }
92
93     /**
94      * The execute method finds a method whose name is the same
95      * as the methodName property, and invokes the method on
96      * the target.
97      *
98      * When the target's class defines many methods with the given name
99      * the implementation should choose the most specific method using
100      * the algorithm specified in the Java Language Specification
101      * (15.11). The dynamic class of the target and arguments are used
102      * in place of the compile-time type information and, like the
103      * <code>java.lang.reflect.Method</code> class itself, conversion between
104      * primitive values and their associated wrapper classes is handled
105      * internally.
106      * <p>
107      * The following method types are handled as special cases:
108      * <ul>
109      * <li>
110      * Static methods may be called by using a class object as the target.
111      * <li>
112      * The reserved method name "new" may be used to call a class's constructor
113      * as if all classes defined static "new" methods. Constructor invocations
114      * are typically considered <code>Expression</code>s rather than <code>Statement</code>s
115      * as they return a value.
116      * <li>
117      * The method names "get" and "set" defined in the <code>java.util.List</code>
118      * interface may also be applied to array instances, mapping to
119      * the static methods of the same name in the <code>Array</code> class.
120      * </ul>
121      */

122     public void execute() throws Exception JavaDoc {
123         invoke();
124     }
125
126     Object JavaDoc invoke() throws Exception JavaDoc {
127         Object JavaDoc target = getTarget();
128         String JavaDoc methodName = getMethodName();
129
130     if (target == null || methodName == null) {
131         throw new NullPointerException JavaDoc((target == null ? "target" :
132                         "methodName") + " should not be null");
133     }
134
135         Object JavaDoc[] arguments = getArguments();
136         // Class.forName() won't load classes outside
137
// of core from a class inside core. Special
138
// case this method.
139
if (target == Class JavaDoc.class && methodName.equals("forName")) {
140             return ObjectHandler.classForName((String JavaDoc)arguments[0]);
141         }
142
143         Class JavaDoc[] argClasses = new Class JavaDoc[arguments.length];
144         for(int i = 0; i < arguments.length; i++) {
145             argClasses[i] = (arguments[i] == null) ? null : arguments[i].getClass();
146         }
147
148         AccessibleObject JavaDoc m = null;
149         if (target instanceof Class JavaDoc) {
150             /*
151             For class methods, simluate the effect of a meta class
152             by taking the union of the static methods of the
153             actual class, with the instance methods of "Class.class"
154             and the overloaded "newInstance" methods defined by the
155             constructors.
156             This way "System.class", for example, will perform both
157             the static method getProperties() and the instance method
158             getSuperclass() defined in "Class.class".
159             */

160             if (methodName.equals("new")) {
161                 methodName = "newInstance";
162             }
163             // Provide a short form for array instantiation by faking an nary-constructor.
164
if (methodName.equals("newInstance") && ((Class JavaDoc)target).isArray()) {
165                 Object JavaDoc result = Array.newInstance(((Class JavaDoc)target).getComponentType(), arguments.length);
166                 for(int i = 0; i < arguments.length; i++) {
167                     Array.set(result, i, arguments[i]);
168                 }
169                 return result;
170             }
171             if (methodName.equals("newInstance") && arguments.length != 0) {
172                 // The Character class, as of 1.4, does not have a constructor
173
// which takes a String. All of the other "wrapper" classes
174
// for Java's primitive types have a String constructor so we
175
// fake such a constructor here so that this special case can be
176
// ignored elsewhere.
177
if (target == Character JavaDoc.class && arguments.length == 1 &&
178             argClasses[0] == String JavaDoc.class) {
179                     return new Character JavaDoc(((String JavaDoc)arguments[0]).charAt(0));
180                 }
181         m = ReflectionUtils.getConstructor((Class JavaDoc)target, argClasses);
182             }
183             if (m == null && target != Class JavaDoc.class) {
184                 m = ReflectionUtils.getMethod((Class JavaDoc)target, methodName, argClasses);
185             }
186             if (m == null) {
187         m = ReflectionUtils.getMethod(Class JavaDoc.class, methodName, argClasses);
188             }
189         }
190         else {
191             /*
192             This special casing of arrays is not necessary, but makes files
193             involving arrays much shorter and simplifies the archiving infrastrcure.
194             The Array.set() method introduces an unusual idea - that of a static method
195             changing the state of an instance. Normally statements with side
196             effects on objects are instance methods of the objects themselves
197             and we reinstate this rule (perhaps temporarily) by special-casing arrays.
198             */

199             if (target.getClass().isArray() &&
200         (methodName.equals("set") || methodName.equals("get"))) {
201                 int index = ((Integer JavaDoc)arguments[0]).intValue();
202                 if (methodName.equals("get")) {
203                     return Array.get(target, index);
204                 }
205                 else {
206                     Array.set(target, index, arguments[1]);
207                     return null;
208                 }
209             }
210             m = ReflectionUtils.getMethod(target.getClass(), methodName, argClasses);
211         }
212         if (m != null) {
213             try {
214                 if (m instanceof Method JavaDoc) {
215                     return MethodUtil.invoke((Method JavaDoc)m, target, arguments);
216         }
217                 else {
218                     return ((Constructor JavaDoc)m).newInstance(arguments);
219                 }
220             }
221             catch (IllegalAccessException JavaDoc iae) {
222                 throw new Exception JavaDoc("Statement cannot invoke: " +
223                     methodName + " on " + target.getClass(),
224                     iae);
225             }
226             catch (InvocationTargetException JavaDoc ite) {
227                 Throwable JavaDoc te = ite.getTargetException();
228                 if (te instanceof Exception JavaDoc) {
229                     throw (Exception JavaDoc)te;
230                 }
231                 else {
232                     throw ite;
233                 }
234             }
235         }
236         throw new NoSuchMethodException JavaDoc(toString());
237     }
238
239     String JavaDoc instanceName(Object JavaDoc instance) {
240     if (instance == null) {
241         return "null";
242     } else if (instance.getClass() == String JavaDoc.class) {
243         return "\""+(String JavaDoc)instance + "\"";
244     } else {
245         // Note: there is a minor problem with using the non-caching
246
// NameGenerator method. The return value will not have
247
// specific information about the inner class name. For example,
248
// In 1.4.2 an inner class would be represented as JList$1 now
249
// would be named Class.
250

251         return NameGenerator.unqualifiedClassName(instance.getClass());
252     }
253     }
254
255     /**
256      * Prints the value of this statement using a Java-style syntax.
257      */

258     public String JavaDoc toString() {
259         // Respect a subclass's implementation here.
260
Object JavaDoc target = getTarget();
261         String JavaDoc methodName = getMethodName();
262         Object JavaDoc[] arguments = getArguments();
263
264         StringBuffer JavaDoc result = new StringBuffer JavaDoc(instanceName(target) + "." + methodName + "(");
265         int n = arguments.length;
266         for(int i = 0; i < n; i++) {
267             result.append(instanceName(arguments[i]));
268             if (i != n -1) {
269                 result.append(", ");
270             }
271         }
272         result.append(");");
273         return result.toString();
274     }
275 }
276
Popular Tags