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 }