001    /*
002     *                    BioJava development code
003     *
004     * This code may be freely distributed and modified under the
005     * terms of the GNU Lesser General Public Licence.  This should
006     * be distributed with the code.  If you do not have a copy,
007     * see:
008     *
009     *      http://www.gnu.org/copyleft/lesser.html
010     *
011     * Copyright for this code is held jointly by the individual
012     * authors.  These should be listed in @author doc comments.
013     *
014     * For more information on the BioJava project and its aims,
015     * or to join the biojava-l mailing list, visit the home page
016     * at:
017     *
018     *      http://www.biojava.org/
019     *
020     */
021    package org.biojava.utils.bytecode;
022    
023    /**
024     * A template type.
025     *
026     * <p>Template types are resolved at code-generation type rather than at
027     * Instruction generation type. They let you bind the concrete type for opcodes
028     * at the last minute, so the same max conditional could be used for all
029     * primative types, with the type only being bound at the last moment.</p>
030     *
031     * <p>Two ParametricType instances are the same if they are the same object,
032     * regardless of their names.</p>
033     *
034     * @author Matthew Pocock
035     */
036    
037    public class ParametricType {
038      private static CodeClass[] OBJECT_CC;
039      
040      static {
041        OBJECT_CC = new CodeClass[] { IntrospectedCodeClass.forClass(Object.class) };
042      }
043      
044      /**
045       * Create a new ParametricType that claims nothing.
046       *
047       * @param name  the name given to this type
048       * @return a new ParametricType instance with that name
049       */
050      public static ParametricType createType(String name) {
051        return new ParametricType(name, false, false, false);
052      }
053      
054      /**
055       * Create a new ParametricType that claims to resolve to a primative type.
056       *
057       * @param name  the name given to this type
058       * @return a new ParametricType instance with that name
059       */
060      public static ParametricType createPrimitiveType(String name) {
061        return new ParametricType(name, true, false, false);
062      }
063      
064      /**
065       * Create a new ParametricType that claims to resolve to an object type.
066       *
067       * @param name  the name given to this type
068       * @return a new ParametricType instance with that name
069       */
070      public static ParametricType createObjectType(String name) {
071        return new ParametricType(name, false, true, false);
072      }
073      
074      /**
075       * Create a new ParametricType that claims to resolve to an array type. All
076       * array types are object types.
077       *
078       * @param name  the name given to this type
079       * @return a new ParametricType instance with that name
080       */
081      public static ParametricType createArrayType(String name) {
082        return new ParametricType(name, false, true, true);
083      }
084      
085      /**
086       * Create a new ParametricType that claims to be castable to all the classes
087       * in a list. Since neither Java nor bytecode support multiple inheritance,
088       * the classes must either be interfaces, or classes that fall into an
089       * inheritance path.
090       *
091       * @param name  the name given to this type
092       * @param classes an array of Class objects that any bound type must be
093       *   castable to
094       * @return a new ParametricType that can bind to classes with these properties
095       */
096      public static ParametricType createType(
097        String name,
098        CodeClass[] classes
099      ) {
100        return new ParametricType(name, classes);
101      }
102      
103      private final String name;
104      private final boolean isPrimitive;
105      private final boolean isObject;
106      private final boolean isArray;
107      private final CodeClass[] classes;
108      
109      private ParametricType(
110        String name,
111        boolean isPrimitive,
112        boolean isObject,
113        boolean isArray
114      ) {
115        this.name = name;
116        this.isPrimitive = isPrimitive;
117        this.isObject = isObject;
118        this.isArray = isArray;
119        if(isObject) {
120          this.classes = OBJECT_CC;
121        } else {
122          this.classes = CodeUtils.EMPTY_LIST;
123        }
124      }
125      
126      private ParametricType(
127        String name,
128        CodeClass[] classes
129      ) {
130        this.name = name;
131        this.classes = classes;
132        this.isObject = true;
133        this.isPrimitive = false;
134        this.isArray = false;
135      }
136      
137      /**
138       * Get the name of this type.
139       *
140       * Names are not unique.
141       *
142       * @return the name given to this type
143       */
144      public String getName() {
145        return name;
146      }
147      
148      /**
149       * Discover if this type must resolve to a primative.
150       *
151       * <p>It is an error for a parametric type to resolve to a non-primative if
152       * this flag is set.</p>
153       *
154       * @return true if this is guaranteed to resolve to a primative
155       */
156      public boolean isPrimitive() {
157        return isPrimitive;
158      }
159      
160      public boolean isObject() {
161        return isObject;
162      }
163      
164      public boolean isArray() {
165        return isArray;
166      }
167      
168      public boolean canAccept(CodeClass cc) {
169        if(cc.isArray() && this.isArray()) {
170          return true;
171        }
172        
173        if(!cc.isPrimitive() && this.isObject()) {
174          return true;
175        }
176        
177        if(cc.isPrimitive() && this.isPrimitive()) {
178          return true;
179        }
180        
181        return false;
182      }
183      
184      public CodeClass[] getClasses() {
185        return classes;
186      }
187      
188      public String toString() {
189        return "GenericType:" + name;
190      }
191    }