View Javadoc

1   /*
2   $Id: ClassHelper.java 4215 2006-11-13 11:18:35Z blackdrag $ created on 25.10.2005
3   
4   Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6   Redistribution and use of this software and associated documentation
7   ("Software"), with or without modification, are permitted provided
8   that the following conditions are met:
9   
10  1. Redistributions of source code must retain copyright
11     statements and notices.  Redistributions must also contain a
12     copy of this document.
13  
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18  
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus.  For written permission,
22     please contact info@codehaus.org.
23  
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28  
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31  
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44  */
45  
46  package org.codehaus.groovy.ast;
47  
48  import groovy.lang.Closure;
49  import groovy.lang.GString;
50  import groovy.lang.MetaClass;
51  import groovy.lang.Range;
52  import groovy.lang.Reference;
53  import groovy.lang.Script;
54  
55  import java.math.BigDecimal;
56  import java.math.BigInteger;
57  import java.util.List;
58  import java.util.Map;
59  import java.util.regex.Pattern;
60  
61  import org.objectweb.asm.Opcodes;
62  
63  /***
64   * This class is a Helper for ClassNode and classes handling ClassNodes.
65   * It does contain a set of predefined ClassNodes for the most used 
66   * types and some code for cached ClassNode creation and basic 
67   * ClassNode handling 
68   * 
69   * @author Jochen Theodorou
70   */
71  public class ClassHelper {
72      
73  
74      private static String[] names = new String[] {
75          boolean.class.getName(),    char.class.getName(), 
76          byte.class.getName(),       short.class.getName(),
77          int.class.getName(),        long.class.getName(),
78          double.class.getName(),     float.class.getName(),
79          Object.class.getName(),     Void.TYPE.getName(),
80          Closure.class.getName(),    GString.class.getName(),
81          List.class.getName(),       Map.class.getName(),
82          Range.class.getName(),      Pattern.class.getName(),
83          Script.class.getName(),     String.class.getName(),
84          Boolean.class.getName(),    Character.class.getName(),
85          Byte.class.getName(),       Short.class.getName(),
86          Integer.class.getName(),    Long.class.getName(),
87          Double.class.getName(),     Float.class.getName(),
88          BigDecimal.class.getName(), BigInteger.class.getName(),
89          Void.class.getName(),       Reference.class.getName(),
90          Class.class.getName(),      MetaClass.class.getName()
91      };
92      
93      private static Class[] classes = new Class[] {
94          Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
95          Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
96          Closure.class, GString.class, List.class, Map.class, Range.class,
97          Pattern.class, Script.class, String.class,  Boolean.class, 
98          Character.class, Byte.class, Short.class, Integer.class, Long.class,
99          Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
100         Reference.class, Class.class, MetaClass.class
101     };
102     
103     public static final ClassNode 
104         DYNAMIC_TYPE = new ClassNode(Object.class),  OBJECT_TYPE = DYNAMIC_TYPE,
105         VOID_TYPE = new ClassNode(Void.TYPE),        CLOSURE_TYPE = new ClassNode(Closure.class),
106         GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
107         MAP_TYPE = new ClassNode(Map.class),         RANGE_TYPE = new ClassNode(Range.class),
108         PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
109         SCRIPT_TYPE = new ClassNode(Script.class),   REFERENCE_TYPE = new ClassNode(Reference.class),
110         
111         boolean_TYPE = new ClassNode(boolean.class),     char_TYPE = new ClassNode(char.class),
112         byte_TYPE = new ClassNode(byte.class),           int_TYPE = new ClassNode(int.class),
113         long_TYPE = new ClassNode(long.class),           short_TYPE = new ClassNode(short.class),
114         double_TYPE = new ClassNode(double.class),       float_TYPE = new ClassNode(float.class),
115         Byte_TYPE = new ClassNode(Byte.class),           Short_TYPE = new ClassNode(Short.class),
116         Integer_TYPE = new ClassNode(Integer.class),     Long_TYPE = new ClassNode(Long.class),
117         Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
118         Double_TYPE = new ClassNode(Double.class),       Boolean_TYPE = new ClassNode(Boolean.class),
119         BigInteger_TYPE =  new ClassNode(java.math.BigInteger.class),
120         BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
121         void_WRAPPER_TYPE = new ClassNode(Void.class),   
122         
123         CLASS_Type = new ClassNode(Class.class),        METACLASS_TYPE = new ClassNode(MetaClass.class);
124         
125     
126     private static ClassNode[] types = new ClassNode[] {
127         OBJECT_TYPE,
128         boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
129         int_TYPE, long_TYPE, double_TYPE, float_TYPE,
130         VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
131         LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
132         SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
133         Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
134         Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE, 
135         void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE
136     };
137 
138     
139     private static ClassNode[] numbers = new ClassNode[] {
140         char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE, 
141         double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
142         Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
143         BigDecimal_TYPE
144     };
145 
146     protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
147     
148     public static final String OBJECT = "java.lang.Object";    
149     
150     
151     /***
152      * Creates an array of ClassNodes using an array of classes.
153      * For each of the given classes a new ClassNode will be 
154      * created
155      * @see #make(Class)
156      * @param classes an array of classes used to create the ClassNodes
157      * @return an array of ClassNodes
158      */
159     public static ClassNode[] make(Class[] classes) {
160     	ClassNode[] cns = new ClassNode[classes.length];
161     	for (int i=0; i<cns.length; i++) {
162     		cns[i] = make(classes[i]);
163     	}
164     	
165     	return cns;
166     }
167     
168     /***
169      * Creates a ClassNode using a given class.
170      * A new ClassNode object is only created if the class
171      * is not one of the predefined ones
172      * 
173      * @param c class used to created the ClassNode
174      * @return ClassNode instance created from the given class
175      */
176     public static ClassNode make(Class c) {
177         for (int i=0; i<classes.length; i++) {
178             if (c==classes[i]) return types[i];
179         }
180         if (c.isArray()) {
181             ClassNode cn = make(c.getComponentType());
182             return cn.makeArray();
183         }
184         ClassNode t = new ClassNode(c);
185         return t;
186     }
187     
188     /***
189      * Creates a ClassNode using a given class.
190      * Unlike make(String) this method will not use the cache
191      * to create the ClassNode. This means the ClassNode created
192      * from this method using the same name will have a different
193      * references
194      * 
195      * @see #make(String)
196      * @param name of the class the ClassNode is representing
197      */
198     public static ClassNode makeWithoutCaching(String name) { 
199         ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
200         cn.isPrimaryNode = false;
201         return cn;
202     }
203     
204     /***
205      * Creates a ClassNode using a given class.
206      * If the name is one of the predefined ClassNodes then the 
207      * corresponding ClassNode instance will be returned. If the
208      * is null of of length 0 the dynamic type is returned
209      * 
210      * @param name of the class the ClassNode is representing
211      */
212     public static ClassNode make(String name) {
213         if (name == null || name.length() == 0) return DYNAMIC_TYPE;
214         
215         for (int i=0; i<classes.length; i++) {
216             String cname = classes[i].getName();
217             if (name.equals(cname)) return types[i];
218         }        
219         return makeWithoutCaching(name);
220     }
221     
222     /***
223      * Creates a ClassNode containing the wrapper of a ClassNode 
224      * of primitive type. Any ClassNode representing a primitive
225      * type should be created using the predefined types used in
226      * class. The method will check the parameter for known 
227      * references of ClassNode representing a primitive type. If
228      * Reference is found, then a ClassNode will be contained that
229      * represents the wrapper class. For exmaple for boolean, the 
230      * wrapper class is java.lang.Boolean.
231      * 
232      * If the parameter is no primitve type, the redirected 
233      * ClassNode will be returned 
234      *   
235      * @see #make(Class)
236      * @see #make(String)
237      * @param cn the ClassNode containing a possible primitive type
238      */
239     public static ClassNode getWrapper(ClassNode cn) {
240         cn = cn.redirect();
241         if (!isPrimitiveType(cn)) return cn;
242         if (cn==boolean_TYPE) {
243             return Boolean_TYPE;
244         } else if (cn==byte_TYPE) {
245             return Byte_TYPE;
246         } else if (cn==char_TYPE) {
247             return Character_TYPE;
248         } else if (cn==short_TYPE) {
249             return Short_TYPE;
250         } else if (cn==int_TYPE) {
251             return Integer_TYPE;
252         } else if (cn==long_TYPE) {
253             return Long_TYPE;
254         } else if (cn==float_TYPE) {
255             return Float_TYPE;
256         } else if (cn==double_TYPE) {
257             return Double_TYPE;
258         } else if (cn==VOID_TYPE) {
259         	return void_WRAPPER_TYPE;
260         }
261         else {
262             return cn;
263         }
264     }
265     
266     /***
267      * Test to determine if a ClasNode is a primitve type. 
268      * Note: this only works for ClassNodes created using a
269      * predefined ClassNode
270      * 
271      * @see #make(Class)
272      * @see #make(String)
273      * @param cn the ClassNode containing a possible primitive type
274      * @return true if the ClassNode is a primitve type
275      */
276     public static boolean isPrimitiveType(ClassNode cn) {
277         return  cn == boolean_TYPE ||
278                 cn == char_TYPE ||
279                 cn == byte_TYPE ||
280                 cn == short_TYPE ||
281                 cn == int_TYPE ||
282                 cn == long_TYPE ||
283                 cn == float_TYPE ||
284                 cn == double_TYPE ||
285                 cn == VOID_TYPE;
286     }
287 
288     public static ClassNode makeReference() {
289         return make(Reference.class);
290     }
291 
292 }