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 */
021package 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
037public 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}