private List<Tuple> _addAncestorJavaClassTuples(
      JavaClass javaClass, List<Tuple> ancestorJavaClassTuples) {

    JavaClass superJavaClass = javaClass.getSuperJavaClass();

    if (superJavaClass != null) {
      ancestorJavaClassTuples.add(new Tuple(superJavaClass));

      ancestorJavaClassTuples =
          _addAncestorJavaClassTuples(superJavaClass, ancestorJavaClassTuples);
    }

    Type[] implementz = javaClass.getImplements();

    for (Type implement : implementz) {
      Type[] actualTypeArguments = implement.getActualTypeArguments();
      JavaClass implementedInterface = implement.getJavaClass();

      if (actualTypeArguments == null) {
        ancestorJavaClassTuples.add(new Tuple(implementedInterface));
      } else {
        ancestorJavaClassTuples.add(new Tuple(implementedInterface, actualTypeArguments));
      }

      ancestorJavaClassTuples =
          _addAncestorJavaClassTuples(implementedInterface, ancestorJavaClassTuples);
    }

    return ancestorJavaClassTuples;
  }
  private void _addReturnElement(Element methodElement, JavaMethod javaMethod) throws Exception {

    Type returns = javaMethod.getReturns();

    if (returns == null) {
      return;
    }

    String returnsValue = returns.getValue();

    if (returnsValue.equals("void")) {
      return;
    }

    Element returnElement = methodElement.addElement("return");

    DocletTag[] returnDocletTags = javaMethod.getTagsByName("return");

    String comment = StringPool.BLANK;

    if (returnDocletTags.length > 0) {
      DocletTag returnDocletTag = returnDocletTags[0];

      comment = GetterUtil.getString(returnDocletTag.getValue());

      DocUtil.add(returnElement, "required", true);
    }

    comment = _trimMultilineText(comment);

    Element commentElement = returnElement.addElement("comment");

    commentElement.addCDATA(comment);
  }
  private void _addThrowsElement(
      Element methodElement, Type exception, DocletTag[] throwsDocletTags) {

    String name = exception.getJavaClass().getName();
    String value = null;

    for (DocletTag throwsDocletTag : throwsDocletTags) {
      String curValue = throwsDocletTag.getValue();

      if (!curValue.startsWith(name)) {
        continue;
      } else {
        curValue = value;

        break;
      }
    }

    Element throwsElement = methodElement.addElement("throws");

    DocUtil.add(throwsElement, "name", name);
    DocUtil.add(throwsElement, "type", exception.getValue());

    if (value != null) {
      value = value.substring(name.length());
    }

    Element commentElement = throwsElement.addElement("comment");

    commentElement.addCDATA(_getCDATA(value));
  }
  private void _addReturnElement(Element methodElement, JavaMethod javaMethod) {

    Type returns = javaMethod.getReturns();

    if ((returns == null) || returns.getValue().equals("void")) {
      return;
    }

    _addDocletElements(methodElement, javaMethod, "return");
  }
  private String _getTypeValue(JavaParameter javaParameter) {
    Type type = javaParameter.getType();

    String typeValue = type.getValue();

    if (type.isArray()) {
      typeValue += "[]";
    }

    return typeValue;
  }
  private String _getDimensions(Type type) {
    String dimensions = "";

    for (int i = 0; i < type.getDimensions(); i++) {
      dimensions += "[]";
    }

    return dimensions;
  }
  private boolean _hasAnnotation(
      AbstractBaseJavaEntity abstractBaseJavaEntity, String annotationName) {

    Annotation[] annotations = abstractBaseJavaEntity.getAnnotations();

    if (annotations == null) {
      return false;
    }

    for (int i = 0; i < annotations.length; i++) {
      Type type = annotations[i].getType();

      JavaClass javaClass = type.getJavaClass();

      if (annotationName.equals(javaClass.getName())) {
        return true;
      }
    }

    return false;
  }
  private void _copyInterface(String parentDir, String srcFile) throws IOException {

    JavaClass javaClass = _getJavaClass(parentDir, srcFile);

    JavaMethod[] methods = javaClass.getMethods();

    Arrays.sort(methods, new JavaMethodComparator());

    StringMaker sm = new StringMaker();

    // Package

    sm.append("package " + javaClass.getPackage() + ";");

    // Imports

    sm.append("[$IMPORTS$]");

    // Class declaration

    sm.append(
        "public class Copy" + javaClass.getName() + " implements " + javaClass.getName() + " {");

    String varName = "_" + TextFormatter.format(javaClass.getName(), TextFormatter.I);

    // Methods

    Set imports = new TreeSet();

    for (int i = 0; i < methods.length; i++) {
      JavaMethod javaMethod = methods[i];

      String methodName = javaMethod.getName();

      if (javaMethod.isPublic()) {
        String returnValueName = javaMethod.getReturns().getValue();

        imports.add(returnValueName);

        sm.append(
            "public "
                + javaMethod.getReturns().getJavaClass().getName()
                + _getDimensions(javaMethod.getReturns())
                + " "
                + methodName
                + "(");

        JavaParameter[] parameters = javaMethod.getParameters();

        for (int j = 0; j < parameters.length; j++) {
          JavaParameter javaParameter = parameters[j];

          sm.append(
              javaParameter.getType().getJavaClass().getName()
                  + _getDimensions(javaParameter.getType())
                  + " "
                  + javaParameter.getName());

          imports.add(javaParameter.getType().getValue());

          if ((j + 1) != parameters.length) {
            sm.append(", ");
          }
        }

        sm.append(")");

        Type[] thrownExceptions = javaMethod.getExceptions();

        Set newExceptions = new LinkedHashSet();

        for (int j = 0; j < thrownExceptions.length; j++) {
          Type thrownException = thrownExceptions[j];

          newExceptions.add(thrownException.getJavaClass().getName());

          imports.add(thrownException.getValue());
        }

        if (newExceptions.size() > 0) {
          sm.append(" throws ");

          Iterator itr = newExceptions.iterator();

          while (itr.hasNext()) {
            sm.append(itr.next());

            if (itr.hasNext()) {
              sm.append(", ");
            }
          }
        }

        sm.append("{");

        if (!returnValueName.equals("void")) {
          sm.append("return ");
        }

        sm.append(varName + "." + methodName + "(");

        for (int j = 0; j < parameters.length; j++) {
          JavaParameter javaParameter = parameters[j];

          sm.append(javaParameter.getName());

          if ((j + 1) != parameters.length) {
            sm.append(", ");
          }
        }

        sm.append(");");
        sm.append("}");
      }
    }

    // Fields

    sm.append("private " + javaClass.getName() + " " + varName + ";");

    // Class close brace

    sm.append("}");

    // Imports

    String content = sm.toString();

    sm = new StringMaker();

    Iterator itr = imports.iterator();

    while (itr.hasNext()) {
      String importClass = (String) itr.next();

      if (!importClass.equals("boolean")
          && !importClass.equals("double")
          && !importClass.equals("int")
          && !importClass.equals("long")
          && !importClass.equals("short")
          && !importClass.equals("void")) {
        sm.append("import " + importClass + ";");
      }
    }

    content = StringUtil.replace(content, "[$IMPORTS$]", sm.toString());

    // Write file

    File file =
        new File(
            parentDir
                + "/"
                + StringUtil.replace(javaClass.getPackage(), ".", "/")
                + "/Copy"
                + javaClass.getName()
                + ".java");

    ServiceBuilder.writeFile(file, content);
  }
  private boolean _isOverrideMethod(
      JavaClass javaClass, JavaMethod javaMethod, Collection<Tuple> ancestorJavaClassTuples) {

    if (javaMethod.isConstructor() || javaMethod.isPrivate() || javaMethod.isStatic()) {

      return false;
    }

    String methodName = javaMethod.getName();

    JavaParameter[] javaParameters = javaMethod.getParameters();

    Type[] types = new Type[javaParameters.length];

    for (int i = 0; i < javaParameters.length; i++) {
      types[i] = javaParameters[i].getType();
    }

    // Check for matching method in each ancestor

    for (Tuple ancestorJavaClassTuple : ancestorJavaClassTuples) {
      JavaClass ancestorJavaClass = (JavaClass) ancestorJavaClassTuple.getObject(0);

      JavaMethod ancestorJavaMethod = null;

      if (ancestorJavaClassTuple.getSize() > 1) {

        // LPS-35613

        Type[] ancestorActualTypeArguments = (Type[]) ancestorJavaClassTuple.getObject(1);

        Type[] genericTypes = new Type[types.length];

        for (int i = 0; i < types.length; i++) {
          Type type = types[i];

          String typeValue = type.getValue();

          boolean useGenericType = false;

          for (int j = 0; j < ancestorActualTypeArguments.length; j++) {

            if (typeValue.equals(ancestorActualTypeArguments[j].getValue())) {

              useGenericType = true;

              break;
            }
          }

          if (useGenericType) {
            genericTypes[i] = new Type("java.lang.Object");
          } else {
            genericTypes[i] = type;
          }
        }

        ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(methodName, genericTypes);
      } else {
        ancestorJavaMethod = ancestorJavaClass.getMethodBySignature(methodName, types);
      }

      if (ancestorJavaMethod == null) {
        continue;
      }

      boolean samePackage = false;

      JavaPackage ancestorJavaPackage = ancestorJavaClass.getPackage();

      if (ancestorJavaPackage != null) {
        samePackage = ancestorJavaPackage.equals(javaClass.getPackage());
      }

      // Check if the method is in scope

      if (samePackage) {
        return !ancestorJavaMethod.isPrivate();
      } else {
        if (ancestorJavaMethod.isProtected() || ancestorJavaMethod.isPublic()) {

          return true;
        } else {
          return false;
        }
      }
    }

    return false;
  }