Forgot a few files, whoops.

Patch by: me, jat, mmendez

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1449 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/HasBounds.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/HasBounds.java
new file mode 100644
index 0000000..b5fd866
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/HasBounds.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo;
+
+/**
+ * Interface implemented by elements that can have can have have bounds, namely
+ * type parameters and wildcards.
+ */
+public interface HasBounds {
+
+  /**
+   * Returns the bounds on this element.
+   * 
+   * @return the bounds of this element; cannot be null
+   */
+  JBound getBounds();
+
+  /**
+   * Returns the first bound of this element.
+   * 
+   * @return the first bound of this element; cannot be null
+   */
+  JClassType getFirstBound();
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/HasTypeParameters.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/HasTypeParameters.java
new file mode 100644
index 0000000..54108e1
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/HasTypeParameters.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo;
+
+/**
+ * Interface implemented by elements that can have can have type parameters,
+ * namely classes and methods.
+ */
+public interface HasTypeParameters {
+
+  /**
+   * Returns the type parameters on this element.
+   * 
+   * @return the type parameters on this element, or zero-sized array if this
+   *         element is not generic
+   */
+  JTypeParameter[] getTypeParameters();
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
new file mode 100644
index 0000000..0668c13
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+/**
+ * Base class for types that delegate to another type, such as a JTypeParameter
+ * or JParameterizedType.
+ */
+abstract class JDelegatingClassType extends JClassType {
+
+  protected JClassType baseType;
+
+  JDelegatingClassType() {
+  }
+
+  @Override
+  public final void addImplementedInterface(JClassType intf) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  public final void addMetaData(String tagName, String[] values) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  public final void addModifierBits(int bits) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  /**
+   * Delegating types generally cannot be constructed.
+   */
+  @Override
+  public JConstructor findConstructor(JType[] paramTypes) {
+    return null;
+  }
+
+  /**
+   * Subclasses will generally need to echo modified fields.
+   */
+  @Override
+  public abstract JField findField(String name);
+
+  /**
+   * Subclasses will generally need to echo modified methods.
+   */
+  @Override
+  public abstract JMethod findMethod(String name, JType[] paramTypes);
+
+  @Override
+  public JClassType findNestedType(String typeName) {
+    return baseType.findNestedType(typeName);
+  }
+
+  @Override
+  public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+    return baseType.getAnnotation(annotationClass);
+  }
+
+  @Override
+  public Annotation[] getAnnotations() {
+    return baseType.getAnnotations();
+  }
+
+  @Override
+  public int getBodyEnd() {
+    return baseType.getBodyEnd();
+  }
+
+  @Override
+  public int getBodyStart() {
+    return baseType.getBodyStart();
+  }
+
+  @Override
+  public CompilationUnitProvider getCompilationUnit() {
+    return baseType.getCompilationUnit();
+  }
+
+  /**
+   * Delegating types generally cannot be constructed.
+   */
+  @Override
+  public JConstructor getConstructor(JType[] paramTypes)
+      throws NotFoundException {
+    throw new NotFoundException();
+  }
+
+  /**
+   * Delegating types generally cannot be constructed.
+   */
+  @Override
+  public JConstructor[] getConstructors() {
+    return TypeOracle.NO_JCTORS;
+  }
+
+  @Override
+  public Annotation[] getDeclaredAnnotations() {
+    return baseType.getDeclaredAnnotations();
+  }
+
+  @Override
+  public JClassType getEnclosingType() {
+    return baseType.getEnclosingType();
+  }
+
+  public JClassType getErasedType() {
+    return baseType.getErasedType();
+  }
+
+  /**
+   * Subclasses will generally need to echo modified fields.
+   */
+  @Override
+  public abstract JField getField(String name);
+
+  /**
+   * Subclasses will generally need to echo modified fields.
+   */
+  @Override
+  public abstract JField[] getFields();
+
+  @Override
+  public JClassType[] getImplementedInterfaces() {
+    return baseType.getImplementedInterfaces();
+  }
+
+  @Override
+  public String getJNISignature() {
+    return baseType.getJNISignature();
+  }
+
+  @Override
+  public String[][] getMetaData(String tagName) {
+    return baseType.getMetaData(tagName);
+  }
+
+  @Override
+  public String[] getMetaDataTags() {
+    return baseType.getMetaDataTags();
+  }
+
+  /**
+   * Subclasses will generally need to echo modified methods.
+   */
+  @Override
+  public abstract JMethod getMethod(String name, JType[] paramTypes)
+      throws NotFoundException;
+
+  /**
+   * Subclasses will generally need to echo modified methods.
+   */
+  @Override
+  public abstract JMethod[] getMethods();
+
+  @Override
+  public String getName() {
+    return baseType.getName();
+  }
+
+  @Override
+  public JClassType getNestedType(String typeName) throws NotFoundException {
+    return baseType.getNestedType(typeName);
+  }
+
+  @Override
+  public JClassType[] getNestedTypes() {
+    return baseType.getNestedTypes();
+  }
+
+  @Override
+  public TypeOracle getOracle() {
+    return baseType.getOracle();
+  }
+
+  @Override
+  public JMethod[] getOverloads(String name) {
+    return baseType.getOverloads(name);
+  }
+
+  @Override
+  public JMethod[] getOverridableMethods() {
+    return baseType.getOverridableMethods();
+  }
+
+  @Override
+  public JPackage getPackage() {
+    return baseType.getPackage();
+  }
+
+  @Override
+  public JClassType[] getSubtypes() {
+    return baseType.getSubtypes();
+  }
+
+  @Override
+  public JClassType getSuperclass() {
+    return baseType.getSuperclass();
+  }
+
+  /**
+   * TODO: What is this???
+   */
+  @Override
+  public String getTypeHash() throws UnableToCompleteException {
+    return baseType.getTypeHash();
+  }
+
+  @Override
+  public int hashCode() {
+    return baseType.hashCode();
+  }
+
+  @Override
+  public boolean isAbstract() {
+    return baseType.isAbstract();
+  }
+
+  @Override
+  public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+    return baseType.isAnnotationPresent(annotationClass);
+  }
+
+  @Override
+  public final JArrayType isArray() {
+    return null;
+  }
+
+  @Override
+  public boolean isAssignableFrom(JClassType possibleSubtype) {
+    return baseType.isAssignableFrom(possibleSubtype);
+  }
+
+  @Override
+  public boolean isAssignableTo(JClassType possibleSupertype) {
+    return baseType.isAssignableTo(possibleSupertype);
+  }
+
+  @Override
+  public JClassType isClass() {
+    return baseType.isClass();
+  }
+
+  @Override
+  public JClassType isClassOrInterface() {
+    return baseType.isClassOrInterface();
+  }
+
+  @Override
+  public boolean isDefaultInstantiable() {
+    return baseType.isDefaultInstantiable();
+  }
+
+  @Override
+  public JClassType isInterface() {
+    return baseType.isInterface();
+  }
+
+  @Override
+  public boolean isLocalType() {
+    return baseType.isLocalType();
+  }
+
+  @Override
+  public boolean isMemberType() {
+    return baseType.isMemberType();
+  }
+
+  @Override
+  public final JPrimitiveType isPrimitive() {
+    return null;
+  }
+
+  @Override
+  public boolean isPrivate() {
+    return baseType.isPrivate();
+  }
+
+  @Override
+  public boolean isProtected() {
+    return baseType.isProtected();
+  }
+
+  @Override
+  public boolean isPublic() {
+    return baseType.isPublic();
+  }
+
+  @Override
+  public boolean isStatic() {
+    return baseType.isStatic();
+  }
+
+  @Override
+  public void setSuperclass(JClassType type) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  public String toString() {
+    if (baseType.isInterface() != null) {
+      return "interface " + getQualifiedSourceName();
+    } else {
+      return "class " + getQualifiedSourceName();
+    }
+  }
+
+  @Override
+  protected void acceptSubtype(JClassType me) {
+    baseType.acceptSubtype(me);
+  }
+
+  @Override
+  protected int getModifierBits() {
+    return baseType.getModifierBits();
+  }
+
+  @Override
+  protected void getOverridableMethodsOnSuperclassesAndThisClass(
+      Map<String, JMethod> methodsBySignature) {
+    baseType.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature);
+  }
+
+  @Override
+  protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(
+      Map<String, JMethod> methodsBySignature) {
+    baseType.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature);
+  }
+
+  @Override
+  protected void notifySuperTypesOf(JClassType me) {
+  }
+
+  @Override
+  protected void removeSubtype(JClassType me) {
+  }
+
+  @Override
+  final void addConstructor(JConstructor ctor) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  final void addField(JField field) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  final void addMethod(JMethod method) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  final void addNestedType(JClassType type) {
+    throw new UnsupportedOperationException("modifying a "
+        + getClass().getSimpleName());
+  }
+
+  @Override
+  JClassType findNestedTypeImpl(String[] typeName, int index) {
+    return baseType.findNestedTypeImpl(typeName, index);
+  }
+
+  @Override
+  void notifySuperTypes() {
+  }
+
+  @Override
+  void removeFromSupertypes() {
+  }
+
+  final void setBaseType(JClassType baseType) {
+    this.baseType = baseType;
+  }
+
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
new file mode 100644
index 0000000..4347df4
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -0,0 +1,699 @@
+/*
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.util.Util;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * Type representing a Java class or interface type.
+ */
+public class JRealClassType extends JClassType {
+
+  private final Set<JClassType> allSubtypes = new HashSet<JClassType>();
+
+  private final Annotations annotations = new Annotations();
+
+  private final int bodyEnd;
+
+  private final int bodyStart;
+
+  private JMethod[] cachedOverridableMethods;
+
+  private final List<JConstructor> constructors = new ArrayList<JConstructor>();
+
+  private final CompilationUnitProvider cup;
+
+  private final JPackage declaringPackage;
+
+  private final int declEnd;
+
+  private final int declStart;
+
+  private final JClassType enclosingType;
+
+  private final Map<String, JField> fields = new HashMap<String, JField>();
+
+  private final List<JClassType> interfaces = new ArrayList<JClassType>();
+
+  private final boolean isInterface;
+
+  private final boolean isLocalType;
+
+  private String lazyHash;
+
+  private String lazyQualifiedName;
+
+  private final HasMetaData metaData = new MetaData();
+
+  private final Map<String, List<JMethod>> methods = new HashMap<String, List<JMethod>>();
+
+  private int modifierBits;
+
+  private final String name;
+
+  private final String nestedName;
+
+  private final Map<String, JClassType> nestedTypes = new HashMap<String, JClassType>();
+
+  private final TypeOracle oracle;
+
+  private JClassType superclass;
+
+  public JRealClassType(TypeOracle oracle, CompilationUnitProvider cup,
+      JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
+      String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
+      boolean isInterface) {
+    oracle.recordTypeInCompilationUnit(cup, this);
+    this.oracle = oracle;
+    this.cup = cup;
+    this.declaringPackage = declaringPackage;
+    this.enclosingType = enclosingType;
+    this.isLocalType = isLocalType;
+    this.name = name;
+    this.declStart = declStart;
+    this.declEnd = declEnd;
+    this.bodyStart = bodyStart;
+    this.bodyEnd = bodyEnd;
+    this.isInterface = isInterface;
+    if (enclosingType == null) {
+      // Add myself to my package.
+      //
+      declaringPackage.addType(this);
+      // The nested name of a top-level class is its simple name.
+      //
+      nestedName = name;
+    } else {
+      // Add myself to my enclosing type.
+      //
+      enclosingType.addNestedType(this);
+      // Compute my "nested name".
+      //
+      JClassType enclosing = enclosingType;
+      String nn = name;
+      do {
+        nn = enclosing.getSimpleSourceName() + "." + nn;
+        enclosing = enclosing.getEnclosingType();
+      } while (enclosing != null);
+      nestedName = nn;
+    }
+  }
+
+  public void addAnnotations(
+      Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
+    annotations.addAnnotations(declaredAnnotations);
+  }
+
+  public void addImplementedInterface(JClassType intf) {
+    assert (intf != null);
+    interfaces.add(intf);
+  }
+
+  public void addMetaData(String tagName, String[] values) {
+    metaData.addMetaData(tagName, values);
+  }
+
+  public void addModifierBits(int bits) {
+    modifierBits |= bits;
+  }
+
+  public JConstructor findConstructor(JType[] paramTypes) {
+    JConstructor[] ctors = getConstructors();
+    for (int i = 0; i < ctors.length; i++) {
+      JConstructor candidate = ctors[i];
+      if (candidate.hasParamTypes(paramTypes)) {
+        return candidate;
+      }
+    }
+    return null;
+  }
+
+  public JField findField(String name) {
+    return fields.get(name);
+  }
+
+  public JMethod findMethod(String name, JType[] paramTypes) {
+    JMethod[] overloads = getOverloads(name);
+    for (int i = 0; i < overloads.length; i++) {
+      JMethod candidate = overloads[i];
+      if (candidate.hasParamTypes(paramTypes)) {
+        return candidate;
+      }
+    }
+    return null;
+  }
+
+  public JClassType findNestedType(String typeName) {
+    String[] parts = typeName.split("\\.");
+    return findNestedTypeImpl(parts, 0);
+  }
+
+  public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+    return annotations.getAnnotation(annotationClass);
+  }
+
+  public Annotation[] getAnnotations() {
+    return annotations.getAnnotations();
+  }
+
+  public int getBodyEnd() {
+    return bodyEnd;
+  }
+
+  public int getBodyStart() {
+    return bodyStart;
+  }
+
+  public CompilationUnitProvider getCompilationUnit() {
+    return cup;
+  }
+
+  public JConstructor getConstructor(JType[] paramTypes)
+      throws NotFoundException {
+    JConstructor result = findConstructor(paramTypes);
+    if (result == null) {
+      throw new NotFoundException();
+    }
+    return result;
+  }
+
+  public JConstructor[] getConstructors() {
+    return constructors.toArray(TypeOracle.NO_JCTORS);
+  }
+
+  public Annotation[] getDeclaredAnnotations() {
+    return annotations.getDeclaredAnnotations();
+  }
+
+  public JClassType getEnclosingType() {
+    return enclosingType;
+  }
+
+  @Override
+  public JClassType getErasedType() {
+    return this;
+  }
+
+  public JField getField(String name) {
+    JField field = findField(name);
+    assert (field != null);
+    return field;
+  }
+
+  public JField[] getFields() {
+    return fields.values().toArray(TypeOracle.NO_JFIELDS);
+  }
+
+  public JClassType[] getImplementedInterfaces() {
+    return interfaces.toArray(TypeOracle.NO_JCLASSES);
+  }
+
+  @Override
+  public String getJNISignature() {
+    String typeName = nestedName.replace('.', '$');
+    String packageName = getPackage().getName().replace('.', '/');
+    if (packageName.length() > 0) {
+      packageName += "/";
+    }
+    return "L" + packageName + typeName + ";";
+  }
+
+  public String[][] getMetaData(String tagName) {
+    return metaData.getMetaData(tagName);
+  }
+
+  public String[] getMetaDataTags() {
+    return metaData.getMetaDataTags();
+  }
+
+  public JMethod getMethod(String name, JType[] paramTypes)
+      throws NotFoundException {
+    JMethod result = findMethod(name, paramTypes);
+    if (result == null) {
+      throw new NotFoundException();
+    }
+    return result;
+  }
+
+  /*
+   * Returns the declared methods of this class (not any superclasses or
+   * superinterfaces).
+   */
+  public JMethod[] getMethods() {
+    List<JMethod> resultMethods = new ArrayList<JMethod>();
+    for (List<JMethod> overloads : methods.values()) {
+      resultMethods.addAll(overloads);
+    }
+    return resultMethods.toArray(TypeOracle.NO_JMETHODS);
+  }
+
+  public String getName() {
+    return nestedName;
+  }
+
+  public JClassType getNestedType(String typeName) throws NotFoundException {
+    JClassType result = findNestedType(typeName);
+    if (result == null) {
+      throw new NotFoundException();
+    }
+    return result;
+  }
+
+  public JClassType[] getNestedTypes() {
+    return nestedTypes.values().toArray(TypeOracle.NO_JCLASSES);
+  }
+
+  public TypeOracle getOracle() {
+    return oracle;
+  }
+
+  public JMethod[] getOverloads(String name) {
+    List<?> resultMethods = methods.get(name);
+    if (resultMethods != null) {
+      return resultMethods.toArray(TypeOracle.NO_JMETHODS);
+    } else {
+      return TypeOracle.NO_JMETHODS;
+    }
+  }
+
+  /**
+   * Iterates over the most-derived declaration of each unique overridable
+   * method available in the type hierarchy of the specified type, including
+   * those found in superclasses and superinterfaces. A method is overridable if
+   * it is not <code>final</code> and its accessibility is <code>public</code>,
+   * <code>protected</code>, or package protected.
+   * 
+   * Deferred binding generators often need to generate method implementations;
+   * this method offers a convenient way to find candidate methods to implement.
+   * 
+   * Note that the behavior does not match
+   * {@link Class#getMethod(String, Class[])}, which does not return the most
+   * derived method in some cases.
+   * 
+   * @return an array of {@link JMethod} objects representing overridable
+   *         methods
+   */
+  public JMethod[] getOverridableMethods() {
+    if (cachedOverridableMethods == null) {
+      Map<String, JMethod> methodsBySignature = new TreeMap<String, JMethod>();
+      getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature);
+      if (isClass() != null) {
+        getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature);
+      }
+      int size = methodsBySignature.size();
+      Collection<JMethod> leafMethods = methodsBySignature.values();
+      cachedOverridableMethods = leafMethods.toArray(new JMethod[size]);
+    }
+    return cachedOverridableMethods;
+  }
+
+  public JPackage getPackage() {
+    return declaringPackage;
+  }
+
+  @Override
+  public String getQualifiedSourceName() {
+    if (lazyQualifiedName == null) {
+      JPackage pkg = getPackage();
+      if (!pkg.isDefault()) {
+        lazyQualifiedName = pkg.getName() + "." + makeCompoundName(this);
+      } else {
+        lazyQualifiedName = makeCompoundName(this);
+      }
+    }
+    return lazyQualifiedName;
+  }
+
+  @Override
+  public String getSimpleSourceName() {
+    return name;
+  }
+
+  public JClassType[] getSubtypes() {
+    return allSubtypes.toArray(TypeOracle.NO_JCLASSES);
+  }
+
+  public JClassType getSuperclass() {
+    return superclass;
+  }
+
+  public String getTypeHash() throws UnableToCompleteException {
+    if (lazyHash == null) {
+      char[] source = cup.getSource();
+      int length = declEnd - declStart + 1;
+      String s = new String(source, declStart, length);
+      try {
+        lazyHash = Util.computeStrongName(s.getBytes(Util.DEFAULT_ENCODING));
+      } catch (UnsupportedEncodingException e) {
+        // Details, details...
+        throw new UnableToCompleteException();
+      }
+    }
+    return lazyHash;
+  }
+
+  public boolean isAbstract() {
+    return 0 != (modifierBits & TypeOracle.MOD_ABSTRACT);
+  }
+
+  public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+    return annotations.isAnnotationPresent(annotationClass);
+  }
+
+  @Override
+  public JArrayType isArray() {
+    // intentional null
+    return null;
+  }
+
+  public boolean isAssignableFrom(JClassType possibleSubtype) {
+    if (possibleSubtype == this) {
+      return true;
+    }
+    if (allSubtypes.contains(possibleSubtype)) {
+      return true;
+    } else if (this == getOracle().getJavaLangObject()) {
+      // This case handles the odd "every interface is an Object"
+      // but doesn't actually have Object as a superclass.
+      //
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  public boolean isAssignableTo(JClassType possibleSupertype) {
+    return possibleSupertype.isAssignableFrom(this);
+  }
+
+  @Override
+  public JClassType isClass() {
+    return isInterface ? null : this;
+  }
+
+  /**
+   * Determines if the class can be constructed using a simple <code>new</code>
+   * operation. Specifically, the class must
+   * <ul>
+   * <li>be a class rather than an interface, </li>
+   * <li>have either no constructors or a parameterless constructor, and</li>
+   * <li>be a top-level class or a static nested class.</li>
+   * </ul>
+   * 
+   * @return <code>true</code> if the type is default instantiable, or
+   *         <code>false</code> otherwise
+   */
+  public boolean isDefaultInstantiable() {
+    if (isInterface() != null) {
+      return false;
+    }
+    if (constructors.isEmpty()) {
+      return true;
+    }
+    JConstructor ctor = findConstructor(TypeOracle.NO_JTYPES);
+    if (ctor != null) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public JGenericType isGenericType() {
+    return null;
+  }
+
+  @Override
+  public JClassType isInterface() {
+    return isInterface ? this : null;
+  }
+
+  /**
+   * Tests if this type is a local type (within a method).
+   * 
+   * @return true if this type is a local type, whether it is named or
+   *         anonymous.
+   */
+  public boolean isLocalType() {
+    return isLocalType;
+  }
+
+  /**
+   * Tests if this type is contained within another type.
+   * 
+   * @return true if this type has an enclosing type, false if this type is a
+   *         top-level type
+   */
+  public boolean isMemberType() {
+    return enclosingType != null;
+  }
+
+  @Override
+  public JParameterizedType isParameterized() {
+    // intentional null
+    return null;
+  }
+
+  @Override
+  public JPrimitiveType isPrimitive() {
+    // intentional null
+    return null;
+  }
+
+  public boolean isPrivate() {
+    return 0 != (modifierBits & TypeOracle.MOD_PRIVATE);
+  }
+
+  public boolean isProtected() {
+    return 0 != (modifierBits & TypeOracle.MOD_PROTECTED);
+  }
+
+  public boolean isPublic() {
+    return 0 != (modifierBits & TypeOracle.MOD_PUBLIC);
+  }
+
+  @Override
+  public JRawType isRawType() {
+    // TODO Override in JGenericType?
+    return null;
+  }
+
+  public boolean isStatic() {
+    return 0 != (modifierBits & TypeOracle.MOD_STATIC);
+  }
+
+  public void setSuperclass(JClassType type) {
+    assert (type != null);
+    assert (isInterface() == null);
+    this.superclass = type;
+    JRealClassType realSuperType;
+    if (type.isParameterized() != null) {
+      realSuperType = type.isParameterized().getBaseType();
+    } else if (type.isRawType() != null) {
+      realSuperType = type.isRawType().getGenericType();
+    } else {
+      realSuperType = (JRealClassType) type;
+    }
+    annotations.setParent(realSuperType.annotations);
+  }
+
+  @Override
+  public String toString() {
+    if (isInterface) {
+      return "interface " + getQualifiedSourceName();
+    } else {
+      return "class " + getQualifiedSourceName();
+    }
+  }
+
+  protected void acceptSubtype(JClassType me) {
+    // TODO(scottb): revisit
+    allSubtypes.add(me);
+    notifySuperTypesOf(me);
+  }
+
+  protected int getModifierBits() {
+    return modifierBits;
+  }
+
+  protected void getOverridableMethodsOnSuperclassesAndThisClass(
+      Map<String, JMethod> methodsBySignature) {
+    assert (isClass() != null);
+
+    // Recurse first so that more derived methods will clobber less derived
+    // methods.
+    JClassType superClass = getSuperclass();
+    if (superClass != null) {
+      superClass.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature);
+    }
+
+    JMethod[] declaredMethods = getMethods();
+    for (int i = 0; i < declaredMethods.length; i++) {
+      JMethod method = declaredMethods[i];
+
+      // Ensure that this method is overridable.
+      if (method.isFinal() || method.isPrivate()) {
+        // We cannot override this method, so skip it.
+        continue;
+      }
+
+      // We can override this method, so record it.
+      String sig = computeInternalSignature(method);
+      methodsBySignature.put(sig, method);
+    }
+  }
+
+  /**
+   * Gets the methods declared in interfaces that this type extends. If this
+   * type is a class, its own methods are not added. If this type is an
+   * interface, its own methods are added. Used internally by
+   * {@link #getOverridableMethods()}.
+   * 
+   * @param methodsBySignature
+   */
+  protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(
+      Map<String, JMethod> methodsBySignature) {
+    // Recurse first so that more derived methods will clobber less derived
+    // methods.
+    JClassType[] superIntfs = getImplementedInterfaces();
+    for (int i = 0; i < superIntfs.length; i++) {
+      JClassType superIntf = superIntfs[i];
+      superIntf.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature);
+    }
+
+    if (isInterface() == null) {
+      // This is not an interface, so we're done after having visited its
+      // implemented interfaces.
+      return;
+    }
+
+    JMethod[] declaredMethods = getMethods();
+    for (int i = 0; i < declaredMethods.length; i++) {
+      JMethod method = declaredMethods[i];
+
+      String sig = computeInternalSignature(method);
+      JMethod existing = methodsBySignature.get(sig);
+      if (existing != null) {
+        JClassType existingType = existing.getEnclosingType();
+        JClassType thisType = method.getEnclosingType();
+        if (thisType.isAssignableFrom(existingType)) {
+          // The existing method is in a more-derived type, so don't replace it.
+          continue;
+        }
+      }
+      methodsBySignature.put(sig, method);
+    }
+  }
+
+  /**
+   * Tells this type's superclasses and superinterfaces about it.
+   */
+  protected void notifySuperTypesOf(JClassType me) {
+    // TODO(scottb): revisit
+    if (superclass != null) {
+      superclass.acceptSubtype(me);
+    }
+    for (int i = 0, n = interfaces.size(); i < n; ++i) {
+      JClassType intf = interfaces.get(i);
+      intf.acceptSubtype(me);
+    }
+  }
+
+  protected void removeSubtype(JClassType me) {
+    // TODO(scottb): revisit
+    allSubtypes.remove(me);
+
+    if (superclass != null) {
+      superclass.removeSubtype(me);
+    }
+
+    for (int i = 0, n = interfaces.size(); i < n; ++i) {
+      JClassType intf = interfaces.get(i);
+
+      intf.removeSubtype(me);
+    }
+  }
+
+  void addConstructor(JConstructor ctor) {
+    assert (!constructors.contains(ctor));
+    constructors.add(ctor);
+  }
+
+  void addField(JField field) {
+    Object existing = fields.put(field.getName(), field);
+    assert (existing == null);
+  }
+
+  void addMethod(JMethod method) {
+    String methodName = method.getName();
+    List<JMethod> overloads = methods.get(methodName);
+    if (overloads == null) {
+      overloads = new ArrayList<JMethod>();
+      methods.put(methodName, overloads);
+    }
+    overloads.add(method);
+  }
+
+  void addNestedType(JClassType type) {
+    nestedTypes.put(type.getSimpleSourceName(), type);
+  }
+
+  JClassType findNestedTypeImpl(String[] typeName, int index) {
+    JClassType found = nestedTypes.get(typeName[index]);
+    if (found == null) {
+      return null;
+    } else if (index < typeName.length - 1) {
+      return found.findNestedTypeImpl(typeName, index + 1);
+    } else {
+      return found;
+    }
+  }
+
+  void notifySuperTypes() {
+    notifySuperTypesOf(this);
+  }
+
+  /**
+   * Removes references to this instance from all of its super types.
+   */
+  void removeFromSupertypes() {
+    removeSubtype(this);
+  }
+
+  private String computeInternalSignature(JMethod method) {
+    StringBuffer sb = new StringBuffer();
+    sb.setLength(0);
+    sb.append(method.getName());
+    JParameter[] params = method.getParameters();
+    for (int j = 0; j < params.length; j++) {
+      JParameter param = params[j];
+      sb.append("/");
+      sb.append(param.getType().getQualifiedSourceName());
+    }
+    return sb.toString();
+  }
+
+}