View Javadoc

1   /*
2   $Id: ClassHelper.java,v 1.4 2006/01/19 00:06:51 blackdrag Exp $ 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.Range;
51  import groovy.lang.Reference;
52  import groovy.lang.Script;
53  
54  import java.math.BigDecimal;
55  import java.math.BigInteger;
56  import java.util.List;
57  import java.util.Map;
58  import java.util.regex.Pattern;
59  
60  import org.objectweb.asm.Opcodes;
61  
62  /***
63   * This class is a Helper for ClassNode and classes handling ClassNodes.
64   * It does contain a set of predefined ClassNodes for the most used 
65   * types and some code for cached ClassNode creation and basic 
66   * ClassNode handling 
67   * 
68   * @author Jochen Theodorou
69   */
70  public class ClassHelper {
71      
72  
73      private static String[] names = new String[] {
74          boolean.class.getName(),    char.class.getName(), 
75          byte.class.getName(),       short.class.getName(),
76          int.class.getName(),        long.class.getName(),
77          double.class.getName(),     float.class.getName(),
78          Object.class.getName(),     Void.TYPE.getName(),
79          Closure.class.getName(),    GString.class.getName(),
80          List.class.getName(),       Map.class.getName(),
81          Range.class.getName(),      Pattern.class.getName(),
82          Script.class.getName(),     String.class.getName(),
83          Boolean.class.getName(),    Character.class.getName(),
84          Byte.class.getName(),       Short.class.getName(),
85          Integer.class.getName(),    Long.class.getName(),
86          Double.class.getName(),     Float.class.getName(),
87          BigDecimal.class.getName(), BigInteger.class.getName(),
88          Void.class.getName(),       Reference.class.getName()
89      };
90      
91      private static Class[] classes = new Class[] {
92          Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
93          Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
94          Closure.class, GString.class, List.class, Map.class, Range.class,
95          Pattern.class, Script.class, String.class,  Boolean.class, 
96          Character.class, Byte.class, Short.class, Integer.class, Long.class,
97          Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
98          Reference.class
99      };
100     
101     public static final ClassNode 
102         DYNAMIC_TYPE = new ClassNode(Object.class),  OBJECT_TYPE = DYNAMIC_TYPE,
103         VOID_TYPE = new ClassNode(Void.TYPE),        CLOSURE_TYPE = new ClassNode(Closure.class),
104         GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
105         MAP_TYPE = new ClassNode(Map.class),         RANGE_TYPE = new ClassNode(Range.class),
106         PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
107         SCRIPT_TYPE = new ClassNode(Script.class),   REFERENCE_TYPE = new ClassNode(Reference.class),
108         
109         boolean_TYPE = new ClassNode(boolean.class),     char_TYPE = new ClassNode(char.class),
110         byte_TYPE = new ClassNode(byte.class),           int_TYPE = new ClassNode(int.class),
111         long_TYPE = new ClassNode(long.class),           short_TYPE = new ClassNode(short.class),
112         double_TYPE = new ClassNode(double.class),       float_TYPE = new ClassNode(float.class),
113         Byte_TYPE = new ClassNode(Byte.class),           Short_TYPE = new ClassNode(Short.class),
114         Integer_TYPE = new ClassNode(Integer.class),     Long_TYPE = new ClassNode(Long.class),
115         Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
116         Double_TYPE = new ClassNode(Double.class),       Boolean_TYPE = new ClassNode(Boolean.class),
117         BigInteger_TYPE =  new ClassNode(java.math.BigInteger.class),
118         BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
119         void_WRAPPER_TYPE = new ClassNode(Void.class);
120         
121     
122     private static ClassNode[] types = new ClassNode[] {
123         OBJECT_TYPE,
124         boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
125         int_TYPE, long_TYPE, double_TYPE, float_TYPE,
126         VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
127         LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
128         SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
129         Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
130         Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE, 
131         void_WRAPPER_TYPE, REFERENCE_TYPE
132     };
133 
134     
135     private static ClassNode[] numbers = new ClassNode[] {
136         char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE, 
137         double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
138         Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
139         BigDecimal_TYPE
140     };
141 
142     protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
143     
144     public static final String OBJECT = "java.lang.Object";    
145     
146     
147     /***
148      * Creates an array of ClassNodes using an array of classes.
149      * For each of the given classes a new ClassNode will be 
150      * created
151      * @see #make(Class)
152      * @param classes an array of classes used to create the ClassNodes
153      * @return an array of ClassNodes
154      */
155     public static ClassNode[] make(Class[] classes) {
156     	ClassNode[] cns = new ClassNode[classes.length];
157     	for (int i=0; i<cns.length; i++) {
158     		cns[i] = make(classes[i]);
159     	}
160     	
161     	return cns;
162     }
163     
164     /***
165      * Creates a ClassNode using a given class.
166      * A new ClassNode object is only created if the class
167      * is not one of the predefined ones
168      * 
169      * @param c class used to created the ClassNode
170      * @return ClassNode instance created from the given class
171      */
172     public static ClassNode make(Class c) {
173         for (int i=0; i<classes.length; i++) {
174             if (c==classes[i]) return types[i];
175         }
176         if (c.isArray()) {
177             ClassNode cn = make(c.getComponentType());
178             return cn.makeArray();
179         }
180         ClassNode t = new ClassNode(c);
181         return t;
182     }
183     
184     /***
185      * Creates a ClassNode using a given class.
186      * Unlike make(String) this method will not use the cache
187      * to create the ClassNode. This means to ClassNode created
188      * from this method using the same name will have a different
189      * reference
190      * 
191      * @see #make(String)
192      * @param name of the class the ClassNode is representing
193      */
194     public static ClassNode makeWithoutCaching(String name) { 
195         ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
196         cn.isPrimaryNode = false;
197         return cn;
198     }
199     
200     /***
201      * Creates a ClassNode using a given class.
202      * If the name is one of the predefined ClassNodes then the 
203      * corresponding ClassNode instance will be returned. If the
204      * is null of of length 0 the dynamic type is returned
205      * 
206      * @param name of the class the ClassNode is representing
207      */
208     public static ClassNode make(String name) {
209         if (name == null || name.length() == 0) return DYNAMIC_TYPE;
210         
211         for (int i=0; i<classes.length; i++) {
212             String cname = classes[i].getName();
213             if (name.equals(cname)) return types[i];
214         }        
215         return makeWithoutCaching(name);
216     }
217     
218     /***
219      * Creates a ClassNode containing the wrapper of a ClassNode 
220      * of primitive type. Any ClassNode representing a primitive
221      * type should be created using the predefined types used in
222      * class. The method will check the parameter for known 
223      * references of ClassNode representing a primitive type. If
224      * Reference is found, then a ClassNode will be contained that
225      * represents the wrapper class. For exmaple for boolean, the 
226      * wrapper class is java.lang.Boolean.
227      * 
228      * If the parameter is no primitve type, the redirected 
229      * ClassNode will be returned 
230      *   
231      * @see #make(Class)
232      * @see #make(String)
233      * @param cn the ClassNode containing a possible primitive type
234      */
235     public static ClassNode getWrapper(ClassNode cn) {
236         cn = cn.redirect();
237         if (!isPrimitiveType(cn)) return cn;
238         if (cn==boolean_TYPE) {
239             return Boolean_TYPE;
240         } else if (cn==byte_TYPE) {
241             return Byte_TYPE;
242         } else if (cn==char_TYPE) {
243             return Character_TYPE;
244         } else if (cn==short_TYPE) {
245             return Short_TYPE;
246         } else if (cn==int_TYPE) {
247             return Integer_TYPE;
248         } else if (cn==long_TYPE) {
249             return Long_TYPE;
250         } else if (cn==float_TYPE) {
251             return Float_TYPE;
252         } else if (cn==double_TYPE) {
253             return Double_TYPE;
254         } else if (cn==VOID_TYPE) {
255         	return void_WRAPPER_TYPE;
256         }
257         else {
258             return cn;
259         }
260     }
261     
262     /***
263      * Test to determine if a ClasNode is a primitve type. 
264      * Note: this only works for ClassNodes created using a
265      * predefined ClassNode
266      * 
267      * @see #make(Class)
268      * @see #make(String)
269      * @param cn the ClassNode containing a possible primitive type
270      * @return true if the ClassNode is a primitve type
271      */
272     public static boolean isPrimitiveType(ClassNode cn) {
273         return  cn == boolean_TYPE ||
274                 cn == char_TYPE ||
275                 cn == byte_TYPE ||
276                 cn == short_TYPE ||
277                 cn == int_TYPE ||
278                 cn == long_TYPE ||
279                 cn == float_TYPE ||
280                 cn == double_TYPE ||
281                 cn == VOID_TYPE;
282     }
283 
284     public static ClassNode makeReference() {
285         return make(Reference.class);
286     }
287 
288 }