@SuppressWarnings("unchecked")
  protected <S extends AbstractJavaStructure> PowerList<S> findTypeParts(
      JavaType type, PowerList<S> typeParts) {
    PowerList<S> ss = Power.list();

    for (AbstractJavaStructure typePart : typeParts) {
      String typeName = typePart.getType().getCanonicalName();
      Pattern p = Pattern.compile("^.*\\b(" + typeName + ")\\b.*$");

      Matcher m = p.matcher(type.getCanonicalName());
      while (m.find()) {
        ss.add((S) typePart);
      }
    }

    return ss;
  }
  protected JavaType replaceTypeParts(
      JavaType type,
      List<? extends AbstractJavaStructure> typeParts,
      Transformation<String, String> replacement) {
    String fullType = type.getCanonicalName();

    for (AbstractJavaStructure typePart : typeParts) {
      String typeName = typePart.getType().getCanonicalName();
      Pattern p = Pattern.compile("^.*\\b(" + typeName + ")\\b.*$");

      Matcher m = p.matcher(fullType);
      while (m.find()) {
        String simpleTypeName = New.type(m.group(1)).getSimpleName().toString();
        fullType =
            fullType.substring(0, m.start(1))
                + replacement.transform(simpleTypeName)
                + fullType.substring(m.end(1));
        m = p.matcher(fullType);
      }
    }

    return New.type(fullType);
  }
  @Override
  public boolean equals(Object obj) {
    if (obj == null) {
      return false;
    }
    if (obj == this) {
      return true;
    }
    if (!(obj instanceof JavaType)) {
      return false;
    }

    JavaType other = (JavaType) obj;
    return new EqualsBuilder()
        .appendSuper(super.equals(other))
        .append(this.getTypeClass(), other.getTypeClass())
        .append(this.getSimpleName(), other.getSimpleName())
        .append(this.getPackageName(), other.getPackageName())
        .append(this.getDefaultValue(), other.getDefaultValue())
        .append(this.getKind(), other.getKind())
        .isEquals();
  }